A shape that is hollow, take the below situation as example, is detected as 2 objects, the outer triangle(can be seen as just an outline) is somehow detected as 2 objects as shown in the second image (2 green outline in and outside of the outer black triangle).
Second Image (Result from my code):
import os import cv2 import numpy as np file_name = os.path.join(os.path.dirname(__file__),'hollowtri.png') assert os.path.exists(file_name) a = cv2.imread(file_name) #Convert image to gray image imgGray = cv2.cvtColor(a,cv2.COLOR_BGR2GRAY) #Doing threshold on the image _,thresh = cv2.threshold(imgGray,100,255,cv2.THRESH_BINARY_INV) #Finding objects contours,_ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) #Print the result based on the contours found num = 0 for contour in contours: cv2.drawContours(a,contours,num,(0,255,0),2) num+=1 cv2.imshow("Thresh", thresh) cv2.imshow("Triangle", a) cv2.waitKey(0)
I don’t want to use
cv2.RETR_EXTERNAL because I want the inner solid triangle to be detected, so is there a solution to this problem? I want the outer triangle to be detected as just 1 object.
Note: Only the shape colored in black are the object of concerned. So the result should contain only 2 objects, but in image 2, the outer triangle is outlined in green twice, inside and outside, my goal is to outline it just once, because a hollow triangle is just 1 object, not 2.
To solve your problem the choice of
flag is important. We are dealing with a situation where there is a contour placed within another contour. We can make use of
RETR_CCOMP flag while finding contours
cv2.findContours(). And analyze the hierarchy output.
In the following binary image we have one object, but while finding contours we end up with 2 (meaning 2 distinct objects).
- Contour 1 (pointed in red) is the outer boundary of the object – this is the parent with value
- Contour 2 (pointed in green) is the inner boundary of the object – this is the child with value
We are interested in finding only the outer boundary of every distinct object. In the image above, that would be only Contour 1.
img = cv2.imread(r'C:\Users\524316\Desktop\Stack\tri.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) th = cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV) # using cv2.RETR_CCOMP flag contours,hierarchy = cv2.findContours(th,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE) # initializing an index list contour_index_list =  # draw every contour whose 4th column in hierarch array is -1 for index in range(0, len(contours)): if (hierarchy[:,index] == -1): contour_index_list.append(index) cv2.drawContours(img, [contours[index]], 0, (0, 255, 0), 3)
hierarchy variable gives an array, with each row assigned to each contour:
array([[[ 1, -1, -1, -1], [-1, 0, 2, -1], [-1, -1, -1, 1]]], dtype=int32)
According to the documentation, the 4th column indicates the parent-child relationship.
If the value is:
- -1 the contour is the parent
- 0 the contour is a child
Answered By – Jeru Luke
Answer Checked By – Candace Johnson (AngularFixing Volunteer)