Python OpenCV - show an image in a Tkinter window
Posted on April 20, 2018 by Paul
This is a short tutorial about using Tkinter, the default Python GUI library, with OpenCV. On Windows, Tkinter is bundled with the official Python installer. On Linux, you can install Tkinter using your distribution package manager. The situation is a bit more complex on macOS, that comes with Python 2.7 and an old version of Tkinter, at the time of this writing, the easiest path is to install Miniconda Python 3 that comes with the latest Tkinter.
OpenCV includes some rudimentary GUI capabilities, useful if you need to show a video or an image, get the mouse or the keyboard input. But, if you need something more complicated like buttons, drop down lists, menus, labels, text boxes and so on, you need to use a dedicated GUI library like Qt or Tkinter.
In the remaining of this article, I’ll assume that you have Python 3.6, Tkinter 8.6 and OpenCV 3.3 or newer installed on your machine. If you need help to install the above on Windows, macOS or Linux check my previous articles.
If you are on a Debian derived system, like Ubuntu, you can install Tkinter with:
Here is how you can create a window with Python 3 and Tkinter:
This is what you can see on a macOS machine if you run the above code:
Next, let’s add an image to our window. In Tkinter you can add an image to various widgets, e.g. you can add an image to a Label or a Button, you can put an image on a Canvas or you can use an image as the background of a Frame. For our purposes, the Tkinter Canvas widget is a good fit since it lets you add multiple overlapping images, draw shapes, write text and so on.
Tkinter stores and displays images using the PhotoImage class. As a side note, the PhotoImage class can read GIF, PPM and PGM images directly from your disk, e.g:
If you need to read or convert other image formats to a PhotoImage object, you can use the Pillow image library. This is how you can install Pillow on most operating systems:
On some cases (e.g. on Debian, Ubuntu, Raspbian), you will need to use pip3 instead of pip for the above install line.
As a side note, Pillow is a Python 3 reimplementation of the old Python Imaging Library.
Please note, that you could use Pillow to read most common image formats directly, but since this article is about using OpenCV with Tkinter, we are going to use OpenCV to read or write images to the disk. We’ll use Pillow to convert an image loaded by OpenCV to a PhotoImage object. Technically, the OpenCV bindings for Python store an image in a NumPy array.
Let’s start by loading the next image using OpenCV:
Now, that we have the image dimensions, let’s add a Tkinter Canvas element that can show the entire image:
Let’s use Pillow to convert the NumPy array that stores the loaded image to a PhotoImage and add this to the Canvas:
If you run the code, you should see something like this:
If the image looks off, it is because by default OpenCV will store a color image in the BGR or BGRA color space, while a Tkinter PhotoImage assumes the image is stored as RGB.
We can convert the image to RGB on the line that loads the image:
Here is the complete code that shows an image using OpenCV and Tkinter:
If you run the code, you should see something like this:
now, the image looks right.
Let’s add a button that, when pressed, will let us blur the image from the above example:
Please note in the above snippet the addition of a callback function that is triggered when the user presses the button. If you run the modified code, this is what you should see:
At this point, if you press the “Blur” button it will simply print blurred on the Terminal.
If we want to be able to blur the loaded image and show the blur effect we need a way to reference cv_img and photo in the blur_image function. An ugly, but effective, solution is to use the global keyword:
If you run the modified code and press the “Blur” button a couple of times, you should see something like this:
For a short example, like the one from this article, you can use global variables and a straightforward, imperative programming style. However, in a slightly larger program you will want to keep the code a bit more organized with classes and avoid the use of global variables.
Let’s see how we can rewrite the above example in a more OOP way:
If you want, you can further enhance the above code, for example, you can add a new button that will let you load a different image, check Tkinter filedialog.askopenfilename. Another feature you can add, is to let the user save the blurred image.
If you want to learn more about OpenCV and Python I would recommend reading OpenCV with Python Blueprints by M. Beyeler:
or, for OpenCV C++, OpenCV By Example by P. Joshi: