Reputation: 215
I want to use cv2.minAreaRect to obtain the maximum contour, as shown in the following image.
cnt, hierarchy = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
min_rect = cv2.minAreaRect(cnt[0])
box = np.int0(cv2.boxPoints(min_rect))
cv2.drawContours(temp_result, [box], 0, (255, 0, 0), 2)
I referred to this post to obtain the ordered coordinates for drawing. However, I obtained the following result, where the lines don't match and the four points cannot be used with cv2.minAreaRect.
def order_points(pts):
# initialzie a list of coordinates that will be ordered
# such that the first entry in the list is the top-left,
# the second entry is the top-right, the third is the
# bottom-right, and the fourth is the bottom-left
rect = np.zeros((4, 2), dtype = "float32")
# the top-left point will have the smallest sum, whereas
# the bottom-right point will have the largest sum
s = np.sum(pts, axis = 1)
rect[0] = pts[np.argmin(s)] # top-left
rect[2] = pts[np.argmax(s)] # bottom-right
# now, compute the difference between the points, the
# top-right point will have the smallest difference,
# whereas the bottom-left will have the largest difference
diff = np.diff(pts, axis = 1)
rect[1] = pts[np.argmin(diff)] # top-right
rect[3] = pts[np.argmax(diff)] # bottom-left
# return the ordered coordinates
return rect
#########################################################################
# pts = [(93, 50), (109, 82), (76, 47), (93, 77), (58, 38), (76, 72), (36, 32), (54, 67), (20, 27), (35, 62), (3, 22), (18, 56), (111, 54), (128, 87)]
t = order_points(pts)
cv2.line(temp_result, pt1=(int(t[0][0]), int(t[0][1])), pt2=(int(t[1][0]), int(t[1][1])), color=(0, 0, 255), thickness=2)
cv2.line(temp_result, pt1=(int(t[3][0]), int(t[3][1])), pt2=(int(t[2][0]), int(t[2][1])), color=(0, 0, 255), thickness=2)
Any help will be appreciated.
Upvotes: 0
Views: 834
Reputation: 32144
We may find the Convex hull of the merged contours:
merged_cnt = cv2.convexHull(np.vstack(cnt))
Code sample:
import cv2
import numpy as np
im_bw = cv2.imread('im_bw.png', cv2.IMREAD_GRAYSCALE) # Read im_bw as grayscale
temp_result = cv2.cvtColor(im_bw, cv2.COLOR_GRAY2BGR)
cnt, hierarchy = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Merge all the contours into one large contour - the result is the convex hull of all contour.
merged_cnt = cv2.convexHull(np.vstack(cnt))
cv2.drawContours(temp_result, [merged_cnt], 0, (255, 0, 0), 2)
# Show result for testing
cv2.imshow('temp_result', temp_result)
cv2.waitKey()
cv2.destroyAllWindows()
In case the objective is to approximate the contour to rectangular polygon, we may use simplify_contour
method from the following answer
approx = simplify_contour(merged_cnt)
cv2.drawContours(temp_result, [approx], 0, (0, 0, 255), 2)
In case the objective is to find minAreaRect
as stated in the title:
min_rect = cv2.minAreaRect(merged_cnt) # Fine minAreaRect of the merged contours
box = np.int0(cv2.boxPoints(min_rect))
We are getting the following output:
Upvotes: 5