Home > database >  How to speed up rgb plotting in real time in python
How to speed up rgb plotting in real time in python

Time:09-22

I've been asked to code a crazy idea. We want to have a screen that will display every possible image it can produce using RGB format and every pixel available. Of course, we understand that such code would take millions of years to run its course (even more), but still, this is what we want to do. I have something that works pretty well, the only problem is that the plotting of the image is really slow...

I am currently using matplotlib, I am open to try something else for speed's sake, but I must admit that I am not familiar with other tools and I often find the documentation hard to follow (with glumpy for exemple)

Here is my code:

import numpy as np
import matplotlib.pyplot as plt
import time
import itertools
from PyQt5 import QtWidgets 
plt.ion()
import ctypes

# Getting the screensize
user32 = ctypes.windll.user32
screensize = user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)


fig = plt.figure()

#To remove toolbar from figure
try:
     win = fig.canvas.manager.window
except AttributeError:
     win = fig.canvas.window()          
toolbar = win.findChild(QtWidgets.QToolBar) #same
toolbar.setVisible(False)                   #same
fig.canvas.manager.full_screen_toggle()     #To display the result in fullscreen

# To remove white space between axis and figure
ax = fig.add_axes([0,0,1,1]) #position: left, bottom, width, height
ax.set_axis_off()
pixel_x, pixel_y = screensize[::-1]

initial_image = np.zeros((pixel_x,pixel_y,3)).astype(np.uint8)
image = ax.imshow(initial_image, animated = True)
ch = ax.get_children()
fig.canvas.draw()

# itertools allow me to iterate over all possible image pretty efficiently
for x in itertools.product(np.arange(0,256,steps,dtype = "uint8"),repeat = pixel_y*pixel_x*3):

    x = np.fromiter(x,dtype = np.uint8) # I read that np.fromiter is quicker than np.array
    x = x.reshape(pixel_x,pixel_y,3)    # Putting everything back in an image appropriate 
                                        # format
   
    ch[-2].set_data(x)       # I try not to redraw the entire figure by only changing this
    ax.draw_artist(ch[-2])   # I redraw the artist
    fig.canvas.blit(fig.bbox)# Read online that this was quicker
    fig.canvas.flush_events()# same...



    j =1
    if j % 10 == 0:
        print(f'{j/(time.time() - t):.2f} iterations per seconde')

So I found that the iterations over the itertools.product relatively fast : this part can go as fast as 40-45 iterations per seconds. Converting itertools output in an numpy array using np.fromiter slows down the process a bunch : it falls to approximately 25 iterations per second. Reshaping the result in a image appropriate format does not seem to slow down anything. Finally, when I include all of the plotting with set_data method and everything, it slows down to 5-6 interations per second which is really slow...

If you have any insight on how I could make this process more efficient, please let me know! It will be really appreciated. Thank you

CodePudding user response:

  1. use matplotlib with caution

  2. If somebody uses matplotlib for imaging, stop reading

  3. For showing video, use openCV. For showing image use opencv/Pillow unless you dont want to show anything extra alongside the image like axes

  4. Take more time thinking about what you are doing, because what you are doing is really not worth doing.

OPENCV implementation (333-500 FPS)

import numpy as np
import time
import itertools

import cv2


steps = 1
pixel_x, pixel_y = [3, 3]
initial_image = np.zeros((pixel_x, pixel_y, 3)).astype(np.uint8)

import time

for x in itertools.product(
    np.arange(0, 256, steps, dtype="uint8"), repeat=pixel_y * pixel_x * 3
):
    s = time.time()
    x = np.fromiter(x, dtype=np.uint8)
    x = x.reshape(pixel_x, pixel_y, 3)
    cv2.imshow("Frame", x)

    if cv2.waitKey(1) & 0xFF == ord("q"):

        break
    print("FPS: ", 1 / (time.time() - s))
cv2.destroyAllWindows()
  • Related