首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Python OpenCV中寻找最大和第二大面积轮廓

在Python OpenCV中寻找最大和第二大面积轮廓
EN

Stack Overflow用户
提问于 2020-08-01 19:44:10
回答 1查看 1.2K关注 0票数 0

我正在开发一个Python脚本,它需要在图像上找到特定颜色的最大和第二大形状。为此,让我们看看下面的示例映像。我想找出两个淡米黄色矩形的坐标:

我设法获得了出现在掩码上的两个轮廓:

代码语言:javascript
运行
复制
img_path = "path\\to\\file.png"
img = cv2.imread(img_path)
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(imgHSV, np.array([21,7,240]), np.array([21,7,255]))
contours = cv2.findContours(mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = imutils.grab_contours(contours)

上面的代码返回了以下列表:

代码语言:javascript
运行
复制
[array([[[  8, 245]], [[  7, 246]], [[  6, 246]], [[  6, 247]], [[  5, 248]], [[  0, 248]], [[  0, 300]], [[676, 300]], [[676, 248]], [[675, 247]], [[675, 246]], [[674, 246]], [[673, 245]]], dtype=int32), 
array([[[ 19,  22]], [[ 18,  23]], [[ 18,  24]], [[ 17,  25]], [[ 17, 120]], [[ 18, 121]], [[ 18, 122]], [[ 19, 123]], [[658, 123]], [[659, 122]], [[661, 122]], [[661,  23]], [[659,  23]], [[658,  22]]], dtype=int32)]

现在,已经确定了形状,我想通过编程找到第一和第二大形状的质心。现在很容易,因为只有两个这样的形状,但在实践中,我可能需要处理数十在同一图像。

我知道cv2.contourArea(c)返回轮廓的区域,cv2.moments(c)返回轮廓的质心(在这两种情况下,c表示contours列表中的一个元素)。

我尝试的方法如下:

max(df['area'])

  • find
  1. contourarea
  2. 在一个数据中组织等值线和区域,通过contour找到最大区域,面积最大的
  3. 得到

G 219的质心

如果可以的话,这将解决问题的前半部分,即找到最大面积的质心:

代码语言:javascript
运行
复制
contour_area = list()
for c in contours:
    contour_area.append(cv2.contourArea(c))
    M = cv2.moments(c)
df = pd.DataFrame(
    {'contour': contours,
     'area': contour_area
    })
largest_contour = df.loc[df['area'] == max(df['area']) ]['contour']
centroid = cv2.moments(largest_contour)

但是在运行它时,我在最后一行中得到了Expected Ptr<cv::UMat> for argument 'array'错误消息。我很快地检查了数据类型,发现原始的contour元素有<class 'numpy.ndarray'>的数据类型,而我的largest_contour元素现在有了<class 'pandas.core.series.Series'>的数据类型。所以我把最后一行改为:

代码语言:javascript
运行
复制
centroid = cv2.moments(largest_contour.to_numpy())

它现在确保largest_contour元素具有与contour元素相同的数据类型(<class 'numpy.ndarray'>)。然而,当重新运行代码时,我得到了完全相同的错误消息:Expected Ptr<cv::UMat> for argument 'array'

我将非常感谢对如何前进的任何帮助或提示!

EN

Stack Overflow用户

回答已采纳

发布于 2020-08-01 22:31:07

这里有一种在Python/OpenCV中实现它的方法。

colorspace

  • Threshold

  • 读取输入

  • 转换为HSV

  • Get contours

  • Create list of (索引、区域、cx、cy)为所有contours

  • Sort的区域列表按反向顺序

  • 打印前两个contours

  • Draw的索引、面积、cx、cy值两种不同颜色的轮廓(

H 117保存结果>H 218f 219)

输入:

代码语言:javascript
运行
复制
import cv2
import numpy as np

# read image
img = cv2.imread('rectangles2.png')

# convert to HSV
imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# threshold on color
lower=(21,7,240)
upper=(21,7,255)
thresh = cv2.inRange(imgHSV, lower, upper)

# get contours
result = img.copy() 
cntrs_info = []
contours = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
index=0
for cntr in contours:
    area = cv2.contourArea(cntr)
    M = cv2.moments(cntr)
    cx = int(M["m10"] / M["m00"])
    cy = int(M["m01"] / M["m00"])
    cntrs_info.append((index,area,cx,cy))
    index = index + 1
    #print(index,area,cx,cy)

# sort contours by area
def takeSecond(elem):
    return elem[1]
cntrs_info.sort(key=takeSecond, reverse=True)

# get index, area and centroid for first two sorted contours
index_first = cntrs_info[0][0]
area_first = cntrs_info[0][1]
cx_first = cntrs_info[0][2]
cy_first = cntrs_info[0][3]
print("index1:", index_first, "area1:", area_first, "cx1:", cx_first, "cy1:", cy_first)
cv2.drawContours(result,[contours[index_first]],0,(0,0,255),1)

index_second = cntrs_info[1][0]
area_second = cntrs_info[1][1]
cx_second = cntrs_info[1][2]
cy_second = cntrs_info[1][3]
print("index2:", index_second, "area2:", area_second, "cx2:", cx_second, "cy2:", cy_second)
cv2.drawContours(result,[contours[index_second]],0,(0,255,0),1)

# save results
cv2.imwrite('rectangles2_thresh.png',thresh)
cv2.imwrite('rectangles2_contours.png',result)

# show results
cv2.imshow("thresh", thresh)
cv2.imshow("result", result)

cv2.waitKey(0)
cv2.destroyAllWindows()

阈值图像:

最大两个等高线:

文本数据:

代码语言:javascript
运行
复制
index1: 1 area1: 65033.0 cx1: 338 cy1: 71
index2: 0 area2: 37568.0 cx2: 339 cy2: 272

票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63209402

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档