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

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


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.

Tags:

Python

Opencv