Skip to content

Commit

Permalink
Merge pull request opencv#16889 from mehlukas:3.4-consolidateImshow
Browse files Browse the repository at this point in the history
* consolidate tutorials on image read/display/write

* fix unsused variables

* apply requested changes

* apply requested changes

* fix mistake
  • Loading branch information
mehlukas authored Apr 7, 2020
1 parent 7347714 commit 75bd9f8
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 349 deletions.
Binary file not shown.
Binary file not shown.
151 changes: 1 addition & 150 deletions doc/py_tutorials/py_gui/py_image_display/py_image_display.markdown
Original file line number Diff line number Diff line change
@@ -1,153 +1,4 @@
Getting Started with Images {#tutorial_py_image_display}
===========================

Goals
-----

- Here, you will learn how to read an image, how to display it, and how to save it back
- You will learn these functions : **cv.imread()**, **cv.imshow()** , **cv.imwrite()**
- Optionally, you will learn how to display images with Matplotlib

Using OpenCV
------------

### Read an image

Use the function **cv.imread()** to read an image. The image should be in the working directory or
a full path of image should be given.

Second argument is a flag which specifies the way image should be read.

- cv.IMREAD_COLOR : Loads a color image. Any transparency of image will be neglected. It is the
default flag.
- cv.IMREAD_GRAYSCALE : Loads image in grayscale mode
- cv.IMREAD_UNCHANGED : Loads image as such including alpha channel

@note Instead of these three flags, you can simply pass integers 1, 0 or -1 respectively.

See the code below:
@code{.py}
import numpy as np
import cv2 as cv

# Load a color image in grayscale
img = cv.imread('messi5.jpg',0)
@endcode

**warning**

Even if the image path is wrong, it won't throw any error, but `print img` will give you `None`

### Display an image

Use the function **cv.imshow()** to display an image in a window. The window automatically fits to
the image size.

First argument is a window name which is a string. Second argument is our image. You can create as
many windows as you wish, but with different window names.
@code{.py}
cv.imshow('image',img)
cv.waitKey(0)
cv.destroyAllWindows()
@endcode
A screenshot of the window will look like this (in Fedora-Gnome machine):

![image](images/opencv_screenshot.jpg)

**cv.waitKey()** is a keyboard binding function. Its argument is the time in milliseconds. The
function waits for specified milliseconds for any keyboard event. If you press any key in that time,
the program continues. If **0** is passed, it waits indefinitely for a key stroke. It can also be
set to detect specific key strokes like, if key a is pressed etc which we will discuss below.

@note Besides binding keyboard events this function also processes many other GUI events, so you
MUST use it to actually display the image.

**cv.destroyAllWindows()** simply destroys all the windows we created. If you want to destroy any
specific window, use the function **cv.destroyWindow()** where you pass the exact window name as
the argument.

@note There is a special case where you can create an empty window and load an image to it later. In
that case, you can specify whether the window is resizable or not. It is done with the function
**cv.namedWindow()**. By default, the flag is cv.WINDOW_AUTOSIZE. But if you specify the flag to be
cv.WINDOW_NORMAL, you can resize window. It will be helpful when an image is too large in dimension
and when adding track bars to windows.

See the code below:
@code{.py}
cv.namedWindow('image', cv.WINDOW_NORMAL)
cv.imshow('image',img)
cv.waitKey(0)
cv.destroyAllWindows()
@endcode
### Write an image

Use the function **cv.imwrite()** to save an image.

First argument is the file name, second argument is the image you want to save.
@code{.py}
cv.imwrite('messigray.png',img)
@endcode
This will save the image in PNG format in the working directory.

### Sum it up

Below program loads an image in grayscale, displays it, saves the image if you press 's' and exit, or
simply exits without saving if you press ESC key.
@code{.py}
import numpy as np
import cv2 as cv

img = cv.imread('messi5.jpg',0)
cv.imshow('image',img)
k = cv.waitKey(0)
if k == 27: # wait for ESC key to exit
cv.destroyAllWindows()
elif k == ord('s'): # wait for 's' key to save and exit
cv.imwrite('messigray.png',img)
cv.destroyAllWindows()
@endcode

**warning**

If you are using a 64-bit machine, you will have to modify `k = cv.waitKey(0)` line as follows :
`k = cv.waitKey(0) & 0xFF`

Using Matplotlib
----------------

Matplotlib is a plotting library for Python which gives you wide variety of plotting methods. You
will see them in coming articles. Here, you will learn how to display image with Matplotlib. You can
zoom images, save them, etc, using Matplotlib.
@code{.py}
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread('messi5.jpg',0)
plt.imshow(img, cmap = 'gray', interpolation = 'bicubic')
plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis
plt.show()
@endcode
A screen-shot of the window will look like this :

![image](images/matplotlib_screenshot.jpg)

@note Plenty of plotting options are available in Matplotlib. Please refer to Matplotlib docs for more
details. Some, we will see on the way.

__warning__

Color image loaded by OpenCV is in BGR mode. But Matplotlib displays in RGB mode. So color images
will not be displayed correctly in Matplotlib if image is read with OpenCV. Please see the exercises
for more details.

Additional Resources
--------------------

-# [Matplotlib Plotting Styles and Features](http://matplotlib.org/api/pyplot_api.html)

Exercises
---------

-# There is some problem when you try to load color image in OpenCV and display it in Matplotlib.
Read [this discussion](http://stackoverflow.com/a/15074748/1134940) and understand it.
Tutorial content has been moved: @ref tutorial_display_image
2 changes: 1 addition & 1 deletion doc/py_tutorials/py_gui/py_table_of_contents_gui.markdown
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Gui Features in OpenCV {#tutorial_py_table_of_contents_gui}
======================

- @subpage tutorial_py_image_display
- @ref tutorial_display_image

Learn to load an
image, display it, and save it back
Expand Down
129 changes: 72 additions & 57 deletions doc/tutorials/introduction/display_image/display_image.markdown
Original file line number Diff line number Diff line change
@@ -1,63 +1,82 @@
Load and Display an Image {#tutorial_display_image}
=========================
Getting Started with Images {#tutorial_display_image}
===========================

Goal
----

In this tutorial you will learn how to:

- Load an image (using @ref cv::imread )
- Create a named OpenCV window (using @ref cv::namedWindow )
- Display an image in an OpenCV window (using @ref cv::imshow )
- Read an image from file (using @ref cv::imread)
- Display an image in an OpenCV window (using @ref cv::imshow)
- Write an image to a file (using @ref cv::imwrite)

Source Code
-----------

Download the source code from
[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/introduction/display_image/display_image.cpp).
@add_toggle_cpp
- **Downloadable code**: Click
[here](https://github.com/opencv/opencv/tree/3.4/samples/cpp/tutorial_code/introduction/display_image/display_image.cpp)

- **Code at glance:**
@include samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
@end_toggle

@add_toggle_python
- **Downloadable code**: Click
[here](https://github.com/opencv/opencv/tree/3.4/samples/python/tutorial_code/introduction/display_image/display_image.py)

- **Code at glance:**
@include samples/python/tutorial_code/introduction/display_image/display_image.py
@end_toggle

@include cpp/tutorial_code/introduction/display_image/display_image.cpp

Explanation
-----------

In OpenCV 2 we have multiple modules. Each one takes care of a different area or approach towards
@add_toggle_cpp
In OpenCV 3 we have multiple modules. Each one takes care of a different area or approach towards
image processing. You could already observe this in the structure of the user guide of these
tutorials itself. Before you use any of them you first need to include the header files where the
content of each individual module is declared.

You'll almost always end up using the:

- *core* section, as here are defined the basic building blocks of the library
- *highgui* module, as this contains the functions for input and output operations
- @ref core "core" section, as here are defined the basic building blocks of the library
- @ref imgcodecs "imgcodecs" module, which provides functions for reading and writing
- @ref highgui "highgui" module, as this contains the functions to show an image in a window

@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp includes

We also include the *iostream* to facilitate console line output and input. To avoid data structure
and function name conflicts with other libraries, OpenCV has its own namespace: *cv*. To avoid the
need appending prior each of these the *cv::* keyword you can import the namespace in the whole file
by using the lines:
We also include the *iostream* to facilitate console line output and input.

@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp namespace
By declaring `using namespace cv;`, in the following, the library functions can be accessed without explicitly stating the namespace.

This is true for the STL library too (used for console I/O). Now, let's analyze the *main* function.
We start up assuring that we acquire a valid image name argument from the command line. Otherwise
take a picture by default: "HappyFish.jpg".
@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp includes
@end_toggle

@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp load
@add_toggle_python
As a first step, the OpenCV python library is imported.
The proper way to do this is to additionally assign it the name *cv*, which is used in the following to reference the library.

Then create a *Mat* object that will store the data of the loaded image.
@snippet samples/python/tutorial_code/introduction/display_image/display_image.py imports
@end_toggle

@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp mat
Now, let's analyze the main code.
As a first step, we read the image "starry_night.jpg" from the OpenCV samples.
In order to do so, a call to the @ref cv::imread function loads the image using the file path specified by the first argument.
The second argument is optional and specifies the format in which we want the image. This may be:

Now we call the @ref cv::imread function which loads the image name specified by the first argument
(*argv[1]*). The second argument specifies the format in what we want the image. This may be:
- IMREAD_COLOR loads the image in the BGR 8-bit format. This is the **default** that is used here.
- IMREAD_UNCHANGED loads the image as is (including the alpha channel if present)
- IMREAD_GRAYSCALE loads the image as an intensity one

- IMREAD_UNCHANGED (\<0) loads the image as is (including the alpha channel if present)
- IMREAD_GRAYSCALE ( 0) loads the image as an intensity one
- IMREAD_COLOR (\>0) loads the image in the RGB format
After reading in the image data will be stored in a @ref cv::Mat object.

@add_toggle_cpp
@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp imread
@end_toggle

@add_toggle_python
@snippet samples/python/tutorial_code/introduction/display_image/display_image.py imread
@end_toggle

@note
OpenCV offers support for the image formats Windows bitmap (bmp), portable image formats (pbm,
Expand All @@ -67,42 +86,38 @@ Now we call the @ref cv::imread function which loads the image name specified by
Jasper), TIFF files (tiff, tif) and portable network graphics (png). Furthermore, OpenEXR is
also a possibility.

After checking that the image data was loaded correctly, we want to display our image, so we create
an OpenCV window using the @ref cv::namedWindow function. These are automatically managed by OpenCV
once you create them. For this you need to specify its name and how it should handle the change of
the image it contains from a size point of view. It may be:

- *WINDOW_AUTOSIZE* is the only supported one if you do not use the Qt backend. In this case the
window size will take up the size of the image it shows. No resize permitted!
- *WINDOW_NORMAL* on Qt you may use this to allow window resize. The image will resize itself
according to the current window size. By using the | operator you also need to specify if you
would like the image to keep its aspect ratio (*WINDOW_KEEPRATIO*) or not
(*WINDOW_FREERATIO*).
Afterwards, a check is executed, if the image was loaded correctly.
@add_toggle_cpp
@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp empty
@end_toggle

@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp window
@add_toggle_python
@snippet samples/python/tutorial_code/introduction/display_image/display_image.py empty
@end_toggle

Finally, to update the content of the OpenCV window with a new image use the @ref cv::imshow
function. Specify the OpenCV window name to update and the image to use during this operation:

@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp imshow
Then, the image is shown using a call to the @ref cv::imshow function.
The first argument is the title of the window and the second argument is the @ref cv::Mat object that will be shown.

Because we want our window to be displayed until the user presses a key (otherwise the program would
end far too quickly), we use the @ref cv::waitKey function whose only parameter is just how long
should it wait for a user input (measured in milliseconds). Zero means to wait forever.
The return value is the key that was pressed.

@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp wait
@add_toggle_cpp
@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp imshow
@end_toggle

Result
------
@add_toggle_python
@snippet samples/python/tutorial_code/introduction/display_image/display_image.py imshow
@end_toggle

- Compile your code and then run the executable giving an image path as argument. If you're on
Windows the executable will of course contain an *exe* extension too. Of course assure the image
file is near your program file.
@code{.sh}
./DisplayImage HappyFish.jpg
@endcode
- You should get a nice window as the one shown below:
In the end, the image is written to a file if the pressed key was the "s"-key.
For this the cv::imwrite function is called that has the file path and the cv::Mat object as an argument.

![](images/Display_Image_Tutorial_Result.jpg)
@add_toggle_cpp
@snippet cpp/tutorial_code/introduction/display_image/display_image.cpp imsave
@end_toggle

@youtube{1OJEqpuaGc4}
@add_toggle_python
@snippet samples/python/tutorial_code/introduction/display_image/display_image.py imsave
@end_toggle
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 75bd9f8

Please sign in to comment.