pythonnumpyopencvscreen-capturepython-mss

OpenCV Not Properly Writing Adding Frames to Video


I'm using mss, numpy, and OpenCV to make my own recording software, but when I record, all of my videos end up with a 258 bytes file size (no matter the length of the video), and I can't view the video. No frames seem to be in my videos. What am I doing wrong?

Here's my code, any help would be greatly appreciated:

import datetime
import numpy as np
import cv2
import mss
import mss.tools


time_stamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
fourcc = cv2.VideoWriter_fourcc("m", "p", "4", "v")
captured_video = cv2.VideoWriter(f"{time_stamp}.mp4", fourcc, 20.0, (1080, 720))

with mss.mss() as sct:
    monitor = {"top": 0, "left": 0, "width": 1080, "height": 720}
    while True:
        img = np.array(sct.grab(monitor))
        img_final0 = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
        img_final = cv2.cvtColor(img_final0, cv2.COLOR_BGR2RGB)
        cv2.imshow('LevelRecorder', img_final)
        capture = captured_video.write(img_final)
        print(capture)
        if cv2.waitKey(10) == ord("q"):
            break

Solution

  • At last, I finally found my answer. Turns out, this problem had a super simple solution that I somehow missed this entire time.

    As it turns out, either NumPy or Open Cv (I don't know which of the two), really really hates mss, but really likes Python Pillow, so, all you have to do is convert it to an image like Python Pillow, and there you go! Here's my new code (which works for me)

    import datetime
    from PIL import Image
    import numpy as np
    import cv2
    from mss import mss
    
    
    time_stamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
    fourcc = cv2.VideoWriter_fourcc("m", "p", "4", "v")
    captured_video = cv2.VideoWriter(f"{time_stamp}.mp4", fourcc, 20.0, (2880, 1800), 3)
    sct = mss()
    
    while True:
        img0 = sct.grab(sct.monitors[1])
        img_PIL = Image.frombytes('RGB', img0.size, img0.bgra, 'raw', 'BGRX') #This is where we convert it to a Pillow-like image
        img1= np.array(img_PIL) #Sorry about my variables, I was too lazy to change them :P
        img = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
        cv2.imshow('LevelRecorder', img)
        captured_video.write(img)
        if cv2.waitKey(1) == ord("q"):
            cv2.destroyAllWindows()
            break
    

    So there it is! Just use Python Pillow to convert each frame into something NumPy and Open Cv like using Image.frombytes(). Thank you so much Christoph Rackwitz for helping , I can not bring forth into words how much of a great help you have been :)