Try to get convexity defects but getting an error

Hi, currently i am working on a final project. And i am using opencv library and python language. Studying on opencv with python, to understand how to use it i am making small projects. In this i try to find contours, hull and convexity defects on a hand photo. But when i run my code, i get this error:

Traceback (most recent call last):
 line 22, in <module>
    defects = cv.convexityDefects(cnt, each)
cv2.error: OpenCV(4.5.1) C:\Users\appveyor\AppData\Local\Temp\1\pip-req-build-oduouqig\opencv\modules\imgproc\src\convhull.cpp:329: error: (-215:Assertion failed) hpoints > 0 in function 'cv::convexityDefects'

I am studying on some documents of opencv and took line of codes from there. I found contours and hull but when it comes to convexitydefects every time i get an error. I already tried other people codes on internet and implement it into mine, gives me same error. I am new at python programming and can not fix this. Can anyone help me? Thanks and sorry for my bad english.

import cv2 as cv
import numpy as np

img = cv.resize(cv.imread("hand.jpg"), (350, 700))

gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

ret, thresh = cv.threshold(gray, 230, 255, cv.THRESH_BINARY_INV)

contours, hierarchy = cv.findContours(thresh.copy(), cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

cnt = contours[0]

hull = []

for i in range(len(contours)):
    print(len(contours[0]))
    hull.append(cv.convexHull(contours[i], False))
    cv.drawContours(img, hull, i, (0, 0, 255), 2, 8)

for each in hull:
    defects = cv.convexityDefects(cnt, each)
    if not defects:
        continue
    for i in range(defects.shape[0]):
        s, e, f, d = defects[i, 0]
        start = tuple(cnt[s][0])
        end = tuple(cnt[e][0])
        far = tuple(cnt[f][0])
        cv.circle(img, far, 5, (0, 0, 255), -1)

cv.drawContours(img, contours, -1, (0, 255, 0), 3)

cv.imshow('Image', img)
cv.imshow('Thresh', thresh)

cv.waitKey(0)

In order to use convexityDefects() you have to use original contour and calculated convex hull, so try changing your for loop to this:

# Draw convexity defects
for i in range(len(contours)):
    defects = cv.convexityDefects(contours[i], hull[i])
    if not defects:
        continue
    for j in range(defects.shape[0]):
        s, e, f, d = defects[j, 0]
        start = tuple(contours[i][s][0])
        end = tuple(contours[i][e][0])
        far = tuple(contours[i][f][0])
        cv.circle(img, far, 5, (0, 0, 255), -1)

It still gives same error. I can find hull and contour but can’t find defects.

I modified and edit your code: Try this.

import cv2 as cv
import numpy as np

img = cv.resize(cv.imread("hand.jpg"), (350, 700))

gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

ret, thresh = cv.threshold(gray, 230, 255, cv.THRESH_BINARY_INV)

contours, hierarchy = cv.findContours(thresh.copy(), cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)

cnt = contours[0]

hull = []

# find largest area contour
max_area = -1
for i in range(len(contours)):
    area = cv.contourArea(contours[i])
    if area>max_area:
        cnt = contours[i]
        max_area = area

cnt = cv.approxPolyDP(cnt,0.01*cv.arcLength(cnt,True),True)
hull = cv.convexHull(cnt, returnPoints=False)

for each in hull:
    defects = cv.convexityDefects(cnt, each)
    if not defects:
        continue
    for i in range(defects.shape[0]):
        s, e, f, d = defects[i, 0]
        start = tuple(cnt[s][0])
        end = tuple(cnt[e][0])
        far = tuple(cnt[f][0])
        cv.circle(img, far, 5, (0, 0, 255), -1)

cv.drawContours(img, contours, -1, (0, 255, 0), 3)

cv.imshow('Image', img)
cv.imshow('Thresh', thresh)

cv.waitKey(0)

Btw, I edited.

You removed hull function. And whether function is in or not it still shows nothing. It is not giving error but not find any defects as well.

I do not have ur image.

images.app.goo.gl/9yfrarSBG3sEQxTk9 Here is the image. Thanks for your effort.

I have that too, but not same.

please see docs , in order to find the convexity defects you need to retrieve the hull indices, not the points

 hull = cv.convexHull(cnt, returnPoints=False)

(like @supra had it)

I already read docs. But even after that code does not find defects. I tried @supra edited code too. There is something missing in code because i am new at it. Thanks anyway.

@ mehmet_zmn.
Can you post error message?

It does not gives error, also not found defects because of the if statement where,

    if not defects:
        continue

like this. When i comment out these lines, it gives this error:

    for i in range(defects.shape[0]):
AttributeError: 'NoneType' object has no attribute 'shape'

But i found a solution in here :Hand Detection and Finger Counting Using OpenCV-Python | by Madhav Mishra | Analytics Vidhya | Medium
I guess in my code, did not find contour area properly.

It is working now. I am using your first post code. Check ur filename, misspelled or extension. The error you posted…shape[0] meaning filename is not in your currently, misspelled, etc.
Go back to your first code. Is the filename in current folder?

Here is an images:

Can you try test this an image? This should be no white background.

I checked my filename. I tried photo you sent. It gives shape[0] error. @Supra

Where did u stored ur filename…currently folder or sub-directory?

I am using pycharm. So in Users–>PycharmProjects–>Contourprojects–> .py file and hand.jpg file are in same folder.

That is problem. I cannot troubleshooting PyCharm. You can download Python IDE 3.10.x.

I have tried on Python IDE, still same. Then i checked the image with print(img) and it was reading the image. defects value is empty one. So i changed hull[hull] and the defectsdefects.any() like this:

for each in [hull]:
    defects = cv.convexityDefects(cnt, each)
    if not defects.any():
        continue

And it worked somehow. Result here:


Defects are not that accurate. And i can not success to draw hull.

That’s very good. You have to play around with threshold from 230 to 75. What if you try second image that I sent? The guy who took picture of his hand probably used cv2.VideoCapture.
Actually, I cannot recalled it. I will check it back on next day.

I checked second image, and it gives me same result as before. So in my opinion the problem is finding max contours area. My code does not return max contour area. I tried code sent here. It works smoothly.