i am new with CV2 with python.
i have many images, they have many big and small curvy structures.
and i have to get the biggest big one contour among all.
but i failed.
my codes and images are below...
import cv2 as cv
img_color = cv.imread('ex1.png')
img_gray = cv.cvtColor(img_color, cv.COLOR_BGR2GRAY)
ret, img_binary = cv.threshold(img_gray, 127, 255, 0)
#dbg contours, hierarchy = cv.findContours(img_binary, cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)
_, contours, hierarchy = cv.findContours(img_binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for cnt in contours:
cv.drawContours(img_color, [cnt], 0, (255, 0, 0), 3) # blue
#dbg cv.imshow("result", img_color)
#dbg cv.waitKey(0)
cv.imwrite('save_image1.png', img_color)
for cnt in contours:
hull = cv.convexHull(cnt)
cv.drawContours(img_color, [hull], 0, (0, 0, 255), 5)
#dbg cv.imshow("result", img_color)
#dbg cv.waitKey(0)
cv.imwrite('save_image2.png', img_color)
example of input image ("ex1.png") is like...
the result output image ("save_image2.png") is like...
...
but,
what i want to retrieve is like below... (any of blue or red, i can use them ;)
i mean, the result contour must be just big one which includes everything.
thank you for reading util here(; )
CodePudding user response:
You asked for outline/contour of all regions rather than just the largest. So here is how to do that in Python/OpenCV.
- Read the input
- Convert to gray
- Threshold to binary
- Get all the points where the value is greater than 0 and transpose (since numpy use y,x convention and OpenCV wants x,y)
- Compute the convex hull of the points
- Draw a poly line on a copy of the input
- Draw a white filled polygon on a black image
- Get the contour of the white filled polygon
- Draw the contour on a copy of the input
- Save results
Input:
import cv2
import numpy as np
img_color = cv2.imread('ex1.png')
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
img_binary = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU)[1]
# get convex hull
points = np.column_stack(np.where(img_binary.transpose() > 0))
hull = cv2.convexHull(points)
# draw convex hull on input image in green
result = img_color.copy()
cv2.polylines(result, [hull], True, (0,0,255), 2)
# draw white filled hull polygon on black background
mask = np.zeros_like(img_binary)
cv2.fillPoly(mask, [hull], 255)
# get the largest contour from result2
contours = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
# draw contour on copy of input
contr = img_color.copy()
contr = cv2.drawContours(contr, [big_contour], 0, (0,0,255), 2)
# save result2
cv2.imwrite('ex1_convex_hull.png', result)
cv2.imwrite('ex1_convex_hull_contour.png', contr)
# show result2
cv2.imshow('result', result)
cv2.imshow('contr', contr)
cv2.waitKey(0)
cv2.destroyAllWindows()
Resulting convex hull:
Contour of convex hull:
CodePudding user response:
Here is one way to do that in Python/OpenCV.
Use max(contours, key=cv2.contourArea)
to get the largest one.
Input:
import cv2
img_color = cv2.imread('ex1.png')
img_gray = cv2.cvtColor(img_color, cv2.COLOR_BGR2GRAY)
img_binary = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU)[1]
contours = cv2.findContours(img_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
big_contour = max(contours, key=cv2.contourArea)
img_contour = img_color.copy()
cv2.drawContours(img_contour, [big_contour], 0, (0,0,255), 2)
cv2.imwrite('ex1_contour.png', img_contour)
cv2.imshow('img_contour', img_contour)
cv2.waitKey(0)
cv2.destroyAllWindows()