Rayyan Batais
Rayyan Batais

Reputation: 11

AttributeError: 'NoneType' object has no attribute 'shape' / Convert from multiple contour box to singular

Hello and good morning!

I am a novice in python and opencv so if I sound or come off unprofessional, i apologize in advance.

I am trying to detect an MCB and determine its dimensions. However this error keeps poping up. AttributError: 'NoneType' object has no attribute 'shape'.

I have done a couple of searches in this forum and other sites, and most were declaring that the video path is the issue, so i tried to adjust or change from capture to videostream however no results were coming.

the code is here:

import cv2
from collections import deque

from scipy.spatial import distance as dist
from imutils import perspective
import numpy as np
import argparse
import imutils
import math
import time

font = cv2.FONT_HERSHEY_SIMPLEX

def midpoint(ptA, ptB):
    return ((ptA[0] + ptB[0]) * 0.5, (ptA[1] + ptB[1]) * 0.5)

ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", help="path to the (optional) video file")
args = vars(ap.parse_args())

sensitivity = 43
greyLower = np.array([96,0,176-sensitivity])
greyUpper = np.array([180,sensitivity,255])
pixelsPerMetric = None
KNOWN_WIDTH = 81

if not args.get("video", False):
    camera = cv2.VideoCapture(0)
else:
    camera = cv2.VideoCapture(args["video"])

while True:
    (grabbed, frame) = camera.read()

    if args.get("video") and not grabbed:
        break

    frame = imutils.resize(frame, width=600)
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    mask = cv2.inRange(hsv,greyLower, greyUpper)
    mask = cv2.erode(mask, None, iterations=2)
    mask = cv2.dilate(mask, None, iterations=2)

    (_, contours, hierarchy) = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    center = None
    for pic, contour in enumerate(contours):

        if len(contours) > 0:
                    c = max(contours, key =cv2.contourArea)
                    x,y,w,h = cv2.boundingRect(contour)
                    rect = (x+w, y+h)
                    rect = cv2.minAreaRect(c)
                    box = cv2.boxPoints(rect)
                    box = np.int0(box)
                    box = perspective.order_points(box)
                    for (x, y) in box:
                        frame = cv2.rectangle(frame,(int(x),int(y)),(int(x+w), int(y+h)),(0,0,139),2)
                    # unpack the ordered bounding box, then compute the midpoint
                    # between the top-left and top-right coordinates, followed by
                    # the midpoint between bottom-left and bottom-right coordinates
                    (tl, tr, br, bl) = box
                    (tltrX, tltrY) = midpoint(tl, tr)
                    (blbrX, blbrY) = midpoint(bl, br)

                    # compute the midpoint between the top-left and top-right points,
                    # followed by the midpoint between the top-righ and bottom-right
                    (tlblX, tlblY) = midpoint(tl, bl)
                    (trbrX, trbrY) = midpoint(tr, br)

                    # draw the midpoints on the image
                    cv2.circle(frame, (int(tltrX), int(tltrY)), 5, (255, 0, 0), -1)
                    cv2.circle(frame, (int(blbrX), int(blbrY)), 5, (255, 0, 0), -1)
                    cv2.circle(frame, (int(tlblX), int(tlblY)), 5, (255, 0, 0), -1)
                    cv2.circle(frame, (int(trbrX), int(trbrY)), 5, (255, 0, 0), -1)

                    # draw lines between the midpoints
                    cv2.line(frame, (int(tltrX), int(tltrY)), (int(blbrX), int(blbrY)),
                            (255, 0, 255), 2)
                    cv2.line(frame, (int(tlblX), int(tlblY)), (int(trbrX), int(trbrY)),
                            (255, 0, 255), 2)
                    # compute the Euclidean distance between the midpoints
                    dA = dist.euclidean((tltrX, tltrY), (blbrX, blbrY))
                    dB = dist.euclidean((tlblX, tlblY), (trbrX, trbrY))

                    # if the pixels per metric has not been initialized, then
                    # compute it as the ratio of pixels to supplied metric
                    # (in this case, inches)

                    # compute the size of the object
                    dimA = dA / KNOWN_WIDTH
                    dimB = dB / KNOWN_WIDTH

                    if rect >300:
                            frame = cv2.rectangle(frame,(int(x),int(y)),(int(x+w), int(y+h)),(0,0,139),2)
                            cv2.putText(frame,"MCB",(x,y),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,139))

                    # draw the object sizes on the image
                    cv2.putText(frame, "{:.1f}in".format(dimA),
                            (int(tltrX - 15), int(tltrY - 10)), cv2.FONT_HERSHEY_SIMPLEX,
                            0.65, (255, 255, 255), 2)
                    cv2.putText(frame, "{:.1f}in".format(dimB),
                            (int(trbrX + 10), int(trbrY)), cv2.FONT_HERSHEY_SIMPLEX,
                            0.65, (255, 255, 255), 2)
                    cv2.imshow("Frame", frame)
                    cv2.imshow("Mask", mask)

                    key = cv2.waitKey(10) & 0xFF

                    if key == ord("q"):
                        break

        camera.release()
        cv2.destroyAllWindows()

The code goes by detecting the MCB's hsv color code (grey) and uses the midpoint to declare the dimensions (referenced from pyimages).

Another issue i'm having is that im trying to create one rectangular box for detection and not multiple. So i tried to set the contour to detect the largest area of the hsv code, however the desired result was not achieved.

Any help or advice will be useful and im open for any critic for i want to learn more about python and expand in this area of expertise.

Thank you.

EDIT: Full traceback:

Traceback (most recent call last):
File "/Users/mac/Desktop/Control EZ/Test/Detect box.py", line 37, in <module>
    frame = imutils.resize(frame, width=600)
  File "/usr/local/lib/python2.7/site-packages/imutils/convenience.py", line 69, in resize
    (h, w) = image.shape[:2]
AttributeError: 'NoneType' object has no attribute 'shape'

Upvotes: 1

Views: 1222

Answers (1)

Michael
Michael

Reputation: 2414

On this line:

(grabbed, frame) = camera.read()

The variable frame is getting set to None here, so the attempt to resize the (non-existent) image fails. I don't know anything about your camera class, but probably that happens when there is no frame data to read. A None object does not have a shape, or really even data; it's basically nothing.

It looks like you're checking the grabbed variable, but only in certain circumstances. Maybe you should always continue if grabbed is false

Upvotes: 1

Related Questions