I created a Tkinter program that displays images processed with OpenCV. The Tkinter GUI has buttons for selecting a folder, viewing the next image, and viewing the previous image, and a canvas showing these images. And when a person checks what type of image this image is using a radio button, the record is saved.
Here’s what it looks like for users:
- When a person presses the view next image button,
- Load the image,
- Process with OpenCV (CPU: 0.8 seconds),
- Show the image on the canvas.
- Check the image and check the radio button (Human: 1 second)
- Goto 1
During the 1 second that 5’s human makes the decision, I want to start processing and preparing the next image of 3, and then display it immediately when I press the button. I think that will dramatically improve the user experience.
How can I make it? I would appreciate it if you could tell me at least a keyword about what technologies I should look into.
I modified the program based on Ahmed AEK’s answer. It worked well and obviously improved the user experience quite a bit by preparing the next image in advance. However, the canvas.draw() part, which draws a pre-prepared image in Tkinter, takes up time on its own. So I couldn’t go far in improving it to a level where there is absolutely no delay. This is my fault for not thoroughly analyzing the time for each step in advance.
I couldn’t try Redis because there was an initial entry barrier.
Thank you both for your excellent answers.
2
Answers
you should be using multithreading, ie: by pushing work to other thread, so that the main thread will not be blocked, the most reliable way is using a Threadpool as follows.
and so every time you get an image, you will be assigning a task to another thread to load and process the next one.
I think you could make a very elegant solution using Redis which is a lightning-fast, in memory data-structure server – ideally suited to caching and prefetching. It has clients for C/C++, Python, Ruby,
bash
, Java and so on. In your case I would use it to store 2 data-structures:The basic idea would be to let the Tk app push a list of image names into the work queue on application startup and whenever the user changes directory, for example. And then pick up the processed image from Redis whenever it needs to display one.
You would then start a worker that purely sits waiting for image names to appear in a queue and processes them and stores the result in a fast Redis cache ready for the Tk app to use.
This has some advantages:
So the code for an image processing worker would be like this, and you can just run multiple, identical workers if you want faster throughput:
BRPOP is described here.
SET is described here.
The code within Tk, would look like this for pushing one or more filenames onto the job queue:
LPUSH is described here.
And when wanting to display a processed image, check it exists in Redis and grab it if it does. If it doesn’t exist in Redis, re-request – probably with RPUSH so it gets higher priority, or process it directly yourself and store result in Redis
GET is described here.
Because Redis has a
bash
(i.e. command-line) client, it also makes this simple to debug. You can check the length of the work queue from your Terminal. You can push items onto the work queue and delete items from the work queue. You can see if an image has been processed and so on, from outside your app and without any need to change it.Examples:
Let’s suppose you call your work queue
WQUEUE
and want to see its length, just using the Terminal:Or you want to list all the items in the queue:
Or you want to push the image filename
londonbridge.jpg
into the work queue:Or you want to see if image
londonbridge.jpg
has been processed and extract it into a file if so:Or you want to see the names of all the processed images:
Note that Redis is networked, so you can run Redis on one machine and connect to it from any other machine by specifying its hostname or IP address: