Search code examples
pythonnumpyopencvcolor-trackingpython-mss

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


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! :)


Solution

  • 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)