Python cv.Minarealect2和ArcGIS(GIS软件)之间的结果不一致。可能的错误?
我有一组从多边形导出的点。我正在测试几种解决方案,以获得最小面积或矩形。作为基准,我使用的是ArcGIS(10.1) 一种解决方案是使用OpenCV的Python cv.Minarealect2和ArcGIS(GIS软件)之间的结果不一致。可能的错误?,python,debugging,opencv,geometry,Python,Debugging,Opencv,Geometry,我有一组从多边形导出的点。我正在测试几种解决方案,以获得最小面积或矩形。作为基准,我使用的是ArcGIS(10.1) 一种解决方案是使用OpenCV的cv.minarealect2() 函数cv.minarearct2查找 通过为二维点集和点集构建凸包,获得二维点集的最小面积 将旋转卡钳技术应用于船体 当我在shapefile中转换box\u vtx以便在ArcGIS中查看并与进行比较时,我可以看到此差异,如下图所示, 其中: 红色=多边形的边界 蓝色=ArGIS(10.1)中最小面积的矩形
cv.minarealect2()
函数cv.minarearct2查找
通过为二维点集和点集构建凸包,获得二维点集的最小面积
将旋转卡钳技术应用于船体
当我在shapefile中转换box\u vtx
以便在ArcGIS中查看并与进行比较时,我可以看到此差异,如下图所示,
其中:
- 红色=多边形的边界
- 蓝色=ArGIS(10.1)中最小面积的矩形
- 黄色和黑色=具有OpenCV最小面积的矩形
使用OpenCV与本文中提出的解决方案进行比较:
导入osgeo.gdal,ogr
导入cv
poly=“…\\polygon.shp”
shp=osgeo.ogr.Open(多边形)
layer=shp.GetLayer()
feature=layer.GetFeature(0)
几何图形=特征。GetGeometryRef()
pts=geometry.GetGeometryRef(0)
#获取多边形边界的点(上面的点)
点数=[]
对于xrange中的p(pts.GetPointCount()):
points.append((pts.GetX(p),pts.GetY(p)))
#凸包
CH1=几何体.convxhull
#我没有找到一种方法来提取这些点
打印CH1()
#使用openCV
cvxHull=cv.ConvexHull2(points,cv.CreateMemStorage(),return_points=True)
打印cvxHull
我还没有看过OpenCV代码,但在计算中,大x,y乘积很可能是从其他大x,y乘积中减去的。x值中的偏移量约为19位,y值中的偏移量约为23位,因此这种减法可能会导致从典型的双精度数字携带的53位中损失约42位。(见维基百科)黄色和黑色矩形的大小和形状看起来合理,但显示的宽度和长度(10.285…,18.335…)与(10.393,18.037…)有1%的不同,后者显示在
简而言之,OpenCV在minarealect2()
或BoxPoints()
中可能存在舍入、下溢或溢出问题
要检查或测试的内容包括:
•显示和打印OpenCV凸包计算的点
•在图形上,显示OpenCV和ArcGIS矩形的中心,并打印从这些中心到所显示矩形角的距离
•使用转换后的数据集(见下文)重新运行计算和图表,以减少相互减去大量数据的下溢效应
在OpenCV计算之前转换数据集可以将丢失的位数减半。通过如下代码生成一组新点,并尝试使用新数据集进行计算:
s = points # points = original data set
n = len(s)
cx = sum(zip(*s)[0])/n
cy = sum(zip(*s)[1])/n
points = map(lambda p: (p[0]-cx, p[1]-cy), s)
# Now points = translated data set
在上面的代码中,zip(*s)
将(x,y)点列表解压为两个列表,其中x值列在zip(*s)[0]中,y值列在zip(*s)[1]中。因此(cx,cy)表示s中列出的点的质心。映射表达式将函数应用于iterable的元素。该函数返回一个点,该点转换为(-cx,-cy)。贴图表达式的值是已转换点的列表。注意,最好设置cx=int(sum(zip(*s)[0])/n)
和cy=int(sum(zip(*s)[1])/n)
,以便晶格点仍然是晶格点,如果这是您正在计算的。删除较大偏移的有利效果仍然存在,并且在转换过程中会出现较少的舍入
注:我使用从数据集和外壳中减去的偏移量进行测试(假设外壳如中所示,可能如中所示),得到的结果不一致,与我在#13542855中给出的方法的结果不一致。因此,根据您的数字很难确定问题发生在哪里。下面显示了一个更简单的测试用例。该测试清楚地表明,大偏移会导致精度差。也许您可以通过ArcGIS运行类似的测试数据。以下是测试结果的一半。minarealect2()和BoxPoints()被赋予基数,并添加了偏移量;对于显示的结果,计算后会减去偏移量,以便比较结果。理想情况下,每列中的所有数字(ox、oy列除外)都是相同的;但随着ox,oy的增加,它们开始不同,很快变得几乎随机
ox oy T cx T cy height width theta
0 0 6.2500 7.7500 11.5709 13.7281 -78.6901
64 125 6.2500 7.7500 11.5709 13.7281 -78.6901
256 625 6.2500 7.7501 11.5709 13.7281 -78.6901
1024 3125 6.2500 7.7500 11.5709 13.7281 -78.6901
4096 15625 6.2500 7.7510 11.5709 13.7281 -78.6901
16384 78125 6.2500 7.7578 11.5709 13.7281 -78.6901
65536 390625 6.2500 7.7812 11.5709 13.7281 -78.6901
262144 1953125 6.3125 7.7500 11.5709 13.7281 -78.6901
1048576 9765625 6.2500 8.0000 11.5709 13.7281 -78.6901
4194304 48828125 7.0000 11.0000 12.0000 14.0000 -90.0000
16777216 244140625 8.0000 15.0000 16.0000 14.0000 -90.0000
67108864 1220703125 8.0000 -21.0000 16.0000 0.0000 -0.0000
以下是生成上述数据的代码:
#!/usr/bin/python
import cv
base = [(1,1), (0,4), (2,9), (5,11), (8,14), (13,9), (14,4), (12,3), (2,1), (1,1)]
ox, oy, boxes = 0, 0, []
print ' ox oy T cx T cy height width theta'
for i in range(3,15):
poly = map(lambda p: (p[0]+ox, p[1]+oy), base)
(x,y), (w,h), th = cv.MinAreaRect2(poly)
boxes.append((ox, oy, cv.BoxPoints(((x,y),(w,h),th))))
print ('{:10d} {:10d} {:9.4f} {:9.4f} {:9.4f} {:9.4f} {:9.4f}'.format(
ox, oy, x-ox, y-oy, w, h, th))
ox, oy = 4**i, 5**i
print '\n ox oy T x T y T x T y T x T y T x T y'
for (ox, oy, box) in boxes:
print '{:10d} {:10d}'.format(ox, oy),
for p in box:
print '{:9.4f} {:9.4f}'.format(p[0]-ox, p[1]-oy),
print
我在寻找最小面积边界矩形的Python解决方案时遇到了这个问题
这是我的实现,已经用Matlab进行了验证:
亲爱的jwpat7。你认为我需要向OpenCV的人发送反馈吗?PS:生活并不容易。今天早上,我非常高兴地找到了计算短轴和长轴的方法。我是诚实的。昨天晚上,我试图将您的方法压缩到一个函数中,但我实际上是Python编程的初学者,无法使用实际的capacity@Gianni当前位置从您的评论中我不清楚您是否能够尝试这些建议(以及它们是否有帮助)。另外,您使用的是什么版本的Python?我在Windows机器上使用的是Python 2.7。我从这个页面下载了用于Python扩展包的非官方Windows二进制文件OpenCV。问题是OpenCV是否有bug。我使用ArcGIS(处理空间数据的非常昂贵的软件)作为Benchmark@Gianni:jwpat7的任何建议是否改善了您的结果?您这样做的主要原因是什么..创建ArcGIS的替代方案,只是测试OpenCV?@martineau:我在做一个脚本(简单)在Python中,从多边形形状文件中提取多个索引。我这样做是为了几个递归:1-ArcGIS非常昂贵(超过8000美元),我只需要计算长度和宽度。2-创建一个特定的脚本t
s = points # points = original data set
n = len(s)
cx = sum(zip(*s)[0])/n
cy = sum(zip(*s)[1])/n
points = map(lambda p: (p[0]-cx, p[1]-cy), s)
# Now points = translated data set
ox oy T cx T cy height width theta
0 0 6.2500 7.7500 11.5709 13.7281 -78.6901
64 125 6.2500 7.7500 11.5709 13.7281 -78.6901
256 625 6.2500 7.7501 11.5709 13.7281 -78.6901
1024 3125 6.2500 7.7500 11.5709 13.7281 -78.6901
4096 15625 6.2500 7.7510 11.5709 13.7281 -78.6901
16384 78125 6.2500 7.7578 11.5709 13.7281 -78.6901
65536 390625 6.2500 7.7812 11.5709 13.7281 -78.6901
262144 1953125 6.3125 7.7500 11.5709 13.7281 -78.6901
1048576 9765625 6.2500 8.0000 11.5709 13.7281 -78.6901
4194304 48828125 7.0000 11.0000 12.0000 14.0000 -90.0000
16777216 244140625 8.0000 15.0000 16.0000 14.0000 -90.0000
67108864 1220703125 8.0000 -21.0000 16.0000 0.0000 -0.0000
#!/usr/bin/python
import cv
base = [(1,1), (0,4), (2,9), (5,11), (8,14), (13,9), (14,4), (12,3), (2,1), (1,1)]
ox, oy, boxes = 0, 0, []
print ' ox oy T cx T cy height width theta'
for i in range(3,15):
poly = map(lambda p: (p[0]+ox, p[1]+oy), base)
(x,y), (w,h), th = cv.MinAreaRect2(poly)
boxes.append((ox, oy, cv.BoxPoints(((x,y),(w,h),th))))
print ('{:10d} {:10d} {:9.4f} {:9.4f} {:9.4f} {:9.4f} {:9.4f}'.format(
ox, oy, x-ox, y-oy, w, h, th))
ox, oy = 4**i, 5**i
print '\n ox oy T x T y T x T y T x T y T x T y'
for (ox, oy, box) in boxes:
print '{:10d} {:10d}'.format(ox, oy),
for p in box:
print '{:9.4f} {:9.4f}'.format(p[0]-ox, p[1]-oy),
print