Reputation: 45
I want to find and draw biggest contour on this frame.
I can find the contours. but when i try to find the biggest contour, it shows a small contour on frame as a biggest frame. when i just draw contours i can see clearly that there is a big contour around the object
here is my try:
import cv2
import numpy as np
#capture.release()
cv2.destroyAllWindows()
capture = cv2.VideoCapture(1)
panel = np.zeros([100, 700], np.uint8)
cv2.namedWindow('panel')
def nothing(x):
pass
#some code about trackbar and panel here
while(True):
ret, frame = capture.read()
#some code about trackbar and panel here
roi = frame[s_r: e_r, s_c: e_c]
roi = cv2.GaussianBlur(roi, (5, 5), 0) #sigma = 0
hsv = cv2.cvtColor( roi, cv2.COLOR_RGB2HSV)
#some code about trackbar and panel here
mask = cv2.inRange(hsv, lower_green, upper_green)
mask_inv = cv2.bitwise_not(mask)
bg = cv2.bitwise_and( roi, roi, mask=mask)
fg = cv2.bitwise_and( roi, roi, mask=mask_inv)
gray = cv2.cvtColor(fg, cv2.COLOR_BGR2GRAY)
contours, hierarchy = cv2.findContours(gray,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
max_area = 0
for contour in contours:
area = cv2.contourArea(contour)
if area > max_area:
area = max_area
x,y,w,h = cv2.boundingRect(contour)
cv2.rectangle(fg,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow('bg', bg)
cv2.imshow('fg', fg)
cv2.imshow('panel', panel)
if cv2.waitKey(30) == 27: #siradaki frame'e gecmeden once 30 ms bekle
break
capture.release()
cv2.destroyAllWindows()
Upvotes: 0
Views: 3841
Reputation: 53081
This method seems to work for me in Python/OpenCV. I do a simple threshold. Then use morphology to smooth and fill in some. Then I get the contours and filter on area. Then I draw the contour on the image. Note that it is sensitive to the size of the morphology kernel and needs to be at least 10 or 11. But if you make it too big, it will change the shape of the region.
Input:
import cv2
import numpy as np
# load image
img = cv2.imread("green_and_red_regions.png")
# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# threshold image
thresh = cv2.threshold(gray,4,255,0)[1]
# apply morphology open to smooth the outline
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)
# find contours
cntrs = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cntrs = cntrs[0] if len(cntrs) == 2 else cntrs[1]
# Contour filtering to get largest area
area_thresh = 0
for c in cntrs:
area = cv2.contourArea(c)
if area > area_thresh:
area = area_thresh
big_contour = c
# draw the contour on a copy of the input image
results = img.copy()
cv2.drawContours(results,[big_contour],0,(0,0,255),2)
# write result to disk
cv2.imwrite("greengreen_and_red_regions_threshold.png", thresh)
cv2.imwrite("green_and_red_regions_big_contour.png", results)
cv2.imshow("THRESH", thresh)
cv2.imshow("RESULTS", results)
cv2.waitKey(0)
cv2.destroyAllWindows()
Thresholded and Smoothed Image:
Contour Outline Drawn On Input:
Upvotes: 2
Reputation: 53081
Python/OpenCV solution:
In your loop over contours, simply do your own finding of the largest area and corresponding boundingRect of that contour.
max_area = 0
for contour in contours:
area = cv2.contourArea(contour)
if area > max_area:
area = max_area
x,y,w,h = cv2.boundingRect(contour)
Alternately, just get the outer contour (presumably only one), if that is relevant to your image. (In the future, please show your input image).
contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
Upvotes: 0