|
|
|
@ -84,57 +84,198 @@ This tutorial's code is shown below. You can also download it |
|
|
|
|
Explanation |
|
|
|
|
----------- |
|
|
|
|
|
|
|
|
|
-# Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in |
|
|
|
|
previous sections). Let's check the general structure of the C++ program: |
|
|
|
|
@add_toggle_cpp |
|
|
|
|
Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in |
|
|
|
|
previous sections). Let's check the general structure of the C++ program: |
|
|
|
|
|
|
|
|
|
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp main |
|
|
|
|
|
|
|
|
|
-# Load an image (can be BGR or grayscale) |
|
|
|
|
-# Create two windows (one for dilation output, the other for erosion) |
|
|
|
|
-# Create a set of two Trackbars for each operation: |
|
|
|
|
- The first trackbar "Element" returns either **erosion_elem** or **dilation_elem** |
|
|
|
|
- The second trackbar "Kernel size" return **erosion_size** or **dilation_size** for the |
|
|
|
|
corresponding operation. |
|
|
|
|
-# Call once erosion and dilation to show the initial image. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Every time we move any slider, the user's function **Erosion** or **Dilation** will be |
|
|
|
|
called and it will update the output image based on the current trackbar values. |
|
|
|
|
|
|
|
|
|
Let's analyze these two functions: |
|
|
|
|
|
|
|
|
|
#### The erosion function |
|
|
|
|
|
|
|
|
|
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp erosion |
|
|
|
|
|
|
|
|
|
The function that performs the *erosion* operation is @ref cv::erode . As we can see, it |
|
|
|
|
receives three arguments: |
|
|
|
|
- *src*: The source image |
|
|
|
|
- *erosion_dst*: The output image |
|
|
|
|
- *element*: This is the kernel we will use to perform the operation. If we do not |
|
|
|
|
specify, the default is a simple `3x3` matrix. Otherwise, we can specify its |
|
|
|
|
shape. For this, we need to use the function cv::getStructuringElement : |
|
|
|
|
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp kernel |
|
|
|
|
|
|
|
|
|
We can choose any of three shapes for our kernel: |
|
|
|
|
|
|
|
|
|
- Rectangular box: MORPH_RECT |
|
|
|
|
- Cross: MORPH_CROSS |
|
|
|
|
- Ellipse: MORPH_ELLIPSE |
|
|
|
|
|
|
|
|
|
Then, we just have to specify the size of our kernel and the *anchor point*. If not |
|
|
|
|
specified, it is assumed to be in the center. |
|
|
|
|
|
|
|
|
|
That is all. We are ready to perform the erosion of our image. |
|
|
|
|
|
|
|
|
|
#### The dilation function |
|
|
|
|
|
|
|
|
|
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**. |
|
|
|
|
Here we also have the option of defining our kernel, its anchor point and the size of the operator |
|
|
|
|
to be used. |
|
|
|
|
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp dilation |
|
|
|
|
@end_toggle |
|
|
|
|
|
|
|
|
|
@add_toggle_java |
|
|
|
|
Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in |
|
|
|
|
previous sections). Let's check however the general structure of the java class. There are 4 main |
|
|
|
|
parts in the java class: |
|
|
|
|
|
|
|
|
|
- the class constructor which setups the window that will be filled with window components |
|
|
|
|
- the `addComponentsToPane` method, which fills out the window |
|
|
|
|
- the `update` method, which determines what happens when the user changes any value |
|
|
|
|
- the `main` method, which is the entry point of the program |
|
|
|
|
|
|
|
|
|
In this tutorial we will focus on the `addComponentsToPane` and `update` methods. However, for completion the |
|
|
|
|
steps followed in the constructor are: |
|
|
|
|
|
|
|
|
|
-# Load an image (can be BGR or grayscale) |
|
|
|
|
-# Create a window |
|
|
|
|
-# Add various control components with `addComponentsToPane` |
|
|
|
|
-# show the window |
|
|
|
|
|
|
|
|
|
The components were added by the following method: |
|
|
|
|
|
|
|
|
|
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java components |
|
|
|
|
|
|
|
|
|
In short we |
|
|
|
|
|
|
|
|
|
-# create a panel for the sliders |
|
|
|
|
-# create a combo box for the element types |
|
|
|
|
-# create a slider for the kernel size |
|
|
|
|
-# create a combo box for the morphology function to use (erosion or dilation) |
|
|
|
|
|
|
|
|
|
The action and state changed listeners added call at the end the `update` method which updates |
|
|
|
|
the image based on the current slider values. So every time we move any slider, the `update` method is triggered. |
|
|
|
|
|
|
|
|
|
- Load an image (can be BGR or grayscale) |
|
|
|
|
- Create two windows (one for dilation output, the other for erosion) |
|
|
|
|
- Create a set of two Trackbars for each operation: |
|
|
|
|
- The first trackbar "Element" returns either **erosion_elem** or **dilation_elem** |
|
|
|
|
- The second trackbar "Kernel size" return **erosion_size** or **dilation_size** for the |
|
|
|
|
corresponding operation. |
|
|
|
|
- Every time we move any slider, the user's function **Erosion** or **Dilation** will be |
|
|
|
|
called and it will update the output image based on the current trackbar values. |
|
|
|
|
#### Updating the image |
|
|
|
|
|
|
|
|
|
Let's analyze these two functions: |
|
|
|
|
To update the image we used the following implementation: |
|
|
|
|
|
|
|
|
|
-# **erosion:** |
|
|
|
|
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp erosion |
|
|
|
|
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java update |
|
|
|
|
|
|
|
|
|
- The function that performs the *erosion* operation is @ref cv::erode . As we can see, it |
|
|
|
|
receives three arguments: |
|
|
|
|
- *src*: The source image |
|
|
|
|
- *erosion_dst*: The output image |
|
|
|
|
- *element*: This is the kernel we will use to perform the operation. If we do not |
|
|
|
|
specify, the default is a simple `3x3` matrix. Otherwise, we can specify its |
|
|
|
|
shape. For this, we need to use the function cv::getStructuringElement : |
|
|
|
|
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp kernel |
|
|
|
|
In other words we |
|
|
|
|
|
|
|
|
|
We can choose any of three shapes for our kernel: |
|
|
|
|
-# get the structuring element the user chose |
|
|
|
|
-# execute the **erosion** or **dilation** function based on `doErosion` |
|
|
|
|
-# reload the image with the morphology applied |
|
|
|
|
-# repaint the frame |
|
|
|
|
|
|
|
|
|
- Rectangular box: MORPH_RECT |
|
|
|
|
- Cross: MORPH_CROSS |
|
|
|
|
- Ellipse: MORPH_ELLIPSE |
|
|
|
|
Let's analyze the `erode` and `dilate` methods: |
|
|
|
|
|
|
|
|
|
Then, we just have to specify the size of our kernel and the *anchor point*. If not |
|
|
|
|
specified, it is assumed to be in the center. |
|
|
|
|
#### The erosion method |
|
|
|
|
|
|
|
|
|
- That is all. We are ready to perform the erosion of our image. |
|
|
|
|
@note Additionally, there is another parameter that allows you to perform multiple erosions |
|
|
|
|
(iterations) at once. However, We haven't used it in this simple tutorial. You can check out the |
|
|
|
|
reference for more details. |
|
|
|
|
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java erosion |
|
|
|
|
|
|
|
|
|
-# **dilation:** |
|
|
|
|
The function that performs the *erosion* operation is @ref cv::erode . As we can see, it |
|
|
|
|
receives three arguments: |
|
|
|
|
- *src*: The source image |
|
|
|
|
- *erosion_dst*: The output image |
|
|
|
|
- *element*: This is the kernel we will use to perform the operation. For specifying the shape, we need to use |
|
|
|
|
the function cv::getStructuringElement : |
|
|
|
|
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java kernel |
|
|
|
|
|
|
|
|
|
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**. |
|
|
|
|
Here we also have the option of defining our kernel, its anchor point and the size of the operator |
|
|
|
|
to be used. |
|
|
|
|
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp dilation |
|
|
|
|
We can choose any of three shapes for our kernel: |
|
|
|
|
|
|
|
|
|
- Rectangular box: CV_SHAPE_RECT |
|
|
|
|
- Cross: CV_SHAPE_CROSS |
|
|
|
|
- Ellipse: CV_SHAPE_ELLIPSE |
|
|
|
|
|
|
|
|
|
Together with the shape we specify the size of our kernel and the *anchor point*. If the anchor point is not |
|
|
|
|
specified, it is assumed to be in the center. |
|
|
|
|
|
|
|
|
|
That is all. We are ready to perform the erosion of our image. |
|
|
|
|
|
|
|
|
|
#### The dilation function |
|
|
|
|
|
|
|
|
|
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**. |
|
|
|
|
Here we also have the option of defining our kernel, its anchor point and the size of the operator |
|
|
|
|
to be used. |
|
|
|
|
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java dilation |
|
|
|
|
@end_toggle |
|
|
|
|
|
|
|
|
|
@add_toggle_python |
|
|
|
|
Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in |
|
|
|
|
previous sections). Let's check the general structure of the python script: |
|
|
|
|
|
|
|
|
|
@snippet python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py main |
|
|
|
|
|
|
|
|
|
-# Load an image (can be BGR or grayscale) |
|
|
|
|
-# Create two windows (one for erosion output, the other for dilation) with a set of trackbars each |
|
|
|
|
- The first trackbar "Element" returns the value for the morphological type that will be mapped |
|
|
|
|
(1 = rectangle, 2 = cross, 3 = ellipse) |
|
|
|
|
- The second trackbar "Kernel size" returns the size of the element for the |
|
|
|
|
corresponding operation |
|
|
|
|
-# Call once erosion and dilation to show the initial image |
|
|
|
|
|
|
|
|
|
Every time we move any slider, the user's function **erosion** or **dilation** will be |
|
|
|
|
called and it will update the output image based on the current trackbar values. |
|
|
|
|
|
|
|
|
|
Let's analyze these two functions: |
|
|
|
|
|
|
|
|
|
#### The erosion function |
|
|
|
|
|
|
|
|
|
@snippet python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py erosion |
|
|
|
|
|
|
|
|
|
The function that performs the *erosion* operation is @ref cv::erode . As we can see, it |
|
|
|
|
receives two arguments and returns the processed image: |
|
|
|
|
- *src*: The source image |
|
|
|
|
- *element*: The kernel we will use to perform the operation. We can specify its |
|
|
|
|
shape by using the function cv::getStructuringElement : |
|
|
|
|
@snippet python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py kernel |
|
|
|
|
|
|
|
|
|
We can choose any of three shapes for our kernel: |
|
|
|
|
|
|
|
|
|
- Rectangular box: MORPH_RECT |
|
|
|
|
- Cross: MORPH_CROSS |
|
|
|
|
- Ellipse: MORPH_ELLIPSE |
|
|
|
|
|
|
|
|
|
Then, we just have to specify the size of our kernel and the *anchor point*. If the anchor point not |
|
|
|
|
specified, it is assumed to be in the center. |
|
|
|
|
|
|
|
|
|
That is all. We are ready to perform the erosion of our image. |
|
|
|
|
|
|
|
|
|
#### The dilation function |
|
|
|
|
|
|
|
|
|
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**. |
|
|
|
|
Here we also have the option of defining our kernel, its anchor point and the size of the operator |
|
|
|
|
to be used. |
|
|
|
|
|
|
|
|
|
@snippet python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py dilation |
|
|
|
|
@end_toggle |
|
|
|
|
|
|
|
|
|
@note Additionally, there are further parameters that allow you to perform multiple erosions/dilations |
|
|
|
|
(iterations) at once and also set the border type and value. However, We haven't used those |
|
|
|
|
in this simple tutorial. You can check out the reference for more details. |
|
|
|
|
|
|
|
|
|
Results |
|
|
|
|
------- |
|
|
|
|
|
|
|
|
|
Compile the code above and execute it with an image as argument. For instance, using this image: |
|
|
|
|
Compile the code above and execute it (or run the script if using python) with an image as argument. |
|
|
|
|
If you do not provide an image as argument the default sample image |
|
|
|
|
([LinuxLogo.jpg](https://github.com/opencv/opencv/tree/master/samples/data/LinuxLogo.jpg)) will be used. |
|
|
|
|
|
|
|
|
|
For instance, using this image: |
|
|
|
|
|
|
|
|
|
 |
|
|
|
|
|
|
|
|
@ -143,3 +284,4 @@ naturally. Try them out! You can even try to add a third Trackbar to control the |
|
|
|
|
iterations. |
|
|
|
|
|
|
|
|
|
 |
|
|
|
|
(depending on the programming language the output might vary a little or be only 1 window) |
|
|
|
|