I'm trying to display a filled contour using the cv2.drawContours
function in OpenCV. I've developed a list of contours from an edge image derived from a Canny
detection, and am finding the contours with RETR_EXTERNAL
enabled for the hierarchy definition. However I'm running into an issue that despite using the -1
flag in the cv2.drawContours
command to indicate a filled contour, only the contour itself(i.e. edge) is displayed. For example:
mask = np.zeros(rawimg.shape, np.uint8)
cv2.drawContours(mask, contours[246], -1, (0,255,255), -1)
results in just the outline of contour 246 being displayed. As I am only retrieving the external contours I don't think I am seeing just the difference between the internal and external contours found at each edge, so I'm a bit confused as to why it is displaying the contour, but not filling as the -1
flag would suggest it should.
EDIT: The full code is included below. The issue is with the line: cv2.drawContours(mask, cnt, 2, (0,255,255), -1) While this is formatted in the manner suggested by Dan, it results in the following image:
. cnt is a single contour, so this makes sense that it would be referring to a single point in the contour. When the line is changed to:
cv2.drawContours(mask, cnt, -1, (0,255,255), -1)
the contour prints as before, however the contour is still not filled as the -1 flag at the end of the command would suggest it should be.
The test image:
import os
import cv2
import numpy as np
from matplotlib import pyplot as plt
import copy as cp
path = 'C:\\Users\\...deleted...\\Desktop\\testimage6.jpg'
#Determine largest contour in the image
def maxContour(contours):
cnt_list = np.zeros(len(contours))
for i in range(0,len(contours)):
cnt_list[i] = cv2.contourArea(contours[i])
max_value = np.amax(cnt_list)
max_index = np.argmax(cnt_list)
cnt = contours[max_index]
return cnt, max_index
if os.path.isfile(path):
# Import the raw image to a working location and save to an isolated variable
# Import the raw image to a working location and save to an isolated variable
img = cv2.imread(path)
rawimg = cv2.imread(path)
saveimg = cv2.imread(path)
imgray = cv2.cvtColor(saveimg, cv2.COLOR_BGR2GRAY)
saveimgray = cp.copy(imgray)
f1 = plt.figure(1)
f1.set_size_inches(8,10)
plt.title('Original Image')
plt.xticks([]), plt.yticks([])
plt.imshow(rawimg, cmap='gray')
plt.savefig('output1.jpg', dpi=300)
cv2.imshow('Raw Image',rawimg)
cv2.waitKey(0)
cv2.destroyWindow('Raw Image')
# Impose an opening function as a filter
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
f2 = plt.figure(2)
f1.set_size_inches(8,10)
plt.title('Opened Image')
plt.xticks([]), plt.yticks([])
plt.imshow(opening, cmap='gray')
plt.savefig('output2.jpg', dpi=300)
cv2.imshow('Opened Image', opening)
cv2.waitKey(0)
cv2.destroyWindow('Opened Image')
#Extract the edges from the filtered image
edges = cv2.Canny(opening,10,100)
cv2.imshow('Edges', edges)
cv2.waitKey(0)
cv2.destroyWindow('Edges')
f3=plt.figure(3)
f3.set_size_inches(16,8)
plt.title('Edge Image')
plt.xticks([]), plt.yticks([])
plt.imshow(edges, cmap='gray')
plt.savefig('output3.jpg', dpi=300)
#Detect contours in the edge image
image, contours, hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(img, contours, -1, (0,255,255), 2)
cv2.imshow('Contours Image', img)
cv2.waitKey(0)
cv2.destroyWindow('Contours Image')
f4=plt.figure(4)
f4.set_size_inches(16,8)
plt.title('Contour Image')
plt.xticks([]), plt.yticks([])
plt.imshow(img)
plt.savefig('output2.jpg', dpi=300)
#Find maximum area contour
cnt, max_index = maxContour(contours)
print(max_index)
# Calculate contour-based statistics
# TBD
#Test of removing max contour
#grayimg = cv2.cvtColor(rawimg, cv2.COLOR_BGR2GRAY)
mask = np.zeros(rawimg.shape, np.uint8)
cv2.drawContours(mask, cnt, 2, (0,255,255), -1)
#ret, mask = cv2.threshold(grayimg, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
cv2.imshow('Mask Image', mask)
cv2.waitKey(0)
cv2.destroyWindow('Mask Image')
cv2.imshow('Mask Image', mask_inv)
cv2.waitKey(0)
cv2.destroyWindow('Mask Image')
#Fit ellipse to contour and calculate ellipse statistics
(x,y), (w,h), angle = cv2.fitEllipse(cnt)
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
x = np.int0(x)
y = np.int0(y)
w = np.int0(0.5*w)
h = np.int0(0.5*h)
#output2 = cv2.ellipse(img, center, dim, angle, 0, 360, (255,0,0), 12)
output2 = cv2.ellipse(img, (x,y), (w,h), angle, 0, 360, (255,0,0), 2)
output3 = cv2.drawContours(output2, [box], 0, (0,255,0), 2)
cv2.imshow('Ellipse Image',output2)
cv2.waitKey(0)
cv2.destroyWindow('Ellipse Image')
else:
print('file does not exist')`
To draw the contours, cv. drawContours function is used. It can also be used to draw any shape provided you have its boundary points. Its first argument is source image, second argument is the contours which should be passed as a Python list, third argument is index of contours (useful when drawing individual contour.
You can use cv::dilate() and cv::erode() then detect the contours again.
The function takes ArrayOfArrays
as input.
Try: cv2.drawContours(mask, [cnt], -1, (0,255,255), -1)
instead of: cv2.drawContours(mask, cnt, -1, (0,255,255), -1)
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With