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:
use matplotlib with caution
If somebody uses matplotlib for imaging, stop reading
For showing video, use openCV. For showing image use opencv/Pillow unless you dont want to show anything extra alongside the image like axes
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()