dgrat
dgrat

Reputation: 2254

OpenCV findContours() complains if used with black-white image

I want to perform edge detection with the following code. However I get an error because of the image color depth. This error in my eyes, makes no sense, as I convert the image properly to a gray-scale image, and in a subsequent step to a black and white image, which is definitely working correctly. When I call findContours I get an error.

import cv2

def bw_scale(file_name, tresh_min, tresh_max):
    image = cv2.imread(file_name)
    image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    #(thresh, im_bw) = cv2.threshold(image, tresh_min, tresh_max, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
    (thresh, im_bw) = cv2.threshold(image, tresh_min, tresh_max, 0)

    cv2.imwrite('bw_'+file_name, im_bw)
    return (thresh, im_bw)

def edge_detect(file_name, tresh_min, tresh_max):
    (thresh, im_bw) = bw_scale(file_name, tresh_min, tresh_max)
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)


if __name__ == '__main__':
  edge_detect('test.jpg', 128, 255)

I get this error:

dgrat@linux-v3pk:~> python aoi.py
OpenCV Error: Unsupported format or combination of formats ([Start]FindContours support only 8uC1 and 32sC1 images) in cvStartFindContours, file /home/abuild/rpmbuild/BUILD/opencv-2.4.9/modules/imgproc/src/contours.cpp, line 196
Traceback (most recent call last):
  File "aoi.py", line 25, in <module>
    edge_detect('test.jpg', 128, 255)
  File "aoi.py", line 19, in edge_detect
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.error: /home/abuild/rpmbuild/BUILD/opencv-2.4.9/modules/imgproc/src/contours.cpp:196: error: (-210) [Start]FindContours support only 8uC1 and 32sC1 images in function cvStartFindContours

Upvotes: 10

Views: 65362

Answers (4)

Siddharth Suresh
Siddharth Suresh

Reputation: 1

Nowadays, findContours is returning only contours and hierarchy.

Before you pass on the image as a param to the function, it must be a uint8 and must be grayscale. These worked when I used RETR_CCOM as the mode.

Upvotes: 0

Shoaib Mohammed
Shoaib Mohammed

Reputation: 1036

I got the same error when trying with grayscale images, then i tried applying gaussian filter with average of 5X5 blocks with Canny edge detector to a cvtColor converted grayscaled image. Voila! contours on the pic.

Try this code

image = cv2.imread('testimage.jpeg')
im_bw = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

blur = cv2.GaussianBlur(im_bw, (5,5), 0)
im_bw = cv2.Canny(blur, 10, 90)

contours, hierarchy = cv2.findContours(im_bw, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(image, contours, -1, (0,255,0), 3)
plt.imshow(image)
plt.show()

Upvotes: 0

Tomas Camin
Tomas Camin

Reputation: 10096

The problem in your code is that you're misusing the return values of cv2.threshold().

cv2.threshold returns 2 parameters:

  • retval

    is used when thresholding using the OTSU method (returning the optimal threshold value) otherwise it returns the same threshold value you passed to the function, 128.0 in your case.

  • dst

    is the thresholded result image

In your code thresh is a float not a Mat.

Change:

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

to

contours, hierarchy = cv2.findContours(im_bw, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

EDIT

Below find a refactored and simplified version of your original code using the following test image.

enter image description here

import cv2

def edge_detect(file_name, tresh_min, tresh_max):
    image = cv2.imread(file_name)
    im_bw = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)

    (thresh, im_bw) = cv2.threshold(im_bw, tresh_min, tresh_max, 0)
    cv2.imwrite('bw_'+file_name, im_bw)

    contours, hierarchy = cv2.findContours(im_bw, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cv2.drawContours(image, contours, -1, (0,255,0), 3)
    cv2.imwrite('cnt_'+file_name, image)

if __name__ == '__main__':
  edge_detect('test.jpg', 128, 255)

This produces the following bw_test.jpg

enter image description here

With the following contours highlighted in cnt_test.jpg

enter image description here

Upvotes: 13

Yan Foto
Yan Foto

Reputation: 11388

UPDATE

Considering that you already convert you image to gray scale, the problem should be with the channel range. FindContours support only 32s and 8u. You could use image.dtype to make sure that you get something like uint8. If not cv2.convertScaleAbs(image) should solve your problem.

ORIGINAL ANSWER

As the error mentions FindContours support only 8uC1 and 32sC1 images. So might want to use something like cv.CvtColor to convert your image to a supported color space.

Upvotes: 14

Related Questions