简体   繁体   English

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

[英]How to convert NumPy arrays obtained from cv2.findContours to Shapely polygons?

I am using CV2 to find contours from an image and then converting them into polygons using Shapely. 我正在使用CV2从图像中查找轮廓,然后使用Shapely将其转换为多边形。 I am currently stuck because when I try putting one of the contour arrays into Polygon() from Shapely it throws an unspecified error. 我目前陷入困境,因为当我尝试将一个轮廓数组从Shapely放入Polygon() ,会引发未指定的错误。

I have double-checked that I imported everything I needed, and that creating a Shapely polygon works when I manually enter the array coordinate points. 我已经仔细检查了是否导入了我需要的所有内容,以及当我手动输入数组坐标点时创建Shapely多边形的工作原理。

Here is the problematic section of the code: 这是代码中有问题的部分:

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

ply = Polygon(testcontour)

Where the list of contours looks like this: 轮廓列表如下所示:

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]]])]

The error I get is: 我得到的错误是:

---------------------------------------------------------------------------
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: 

The problem is that for some reason cv2.findContours returns each contour as a 3D NumPy array with one redundant dimension: 问题是由于某种原因cv2.findContours将每个轮廓作为具有一个冗余尺寸的3D NumPy数组返回:

>>> contours[1]
array([[[774, 775]],
       [[775, 774]],
       [[824, 774]],
       [[825, 775]],
       [[825, 824]],
       [[824, 825]],
       [[775, 825]],
       [[774, 824]]])

but Shapely expects a 2D array in this form ( see the docs ): 但Shapely希望采用这种形式的2D数组( 请参阅docs ):

array([[774, 775],
       [775, 774],
       [824, 774],
       [825, 775],
       [825, 824],
       [824, 825],
       [775, 825],
       [774, 824]])

So, what we can do is to use np.squeeze to remove that redundant dimension, and use the result to obtain our polygon: 因此,我们可以做的是使用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))

In case if you want to convert all of the contours at once, I would do it like this: 如果您想一次转换所有轮廓,我会这样做:

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

The resulting multipolygon will look like this: 产生的multipolygon将如下所示:

在此处输入图片说明

And to get the second polygon from here you would just write: 要从此处获取第二个多边形,您只需编写:

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))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM