Merge remote-tracking branch 'upstream/3.4' into merge-3.4
@@ -32,11 +32,11 @@ Unspecified error: Can't create layer "layer_name" of type "MyType" in function
|
||||
To import the model correctly you have to derive a class from cv::dnn::Layer with
|
||||
the following methods:
|
||||
|
||||
@snippet dnn/custom_layers.cpp A custom layer interface
|
||||
@snippet dnn/custom_layers.hpp A custom layer interface
|
||||
|
||||
And register it before the import:
|
||||
|
||||
@snippet dnn/custom_layers.cpp Register a custom layer
|
||||
@snippet dnn/custom_layers.hpp Register a custom layer
|
||||
|
||||
@note `MyType` is a type of unimplemented layer from the thrown exception.
|
||||
|
||||
@@ -44,27 +44,27 @@ Let's see what all the methods do:
|
||||
|
||||
- Constructor
|
||||
|
||||
@snippet dnn/custom_layers.cpp MyLayer::MyLayer
|
||||
@snippet dnn/custom_layers.hpp MyLayer::MyLayer
|
||||
|
||||
Retrieves hyper-parameters from cv::dnn::LayerParams. If your layer has trainable
|
||||
weights they will be already stored in the Layer's member cv::dnn::Layer::blobs.
|
||||
|
||||
- A static method `create`
|
||||
|
||||
@snippet dnn/custom_layers.cpp MyLayer::create
|
||||
@snippet dnn/custom_layers.hpp MyLayer::create
|
||||
|
||||
This method should create an instance of you layer and return cv::Ptr with it.
|
||||
|
||||
- Output blobs' shape computation
|
||||
|
||||
@snippet dnn/custom_layers.cpp MyLayer::getMemoryShapes
|
||||
@snippet dnn/custom_layers.hpp MyLayer::getMemoryShapes
|
||||
|
||||
Returns layer's output shapes depends on input shapes. You may request an extra
|
||||
memory using `internals`.
|
||||
|
||||
- Run a layer
|
||||
|
||||
@snippet dnn/custom_layers.cpp MyLayer::forward
|
||||
@snippet dnn/custom_layers.hpp MyLayer::forward
|
||||
|
||||
Implement a layer's logic here. Compute outputs for given inputs.
|
||||
|
||||
@@ -74,7 +74,7 @@ the second invocation of `forward` will has the same data at `outputs` and `inte
|
||||
|
||||
- Optional `finalize` method
|
||||
|
||||
@snippet dnn/custom_layers.cpp MyLayer::finalize
|
||||
@snippet dnn/custom_layers.hpp MyLayer::finalize
|
||||
|
||||
The chain of methods are the following: OpenCV deep learning engine calls `create`
|
||||
method once then it calls `getMemoryShapes` for an every created layer then you
|
||||
@@ -108,11 +108,11 @@ layer {
|
||||
|
||||
This way our implementation can look like:
|
||||
|
||||
@snippet dnn/custom_layers.cpp InterpLayer
|
||||
@snippet dnn/custom_layers.hpp InterpLayer
|
||||
|
||||
Next we need to register a new layer type and try to import the model.
|
||||
|
||||
@snippet dnn/custom_layers.cpp Register InterpLayer
|
||||
@snippet dnn/custom_layers.hpp Register InterpLayer
|
||||
|
||||
## Example: custom layer from TensorFlow
|
||||
This is an example of how to import a network with [tf.image.resize_bilinear](https://www.tensorflow.org/versions/master/api_docs/python/tf/image/resize_bilinear)
|
||||
@@ -185,11 +185,11 @@ Custom layers import from TensorFlow is designed to put all layer's `attr` into
|
||||
cv::dnn::LayerParams but input `Const` blobs into cv::dnn::Layer::blobs.
|
||||
In our case resize's output shape will be stored in layer's `blobs[0]`.
|
||||
|
||||
@snippet dnn/custom_layers.cpp ResizeBilinearLayer
|
||||
@snippet dnn/custom_layers.hpp ResizeBilinearLayer
|
||||
|
||||
Next we register a layer and try to import the model.
|
||||
|
||||
@snippet dnn/custom_layers.cpp Register ResizeBilinearLayer
|
||||
@snippet dnn/custom_layers.hpp Register ResizeBilinearLayer
|
||||
|
||||
## Define a custom layer in Python
|
||||
The following example shows how to customize OpenCV's layers in Python.
|
||||
|
||||
@@ -5,6 +5,8 @@ This section contains tutorials about how to use the built-in graphical user int
|
||||
|
||||
- @subpage tutorial_trackbar
|
||||
|
||||
*Languages:* C++, Java, Python
|
||||
|
||||
*Compatibility:* \> OpenCV 2.0
|
||||
|
||||
*Author:* Ana Huamán
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
Adding a Trackbar to our applications! {#tutorial_trackbar}
|
||||
======================================
|
||||
|
||||
- In the previous tutorials (about *linear blending* and the *brightness and contrast
|
||||
adjustments*) you might have noted that we needed to give some **input** to our programs, such
|
||||
as \f$\alpha\f$ and \f$beta\f$. We accomplished that by entering this data using the Terminal
|
||||
- Well, it is time to use some fancy GUI tools. OpenCV provides some GUI utilities (*highgui.hpp*)
|
||||
for you. An example of this is a **Trackbar**
|
||||
- In the previous tutorials (about @ref tutorial_adding_images and the @ref tutorial_basic_linear_transform)
|
||||
you might have noted that we needed to give some **input** to our programs, such
|
||||
as \f$\alpha\f$ and \f$beta\f$. We accomplished that by entering this data using the Terminal.
|
||||
- Well, it is time to use some fancy GUI tools. OpenCV provides some GUI utilities (**highgui** module)
|
||||
for you. An example of this is a **Trackbar**.
|
||||
|
||||

|
||||
|
||||
@@ -24,26 +24,73 @@ Code
|
||||
|
||||
Let's modify the program made in the tutorial @ref tutorial_adding_images. We will let the user enter the
|
||||
\f$\alpha\f$ value by using the Trackbar.
|
||||
|
||||
@add_toggle_cpp
|
||||
This tutorial code's is shown lines below. You can also download it from
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp)
|
||||
@include cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
This tutorial code's is shown lines below. You can also download it from
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/highgui/trackbar/AddingImagesTrackbar.java)
|
||||
@include java/tutorial_code/highgui/trackbar/AddingImagesTrackbar.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
This tutorial code's is shown lines below. You can also download it from
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/highgui/trackbar/AddingImagesTrackbar.py)
|
||||
@include python/tutorial_code/highgui/trackbar/AddingImagesTrackbar.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
We only analyze the code that is related to Trackbar:
|
||||
|
||||
-# First, we load two images, which are going to be blended.
|
||||
@snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp load
|
||||
- First, we load two images, which are going to be blended.
|
||||
|
||||
-# To create a trackbar, first we have to create the window in which it is going to be located. So:
|
||||
@snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp window
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp load
|
||||
@end_toggle
|
||||
|
||||
-# Now we can create the Trackbar:
|
||||
@snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp create_trackbar
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/highgui/trackbar/AddingImagesTrackbar.java load
|
||||
@end_toggle
|
||||
|
||||
Note the following:
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/highgui/trackbar/AddingImagesTrackbar.py load
|
||||
@end_toggle
|
||||
|
||||
- To create a trackbar, first we have to create the window in which it is going to be located. So:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp window
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/highgui/trackbar/AddingImagesTrackbar.java window
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/highgui/trackbar/AddingImagesTrackbar.py window
|
||||
@end_toggle
|
||||
|
||||
- Now we can create the Trackbar:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp create_trackbar
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/highgui/trackbar/AddingImagesTrackbar.java create_trackbar
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/highgui/trackbar/AddingImagesTrackbar.py create_trackbar
|
||||
@end_toggle
|
||||
|
||||
Note the following (C++ code):
|
||||
- Our Trackbar has a label **TrackbarName**
|
||||
- The Trackbar is located in the window named **Linear Blend**
|
||||
- The Trackbar values will be in the range from \f$0\f$ to **alpha_slider_max** (the minimum
|
||||
@@ -51,10 +98,21 @@ We only analyze the code that is related to Trackbar:
|
||||
- The numerical value of Trackbar is stored in **alpha_slider**
|
||||
- Whenever the user moves the Trackbar, the callback function **on_trackbar** is called
|
||||
|
||||
-# Finally, we have to define the callback function **on_trackbar**
|
||||
@snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp on_trackbar
|
||||
Finally, we have to define the callback function **on_trackbar** for C++ and Python code, using an anonymous inner class listener in Java
|
||||
|
||||
Note that:
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp on_trackbar
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/highgui/trackbar/AddingImagesTrackbar.java on_trackbar
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/highgui/trackbar/AddingImagesTrackbar.py on_trackbar
|
||||
@end_toggle
|
||||
|
||||
Note that (C++ code):
|
||||
- We use the value of **alpha_slider** (integer) to get a double value for **alpha**.
|
||||
- **alpha_slider** is updated each time the trackbar is displaced by the user.
|
||||
- We define *src1*, *src2*, *dist*, *alpha*, *alpha_slider* and *beta* as global variables,
|
||||
|
||||
@@ -11,9 +11,6 @@ In this tutorial you will learn how to:
|
||||
- @ref cv::erode
|
||||
- @ref cv::dilate
|
||||
|
||||
Interesting fact
|
||||
-----------
|
||||
|
||||
@note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler.
|
||||
|
||||
Morphological Operations
|
||||
@@ -38,19 +35,14 @@ Morphological Operations
|
||||
- As the kernel \f$B\f$ is scanned over the image, we compute the maximal pixel value overlapped by
|
||||
\f$B\f$ and replace the image pixel in the anchor point position with that maximal value. As you can
|
||||
deduce, this maximizing operation causes bright regions within an image to "grow" (therefore the
|
||||
name *dilation*). Take the above image as an example. Applying dilation we can get:
|
||||
name *dilation*).
|
||||
- The dilatation operation is: \f$\texttt{dst} (x,y) = \max _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f$
|
||||
|
||||
- Take the above image as an example. Applying dilation we can get:
|
||||
|
||||

|
||||
|
||||
The background (bright) dilates around the black regions of the letter.
|
||||
|
||||
To better grasp the idea and avoid possible confusion, in this other example we have inverted the original
|
||||
image such as the object in white is now the letter. We have performed two dilatations with a rectangular
|
||||
structuring element of size `3x3`.
|
||||
|
||||

|
||||
|
||||
The dilatation makes the object in white bigger.
|
||||
- The bright area of the letter dilates around the black regions of the background.
|
||||
|
||||
### Erosion
|
||||
|
||||
@@ -58,31 +50,39 @@ The dilatation makes the object in white bigger.
|
||||
area of given kernel.
|
||||
- As the kernel \f$B\f$ is scanned over the image, we compute the minimal pixel value overlapped by
|
||||
\f$B\f$ and replace the image pixel under the anchor point with that minimal value.
|
||||
- The erosion operation is: \f$\texttt{dst} (x,y) = \min _{(x',y'): \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f$
|
||||
- Analagously to the example for dilation, we can apply the erosion operator to the original image
|
||||
(shown above). You can see in the result below that the bright areas of the image (the
|
||||
background, apparently), get thinner, whereas the dark zones (the "writing") gets bigger.
|
||||
(shown above). You can see in the result below that the bright areas of the image get thinner,
|
||||
whereas the dark zones gets bigger.
|
||||
|
||||

|
||||
|
||||
In similar manner, the corresponding image results by applying erosion operation on the inverted original image (two erosions
|
||||
with a rectangular structuring element of size `3x3`):
|
||||
|
||||

|
||||
|
||||
The erosion makes the object in white smaller.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
@add_toggle_cpp
|
||||
This tutorial's code is shown below. You can also download it
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp)
|
||||
@include samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
This tutorial's code is shown below. You can also download it
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java)
|
||||
@include samples/java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
This tutorial's code is shown below. You can also download it
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py)
|
||||
@include samples/python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py
|
||||
@end_toggle
|
||||
|
||||
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 program:
|
||||
previous sections). Let's check the general structure of the C++ program:
|
||||
|
||||
- Load an image (can be BGR or grayscale)
|
||||
- Create two windows (one for dilation output, the other for erosion)
|
||||
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 410 B After Width: | Height: | Size: 923 B |
|
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 844 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 458 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 685 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 558 B After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 608 B After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 617 B After Width: | Height: | Size: 1.5 KiB |
@@ -36,15 +36,10 @@ discuss briefly 5 operations offered by OpenCV:
|
||||
foreground)
|
||||
- For instance, check out the example below. The image at the left is the original and the image
|
||||
at the right is the result after applying the opening transformation. We can observe that the
|
||||
small spaces in the corners of the letter tend to disappear.
|
||||
small dots have disappeared.
|
||||
|
||||

|
||||
|
||||
For the sake of clarity, we have performed the opening operation (`7x7` rectangular structuring element)
|
||||
on the same original image but inverted such as the object in white is now the letter.
|
||||
|
||||

|
||||
|
||||
### Closing
|
||||
|
||||
- It is obtained by the dilation of an image followed by an erosion.
|
||||
@@ -55,10 +50,6 @@ on the same original image but inverted such as the object in white is now the l
|
||||
|
||||

|
||||
|
||||
On the inverted image, we have performed the closing operation (`7x7` rectangular structuring element):
|
||||
|
||||

|
||||
|
||||
### Morphological Gradient
|
||||
|
||||
- It is the difference between the dilation and the erosion of an image.
|
||||
@@ -88,14 +79,28 @@ On the inverted image, we have performed the closing operation (`7x7` rectangula
|
||||
Code
|
||||
----
|
||||
|
||||
This tutorial code's is shown lines below. You can also download it from
|
||||
@add_toggle_cpp
|
||||
This tutorial's code is shown below. You can also download it
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp)
|
||||
@include cpp/tutorial_code/ImgProc/Morphology_2.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
This tutorial's code is shown below. You can also download it
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/java/tutorial_code/ImgProc/opening_closing_hats/MorphologyDemo2.java)
|
||||
@include java/tutorial_code/ImgProc/opening_closing_hats/MorphologyDemo2.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
This tutorial's code is shown below. You can also download it
|
||||
[here](https://github.com/opencv/opencv/tree/master/samples/python/tutorial_code/imgProc/opening_closing_hats/morphology_2.py)
|
||||
@include python/tutorial_code/imgProc/opening_closing_hats/morphology_2.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
-# Let's check the general structure of the program:
|
||||
-# Let's check the general structure of the C++ program:
|
||||
- Load an image
|
||||
- Create a window to display results of the Morphological operations
|
||||
- Create three Trackbars for the user to enter parameters:
|
||||
@@ -139,8 +144,8 @@ Explanation
|
||||
Results
|
||||
-------
|
||||
|
||||
- After compiling the code above we can execute it giving an image path as an argument. For this
|
||||
tutorial we use as input the image: **baboon.png**:
|
||||
- After compiling the code above we can execute it giving an image path as an argument. Results using
|
||||
the image: **baboon.png**:
|
||||
|
||||

|
||||
|
||||
|
||||