I use OpenCV findContours() to extract contours, which I then draw in a figure. The contours themselves sometimes enclose holes. When using drawContours(), these holes are not drawn, but filled instead. I am using the full hierarchy, but do I also need to pass that hierarchy into the drawContours function somehow?
import cv2
import numpy as np
import matplotlib.pyplot as plt
f = "file"
width = 853
height = 418
img = cv2.imread(f,-1)
roi = np.zeros(img.shape[:2], np.uint16)
roi = cv2.rectangle(roi, (13,78), (width,height), 65535, cv2.FILLED)
mask = cv2.bitwise_and(roi, img)
threshold = 350
ret, th1 = cv2.threshold(mask,threshold,255,cv2.THRESH_BINARY)
contour,hier = cv2.findContours(th1.astype(np.uint8),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
canvas = np.zeros(img.shape[:2], np.uint8)
canvas2 = np.zeros(img.shape[:2], np.uint8)
for cnt in contour:
cv2.drawContours(canvas,[cnt],0,255,2)
cv2.drawContours(canvas2,[cnt],0,255,-1)
fig, ax = plt.subplots(3,1)
ax[0].imshow(img, 'gray')
ax[1].imshow(canvas, 'gray')
ax[2].imshow(canvas2, 'gray')
Which produces the following results
How can I prevent the inner contours from being filled?
I use OpenCV findContours() to extract contours, which I then draw in a figure. The contours themselves sometimes enclose holes. When using drawContours(), these holes are not drawn, but filled instead. I am using the full hierarchy, but do I also need to pass that hierarchy into the drawContours function somehow?
import cv2
import numpy as np
import matplotlib.pyplot as plt
f = "file"
width = 853
height = 418
img = cv2.imread(f,-1)
roi = np.zeros(img.shape[:2], np.uint16)
roi = cv2.rectangle(roi, (13,78), (width,height), 65535, cv2.FILLED)
mask = cv2.bitwise_and(roi, img)
threshold = 350
ret, th1 = cv2.threshold(mask,threshold,255,cv2.THRESH_BINARY)
contour,hier = cv2.findContours(th1.astype(np.uint8),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
canvas = np.zeros(img.shape[:2], np.uint8)
canvas2 = np.zeros(img.shape[:2], np.uint8)
for cnt in contour:
cv2.drawContours(canvas,[cnt],0,255,2)
cv2.drawContours(canvas2,[cnt],0,255,-1)
fig, ax = plt.subplots(3,1)
ax[0].imshow(img, 'gray')
ax[1].imshow(canvas, 'gray')
ax[2].imshow(canvas2, 'gray')
Which produces the following results
How can I prevent the inner contours from being filled?
Share Improve this question edited Feb 3 at 11:31 DozerD asked Feb 3 at 11:29 DozerDDozerD 73 bronze badges 4 |1 Answer
Reset to default 0Looking at bit more into the hierarchy structure I found that all top-level contours have value -1 in the third entry. This is how I finally got what I wanted:
import cv2
import numpy as np
import matplotlib.pyplot as plt
path = "f"
pixelSize = 0.1172
pixelArea = pixelSize*pixelSize
sliceThickness = 0.75
width = 853
height = 420
area = width*height*pixelArea
img = cv2.imread(f,-1)
roi = np.zeros(img.shape[:2], np.uint16)
roi = cv2.rectangle(roi, (13,76), (width,height), 65535, cv2.FILLED)
mask = cv2.bitwise_and(roi, img)
threshold = 350
ret, th1 = cv2.threshold(mask,threshold,255,cv2.THRESH_BINARY)
contour,hier = cv2.findContours(th1.astype(np.uint8),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
canvas = np.zeros(img.shape[:2], np.uint8)
canvas2 = np.zeros(img.shape[:2], np.uint8)
neg = np.zeros(img.shape[:2], np.uint8)
fin = np.zeros(img.shape[:2], np.uint8)
for cnt, hr in zip(contour, hier[0]):
if hr[3] != -1:
cv2.drawContours(neg,[cnt],0,255,-1)
cv2.drawContours(canvas,[cnt],0,255,2)
cv2.drawContours(canvas2,[cnt],0,255,-1)
fin = canvas2-neg
fig, ax = plt.subplots(5,1)
ax[0].imshow(img, 'gray')
ax[1].imshow(canvas, 'gray')
ax[2].imshow(canvas2, 'gray')
ax[3].imshow(neg, 'gray')
ax[4].imshow(fin, 'gray')
And the result.
cv2.drawContours(canvas2,[cnt],0,255,2)
? I suspect that using-1
will fill the contour. – DrBwts Commented Feb 3 at 12:34