Hi there 
I want to report the result that I compared the drawing speed of wx, qt, cv, and matplotlib using the following packages.
- wx.version 4.1.1 msw (phoenix) wxWidgets 3.1.5
- scipy/numpy version 1.6.0/1.20.1
- matplotlib verison 3.4.2
- Image verison 8.1.0
- cv2 verison 4.5.1
- pyqtgraph 0.12.2
- PySide2 5.15.2
Result
Tested with VAIO CORE i3-2350M Windows10 64 bit OS (my poor PC)
| Rank |
test script |
Speed |
Modules |
| 1 |
test_qt |
47.4 fps |
pyqtgraph/PySide2 |
| 2 |
test_cv2 |
43.5 fps |
opencv |
| 3 |
test_wx_bmp |
22.5 fps |
wx using StaticBitmap |
| 4 |
test_wx_dc1 |
22.5 fps |
wx using DC single buffering |
| 5 |
test_wx_dc2 |
22.2 fps |
wx using DC double buffering |
| 6 |
test_wx_agg |
16.1 fps |
matplotlib with wxagg backend |
| 7 |
test_mpl |
10.6 fps |
matplotlib with pyplot |
test-drawing-speed.zip (5.2 KB)
NOTE
- Pyqtgraph (1) is the fastest as far as I know.
- OpenCV (2) is a little bit slower than Qt but fast enough.
- Wx is twice as slow as OpenCV. Interestingly, using StaticBitmap (3), PaintDC (4), and BufferedPaintDC (5) makes no difference except for the effect of flicker.
- wxWidgets doesn’t support grayscale images. So, we have to make an RGB image first and convert it to a grayscale bitmap. I think this is probably the cause of the overhead.
- It is interesting that wxagg (6) is faster than the native viewer of matplotlib (7). In addition, when you make the window size smaller, it becomes even faster than wx bitmap (3,4,5) drawing!
That’s it!
I would appreciate it if you could tell me anything about other high-speed libraries, how to make wx code even faster, anything to improve code in my attached file, etc.
2 Likes
komoto48g,
Those results are pretty consistent with what I’ve seen. A couple of comments:
a) you’re rescaling and interpolating some of those images, and in slightly inconsistent ways. It won’t really change the results, but I might suggest using a slightly smaller size, say 800x600, consistently and not doing any rescaling.
b) wx.Timer.Start() needs an argument, and that argument needs to be greater than 0. I would say to make it “10”.
For matplotlib using the pyplot interface is going to be slower than updating the WXAgg backend, and a factor of 2 is about what I see too.
On MacOS (and also “not new” hardware), I see that the absolute rates are faster, but the results mostly consistent, except that opencv is not ~80% to 90% of PyQtGraph, more like 60%, and the fastest wx times are comparable to that.
But finally, and actually most importantly, what frame rate do you think you need? Are you rendering high-speed video for sports or games? For many decades, film - like real film on reels - was displayed at 24 fps (“Photography is Truth, and Film is Truth 24 times a second”, said Godard). Video was 30 fps, but interlaced, so really 15 fps. That is, one interpretation is that all of these approaches (except for you, pyplot) are “there”.
1 Like
Thank you very much for your advice, Matthew.
I modified the part of the code that you pointed out and tested it for the same (600,900) client size.
From (1) to (5), the speed does not depend on the client size, but (6), (7) matplot strongly does.
| Rank |
test script |
Speed |
Modules |
| 1 |
test_qt |
74.4 fps |
pyqtgraph/PySide2 |
| 2 |
test_cv2 |
63.6 fps |
opencv |
| 3 |
test_wx_bmp |
36.1 fps |
wx using StaticBitmap |
| 4 |
test_wx_dc1 |
35.8 fps |
wx using DC single buffering |
| 5 |
test_wx_dc2 |
36.1 fps |
wx using DC double buffering |
| 6 |
test_wx_agg |
11.1 fps |
matplotlib with wxagg backend |
| 7 |
test_mpl |
7.3 fps |
matplotlib with pyplot |
test-drawing-speed-ver2.zip (5.5 KB)
On MacOS (and also “not new” hardware), I see that the absolute rates are faster, but the results mostly consistent, except that opencv is not ~80% to 90% of PyQtGraph, more like 60%, and the fastest wx times are comparable to that.
Hmmm, is that due to the version? I tested with OpenCV4.
But finally, and actually most importantly, what frame rate do you think you need?
It is difficult.
10 fps can be stressful and I think 20 fps is enough. 30 fps is good for in-situ observation. 50 fps is a bit meaningless as it exceeds the refresh rate of the device.
I work with electron microscopy images that are 2-byte grayscale and my application handles live-view of 512 x 512 at 20 fps (= 10 MB/s) in a remote. I plan to deal with bigger images in the future. The size of 2k x 2k image was normal, 4k x 4k CMOS image is becoming standard, and 8k x 8k sometimes.
For now, the faster the better. “The practical scientist is trying to solve tomorrow’s problem with yesterday’s computer”
“Photography is Truth, and Film is Truth 24 times a second”, said Godard
Impressing! Did Godard talk about Japanese anime? 
Two points in addition.
- I modified it as follows,
- wx.BufferedPaintDC(self.panel, self.bitmap)
+ dc = wx.BufferedPaintDC(self.panel, self.bitmap)
I attach the last modified files. I hope these would help people who want to start dealing with images.
test-drawing-speed-ver2+.zip (5.5 KB)
- Someone may want to use wx GUI and pyqtgraph function lIke this.
import wx
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.btn = wx.Button(self, label="Press me")
self.btn.Bind(wx.EVT_BUTTON, self.run)
def run(self, evt):
self.qfrm = pg.GraphicsLayoutWidget(title=self.__module__)
image = pg.ImageItem() # create image
view = self.qfrm.addViewBox() # create view
view.setAspectLocked(True)
view.addItem(image)
def update():
h, w = 768, 1152
src = (255 * np.random.rand(h, w)).astype(np.uint8)
image.setImage(src.T)
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start()
self.qfrm.show()
pg.exec()
if __name__ == "__main__":
qApp = QtGui.QApplication()
app = wx.App()
frm = Frame(None)
frm.Show()
app.MainLoop()
WX-QT Dream Tag!