Reputation: 687
I have a script which generate a HSV mask, and detect some rectangles based on area:
I've already included some area limits, my goal is to detect only the lowest bottom box (the one in red in above picture).
This is my detecting code part where I'd like to add the new function capable to keep only 1 box:
cnts, hierarchy = cv2.findContours(mask_merged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in cnts:
p_box = round((cv2.contourArea(c)/image_area)*100,1)
print('p_box'+str(p_box))
if (p_box <= 2.2) and (p_box >= 0.7):
(x, y, w, h) = cv2.boundingRect(c)
print(x,y,w,h)
print(cv2.contourArea(c))
cv2.imshow('frame_ocr_zone',image_src[y:y+h, x:x+w])
cv2.rectangle(image_src, (x,y), (x+w,y+h), (0, 255, 0), 2)
## BEGIN - draw rotated rectangle
rect = cv2.minAreaRect(c)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(image_src,[box],0,(123, 245, 66),5)
font = cv2.FONT_HERSHEY_SIMPLEX
color = (157,252,3)
thickness = 2
fontScale = 1
org = (x-50,y-20)
I was looking to code reported here: https://www.pyimagesearch.com/2015/04/20/sorting-contours-using-python-and-opencv/#pyi-pyimagesearch-plus-pricing-modal
I was thinking to modify the function here (sorting):
def sort_contours(cnts, method="left-to-right"):
# initialize the reverse flag and sort index
reverse = False
i = 0
# handle if we need to sort in reverse
if method == "right-to-left" or method == "bottom-to-top":
reverse = True
# handle if we are sorting against the y-coordinate rather than
# the x-coordinate of the bounding box
if method == "top-to-bottom" or method == "bottom-to-top":
i = 1
# construct the list of bounding boxes and sort them from top to
# bottom
boundingBoxes = [cv2.boundingRect(c) for c in cnts]
(cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
key=lambda b:b[1][i], reverse=reverse))
# return the list of sorted contours and bounding boxes
return (cnts, boundingBoxes)
But I cannot figure out on just retrieve 1 box (order top-to-bottom, and keep max of c?)
Thanks in advance for any suggestion.
###UPDATE I did found this post here: Python opencv sorting contours
This code is acually capable to do so:
def get_contour_precedence(contour, cols):
tolerance_factor = 10
origin = cv2.boundingRect(contour)
return ((origin[1] // tolerance_factor) * tolerance_factor) * cols + origin[0]
im, contours, h = cv2.findContours(img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours.sort(key=lambda x:get_contour_precedence(x, img.shape[1]))
Upvotes: 1
Views: 378
Reputation: 687
def get_contour_precedence(contour, cols):
tolerance_factor = 10
origin = cv2.boundingRect(contour)
return ((origin[1] // tolerance_factor) * tolerance_factor) * cols + origin[0]
im, contours, h = cv2.findContours(img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours.sort(key=lambda x:get_contour_precedence(x, img.shape[1]))
Upvotes: 0
Reputation: 6333
First we define initial X, and Intial Y as 0 also we don't have a contour so that is none then we are looping over contours check the x coordinate and y coordinate since the bottom corner has x and y are greater than others
intial_x,intial_y = 0,0
my_cnt =None
for c in cnts:
(x, y, w, h) = cv2.boundingRect(c)
if x>intial_x and y>intial_y:
my_cnt = c
intial_x = x+w
intial_y =y+h
else:
continue
Upvotes: 1