Skip to content Skip to sidebar Skip to footer

Efficiently Render 3d Numpy Bitmap Array (y, X, Rgb) To Window On Macos (using Opencv Or Otherwise)

I'm rendering a dynamically changing numpy bitmap array and trying to improve my framerate. Currently I'm using openCV: cv2.imshow(WINDOW_NAME, 𐌎) cv2.waitKey(1) This takes ~20

Solution 1:

You may render the video using external sub-process video renderer.

I tested the suggested solution by piping the video frames to FFplay. The solution is not working so well - the last frames are not shown.

Treat the solution as conceptual solution.

The code opens FFplay as sub-process, and write the raw frames to stdin pipe of FFplay.

Here is the code:

import cv2
import numpy as np
import subprocess as sp
import shlex
import time

# Synthetic "raw BGR" image for testing
width, height, n_frames = 1920, 1080, 1000# 1000 frames, resolution 1920x1080

img = np.full((height, width, 3), 60, np.uint8)

defmake_bgr_frame(i):
    """ Draw a blue number in the center of img """
    cx, cy = width//2, height//2
    l = len(str(i+1))

    img[cy-20:cy+20, cx-15*l:cx+15*l, :] = 0# Blue number
    cv2.putText(
        img,
        str(i+1),
        (cx-10*l, h+10),
        cv2.FONT_HERSHEY_DUPLEX,
        1,
        (255, 30, 30),
        2
        )

# FFplay input: raw video frames from stdin pipe.
ffplay_process = sp.Popen(
    shlex.split(
        f'ffplay -hide_banner -loglevel error'f' -exitonkeydown -framerate 1000 -fast'f' -probesize 32 -flags low_delay'f' -f rawvideo -video_size {width}x{height}'f' -pixel_format bgr24 -an -sn -i pipe:'
    ),
    stdin=sp.PIPE
)

t = time.time()

for i inrange(n_frames):
    make_bgr_frame(i)
    
    if ffplay_process.poll() isnotNone:
        break# Break if FFplay process is closedtry:
        # Write raw video frame to stdin pipe of FFplay sub-process.
        ffplay_process.stdin.write(img.tobytes())
        # ffplay_process.stdin.flush()except Exception as e:
        break

elapsed = time.time() - t
arg_fps = n_frames / elapsed

print(f'FFplay elapsed time = {elapsed:.2f}')
print(f'FFplay average fps = {arg_fps:.2f}')

ffplay_process.stdin.close()
ffplay_process.terminate()


# OpenCV##########################################################
t = time.time()

for i inrange(n_frames):
    make_bgr_frame(i)
    cv2.imshow("img", img)
    cv2.waitKey(1)

elapsed = time.time() - t
arg_fps = n_frames / elapsed

print(f'OpenCV elapsed time = {elapsed:.2f}')
print(f'OpenCV average fps = {arg_fps:.2f}')

cv2.destroyAllWindows()
##########################################################

Result (Windows 10):

FFplay elapsed time = 5.53
FFplay average fps = 180.98
OpenCV elapsed time = 6.16
OpenCV average fps = 162.32

On my machine the differences are very small.

Post a Comment for "Efficiently Render 3d Numpy Bitmap Array (y, X, Rgb) To Window On Macos (using Opencv Or Otherwise)"