c#-如何按顺时针顺序(tl、tr、br、bl)排列4个点的列表,以便在opencv getPerspective中使用?

c#-如何按顺时针顺序(tl、tr、br、bl)排列4个点的列表,以便在opencv getPerspective中使用?,c#,python,arrays,sorting,opencv,C#,Python,Arrays,Sorting,Opencv,我正在使用c#中的opencv检测网络摄像头图像中的轮廓。如果轮廓有4个点,我想使用opencv的getPerspective和warpPerspective来校正此轮廓中包含的像素的透视图。功能 以下是获得这4点的代码: Imgproc.approxPolyDP(perimMat,polyMat,0.005 * perim, true); //get contour of the current detected perimeter as polyMat List<Poi

我正在使用c#中的opencv检测网络摄像头图像中的轮廓。如果轮廓有4个点,我想使用opencv的
getPerspective
warpPerspective
来校正此轮廓中包含的像素的透视图。功能

以下是获得这4点的代码:

    Imgproc.approxPolyDP(perimMat,polyMat,0.005 * perim, true); //get contour of the current detected perimeter as polyMat
    List<Point> polyMatList = polyMat.toList(); //convert it to a list of points
    if (polyMatList.Count == 4){ //this contour has 4 points, we can use it for getting perspective
      Debug.Log("p1x: " + polyMatList[0].x + "p1y: " + polyMatList[0].y); //example log: p1x: 203,p1y: 111
    }
Imgproc.approxPolyDP(perimMat,polyMat,0.005*perim,真)//以polyMat的形式获取当前检测周长的轮廓
List polyMatList=polyMat.toList()//将其转换为点列表
如果(polyMatList.Count==4){//此轮廓有4个点,我们可以使用它获取透视图
Debug.Log(“p1x:+polyMatList[0].x+“p1y:+polyMatList[0].y);//示例日志:p1x:203,p1y:111
}
现在我有了这个点列表,我需要确保它的顺序是左上角、右上角、右下角、左下角,这样我就可以在
getPerspective
中使用它了。我该怎么做

我见过其他语言的例子,但它们通常使用numpy之类的东西来进行排序。我对C#(由于统一性而使用它)有点不熟悉,但我假设有一些辅助方法可以从中借鉴

到目前为止,这一直是我调整透视图的主要指南,而
for_point_warp
函数似乎提供了一个不错的指南。我只是不知道c的等价物。

//首先使用list.sort()按y值对列表进行排序
polymatalist.sort((pnt_a,pnt_b)=>pnt_b.y-pnt_a.y);//根据定义,点0和点1将是你的最高点,点2和点3将是你的最低点。
//现在,您的前2点可能不符合顺序,因为我们在上一步中仅按y排序
点温点;
if(多材料列表[0].x>多材料列表[1].x)
{
tempPoint=polymatalist[0];
多材料列表[0]=多材料列表[1];
polyMatList[1]=临时点;
}
//这同样适用于你的底线两点
if(polyMatList[2].x>polyMatList[3].x)
{
tempPoint=多元材料列表[2];
多元材料列表[2]=多元材料列表[3];
polyMatList[3]=临时点;
}
//现在您的列表将按tl、tr、bl、br排序

以下是我基于的实现(尽管我相信我可以做一些更优雅的事情)

polyMat.convertTo(方向码,CvType.cv32s)//将MatOfPoint2f转换回MatofPoint,以便可以绘制
//按y值排序
polyMatList=polyMatList.OrderBy(p=>p.x.ToList();
List leftmostPts=新列表();
leftmostPts.Add(polyMatList[0]);
leftmostPts.Add(polyMatList[1]);
List rightmostPts=新列表();
添加(polyMatList[2]);
添加(polyMatList[3]);
//我们现在有一个左上角的点
leftmostPts=leftmostPts.OrderBy(p=>p.y.ToList();
//计算从左上方到最右侧的2个点之间的距离:
double dX0=rightmostPts[0].x-leftmostPts[0].x;
双dY0=rightmostPts[0].y-leftmostPts[0].y;
双d0=数学Sqrt(dX0*dX0+dY0*dY0);
double dX1=rightmostPts[1].x-leftmostPts[0].x;
双dY1=rightmostPts[1].y-leftmostPts[0].y;
双d1=数学Sqrt(dX1*dX1+dY1*dY1);
List orderedPolyMat=新列表();
orderedPolyMat.Add(leftmostPts[0]);
如果(d0>d1){//右两点之间的最大距离为右下角
orderedPolyMat.Add(rightmostPts[1]);
orderedPolyMat.Add(rightmostPts[0]);
}否则{
orderedPolyMat.Add(rightmostPts[0]);
orderedPolyMat.Add(rightmostPts[1]);
}
orderedPolyMat.Add(leftmostPts[1]);

我认为这不能正常工作。我正在记录值,但它们没有按正确的顺序出现:
0:{97176},1:{333156},2:{98424},3:{341431}
change polyMatList.sort((pnt_a,pnt_b)=>pnt_a.y-pnt_b.y)到polyMatList.sort((pnt_a,pnt_b)=>pnt_b.y-pnt_a.y)现在,y值最大的点将出现在列表的开头。注意,我在回答中概述的方法可能无法很好地处理退化情况,例如{(-1,0)(0,1)(1,0)(0,-1)}。您可以通过检查中间两个元素在按Y排序后是否具有相同的Y值来检测这种情况。在这种情况下,您应该在调用polyMatList.sort后立即按x值对中间的2个元素进行排序。
polyMat.convertTo(orientationMat, CvType.CV_32S); //conver MatOfPoint2f back to MatofPoint so it can be drawn
//sort by y val

polyMatList = polyMatList.OrderBy(p => p.x).ToList();

List<Point> leftmostPts = new List<Point>();
leftmostPts.Add(polyMatList[0]);
leftmostPts.Add(polyMatList[1]);

List<Point> rightmostPts = new List<Point>();
rightmostPts.Add(polyMatList[2]);
rightmostPts.Add(polyMatList[3]);

//we now have a top left point
leftmostPts = leftmostPts.OrderBy(p => p.y).ToList();

//calculate distance from top left to rightmost 2 points:
double dX0 = rightmostPts[0].x - leftmostPts[0].x;
double dY0 = rightmostPts[0].y - leftmostPts[0].y;
double d0 = Math.Sqrt(dX0 * dX0 + dY0 * dY0); 

double dX1 = rightmostPts[1].x - leftmostPts[0].x;
double dY1 = rightmostPts[1].y - leftmostPts[0].y;
double d1 = Math.Sqrt(dX1 * dX1 + dY1 * dY1);

List<Point> orderedPolyMat = new List<Point>();
orderedPolyMat.Add(leftmostPts[0]);
if (d0 > d1){ //greatest distance between right two points will be bottom right
    orderedPolyMat.Add(rightmostPts[1]);
    orderedPolyMat.Add(rightmostPts[0]);
} else {
    orderedPolyMat.Add(rightmostPts[0]);
    orderedPolyMat.Add(rightmostPts[1]);
}
orderedPolyMat.Add(leftmostPts[1]);