Reputation: 45
I've used Contour based approach but its detecting so many contours. How can I extract my ROI contour?
image = cv2.imread('ULTI.png')
original = image.copy()
cv2.imwrite("bg.png",bg)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
canny = cv2.Canny(blurred, 120, 255, 1)
kernel = np.ones((5,5),np.uint8)
dilate = cv2.dilate(canny, kernel, iterations=1)
# Find contours
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
# Iterate thorugh contours and filter for ROI
image_number = 0
cnts = max(cnts, key = cv2.contourArea)
print("no ",len(cnts))
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
ROI = original[y:y+h, x:x+w]
#cv2.imwrite("ROI_{}.png".format(image_number), ROI)
image_number += 1
Upvotes: 1
Views: 1127
Reputation: 27577
You can get your ROI by specifying that you only want to use the contour that has the greatest area, that is, if your diagram will produce a contour with an area greater then the rest of the components in your image.
Here is an example:
import cv2
def preprocess(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 1)
img_canny = cv2.Canny(img_blur, 50, 50)
return img_canny
def get_roi(img, pad=3):
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
max_area = 0
for cnt in contours:
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
x, y, w, h = cv2.boundingRect(approx)
rect_area = w * h
if rect_area > max_area:
max_area = rect_area
dim = x, y, w, h
if max_area:
x, y, w, h = dim
return x - pad, y - pad, w + pad * 2, h + pad * 2
img = cv2.imread("ULTI.png")
img_processed = preprocess(img)
x, y, w, h = get_roi(img_processed)
cv2.imshow("Image", img[y:y + h, x:x + w])
cv2.waitKey(0)
Output:
Explanation:
import cv2
def preprocess(img):
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
img_blur = cv2.GaussianBlur(img_gray, (5, 5), 1)
img_canny = cv2.Canny(img_blur, 50, 50)
return img_canny
def get_roi(img, pad=3):
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
max_area = 0
for
loop to loop through the contours, and find the area of the contour of each iteration of the loop: for cnt in contours:
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
area = cv2.contourArea(approx)
if
statement to check if the area is greater than the defined variable that should store that greatest area. If the are of the contour of that iteration is greater than the variable, update the value of the variable to be equal to the new area. Also, save the contour of that iteration to a variable: if area > max_area:
max_area = area
max_cnt = approx
for
loop, if the max_area
variable doesn't equal to 0
, then a max_cnt
has also been defined. Use the cv2.boundingRect
to get the x
, y
, w
and h
properties: if max_area:
x, y, w, h = cv2.boundingRect(max_cnt)
return x - pad, y - pad, w + pad * 2, h + pad * 2
img = cv2.imread("ULTI.png")
img_processed = preprocess(img)
x, y, w, h = get_roi(img_processed)
cv2.imshow("Image", img[y:y + h, x:x + w])
cv2.waitKey(0)
Note: The code likely will not work for all diagrams. But again, you can tweak the values in the preprocess
function to meet your needs.
Upvotes: 2