![](/img/trans.png)
[英]Python OpenCV - Extrapolating the largest rectangle off of a set of contour points
[英]How to draw lines parallel to the width of minimum area rectangle joing opposite contour points using OpenCV python
我正在尝试绘制与轮廓上绘制的最小面积矩形的宽度平行的线,这些矩形连接轮廓的相对点。 我打算用这个做的是找到轮廓的真实宽度。 为了找到对象的实际宽度,我目前在图像中使用参考 object 并找到每厘米像素值,该值用于将像素中获得的宽度值转换为厘米。要找到宽度,我使用的是最小面积矩形方法出现在 OpenCV 中,我还尝试找到最左边和最右边的轮廓点,然后将它们连接起来以找到长度,但这些值总是被过度预测。 以下是我用来查找值的代码。
commodity_mask = copy.deepcopy(r['masks'][i]).astype(np.uint8)
im, contours_m, hierarchy = cv2.findContours(commodity_mask, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
contours = max(contours_m, key=cv2.contourArea)leftmost = tuple(contours[contours[:,:,0].argmin()][0])
rightmost = tuple(contours[contours[:,:,0].argmax()][0])
topmost = tuple(contours[contours[:,:,1].argmin()][0])
bottommost = tuple(contours[contours[:,:,1].argmax()][0])
cv2.circle(minrect, leftmost, 8, (0, 50, 255), -1)
cv2.circle(minrect, rightmost, 8, (0, 50, 255), -1)
cv2.line(minrect, leftmost, rightmost, (0,0,255),2)
dist = np.sqrt((leftmost[0]-rightmost[0])**2 + (leftmost[1]-rightmost[1])**2)
dist = dist*ratio #finding distance b/w leftmost and rightmost contour point and converting them to pixels.
commodity_rect = cv2.minAreaRect(commodity_contour) # (top-left corner(x,y), (width, height), angle of rotation)
cv2.drawContours(minrect, [np.int0(cv2.boxPoints(commodity_rect))], 0, (0, 255, 0), 2)
(xrect, yrect), (wrect, hrect), alpha = commodity_rect
print('Width: ', wrect * ratio, 'Height: ', hrect * ratio)
r['masks'][i]
值是从图像中获得的第 i 个轮廓。
到目前为止,我已经实现了以下图像。
绿色框是在轮廓上绘制的最小面积矩形,红线连接轮廓的最左边和最右边的点。
我想做的是以下。
绘制平行于矩形宽度的线(黄色线)连接轮廓的相对点,然后我可以找到它们的长度并使用它们来找到轮廓的宽度。
这是原始图像,没有绘制矩形。
这将帮助您找到所需的线坐标。 我在轮廓点上使用了cv2.pointPolygonTest
来找到您想要的点。 更多关于cv2.pointPolygonTest
在这里
import numpy as np
import cv2
image = cv2.imread('image.png')
image = cv2.resize(image, (800, 800))
output_image = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
HSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
low = np.array([33, 91, 21])
high = np.array([253, 255, 255])
mask = cv2.inRange(HSV, low, high)
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
sorted_contour = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)
# As I know there is 6 max contour we want I'm selecting 6 contour only to creating perfact mask
selected_contour = sorted_contour[:6]
blank_mask = np.zeros_like(mask)
mask = cv2.drawContours(blank_mask, selected_contour, -1, 255, -1)
cv2.imshow("mask", mask)
for i, cnt in enumerate(selected_contour):
# find min enclosing rect
commodity_rect = cv2.minAreaRect(cnt)
cv2.drawContours(output_image, [np.int0(cv2.boxPoints(commodity_rect))], 0, (0, 255, 0), 2)
# find center point of rect
M = cv2.moments(cnt)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
cv2.circle(output_image, (cX, cY), 5, (0, 255, 255), -1)
selceted_points = [[px, cY] for [[px, py]] in cnt if cv2.pointPolygonTest(cnt, (px, cY), measureDist=False) == 0]
left_point = min(selceted_points, key=lambda x: x[0])
right_point = max(selceted_points, key=lambda x: x[0])
print(f"\nfor {i}th contour : ")
print("left_point : ", left_point)
print("right_point : ", right_point)
cv2.circle(output_image, tuple(left_point), 3, (255, 0, 0), -1)
cv2.circle(output_image, tuple(right_point), 3, (255, 0, 0), -1)
cv2.line(output_image, tuple(left_point), tuple(right_point), (0, 0, 255), 1)
cv2.imshow("output_image", output_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Output:
for 0th contour :
left_point : [606, 613]
right_point : [786, 613]
for 1th contour :
left_point : [73, 233]
right_point : [211, 233]
for 2th contour :
left_point : [329, 248]
right_point : [501, 248]
for 3th contour :
left_point : [58, 637]
right_point : [246, 637]
for 4th contour :
left_point : [364, 600]
right_point : [508, 600]
for 5th contour :
left_point : [605, 237]
right_point : [753, 237]
在解决方案一中,我误解了一些东西并在边界框上找到了一条水平线,这是您想要的线坐标。
import numpy as np
import cv2
def get_order_points(pts):
# first - top-left,
# second - top-right
# third - bottom-right
# fourth - bottom-left
rect = np.zeros((4, 2), dtype="int")
# top-left point will have the smallest sum
# bottom-right point will have the largest sum
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)]
rect[2] = pts[np.argmax(s)]
# top-right point will have the smallest difference
# bottom-left will have the largest difference
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)]
rect[3] = pts[np.argmax(diff)]
return rect
image = cv2.imread('image.png')
image = cv2.resize(image, (800, 800))
output_image = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
HSV = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
low = np.array([33, 91, 21])
high = np.array([253, 255, 255])
mask = cv2.inRange(HSV, low, high)
contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
sorted_contour = sorted(contours, key=lambda x: cv2.contourArea(x), reverse=True)
# As I know there is 6 max contour we want I'm selecting 6 contour only to creating perfact mask
selected_contour = sorted_contour[:6]
blank_mask = np.zeros_like(mask)
mask = cv2.drawContours(blank_mask, selected_contour, -1, 255, -1)
cv2.imshow("mask", mask)
cv2.imwrite("mask.png", mask)
for i, cnt in enumerate(selected_contour):
# find min enclosing rect
commodity_rect = cv2.minAreaRect(cnt)
bounding_rect_points = np.array(cv2.boxPoints(commodity_rect), dtype=np.int)
cv2.drawContours(output_image, [bounding_rect_points], 0, (0, 255, 0), 2)
tl, tr, br, bl = get_order_points(bounding_rect_points)
left_point = (tl + bl) // 2
right_point = (tr + br) // 2
print(f"\nfor {i}th contour : ")
print("left_point : ", left_point)
print("right_point : ", right_point)
cv2.circle(output_image, tuple(left_point), 3, (255, 0, 0), -1)
cv2.circle(output_image, tuple(right_point), 3, (255, 0, 0), -1)
cv2.line(output_image, tuple(left_point), tuple(right_point), (0, 0, 255), 1)
cv2.imshow("output_image", output_image)
cv2.imwrite("output_image.png", output_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Output:
for 0th contour :
left_point : [606 597]
right_point : [785 622]
for 1th contour :
left_point : [ 64 236]
right_point : [214 236]
for 2th contour :
left_point : [325 201]
right_point : [507 295]
for 3th contour :
left_point : [ 56 638]
right_point : [244 619]
for 4th contour :
left_point : [359 574]
right_point : [504 625]
for 5th contour :
left_point : [605 241]
right_point : [753 241]
你有没有尝试过这样的事情:
commodity_rect = cv2.minAreaRect(commodity_contour) #Find the minAreaRect for each contour
minAxis = round(min(commodity_rect[1])) #Find minor axis size
maxAxis = round(max(commodity_rect[1])) #Find major axis size
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.