Read video frame directly in grayscale with Python OpenCV cv2.VideoCapture()

Issue

I am working with OpenCV. I have a video file, and I want to read it in grayscale, instead of converting every frame in grayscale. i.e

cap = cv2.VideoCapture(VIDEO_PATH)

results = {}
curr_frame = 0
start = time.time()
while(cap.isOpened()):
    # Capture frame-by-frame
    ret, frame = cap.read()
    if ret == True:
        curr_frame+=1
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

I do not want to do this, instead I want to read it directly in grayscale as we do in images i.e

im_gray = cv2.imread('grayscale_image.png', cv2.IMREAD_GRAYSCALE)

Now upon inspecting the documentation, I found that the read function "The method/function combines VideoCapture::grab() and VideoCapture::retrieve() in one call."
And inside retrieve, we can pass a flag value. Is it possible to combine it with read and read it in gray scale instead of converting it explicitly?

I tried doing

ret, frame = cap.read(flag=0)

But it is not a valid keyword argument.

error: OpenCV(4.5.5) :-1: error: (-5:Bad argument) in function 'read'
> Overload resolution failed:
>  - 'flag' is an invalid keyword argument for VideoCapture.read()
>  - 'flag' is an invalid keyword argument for VideoCapture.read()

But I can pass in any random number in cap.read() and it works.

cap.read(-4)

I was looking for source code in Python, but can not found any source code in Python for this function on github.

Solution

According to the VideoCaptureModes documentation, there are four possible modes:

cv2.CAP_MODE_BGR - BGR24 (default)
cv2.CAP_MODE_RGB - RGB24
cv2.CAP_MODE_GRAY - Y8
cv2.CAP_MODE_YUYV - YUYV

Also note:

Currently, these are supported through the libv4l backend only.

So to read video frames directly as grayscale using cv2.VideoCapture(), you have to set the mode to grayscale with cv2.CAP_MODE_GRAY like this:

capture = cv2.VideoCapture(0)
possible = capture.set(cv2.CAP_PROP_MODE, cv2.CAP_MODE_GRAY)
print(possible)

# IMPORTANT: Check this value to see if it's supported by your system

You have to check the returned bool value to see if it’s possible since it may or may not be supported by your OS, camera, hardware, or backend. If the returned value is False or you get an error like this

AttributeError: module ‘cv2’ has no attribute ‘CAP_MODE_GRAY’

then unfortunately it’s not possible for your system, the best thing you can do is convert to grayscale with cv2.cvtColor after retrieving the frame.


Here’s a working example to read frames directly as grayscale from a webcam

import multiprocessing as mp
import cv2, time

def capture_frames():
    capture = cv2.VideoCapture(0)
    possible = capture.set(cv2.CAP_PROP_MODE, cv2.CAP_MODE_GRAY)
    print(possible)

    # FPS = 1/X, X = desired FPS
    FPS = 1/120
    FPS_MS = int(FPS * 1000)

    while True:
        # Ensure camera is connected
        if capture.isOpened():
            (status, frame) = capture.read()
            
            # Ensure valid frame
            if status:
                cv2.imshow('frame', frame)
            else:
                break
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
            time.sleep(FPS)

    capture.release()
    cv2.destroyAllWindows()

if __name__ == '__main__':
    print('Starting video stream')
    capture_process = mp.Process(target=capture_frames, args=())
    capture_process.start()

Answered By – nathancy

Answer Checked By – Cary Denson (AngularFixing Admin)

Leave a Reply

Your email address will not be published.