我正在开发一个Python脚本,它需要在图像上找到特定颜色的最大和第二大形状。为此,让我们看看下面的示例映像。我想找出两个淡米黄色矩形的坐标:
我设法获得了出现在掩码上的两个轮廓:
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)
上面的代码返回了以下列表:
[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'])
contour
和area
列contour
找到最大区域,面积最大的G 219
的质心
如果可以的话,这将解决问题的前半部分,即找到最大面积的质心:
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'>
的数据类型。所以我把最后一行改为:
centroid = cv2.moments(largest_contour.to_numpy())
它现在确保largest_contour
元素具有与contour
元素相同的数据类型(<class 'numpy.ndarray'>
)。然而,当重新运行代码时,我得到了完全相同的错误消息:Expected Ptr<cv::UMat> for argument 'array'
。
我将非常感谢对如何前进的任何帮助或提示!
发布于 2020-08-01 22:31:07
这里有一种在Python/OpenCV中实现它的方法。
colorspace
H 117保存结果>H 218f 219
)
输入:
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()
阈值图像:
最大两个等高线:
文本数据:
index1: 1 area1: 65033.0 cx1: 338 cy1: 71
index2: 0 area2: 37568.0 cx2: 339 cy2: 272
https://stackoverflow.com/questions/63209402
复制相似问题