opencv cap.read has an Attribute error. How to troubleshoot?

572 Views Asked by At

We are currently integrating two codes: 1. mss Image grab for screen recording 2. opencv color tracker

We encountered this error:

File "C:/Users/John Wong/Desktop/Test2.py", line 28, in <module>
_, img = cap.read()

AttributeError: 'NoneType' object has no attribute 'read'

We would like to use the screen grab as our input for the color tracking codes. What will happen is that while the codes for screen capturing is taking place, the codes for color tracking will take effect simultaneously on the screen that is captured.

We do not know what is wrong with our codes, here is the script below:

import cv2
import numpy as np
import time
import mss
import numpy


with mss.mss() as sct:
    # Part of the screen to capture
    monitor = {'top': 80, 'left': 20, 'width': 800, 'height': 770}
    while 'Screen capturing':
        last_time = time.time()

        # Get raw pixels from the screen, save it to a Numpy array
        img = numpy.array(sct.grab(monitor))


        cap = cv2.imshow('OpenCV/Numpy normal', img)

        while(True):
            _, img = cap.read()
            hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

            red_lower = np.array([170,87,97],np.uint8)
            red_upper = np.array([180,255,255],np.uint8)

            blue_lower = np.array([23,59,119],np.uint8)
            blue_upper = np.array([54,255,255],np.uint8)

            yellow_lower = np.array([0,50,80],np.uint8)
            yellow_upper = np.array([20,255,255],np.uint8)

            red = cv2.inRange(hsv, red_lower, red_upper)
            blue = cv2.inRange(hsv, blue_lower, blue_upper)
            yellow = cv2.inRange(hsv, yellow_lower, yellow_upper)

            kernal = np.ones((5,5), "uint8")

            red = cv2.dilate(red,kernal)
            res = cv2.bitwise_and(img, img, mask = red)

            blue = cv2.dilate(blue, kernal)
            res1 = cv2.bitwise_and(img, img, mask = blue)

            yellow = cv2.dilate(yellow, kernal)
            res2 = cv2.bitwise_and(img, img, mask = yellow)

            (_,contours, heirarchy) = cv2.findContours(red,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

            for pic, contour in enumerate(contours):
                area = cv2.contourArea(contour)
                if(area>300):
                    x,y,w,h = cv2.boundingRect(contour)
                    img = cv2.rectangle(img,(x,y),(x+w,y+h),(61,26,76),2)
                    cv2.putText(img,"PRIORITY",(x,y),cv2.FONT_HERSHEY_SIMPLEX,0.7,(61,26,76))

            (_,contours, heirarchy) = cv2.findContours(blue,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
            for pic, contour in enumerate(contours):
                area = cv2.contourArea(contour)
                if(area>300):
                    x,y,w,h = cv2.boundingRect(contour)
                    img = cv2.rectangle(img,(x,y),(x+w,y+h), (255,0,0),2)
                    cv2.putText(img,"SECOND",(x,y),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,0,0))

            (_,contours,heirarchy) = cv2.findContours(yellow,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
            for pic, contour in enumerate(contours):
                area = cv2.contourArea(contour)
                if(area>300):
                    x,y,w,h = cv2.boundingRect(contour)
                    img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,217),2)
                    cv2.putText(img,"ALERT",(x,y),cv2.FONT_HERSHEY_SIMPLEX,1.0, (0,255,217))

            cv2.imshow("Color Tracking", img)

            if cv2.waitKey(10) & 0xFF == ord('q'):
                cap.release()
                cv2.destroyAllWindows()
                break

Thank you in advance! :)

1

There are 1 best solutions below

4
On BEST ANSWER

I don't really understand what is going on in this code, and what you are expecting cap to be, however:

This line here reads the image into img

        img = numpy.array(sct.grab(monitor))

and then you show that image in a window using this line:

        cap = cv2.imshow('OpenCV/Numpy normal', img)

The cap is now a NoneType as shown in your error message (Thanks @DanMašek), so instead of using Cap as the image in the rest of your code use img instead.

while(True):
        # Remove this line: _, img = cap.read()
        # Get raw pixels from the screen, save it to a Numpy array
        img = numpy.array(sct.grab(monitor)) #Update the new image
        hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

        red_lower = np.array([170,87,97],np.uint8)
        red_upper = np.array([180,255,255],np.uint8)

        blue_lower = np.array([23,59,119],np.uint8)
        blue_upper = np.array([54,255,255],np.uint8)

        yellow_lower = np.array([0,50,80],np.uint8)
        yellow_upper = np.array([20,255,255],np.uint8)

        red = cv2.inRange(hsv, red_lower, red_upper)
        blue = cv2.inRange(hsv, blue_lower, blue_upper)
        yellow = cv2.inRange(hsv, yellow_lower, yellow_upper)

        cv2.imshow('Processed', img)
        cv2.waitKey(1)