如何将从 cv2.findContours 获得的 NumPy 数组转换为 Shapely 多边形?

Ops*_*ger 9 python opencv numpy shapely

我正在使用 CV2 从图像中查找轮廓,然后使用 Shapely 将它们转换为多边形。我目前陷入困境,因为当我尝试将其中一个轮廓数组放入Polygon()Shapely 时,它会引发未指定的错误。

我已经仔细检查过我导入了我需要的所有东西,并且当我手动输入数组坐标点时,创建一个 Shapely 多边形是有效的。

这是代码的问题部分:

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
testcontour = contours[1]

ply = Polygon(testcontour)
Run Code Online (Sandbox Code Playgroud)

轮廓列表如下所示:

contours = [np.array([[[700, 700]],
                      [[700, 899]],
                      [[899, 899]],
                      [[899, 700]]]), 
            np.array([[[774, 775]], 
                      [[775, 774]],
                      [[824, 774]],
                      [[825, 775]],
                      [[825, 824]],
                      [[824, 825]],
                      [[775, 825]],
                      [[774, 824]]]), 
            np.array([[[200, 200]],
                      [[200, 399]],
                      [[399, 399]],
                      [[399, 200]]]), 
            np.array([[[274, 275]],
                      [[275, 274]],
                      [[324, 274]],
                      [[325, 275]],
                      [[325, 324]],
                      [[324, 325]],
                      [[275, 325]],
                      [[274, 324]]])]
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-65-4124f49b42e1> in <module>
----> 1 ply = Polygon(testcontour)

~\AppData\Local\Continuum\anaconda3\envs\geocomp\lib\site-packages\shapely\geometry\polygon.py in __init__(self, shell, holes)
    238 
    239         if shell is not None:
--> 240             ret = geos_polygon_from_py(shell, holes)
    241             if ret is not None:
    242                 self._geom, self._ndim = ret

~\AppData\Local\Continuum\anaconda3\envs\geocomp\lib\site-packages\shapely\geometry\polygon.py in geos_polygon_from_py(shell, holes)
    492 
    493     if shell is not None:
--> 494         ret = geos_linearring_from_py(shell)
    495         if ret is None:
    496             return None

~\AppData\Local\Continuum\anaconda3\envs\geocomp\lib\site-packages\shapely\speedups\_speedups.pyx in shapely.speedups._speedups.geos_linearring_from_py()

AssertionError: 
Run Code Online (Sandbox Code Playgroud)

Geo*_*rgy 11

问题是由于某种原因cv2.findContours将每个轮廓作为具有一个冗余维度的 3D NumPy 数组返回:

>>> contours[1]
array([[[774, 775]],
       [[775, 774]],
       [[824, 774]],
       [[825, 775]],
       [[825, 824]],
       [[824, 825]],
       [[775, 825]],
       [[774, 824]]])
Run Code Online (Sandbox Code Playgroud)

但 Shapely 需要这种形式的 2D 数组(请参阅文档):

array([[774, 775],
       [775, 774],
       [824, 774],
       [825, 775],
       [825, 824],
       [824, 825],
       [775, 825],
       [774, 824]])
Run Code Online (Sandbox Code Playgroud)

所以,我们可以做的是使用np.squeeze去除那个多余的维度,并使用结果来获得我们的多边形:

import numpy as np
from shapely.geometry import Polygon

contour = np.squeeze(contours[1])
polygon = Polygon(contour)
print(polygon.wkt)
# POLYGON ((774 775, 775 774, 824 774, 825 775, 825 824, 824 825, 775 825, 774 824, 774 775))
Run Code Online (Sandbox Code Playgroud)

如果您想一次转换所有轮廓,我会这样做:

contours = map(np.squeeze, contours)  # removing redundant dimensions
polygons = map(Polygon, contours)  # converting to Polygons
multipolygon = MultiPolygon(polygons)  # putting it all together in a MultiPolygon
Run Code Online (Sandbox Code Playgroud)

结果multipolygon将如下所示:

在此处输入图片说明

要从这里获取第二个多边形,您只需编写:

my_polygon = multipolygon[1]
print(my_polygon.wkt)
# POLYGON ((774 775, 775 774, 824 774, 825 775, 825 824, 824 825, 775 825, 774 824, 774 775))
Run Code Online (Sandbox Code Playgroud)