pythonopencvwebcamyolov5roboflow

Using Webcam with Yolov5 Models


I tried to run the example infer-simple.py, but I can't succeed, because the code is returning a None value when the command line (image = cv2.imdecode(image, cv2.IMREAD_COLOR)) is executed.

  1. code:
def infer():
    # Get the current image from the webcam
    ret, img = video.read()

    # Resize (while maintaining the aspect ratio) to improve speed and save bandwidth
    height, width, channels = img.shape
    scale = ROBOFLOW_SIZE / max(height, width)
    img = cv2.resize(img, (round(scale * width), round(scale * height)))

    # Encode image to base64 string
    retval, buffer = cv2.imencode('.jpg', img)
    img_str = base64.b64encode(buffer)

    # Get prediction from Roboflow Infer API
    resp = requests.post(upload_url, data=img_str, headers={
        "Content-Type": "application/x-www-form-urlencoded"
    }, stream=True).raw

    # Parse result image
    image = np.asarray(bytearray(resp.read()), dtype="uint8")
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    
    return image

Always before the imdecode image is array not None, bellow is displayed one debug example.

  1. Debug
resp: <urllib3.response.HTTPResponse object at 0x0000015055DE7070>

image: array([ 11, 214,  13, ..., 170,   1,   3], dtype=uint8)

However, when I run cv2.imdecode(image, cv2.IMREAD_COLOR)) I get a none value for image.

3.Error

Exception has occurred: error OpenCV(4.6.0) D:\a\opencv-python\opencv-python\opencv\modules\imgcodecs\src\loadsave.cpp:816: 
error: (-215:Assertion failed) !buf.empty() in function 'cv::imdecode_'

  File "C:\Users\diego\codes\Webcam\infer-simple.py", line 48, in infer
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
  File "C:\Users\diego\codes\Webcam\infer-simple.py", line 63, in <module>
    image = infer()

I did it all step by step according to https://blog.roboflow.com/python-webcam.

I applied solutions found on the Internet and also reinstalled all necessary packages but nothing worked.


Solution

  • Problem is not when you get image from camera but when you get image from server.

    You have to create project on roboflow.com and gets model's name and api key - and use all this to create correct url.

    I created project and trained model with name chess-sample-cpuhx/1 and got API KEY like tE7xxxxxxxxx so I have full url

    https://detect.roboflow.com/chess-sample-cpuhx/1?format=image&stroke=5&api_key=tE7xxxxxxxxx
    

    My code with few changes.

    I check

    # all `import` at the beginning
    import json
    import base64
    import cv2
    import numpy as np
    import requests
    import time
    
    # --- constants ---  
    
    ROBOFLOW_API_KEY = 'tE7xxxxxxxxx'
    ROBOFLOW_MODEL = 'chess-sample-cpuhx/1'
    ROBOFLOW_SIZE = 400
    
    # --- functions ---
    
    params = {
        "api_key": ROBOFLOW_API_KEY,
        "format": "image",
        "stroke": "5"
    }
    
    headers = {
        "Content-Type": "application/x-www-form-urlencoded"
    }
    
    url = f"https://detect.roboflow.com/{ROBOFLOW_MODEL}"
    
    
    def infer(img):
        # Resize (while maintaining the aspect ratio) to improve speed and save bandwidth
        height, width, channels = img.shape
        scale = ROBOFLOW_SIZE / max(height, width)
        img = cv2.resize(img, (round(scale * width), round(scale * height)))
    
        # Encode image to base64 string
        retval, buffer = cv2.imencode('.jpg', img)
        img_str = base64.b64encode(buffer)
    
        # Get prediction from Roboflow Infer API
        response = requests.post(url, params=params, data=img_str, headers=headers, stream=True)
        data = response.raw.read()
        
        #print(response.request.url)
        
        if not response.ok:
            print('status:', response.status_code)
            print('data:', data)
            return
        
        # Parse result image
        image = np.asarray(bytearray(data), dtype="uint8")
        image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    
        return image
    
    # --- main ---
    
    video = cv2.VideoCapture(0)
    
    while True:
    
        start = time.time()
    
        ret, img = video.read()
        
        if ret:
            
            image = infer(img)
            
            if image is not None:
                cv2.imshow('image', image)
            
                if cv2.waitKey(1) == ord('q'):  # `waitKey` should be after `imshow()` - to update image in window and to get key from window
                    break
            
                end = time.time()
                print( 1/(end-start), "fps")  # print() automatically add space between elements - you don't need space in "fps"
            
    # - end -
    
    video.release()
    cv2.destroyAllWindows()