"TypeError: 'NoneType' object is not subscriptable

Zulfikri Aulia Azka picture Zulfikri Aulia Azka · Sep 4, 2017 · Viewed 8.8k times · Source

I'm trying to add some feature to this code that i got from https://raw.githubusercontent.com/vipul-sharma20/gesture-opencv/master/gesture.py that i can capture any palm that i need and save it in folder, in first try its success,but the second is failure said:

Traceback (most recent call last):
File "home/pi/Downloads/palmdetect.py", line 97, in<module>
    camera_capture = get_image()
File "home/pi/Downloads/palmdetect.py", line 11, in get_image
    crop_image = img[100:450, 100:450]
TypeError: 'NoneType' object is not subscriptable

Code in palmdetect.py:

import cv2
import numpy as np
import math

cap = cv2.VideoCapture(0)


def get_image():
    # read image
    ret, img = cap.read()
    # get hand data from the rectangle sub window on the screen
    cv2.rectangle(img, (300, 300), (100, 100), (0, 255, 0), 0)
    crop_img = img[100:300, 100:300]

    # convert to grayscale
    grey = cv2.cvtColor(crop_img, cv2.COLOR_BGR2GRAY)

    # applying gaussian blur
    value = (35, 35)
    blurred = cv2.GaussianBlur(grey, value, 0)

    # thresholdin: Otsu's Binarization method
    _, thresh1 = cv2.threshold(blurred, 127, 255,
                               cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

    # show thresholded image
    cv2.imshow('Thresholded', thresh1)

    # check OpenCV version to avoid unpacking error
    (version, _, _) = cv2.__version__.split('.')

    if version == '3':
        image, contours, hierarchy = cv2.findContours(
            thresh1.copy(),
            cv2.RETR_TREE,
            cv2.CHAIN_APPROX_NONE
        )
    elif version == '2':
        contours, hierarchy = cv2.findContours(
            thresh1.copy(),
            cv2.RETR_TREE,
            cv2.CHAIN_APPROX_NONE
        )

    # find contour with max area
    cnt = max(contours, key=lambda x: cv2.contourArea(x))

    # create bounding rectangle around the contour (can skip below two lines)
    x, y, w, h = cv2.boundingRect(cnt)
    cv2.rectangle(crop_img, (x, y), (x+w, y+h), (0, 0, 255), 0)

    # finding convex hull
    hull = cv2.convexHull(cnt)

    # drawing contours
    drawing = np.zeros(crop_img.shape, np.uint8)
    cv2.drawContours(drawing, [cnt], 0, (0, 255, 0), 0)
    cv2.drawContours(drawing, [hull], 0, (0, 0, 255), 0)

    # finding convex hull
    hull = cv2.convexHull(cnt, returnPoints=False)

    # finding convexity defects
    defects = cv2.convexityDefects(cnt, hull)
    count_defects = 0
    cv2.drawContours(thresh1, contours, -1, (0, 255, 0), 3)

    # applying Cosine Rule to find angle for all defects (between fingers)
    # with angle > 90 degrees and ignore defects
    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])

        # find length of all sides of triangle
        a = math.sqrt((end[0] - start[0])**2 + (end[1] - start[1])**2)
        b = math.sqrt((far[0] - start[0])**2 + (far[1] - start[1])**2)
        c = math.sqrt((end[0] - far[0])**2 + (end[1] - far[1])**2)

        # apply cosine rule here
        angle = math.acos((b**2 + c**2 - a**2)/(2*b*c)) * 57

        # ignore angles > 90 and highlight rest with red dots
        if angle <= 90:
            count_defects += 1
            cv2.circle(crop_img, far, 1, [0, 0, 255], -1)
        # dist = cv2.pointPolygonTest(cnt,far,True)

        # draw a line from start to end i.e. the convex points (finger tips)
        # (can skip this part)
        cv2.line(crop_img, start, end, [0, 255,  0], 2)
        # cv2.circle(crop_img,far,5,[0,0,255],-1)

    # show appropriate images in windows
    cv2.imshow('Gesture', img)
    all_img = np.hstack((drawing, crop_img))

    return img


temp = get_image()
print("Taking Image...")

camera_capture = get_image()
file = "home/pi/Desktop/image.jpg"

cv2.imwrite(file, camera_capture)

del(camera)

anyone knows how to fix it and the threshold windows doesn't appear

Answer

lee-pai-long picture lee-pai-long · Sep 7, 2017

The documentation says that VideoCapture.read()

combine VideoCapture::grab() and VideoCapture::retrieve() in one call

And VideoCapture::retrieve()

decode and return the just grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more frames in video file), the methods return false and the functions return NULL pointer.

Translated in python you must expect retvar and frame where frame is not None only if retval is True.

In your code this line:

# read image
ret, img = cap.read()

Potentially give you img as None, so when you try to crop it here:

crop_img = img[100:300, 100:300]

You get your error:

"TypeError: 'NoneType' object is not subscriptable

You either need to test retval first:

retval, img = cap.read()
if retval:
    # get hand data from the rectangle sub window on the screen
    cv2.rectangle(img, (300, 300), (100, 100), (0, 255, 0), 0)
    crop_img = img[100:300, 100:300]
    ...

Or test for img not at None first:

# Since we don't use the return value let's just forget it
_, img = cap.read()
if img is not None:
    # get hand data from the rectangle sub window on the screen
    cv2.rectangle(img, (300, 300), (100, 100), (0, 255, 0), 0)
    crop_img = img[100:300, 100:300]
    ...

Then you'll have to handle the fact that your get_image function get no image (either return None or raise an Exception).

Sidenote: Your code still have two issue, you have a line all_img = np.hstack((drawing, crop_img)) at the end of your function but you never use all_img. At the end of the module you do a del(camera) but camera is never defined. Finally if you have to share you code publicly please follow PEP8 (Install pylint or just flake8 in you editor or choice).