Ask Your Question
0

Python, eliminate small contours

asked 2019-12-11 05:40:44 -0500

I'm attempting to do the same thing as https://answers.opencv.org/question/1... but in Python and I am working from their solution. I am getting an error "SystemError: <built-in drawcontours="" function=""> returned NULL without setting an error". I also suspect I am doing other things wrong as I don't know what the Vector lines are for and I removed the Point() at the end of the findCountours function as it was causing errors. Here is what I have, I appreciate any help:</built-in>

import numpy as np 
import cv2

# Mat result
# vector<vector<Point> >contours
# vector<Vec4i>hierarchy
savedContour = -1
maxArea = 0.0

# load image
image = cv2.imread('vlcsnap2.png')
binarayImage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Find the largest contour
contours, hierarchy = cv2.findContours(binarayImage, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for i in range(0, len(contours)):
    area = cv2.contourArea(contours[i])
    if area > maxArea:
        maxArea = area
        savedContour = i

# Create mask
result = cv2.drawContours(binarayImage, savedContour, 255, cv2.FILLED, 8)

# apply the mask:
binarayImage &= result

#show image
cv2.imshow("Result", result)

cv2.waitKey(0)
cv2.destroyAllWindows()

Ultimately, I'm trying to get from here:

image description

to Here:

image description

edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
0

answered 2019-12-12 08:38:07 -0500

supra56 gravatar image

updated 2019-12-12 08:46:51 -0500

I solved it:

#!/usr/bin/python37
#OpenCV 4.1.2, Raspberry pi 3/3b/4
#Date: 12th December, 2019

import cv2 as cv
import numpy as np

img = cv.imread('small_contour.jpg')
image_contours = np.zeros((img.shape[1], img.shape[0], 1), np.uint8)

image_binary = np.zeros((img.shape[1], img.shape[0], 1), np.uint8)

for channel in range(img.shape[2]):
    ret, image_thresh = cv.threshold(img[:, :, channel], 127, 255, cv.THRESH_BINARY)    
    contours = cv.findContours(image_thresh, 1, 1)[0]   
    cv.drawContours(image_contours, contours, -1, (255,255,255), 3)

contours = cv.findContours(image_contours, cv.RETR_LIST,
                           cv.CHAIN_APPROX_SIMPLE)[0]

cv.drawContours(image_binary, [max(contours, key = cv.contourArea)],
                -1, (255, 255, 255), -1)

cv.imwrite('fill_contour.jpg', image_binary)
cv.imshow('Small Contour', image_binary)
cv.waitKey(0)

Output: image description

edit flag offensive delete link more

Comments

1

Wow, that is progress! I need to keep the holes (small contours) within the main contour though (see my output image), so I know I need to use the hierarchy function for that (which is what I think the loop function they had is for).

sirpuppington gravatar imagesirpuppington ( 2019-12-12 08:50:24 -0500 )edit

Oh! you wanna black hole?

supra56 gravatar imagesupra56 ( 2019-12-12 08:53:55 -0500 )edit

Yeah, I'm trying to retain the black holes that are inside of the white planet.

sirpuppington gravatar imagesirpuppington ( 2019-12-12 09:48:18 -0500 )edit

Don't be foolish. There are no holes in snooker balls. White become black and black become white. What you see is light shined on balls.

supra56 gravatar imagesupra56 ( 2019-12-12 11:59:10 -0500 )edit

Hi supra56, the problem with this output is it removes the small contours within the large contour. Do you know how one would keep the black spots within the largest contour?

sirpuppington gravatar imagesirpuppington ( 2020-03-22 09:13:31 -0500 )edit
0

answered 2019-12-11 10:43:14 -0500

mvuori gravatar image

At least your drawContours call lacks contours as second parameter. Without passing that, how would OpenCV know what to draw...

The point parameter in findContours is optional, anyway, and OpenCV documentation would tell you its purpose.

The Vector line just defines type of contours, a necessity in typed languages, such as C++.

edit flag offensive delete link more

Comments

Thanks you, I've changed that line to the below which solves the error but it looks like the apply mask line was old/C++ specific and my new solution for that isn't working either.

# Create mask
mask = cv2.drawContours(savedContour, contours, (255), cv2.FILLED, 8)

# apply the mask to the original image
result = cv2.bitwise_and(binarayImage,image, mask= mask)
sirpuppington gravatar imagesirpuppington ( 2019-12-11 11:27:05 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

Asked: 2019-12-11 05:40:44 -0500

Seen: 124 times

Last updated: Dec 12 '19