init - 初始化项目
@@ -0,0 +1,174 @@
|
||||
Canny Edge Detector {#tutorial_canny_detector}
|
||||
===================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_laplace_operator}
|
||||
@next_tutorial{tutorial_hough_lines}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV function @ref cv::Canny to implement the Canny Edge Detector.
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
The *Canny Edge detector* @cite Canny86 was developed by John F. Canny in 1986. Also known to many as the
|
||||
*optimal detector*, the Canny algorithm aims to satisfy three main criteria:
|
||||
- **Low error rate:** Meaning a good detection of only existent edges.
|
||||
- **Good localization:** The distance between edge pixels detected and real edge pixels have
|
||||
to be minimized.
|
||||
- **Minimal response:** Only one detector response per edge.
|
||||
|
||||
### Steps
|
||||
|
||||
-# Filter out any noise. The Gaussian filter is used for this purpose. An example of a Gaussian
|
||||
kernel of \f$size = 5\f$ that might be used is shown below:
|
||||
|
||||
\f[K = \dfrac{1}{159}\begin{bmatrix}
|
||||
2 & 4 & 5 & 4 & 2 \\
|
||||
4 & 9 & 12 & 9 & 4 \\
|
||||
5 & 12 & 15 & 12 & 5 \\
|
||||
4 & 9 & 12 & 9 & 4 \\
|
||||
2 & 4 & 5 & 4 & 2
|
||||
\end{bmatrix}\f]
|
||||
|
||||
-# Find the intensity gradient of the image. For this, we follow a procedure analogous to Sobel:
|
||||
-# Apply a pair of convolution masks (in \f$x\f$ and \f$y\f$ directions:
|
||||
\f[G_{x} = \begin{bmatrix}
|
||||
-1 & 0 & +1 \\
|
||||
-2 & 0 & +2 \\
|
||||
-1 & 0 & +1
|
||||
\end{bmatrix}\f]\f[G_{y} = \begin{bmatrix}
|
||||
-1 & -2 & -1 \\
|
||||
0 & 0 & 0 \\
|
||||
+1 & +2 & +1
|
||||
\end{bmatrix}\f]
|
||||
|
||||
-# Find the gradient strength and direction with:
|
||||
\f[\begin{array}{l}
|
||||
G = \sqrt{ G_{x}^{2} + G_{y}^{2} } \\
|
||||
\theta = \arctan(\dfrac{ G_{y} }{ G_{x} })
|
||||
\end{array}\f]
|
||||
The direction is rounded to one of four possible angles (namely 0, 45, 90 or 135)
|
||||
|
||||
-# *Non-maximum* suppression is applied. This removes pixels that are not considered to be part of
|
||||
an edge. Hence, only thin lines (candidate edges) will remain.
|
||||
-# *Hysteresis*: The final step. Canny does use two thresholds (upper and lower):
|
||||
|
||||
-# If a pixel gradient is higher than the *upper* threshold, the pixel is accepted as an edge
|
||||
-# If a pixel gradient value is below the *lower* threshold, then it is rejected.
|
||||
-# If the pixel gradient is between the two thresholds, then it will be accepted only if it is
|
||||
connected to a pixel that is above the *upper* threshold.
|
||||
|
||||
Canny recommended a *upper*:*lower* ratio between 2:1 and 3:1.
|
||||
|
||||
-# For more details, you can always consult your favorite Computer Vision book.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
@add_toggle_cpp
|
||||
- The 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/ImgTrans/CannyDetector_Demo.cpp)
|
||||
@include samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
- The 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/ImgTrans/canny_detector/CannyDetectorDemo.java)
|
||||
@include samples/java/tutorial_code/ImgTrans/canny_detector/CannyDetectorDemo.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
- The 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/ImgTrans/canny_detector/CannyDetector_Demo.py)
|
||||
@include samples/python/tutorial_code/ImgTrans/canny_detector/CannyDetector_Demo.py
|
||||
@end_toggle
|
||||
|
||||
- **What does this program do?**
|
||||
- Asks the user to enter a numerical value to set the lower threshold for our *Canny Edge
|
||||
Detector* (by means of a Trackbar).
|
||||
- Applies the *Canny Detector* and generates a **mask** (bright lines representing the edges
|
||||
on a black background).
|
||||
- Applies the mask obtained on the original image and display it in a window.
|
||||
|
||||
Explanation (C++ code)
|
||||
----------------------
|
||||
|
||||
-# Create some needed variables:
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp variables
|
||||
|
||||
Note the following:
|
||||
|
||||
-# We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*).
|
||||
-# We set the kernel size of \f$3\f$ (for the Sobel operations to be performed internally by the
|
||||
Canny function).
|
||||
-# We set a maximum value for the lower Threshold of \f$100\f$.
|
||||
|
||||
-# Loads the source image:
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp load
|
||||
|
||||
-# Create a matrix of the same type and size of *src* (to be *dst*):
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_mat
|
||||
-# Convert the image to grayscale (using the function @ref cv::cvtColor ):
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp convert_to_gray
|
||||
-# Create a window to display the results:
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_window
|
||||
-# Create a Trackbar for the user to enter the lower threshold for our Canny detector:
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_trackbar
|
||||
Observe the following:
|
||||
|
||||
-# The variable to be controlled by the Trackbar is *lowThreshold* with a limit of
|
||||
*max_lowThreshold* (which we set to 100 previously)
|
||||
-# Each time the Trackbar registers an action, the callback function *CannyThreshold* will be
|
||||
invoked.
|
||||
|
||||
-# Let's check the *CannyThreshold* function, step by step:
|
||||
-# First, we blur the image with a filter of kernel size 3:
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp reduce_noise
|
||||
-# Second, we apply the OpenCV function @ref cv::Canny :
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp canny
|
||||
where the arguments are:
|
||||
|
||||
- *detected_edges*: Source image, grayscale
|
||||
- *detected_edges*: Output of the detector (can be the same as the input)
|
||||
- *lowThreshold*: The value entered by the user moving the Trackbar
|
||||
- *highThreshold*: Set in the program as three times the lower threshold (following
|
||||
Canny's recommendation)
|
||||
- *kernel_size*: We defined it to be 3 (the size of the Sobel kernel to be used
|
||||
internally)
|
||||
|
||||
-# We fill a *dst* image with zeros (meaning the image is completely black).
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp fill
|
||||
-# Finally, we will use the function @ref cv::Mat::copyTo to map only the areas of the image that are
|
||||
identified as edges (on a black background).
|
||||
@ref cv::Mat::copyTo copy the *src* image onto *dst*. However, it will only copy the pixels in the
|
||||
locations where they have non-zero values. Since the output of the Canny detector is the edge
|
||||
contours on a black background, the resulting *dst* will be black in all the area but the
|
||||
detected edges.
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp copyto
|
||||
-# We display our result:
|
||||
@snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp display
|
||||
|
||||
Result
|
||||
------
|
||||
|
||||
- After compiling the code above, we can run it giving as argument the path to an image. For
|
||||
example, using as an input the following image:
|
||||
|
||||

|
||||
|
||||
- Moving the slider, trying different threshold, we obtain the following result:
|
||||
|
||||

|
||||
|
||||
- Notice how the image is superposed to the black background on the edge regions.
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -0,0 +1,243 @@
|
||||
Adding borders to your images {#tutorial_copyMakeBorder}
|
||||
=============================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_filter_2d}
|
||||
@next_tutorial{tutorial_sobel_derivatives}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV function **copyMakeBorder()** to set the borders (extra padding to your
|
||||
image).
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
@note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler.
|
||||
|
||||
-# In our previous tutorial we learned to use convolution to operate on images. One problem that
|
||||
naturally arises is how to handle the boundaries. How can we convolve them if the evaluated
|
||||
points are at the edge of the image?
|
||||
-# What most of OpenCV functions do is to copy a given image onto another slightly larger image and
|
||||
then automatically pads the boundary (by any of the methods explained in the sample code just
|
||||
below). This way, the convolution can be performed over the needed pixels without problems (the
|
||||
extra padding is cut after the operation is done).
|
||||
-# In this tutorial, we will briefly explore two ways of defining the extra padding (border) for an
|
||||
image:
|
||||
|
||||
-# **BORDER_CONSTANT**: Pad the image with a constant value (i.e. black or \f$0\f$
|
||||
-# **BORDER_REPLICATE**: The row or column at the very edge of the original is replicated to
|
||||
the extra border.
|
||||
|
||||
This will be seen more clearly in the Code section.
|
||||
|
||||
- **What does this program do?**
|
||||
- Load an image
|
||||
- Let the user choose what kind of padding use in the input image. There are two options:
|
||||
|
||||
-# *Constant value border*: Applies a padding of a constant value for the whole border.
|
||||
This value will be updated randomly each 0.5 seconds.
|
||||
-# *Replicated border*: The border will be replicated from the pixel values at the edges of
|
||||
the original image.
|
||||
|
||||
The user chooses either option by pressing 'c' (constant) or 'r' (replicate)
|
||||
- The program finishes when the user presses 'ESC'
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
The tutorial code's is shown lines below.
|
||||
|
||||
@add_toggle_cpp
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp)
|
||||
@include samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java)
|
||||
@include samples/java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py)
|
||||
@include samples/python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
#### Declare the variables
|
||||
|
||||
First we declare the variables we are going to use:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp variables
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java variables
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py variables
|
||||
@end_toggle
|
||||
|
||||
Especial attention deserves the variable *rng* which is a random number generator. We use it to
|
||||
generate the random border color, as we will see soon.
|
||||
|
||||
#### Load an image
|
||||
|
||||
As usual we load our source image *src*:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py load
|
||||
@end_toggle
|
||||
|
||||
#### Create a window
|
||||
|
||||
After giving a short intro of how to use the program, we create a window:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp create_window
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java create_window
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py create_window
|
||||
@end_toggle
|
||||
|
||||
#### Initialize arguments
|
||||
|
||||
Now we initialize the argument that defines the size of the borders (*top*, *bottom*, *left* and
|
||||
*right*). We give them a value of 5% the size of *src*.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp init_arguments
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java init_arguments
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py init_arguments
|
||||
@end_toggle
|
||||
|
||||
#### Loop
|
||||
|
||||
The program runs in an infinite loop while the key **ESC** isn't pressed.
|
||||
If the user presses '**c**' or '**r**', the *borderType* variable
|
||||
takes the value of *BORDER_CONSTANT* or *BORDER_REPLICATE* respectively:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp check_keypress
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java check_keypress
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py check_keypress
|
||||
@end_toggle
|
||||
|
||||
#### Random color
|
||||
|
||||
In each iteration (after 0.5 seconds), the random border color (*value*) is updated...
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp update_value
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java update_value
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py update_value
|
||||
@end_toggle
|
||||
|
||||
This value is a set of three numbers picked randomly in the range \f$[0,255]\f$.
|
||||
|
||||
#### Form a border around the image
|
||||
|
||||
Finally, we call the function **copyMakeBorder()** to apply the respective padding:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp copymakeborder
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java copymakeborder
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py copymakeborder
|
||||
@end_toggle
|
||||
|
||||
- The arguments are:
|
||||
|
||||
-# *src*: Source image
|
||||
-# *dst*: Destination image
|
||||
-# *top*, *bottom*, *left*, *right*: Length in pixels of the borders at each side of the image.
|
||||
We define them as being 5% of the original size of the image.
|
||||
-# *borderType*: Define what type of border is applied. It can be constant or replicate for
|
||||
this example.
|
||||
-# *value*: If *borderType* is *BORDER_CONSTANT*, this is the value used to fill the border
|
||||
pixels.
|
||||
|
||||
#### Display the results
|
||||
|
||||
We display our output image in the image created previously
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp display
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/MakeBorder/CopyMakeBorder.java display
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/MakeBorder/copy_make_border.py display
|
||||
@end_toggle
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
-# After compiling the code above, you can execute it giving as argument the path of an image. The
|
||||
result should be:
|
||||
|
||||
- By default, it begins with the border set to BORDER_CONSTANT. Hence, a succession of random
|
||||
colored borders will be shown.
|
||||
- If you press 'r', the border will become a replica of the edge pixels.
|
||||
- If you press 'c', the random colored borders will appear again
|
||||
- If you press 'ESC' the program will exit.
|
||||
|
||||
Below some screenshot showing how the border changes color and how the *BORDER_REPLICATE*
|
||||
option looks:
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,177 @@
|
||||
Image Segmentation with Distance Transform and Watershed Algorithm {#tutorial_distance_transform}
|
||||
=============
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_point_polygon_test}
|
||||
@next_tutorial{tutorial_out_of_focus_deblur_filter}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Theodore Tsesmelis |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV function @ref cv::filter2D in order to perform some laplacian filtering for image sharpening
|
||||
- Use the OpenCV function @ref cv::distanceTransform in order to obtain the derived representation of a binary image, where the value of each pixel is replaced by its distance to the nearest background pixel
|
||||
- Use the OpenCV function @ref cv::watershed in order to isolate objects in the image from the background
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
@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/ImgTrans/imageSegmentation.cpp).
|
||||
@include samples/cpp/tutorial_code/ImgTrans/imageSegmentation.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/ImgTrans/distance_transformation/ImageSegmentationDemo.java)
|
||||
@include samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.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/ImgTrans/distance_transformation/imageSegmentation.py)
|
||||
@include samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py
|
||||
@end_toggle
|
||||
|
||||
Explanation / Result
|
||||
--------------------
|
||||
|
||||
- Load the source image and check if it is loaded without any problem, then show it:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp load_image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java load_image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py load_image
|
||||
@end_toggle
|
||||
|
||||

|
||||
|
||||
- Then if we have an image with a white background, it is good to transform it to black. This will help us to discriminate the foreground objects easier when we will apply the Distance Transform:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp black_bg
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java black_bg
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py black_bg
|
||||
@end_toggle
|
||||
|
||||

|
||||
|
||||
- Afterwards we will sharpen our image in order to acute the edges of the foreground objects. We will apply a laplacian filter with a quite strong filter (an approximation of second derivative):
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp sharp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java sharp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py sharp
|
||||
@end_toggle
|
||||
|
||||

|
||||

|
||||
|
||||
- Now we transform our new sharpened source image to a grayscale and a binary one, respectively:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp bin
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java bin
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py bin
|
||||
@end_toggle
|
||||
|
||||

|
||||
|
||||
- We are ready now to apply the Distance Transform on the binary image. Moreover, we normalize the output image in order to be able visualize and threshold the result:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp dist
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java dist
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py dist
|
||||
@end_toggle
|
||||
|
||||

|
||||
|
||||
- We threshold the *dist* image and then perform some morphology operation (i.e. dilation) in order to extract the peaks from the above image:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp peaks
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java peaks
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py peaks
|
||||
@end_toggle
|
||||
|
||||

|
||||
|
||||
- From each blob then we create a seed/marker for the watershed algorithm with the help of the @ref cv::findContours function:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp seeds
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java seeds
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py seeds
|
||||
@end_toggle
|
||||
|
||||

|
||||
|
||||
- Finally, we can apply the watershed algorithm, and visualize the result:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp watershed
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/distance_transformation/ImageSegmentationDemo.java watershed
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/distance_transformation/imageSegmentation.py watershed
|
||||
@end_toggle
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 46 KiB |
183
doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.markdown
Normal file
@@ -0,0 +1,183 @@
|
||||
Making your own linear filters! {#tutorial_filter_2d}
|
||||
===============================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_threshold_inRange}
|
||||
@next_tutorial{tutorial_copyMakeBorder}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV function **filter2D()** to create your own linear filters.
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
@note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler.
|
||||
|
||||
### Correlation
|
||||
|
||||
In a very general sense, correlation is an operation between every part of an image and an operator
|
||||
(kernel).
|
||||
|
||||
### What is a kernel?
|
||||
|
||||
A kernel is essentially a fixed size array of numerical coefficients along with an *anchor point* in
|
||||
that array, which is typically located at the center.
|
||||
|
||||

|
||||
|
||||
### How does correlation with a kernel work?
|
||||
|
||||
Assume you want to know the resulting value of a particular location in the image. The value of the
|
||||
correlation is calculated in the following way:
|
||||
|
||||
-# Place the kernel anchor on top of a determined pixel, with the rest of the kernel overlaying the
|
||||
corresponding local pixels in the image.
|
||||
-# Multiply the kernel coefficients by the corresponding image pixel values and sum the result.
|
||||
-# Place the result to the location of the *anchor* in the input image.
|
||||
-# Repeat the process for all pixels by scanning the kernel over the entire image.
|
||||
|
||||
Expressing the procedure above in the form of an equation we would have:
|
||||
|
||||
\f[H(x,y) = \sum_{i=0}^{M_{i} - 1} \sum_{j=0}^{M_{j}-1} I(x+i - a_{i}, y + j - a_{j})K(i,j)\f]
|
||||
|
||||
Fortunately, OpenCV provides you with the function **filter2D()** so you do not have to code all
|
||||
these operations.
|
||||
|
||||
### What does this program do?
|
||||
- Loads an image
|
||||
- Performs a *normalized box filter*. For instance, for a kernel of size \f$size = 3\f$, the
|
||||
kernel would be:
|
||||
|
||||
\f[K = \dfrac{1}{3 \cdot 3} \begin{bmatrix}
|
||||
1 & 1 & 1 \\
|
||||
1 & 1 & 1 \\
|
||||
1 & 1 & 1
|
||||
\end{bmatrix}\f]
|
||||
|
||||
The program will perform the filter operation with kernels of sizes 3, 5, 7, 9 and 11.
|
||||
|
||||
- The filter output (with each kernel) will be shown during 500 milliseconds
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
The tutorial code's is shown in the lines below.
|
||||
|
||||
@add_toggle_cpp
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp)
|
||||
@include cpp/tutorial_code/ImgTrans/filter2D_demo.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java)
|
||||
@include java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/Filter2D/filter2D.py)
|
||||
@include python/tutorial_code/ImgTrans/Filter2D/filter2D.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
#### Load an image
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/Filter2D/filter2D.py load
|
||||
@end_toggle
|
||||
|
||||
#### Initialize the arguments
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp init_arguments
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java init_arguments
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/Filter2D/filter2D.py init_arguments
|
||||
@end_toggle
|
||||
|
||||
##### Loop
|
||||
|
||||
Perform an infinite loop updating the kernel size and applying our linear filter to the input
|
||||
image. Let's analyze that more in detail:
|
||||
|
||||
- First we define the kernel our filter is going to use. Here it is:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp update_kernel
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java update_kernel
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/Filter2D/filter2D.py update_kernel
|
||||
@end_toggle
|
||||
|
||||
The first line is to update the *kernel_size* to odd values in the range: \f$[3,11]\f$.
|
||||
The second line actually builds the kernel by setting its value to a matrix filled with
|
||||
\f$1's\f$ and normalizing it by dividing it between the number of elements.
|
||||
|
||||
- After setting the kernel, we can generate the filter by using the function **filter2D()** :
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp apply_filter
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet java/tutorial_code/ImgTrans/Filter2D/Filter2D_Demo.java apply_filter
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet python/tutorial_code/ImgTrans/Filter2D/filter2D.py apply_filter
|
||||
@end_toggle
|
||||
|
||||
- The arguments denote:
|
||||
- *src*: Source image
|
||||
- *dst*: Destination image
|
||||
- *ddepth*: The depth of *dst*. A negative value (such as \f$-1\f$) indicates that the depth is
|
||||
the same as the source.
|
||||
- *kernel*: The kernel to be scanned through the image
|
||||
- *anchor*: The position of the anchor relative to its kernel. The location *Point(-1, -1)*
|
||||
indicates the center by default.
|
||||
- *delta*: A value to be added to each pixel during the correlation. By default it is \f$0\f$
|
||||
- *BORDER_DEFAULT*: We let this value by default (more details in the following tutorial)
|
||||
|
||||
- Our program will effectuate a *while* loop, each 500 ms the kernel size of our filter will be
|
||||
updated in the range indicated.
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
-# After compiling the code above, you can execute it giving as argument the path of an image. The
|
||||
result should be a window that shows an image blurred by a normalized filter. Each 0.5 seconds
|
||||
the kernel size should change, as can be seen in the series of snapshots below:
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,182 @@
|
||||
Hough Circle Transform {#tutorial_hough_circle}
|
||||
======================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_hough_lines}
|
||||
@next_tutorial{tutorial_remap}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV function **HoughCircles()** to detect circles in an image.
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
### Hough Circle Transform
|
||||
|
||||
- The Hough Circle Transform works in a *roughly* analogous way to the Hough Line Transform
|
||||
explained in the previous tutorial.
|
||||
- In the line detection case, a line was defined by two parameters \f$(r, \theta)\f$. In the circle
|
||||
case, we need three parameters to define a circle:
|
||||
|
||||
\f[C : ( x_{center}, y_{center}, r )\f]
|
||||
|
||||
where \f$(x_{center}, y_{center})\f$ define the center position (green point) and \f$r\f$ is the radius,
|
||||
which allows us to completely define a circle, as it can be seen below:
|
||||
|
||||

|
||||
|
||||
- For sake of efficiency, OpenCV implements a detection method slightly trickier than the standard
|
||||
Hough Transform: *The Hough gradient method*, which is made up of two main stages. The first
|
||||
stage involves edge detection and finding the possible circle centers and the second stage finds
|
||||
the best radius for each candidate center. For more details, please check the book *Learning
|
||||
OpenCV* or your favorite Computer Vision bibliography
|
||||
|
||||
#### What does this program do?
|
||||
- Loads an image and blur it to reduce the noise
|
||||
- Applies the *Hough Circle Transform* to the blurred image .
|
||||
- Display the detected circle in a window.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
@add_toggle_cpp
|
||||
The sample code that we will explain can be downloaded from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp).
|
||||
A slightly fancier version (which shows trackbars for changing the threshold values) can be found
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp).
|
||||
@include samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
The sample code that we will explain can be downloaded from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java).
|
||||
@include samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
The sample code that we will explain can be downloaded from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py).
|
||||
@include samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
The image we used can be found [here](https://raw.githubusercontent.com/opencv/opencv/master/samples/data/smarties.png)
|
||||
|
||||
#### Load an image:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java load
|
||||
@end_toggle
|
||||
|
||||
#### Convert it to grayscale:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp convert_to_gray
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py convert_to_gray
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java convert_to_gray
|
||||
@end_toggle
|
||||
|
||||
#### Apply a Median blur to reduce noise and avoid false circle detection:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp reduce_noise
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py reduce_noise
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java reduce_noise
|
||||
@end_toggle
|
||||
|
||||
#### Proceed to apply Hough Circle Transform:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp houghcircles
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py houghcircles
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java houghcircles
|
||||
@end_toggle
|
||||
|
||||
- with the arguments:
|
||||
|
||||
- *gray*: Input image (grayscale).
|
||||
- *circles*: A vector that stores sets of 3 values: \f$x_{c}, y_{c}, r\f$ for each detected
|
||||
circle.
|
||||
- *HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in
|
||||
OpenCV.
|
||||
- *dp = 1*: The inverse ratio of resolution.
|
||||
- *min_dist = gray.rows/16*: Minimum distance between detected centers.
|
||||
- *param_1 = 200*: Upper threshold for the internal Canny edge detector.
|
||||
- *param_2* = 100\*: Threshold for center detection.
|
||||
- *min_radius = 0*: Minimum radius to be detected. If unknown, put zero as default.
|
||||
- *max_radius = 0*: Maximum radius to be detected. If unknown, put zero as default.
|
||||
|
||||
#### Draw the detected circles:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp draw
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py draw
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java draw
|
||||
@end_toggle
|
||||
|
||||
You can see that we will draw the circle(s) on red and the center(s) with a small green dot
|
||||
|
||||
#### Display the detected circle(s) and wait for the user to exit the program:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghcircles.cpp display
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughCircle/hough_circle.py display
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughCircle/HoughCircles.java display
|
||||
@end_toggle
|
||||
|
||||
Result
|
||||
------
|
||||
|
||||
The result of running the code above with a test image is shown below:
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 77 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
289
doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.markdown
Normal file
@@ -0,0 +1,289 @@
|
||||
Hough Line Transform {#tutorial_hough_lines}
|
||||
====================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_canny_detector}
|
||||
@next_tutorial{tutorial_hough_circle}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV functions **HoughLines()** and **HoughLinesP()** to detect lines in an
|
||||
image.
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
@note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler.
|
||||
|
||||
Hough Line Transform
|
||||
--------------------
|
||||
|
||||
-# The Hough Line Transform is a transform used to detect straight lines.
|
||||
-# To apply the Transform, first an edge detection pre-processing is desirable.
|
||||
|
||||
### How does it work?
|
||||
|
||||
-# As you know, a line in the image space can be expressed with two variables. For example:
|
||||
|
||||
-# In the **Cartesian coordinate system:** Parameters: \f$(m,b)\f$.
|
||||
-# In the **Polar coordinate system:** Parameters: \f$(r,\theta)\f$
|
||||
|
||||

|
||||
|
||||
For Hough Transforms, we will express lines in the *Polar system*. Hence, a line equation can be
|
||||
written as:
|
||||
|
||||
\f[y = \left ( -\dfrac{\cos \theta}{\sin \theta} \right ) x + \left ( \dfrac{r}{\sin \theta} \right )\f]
|
||||
|
||||
Arranging the terms: \f$r = x \cos \theta + y \sin \theta\f$
|
||||
|
||||
-# In general for each point \f$(x_{0}, y_{0})\f$, we can define the family of lines that goes through
|
||||
that point as:
|
||||
|
||||
\f[r_{\theta} = x_{0} \cdot \cos \theta + y_{0} \cdot \sin \theta\f]
|
||||
|
||||
Meaning that each pair \f$(r_{\theta},\theta)\f$ represents each line that passes by
|
||||
\f$(x_{0}, y_{0})\f$.
|
||||
|
||||
-# If for a given \f$(x_{0}, y_{0})\f$ we plot the family of lines that goes through it, we get a
|
||||
sinusoid. For instance, for \f$x_{0} = 8\f$ and \f$y_{0} = 6\f$ we get the following plot (in a plane
|
||||
\f$\theta\f$ - \f$r\f$):
|
||||
|
||||

|
||||
|
||||
We consider only points such that \f$r > 0\f$ and \f$0< \theta < 2 \pi\f$.
|
||||
|
||||
-# We can do the same operation above for all the points in an image. If the curves of two
|
||||
different points intersect in the plane \f$\theta\f$ - \f$r\f$, that means that both points belong to a
|
||||
same line. For instance, following with the example above and drawing the plot for two more
|
||||
points: \f$x_{1} = 4\f$, \f$y_{1} = 9\f$ and \f$x_{2} = 12\f$, \f$y_{2} = 3\f$, we get:
|
||||
|
||||

|
||||
|
||||
The three plots intersect in one single point \f$(0.925, 9.6)\f$, these coordinates are the
|
||||
parameters (\f$\theta, r\f$) or the line in which \f$(x_{0}, y_{0})\f$, \f$(x_{1}, y_{1})\f$ and
|
||||
\f$(x_{2}, y_{2})\f$ lay.
|
||||
|
||||
-# What does all the stuff above mean? It means that in general, a line can be *detected* by
|
||||
finding the number of intersections between curves.The more curves intersecting means that the
|
||||
line represented by that intersection have more points. In general, we can define a *threshold*
|
||||
of the minimum number of intersections needed to *detect* a line.
|
||||
-# This is what the Hough Line Transform does. It keeps track of the intersection between curves of
|
||||
every point in the image. If the number of intersections is above some *threshold*, then it
|
||||
declares it as a line with the parameters \f$(\theta, r_{\theta})\f$ of the intersection point.
|
||||
|
||||
### Standard and Probabilistic Hough Line Transform
|
||||
|
||||
OpenCV implements two kind of Hough Line Transforms:
|
||||
|
||||
a. **The Standard Hough Transform**
|
||||
|
||||
- It consists in pretty much what we just explained in the previous section. It gives you as
|
||||
result a vector of couples \f$(\theta, r_{\theta})\f$
|
||||
- In OpenCV it is implemented with the function **HoughLines()**
|
||||
|
||||
b. **The Probabilistic Hough Line Transform**
|
||||
|
||||
- A more efficient implementation of the Hough Line Transform. It gives as output the extremes
|
||||
of the detected lines \f$(x_{0}, y_{0}, x_{1}, y_{1})\f$
|
||||
- In OpenCV it is implemented with the function **HoughLinesP()**
|
||||
|
||||
### What does this program do?
|
||||
- Loads an image
|
||||
- Applies a *Standard Hough Line Transform* and a *Probabilistic Line Transform*.
|
||||
- Display the original image and the detected line in three windows.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
@add_toggle_cpp
|
||||
The sample code that we will explain can be downloaded from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/houghlines.cpp).
|
||||
A slightly fancier version (which shows both Hough standard and probabilistic
|
||||
with trackbars for changing the threshold values) can be found
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp).
|
||||
@include samples/cpp/tutorial_code/ImgTrans/houghlines.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
The sample code that we will explain can be downloaded from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java).
|
||||
@include samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
The sample code that we will explain can be downloaded from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py).
|
||||
@include samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
#### Load an image:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghlines.cpp load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py load
|
||||
@end_toggle
|
||||
|
||||
#### Detect the edges of the image by using a Canny detector:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghlines.cpp edge_detection
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java edge_detection
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py edge_detection
|
||||
@end_toggle
|
||||
|
||||
Now we will apply the Hough Line Transform. We will explain how to use both OpenCV functions
|
||||
available for this purpose.
|
||||
|
||||
#### Standard Hough Line Transform:
|
||||
First, you apply the Transform:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghlines.cpp hough_lines
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java hough_lines
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py hough_lines
|
||||
@end_toggle
|
||||
|
||||
- with the following arguments:
|
||||
|
||||
- *dst*: Output of the edge detector. It should be a grayscale image (although in fact it
|
||||
is a binary one)
|
||||
- *lines*: A vector that will store the parameters \f$(r,\theta)\f$ of the detected lines
|
||||
- *rho* : The resolution of the parameter \f$r\f$ in pixels. We use **1** pixel.
|
||||
- *theta*: The resolution of the parameter \f$\theta\f$ in radians. We use **1 degree**
|
||||
(CV_PI/180)
|
||||
- *threshold*: The minimum number of intersections to "*detect*" a line
|
||||
- *srn* and *stn*: Default parameters to zero. Check OpenCV reference for more info.
|
||||
|
||||
And then you display the result by drawing the lines.
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghlines.cpp draw_lines
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java draw_lines
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py draw_lines
|
||||
@end_toggle
|
||||
|
||||
#### Probabilistic Hough Line Transform
|
||||
First you apply the transform:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghlines.cpp hough_lines_p
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java hough_lines_p
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py hough_lines_p
|
||||
@end_toggle
|
||||
|
||||
- with the arguments:
|
||||
|
||||
- *dst*: Output of the edge detector. It should be a grayscale image (although in fact it
|
||||
is a binary one)
|
||||
- *lines*: A vector that will store the parameters
|
||||
\f$(x_{start}, y_{start}, x_{end}, y_{end})\f$ of the detected lines
|
||||
- *rho* : The resolution of the parameter \f$r\f$ in pixels. We use **1** pixel.
|
||||
- *theta*: The resolution of the parameter \f$\theta\f$ in radians. We use **1 degree**
|
||||
(CV_PI/180)
|
||||
- *threshold*: The minimum number of intersections to "*detect*" a line
|
||||
- *minLineLength*: The minimum number of points that can form a line. Lines with less than
|
||||
this number of points are disregarded.
|
||||
- *maxLineGap*: The maximum gap between two points to be considered in the same line.
|
||||
|
||||
And then you display the result by drawing the lines.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghlines.cpp draw_lines_p
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java draw_lines_p
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py draw_lines_p
|
||||
@end_toggle
|
||||
|
||||
#### Display the original image and the detected lines:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghlines.cpp imshow
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java imshow
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py imshow
|
||||
@end_toggle
|
||||
|
||||
#### Wait until the user exits the program
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/houghlines.cpp exit
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/HoughLine/HoughLines.java exit
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/HoughLine/hough_lines.py exit
|
||||
@end_toggle
|
||||
|
||||
Result
|
||||
------
|
||||
|
||||
@note
|
||||
The results below are obtained using the slightly fancier version we mentioned in the *Code*
|
||||
section. It still implements the same stuff as above, only adding the Trackbar for the
|
||||
Threshold.
|
||||
|
||||
Using an input image such as a [sudoku image](https://raw.githubusercontent.com/opencv/opencv/master/samples/data/sudoku.png).
|
||||
We get the following result by using the Standard Hough Line Transform:
|
||||

|
||||
And by using the Probabilistic Hough Line Transform:
|
||||

|
||||
|
||||
You may observe that the number of lines detected vary while you change the *threshold*. The
|
||||
explanation is sort of evident: If you establish a higher threshold, fewer lines will be detected
|
||||
(since you will need more points to declare a line detected).
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
@@ -0,0 +1,204 @@
|
||||
Laplace Operator {#tutorial_laplace_operator}
|
||||
================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_sobel_derivatives}
|
||||
@next_tutorial{tutorial_canny_detector}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV function **Laplacian()** to implement a discrete analog of the *Laplacian
|
||||
operator*.
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
-# In the previous tutorial we learned how to use the *Sobel Operator*. It was based on the fact
|
||||
that in the edge area, the pixel intensity shows a "jump" or a high variation of intensity.
|
||||
Getting the first derivative of the intensity, we observed that an edge is characterized by a
|
||||
maximum, as it can be seen in the figure:
|
||||
|
||||

|
||||
|
||||
-# And...what happens if we take the second derivative?
|
||||
|
||||

|
||||
|
||||
You can observe that the second derivative is zero! So, we can also use this criterion to
|
||||
attempt to detect edges in an image. However, note that zeros will not only appear in edges
|
||||
(they can actually appear in other meaningless locations); this can be solved by applying
|
||||
filtering where needed.
|
||||
|
||||
### Laplacian Operator
|
||||
|
||||
-# From the explanation above, we deduce that the second derivative can be used to *detect edges*.
|
||||
Since images are "*2D*", we would need to take the derivative in both dimensions. Here, the
|
||||
Laplacian operator comes handy.
|
||||
-# The *Laplacian operator* is defined by:
|
||||
|
||||
\f[Laplace(f) = \dfrac{\partial^{2} f}{\partial x^{2}} + \dfrac{\partial^{2} f}{\partial y^{2}}\f]
|
||||
|
||||
-# The Laplacian operator is implemented in OpenCV by the function **Laplacian()** . In fact,
|
||||
since the Laplacian uses the gradient of images, it calls internally the *Sobel* operator to
|
||||
perform its computation.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
-# **What does this program do?**
|
||||
- Loads an image
|
||||
- Remove noise by applying a Gaussian blur and then convert the original image to grayscale
|
||||
- Applies a Laplacian operator to the grayscale image and stores the output image
|
||||
- Display the result in a window
|
||||
|
||||
@add_toggle_cpp
|
||||
-# The tutorial code's is shown lines below. You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp)
|
||||
@include samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
-# The tutorial code's is shown lines below. You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java)
|
||||
@include samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
-# The tutorial code's is shown lines below. You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py)
|
||||
@include samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
#### Declare variables
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp variables
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java variables
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py variables
|
||||
@end_toggle
|
||||
|
||||
#### Load source image
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py load
|
||||
@end_toggle
|
||||
|
||||
#### Reduce noise
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp reduce_noise
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java reduce_noise
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py reduce_noise
|
||||
@end_toggle
|
||||
|
||||
#### Grayscale
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp convert_to_gray
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java convert_to_gray
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py convert_to_gray
|
||||
@end_toggle
|
||||
|
||||
#### Laplacian operator
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp laplacian
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java laplacian
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py laplacian
|
||||
@end_toggle
|
||||
|
||||
- The arguments are:
|
||||
- *src_gray*: The input image.
|
||||
- *dst*: Destination (output) image
|
||||
- *ddepth*: Depth of the destination image. Since our input is *CV_8U* we define *ddepth* =
|
||||
*CV_16S* to avoid overflow
|
||||
- *kernel_size*: The kernel size of the Sobel operator to be applied internally. We use 3 in
|
||||
this example.
|
||||
- *scale*, *delta* and *BORDER_DEFAULT*: We leave them as default values.
|
||||
|
||||
#### Convert output to a *CV_8U* image
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp convert
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java convert
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py convert
|
||||
@end_toggle
|
||||
|
||||
#### Display the result
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp display
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/LaPlace/LaplaceDemo.java display
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/LaPlace/laplace_demo.py display
|
||||
@end_toggle
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
-# After compiling the code above, we can run it giving as argument the path to an image. For
|
||||
example, using as an input:
|
||||
|
||||

|
||||
|
||||
-# We obtain the following result. Notice how the trees and the silhouette of the cow are
|
||||
approximately well defined (except in areas in which the intensity are very similar, i.e. around
|
||||
the cow's head). Also, note that the roof of the house behind the trees (right side) is
|
||||
notoriously marked. This is due to the fact that the contrast is higher in that region.
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
201
doc/tutorials/imgproc/imgtrans/remap/remap.markdown
Normal file
@@ -0,0 +1,201 @@
|
||||
Remapping {#tutorial_remap}
|
||||
=========
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_hough_circle}
|
||||
@next_tutorial{tutorial_warp_affine}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
a. Use the OpenCV function @ref cv::remap to implement simple remapping routines.
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
### What is remapping?
|
||||
|
||||
- It is the process of taking pixels from one place in the image and locating them in another
|
||||
position in a new image.
|
||||
- To accomplish the mapping process, it might be necessary to do some interpolation for
|
||||
non-integer pixel locations, since there will not always be a one-to-one-pixel correspondence
|
||||
between source and destination images.
|
||||
- We can express the remap for every pixel location \f$(x,y)\f$ as:
|
||||
|
||||
\f[g(x,y) = f ( h(x,y) )\f]
|
||||
|
||||
where \f$g()\f$ is the remapped image, \f$f()\f$ the source image and \f$h(x,y)\f$ is the mapping function
|
||||
that operates on \f$(x,y)\f$.
|
||||
|
||||
- Let's think in a quick example. Imagine that we have an image \f$I\f$ and, say, we want to do a
|
||||
remap such that:
|
||||
|
||||
\f[h(x,y) = (I.cols - x, y )\f]
|
||||
|
||||
What would happen? It is easily seen that the image would flip in the \f$x\f$ direction. For
|
||||
instance, consider the input image:
|
||||
|
||||

|
||||
|
||||
observe how the red circle changes positions with respect to x (considering \f$x\f$ the horizontal
|
||||
direction):
|
||||
|
||||

|
||||
|
||||
- In OpenCV, the function @ref cv::remap offers a simple remapping implementation.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
- **What does this program do?**
|
||||
- Loads an image
|
||||
- Each second, apply 1 of 4 different remapping processes to the image and display them
|
||||
indefinitely in a window.
|
||||
- Wait for the user to exit the program
|
||||
|
||||
@add_toggle_cpp
|
||||
- The 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/ImgTrans/Remap_Demo.cpp)
|
||||
@include samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
- The 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/ImgTrans/remap/RemapDemo.java)
|
||||
@include samples/java/tutorial_code/ImgTrans/remap/RemapDemo.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
- The 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/ImgTrans/remap/Remap_Demo.py)
|
||||
@include samples/python/tutorial_code/ImgTrans/remap/Remap_Demo.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
- Load an image:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp Load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/remap/RemapDemo.java Load
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/remap/Remap_Demo.py Load
|
||||
@end_toggle
|
||||
|
||||
- Create the destination image and the two mapping matrices (for x and y )
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp Create
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/remap/RemapDemo.java Create
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/remap/Remap_Demo.py Create
|
||||
@end_toggle
|
||||
|
||||
- Create a window to display results
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp Window
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/remap/RemapDemo.java Window
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/remap/Remap_Demo.py Window
|
||||
@end_toggle
|
||||
|
||||
- Establish a loop. Each 1000 ms we update our mapping matrices (*mat_x* and *mat_y*) and apply
|
||||
them to our source image:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp Loop
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/remap/RemapDemo.java Loop
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/remap/Remap_Demo.py Loop
|
||||
@end_toggle
|
||||
|
||||
- The function that applies the remapping is @ref cv::remap . We give the following arguments:
|
||||
- **src**: Source image
|
||||
- **dst**: Destination image of same size as *src*
|
||||
- **map_x**: The mapping function in the x direction. It is equivalent to the first component
|
||||
of \f$h(i,j)\f$
|
||||
- **map_y**: Same as above, but in y direction. Note that *map_y* and *map_x* are both of
|
||||
the same size as *src*
|
||||
- **INTER_LINEAR**: The type of interpolation to use for non-integer pixels. This is by
|
||||
default.
|
||||
- **BORDER_CONSTANT**: Default
|
||||
|
||||
How do we update our mapping matrices *mat_x* and *mat_y*? Go on reading:
|
||||
|
||||
- **Updating the mapping matrices:** We are going to perform 4 different mappings:
|
||||
-# Reduce the picture to half its size and will display it in the middle:
|
||||
\f[h(i,j) = ( 2 \times i - src.cols/2 + 0.5, 2 \times j - src.rows/2 + 0.5)\f]
|
||||
for all pairs \f$(i,j)\f$ such that: \f$\dfrac{src.cols}{4}<i<\dfrac{3 \cdot src.cols}{4}\f$ and
|
||||
\f$\dfrac{src.rows}{4}<j<\dfrac{3 \cdot src.rows}{4}\f$
|
||||
-# Turn the image upside down: \f$h( i, j ) = (i, src.rows - j)\f$
|
||||
-# Reflect the image from left to right: \f$h(i,j) = ( src.cols - i, j )\f$
|
||||
-# Combination of b and c: \f$h(i,j) = ( src.cols - i, src.rows - j )\f$
|
||||
|
||||
This is expressed in the following snippet. Here, *map_x* represents the first coordinate of
|
||||
*h(i,j)* and *map_y* the second coordinate.
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp Update
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/remap/RemapDemo.java Update
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/remap/Remap_Demo.py Update
|
||||
@end_toggle
|
||||
|
||||
Result
|
||||
------
|
||||
|
||||
-# After compiling the code above, you can execute it giving as argument an image path. For
|
||||
instance, by using the following image:
|
||||
|
||||

|
||||
|
||||
-# This is the result of reducing it to half the size and centering it:
|
||||
|
||||

|
||||
|
||||
-# Turning it upside down:
|
||||
|
||||

|
||||
|
||||
-# Reflecting it in the x direction:
|
||||
|
||||

|
||||
|
||||
-# Reflecting it in both directions:
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1,197 @@
|
||||
Sobel Derivatives {#tutorial_sobel_derivatives}
|
||||
=================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_copyMakeBorder}
|
||||
@next_tutorial{tutorial_laplace_operator}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV function **Sobel()** to calculate the derivatives from an image.
|
||||
- Use the OpenCV function **Scharr()** to calculate a more accurate derivative for a kernel of
|
||||
size \f$3 \cdot 3\f$
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
@note The explanation below belongs to the book **Learning OpenCV** by Bradski and Kaehler.
|
||||
|
||||
-# In the last two tutorials we have seen applicative examples of convolutions. One of the most
|
||||
important convolutions is the computation of derivatives in an image (or an approximation to
|
||||
them).
|
||||
-# Why may be important the calculus of the derivatives in an image? Let's imagine we want to
|
||||
detect the *edges* present in the image. For instance:
|
||||
|
||||

|
||||
|
||||
You can easily notice that in an *edge*, the pixel intensity *changes* in a notorious way. A
|
||||
good way to express *changes* is by using *derivatives*. A high change in gradient indicates a
|
||||
major change in the image.
|
||||
|
||||
-# To be more graphical, let's assume we have a 1D-image. An edge is shown by the "jump" in
|
||||
intensity in the plot below:
|
||||
|
||||

|
||||
|
||||
-# The edge "jump" can be seen more easily if we take the first derivative (actually, here appears
|
||||
as a maximum)
|
||||
|
||||

|
||||
|
||||
-# So, from the explanation above, we can deduce that a method to detect edges in an image can be
|
||||
performed by locating pixel locations where the gradient is higher than its neighbors (or to
|
||||
generalize, higher than a threshold).
|
||||
-# More detailed explanation, please refer to **Learning OpenCV** by Bradski and Kaehler
|
||||
|
||||
### Sobel Operator
|
||||
|
||||
-# The Sobel Operator is a discrete differentiation operator. It computes an approximation of the
|
||||
gradient of an image intensity function.
|
||||
-# The Sobel Operator combines Gaussian smoothing and differentiation.
|
||||
|
||||
#### Formulation
|
||||
|
||||
Assuming that the image to be operated is \f$I\f$:
|
||||
|
||||
-# We calculate two derivatives:
|
||||
-# **Horizontal changes**: This is computed by convolving \f$I\f$ with a kernel \f$G_{x}\f$ with odd
|
||||
size. For example for a kernel size of 3, \f$G_{x}\f$ would be computed as:
|
||||
|
||||
\f[G_{x} = \begin{bmatrix}
|
||||
-1 & 0 & +1 \\
|
||||
-2 & 0 & +2 \\
|
||||
-1 & 0 & +1
|
||||
\end{bmatrix} * I\f]
|
||||
|
||||
-# **Vertical changes**: This is computed by convolving \f$I\f$ with a kernel \f$G_{y}\f$ with odd
|
||||
size. For example for a kernel size of 3, \f$G_{y}\f$ would be computed as:
|
||||
|
||||
\f[G_{y} = \begin{bmatrix}
|
||||
-1 & -2 & -1 \\
|
||||
0 & 0 & 0 \\
|
||||
+1 & +2 & +1
|
||||
\end{bmatrix} * I\f]
|
||||
|
||||
-# At each point of the image we calculate an approximation of the *gradient* in that point by
|
||||
combining both results above:
|
||||
|
||||
\f[G = \sqrt{ G_{x}^{2} + G_{y}^{2} }\f]
|
||||
|
||||
Although sometimes the following simpler equation is used:
|
||||
|
||||
\f[G = |G_{x}| + |G_{y}|\f]
|
||||
|
||||
@note
|
||||
When the size of the kernel is `3`, the Sobel kernel shown above may produce noticeable
|
||||
inaccuracies (after all, Sobel is only an approximation of the derivative). OpenCV addresses
|
||||
this inaccuracy for kernels of size 3 by using the **Scharr()** function. This is as fast
|
||||
but more accurate than the standard Sobel function. It implements the following kernels:
|
||||
\f[G_{x} = \begin{bmatrix}
|
||||
-3 & 0 & +3 \\
|
||||
-10 & 0 & +10 \\
|
||||
-3 & 0 & +3
|
||||
\end{bmatrix}\f]\f[G_{y} = \begin{bmatrix}
|
||||
-3 & -10 & -3 \\
|
||||
0 & 0 & 0 \\
|
||||
+3 & +10 & +3
|
||||
\end{bmatrix}\f]
|
||||
@note
|
||||
You can check out more information of this function in the OpenCV reference - **Scharr()** .
|
||||
Also, in the sample code below, you will notice that above the code for **Sobel()** function
|
||||
there is also code for the **Scharr()** function commented. Uncommenting it (and obviously
|
||||
commenting the Sobel stuff) should give you an idea of how this function works.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
-# **What does this program do?**
|
||||
- Applies the *Sobel Operator* and generates as output an image with the detected *edges*
|
||||
bright on a darker background.
|
||||
|
||||
-# The tutorial code's is shown lines below.
|
||||
|
||||
@add_toggle_cpp
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp)
|
||||
@include samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java)
|
||||
@include samples/java/tutorial_code/ImgTrans/SobelDemo/SobelDemo.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
You can also download it from
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py)
|
||||
@include samples/python/tutorial_code/ImgTrans/SobelDemo/sobel_demo.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
#### Declare variables
|
||||
|
||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp variables
|
||||
|
||||
#### Load source image
|
||||
|
||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp load
|
||||
|
||||
#### Reduce noise
|
||||
|
||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
|
||||
|
||||
#### Grayscale
|
||||
|
||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert_to_gray
|
||||
|
||||
#### Sobel Operator
|
||||
|
||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel
|
||||
|
||||
- We calculate the "derivatives" in *x* and *y* directions. For this, we use the
|
||||
function **Sobel()** as shown below:
|
||||
The function takes the following arguments:
|
||||
|
||||
- *src_gray*: In our example, the input image. Here it is *CV_8U*
|
||||
- *grad_x* / *grad_y* : The output image.
|
||||
- *ddepth*: The depth of the output image. We set it to *CV_16S* to avoid overflow.
|
||||
- *x_order*: The order of the derivative in **x** direction.
|
||||
- *y_order*: The order of the derivative in **y** direction.
|
||||
- *scale*, *delta* and *BORDER_DEFAULT*: We use default values.
|
||||
|
||||
Notice that to calculate the gradient in *x* direction we use: \f$x_{order}= 1\f$ and
|
||||
\f$y_{order} = 0\f$. We do analogously for the *y* direction.
|
||||
|
||||
#### Convert output to a CV_8U image
|
||||
|
||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert
|
||||
|
||||
#### Gradient
|
||||
|
||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
|
||||
|
||||
We try to approximate the *gradient* by adding both directional gradients (note that
|
||||
this is not an exact calculation at all! but it is good for our purposes).
|
||||
|
||||
#### Show results
|
||||
|
||||
@snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp display
|
||||
|
||||
Results
|
||||
-------
|
||||
|
||||
-# Here is the output of applying our basic detector to *lena.jpg*:
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
285
doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.markdown
Normal file
@@ -0,0 +1,285 @@
|
||||
Affine Transformations {#tutorial_warp_affine}
|
||||
======================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
@prev_tutorial{tutorial_remap}
|
||||
@next_tutorial{tutorial_histogram_equalization}
|
||||
|
||||
| | |
|
||||
| -: | :- |
|
||||
| Original author | Ana Huamán |
|
||||
| Compatibility | OpenCV >= 3.0 |
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
In this tutorial you will learn how to:
|
||||
|
||||
- Use the OpenCV function @ref cv::warpAffine to implement simple remapping routines.
|
||||
- Use the OpenCV function @ref cv::getRotationMatrix2D to obtain a \f$2 \times 3\f$ rotation matrix
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
### What is an Affine Transformation?
|
||||
|
||||
-# A transformation that can be expressed in the form of a *matrix multiplication* (linear
|
||||
transformation) followed by a *vector addition* (translation).
|
||||
-# From the above, we can use an Affine Transformation to express:
|
||||
|
||||
-# Rotations (linear transformation)
|
||||
-# Translations (vector addition)
|
||||
-# Scale operations (linear transformation)
|
||||
|
||||
you can see that, in essence, an Affine Transformation represents a **relation** between two
|
||||
images.
|
||||
|
||||
-# The usual way to represent an Affine Transformation is by using a \f$2 \times 3\f$ matrix.
|
||||
|
||||
\f[
|
||||
A = \begin{bmatrix}
|
||||
a_{00} & a_{01} \\
|
||||
a_{10} & a_{11}
|
||||
\end{bmatrix}_{2 \times 2}
|
||||
B = \begin{bmatrix}
|
||||
b_{00} \\
|
||||
b_{10}
|
||||
\end{bmatrix}_{2 \times 1}
|
||||
\f]
|
||||
\f[
|
||||
M = \begin{bmatrix}
|
||||
A & B
|
||||
\end{bmatrix}
|
||||
=
|
||||
\begin{bmatrix}
|
||||
a_{00} & a_{01} & b_{00} \\
|
||||
a_{10} & a_{11} & b_{10}
|
||||
\end{bmatrix}_{2 \times 3}
|
||||
\f]
|
||||
|
||||
Considering that we want to transform a 2D vector \f$X = \begin{bmatrix}x \\ y\end{bmatrix}\f$ by
|
||||
using \f$A\f$ and \f$B\f$, we can do the same with:
|
||||
|
||||
\f$T = A \cdot \begin{bmatrix}x \\ y\end{bmatrix} + B\f$ or \f$T = M \cdot [x, y, 1]^{T}\f$
|
||||
|
||||
\f[T = \begin{bmatrix}
|
||||
a_{00}x + a_{01}y + b_{00} \\
|
||||
a_{10}x + a_{11}y + b_{10}
|
||||
\end{bmatrix}\f]
|
||||
|
||||
### How do we get an Affine Transformation?
|
||||
|
||||
-# We mentioned that an Affine Transformation is basically a **relation**
|
||||
between two images. The information about this relation can come, roughly, in two ways:
|
||||
-# We know both \f$X\f$ and T and we also know that they are related. Then our task is to find \f$M\f$
|
||||
-# We know \f$M\f$ and \f$X\f$. To obtain \f$T\f$ we only need to apply \f$T = M \cdot X\f$. Our information
|
||||
for \f$M\f$ may be explicit (i.e. have the 2-by-3 matrix) or it can come as a geometric relation
|
||||
between points.
|
||||
|
||||
-# Let's explain this in a better way (b). Since \f$M\f$ relates 2 images, we can analyze the simplest
|
||||
case in which it relates three points in both images. Look at the figure below:
|
||||
|
||||

|
||||
|
||||
the points 1, 2 and 3 (forming a triangle in image 1) are mapped into image 2, still forming a
|
||||
triangle, but now they have changed notoriously. If we find the Affine Transformation with these
|
||||
3 points (you can choose them as you like), then we can apply this found relation to all the
|
||||
pixels in an image.
|
||||
|
||||
Code
|
||||
----
|
||||
|
||||
- **What does this program do?**
|
||||
- Loads an image
|
||||
- Applies an Affine Transform to the image. This transform is obtained from the relation
|
||||
between three points. We use the function @ref cv::warpAffine for that purpose.
|
||||
- Applies a Rotation to the image after being transformed. This rotation is with respect to
|
||||
the image center
|
||||
- Waits until the user exits the program
|
||||
|
||||
@add_toggle_cpp
|
||||
- The tutorial's code is shown below. You can also download it
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp)
|
||||
@include samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
- The tutorial's code is shown below. You can also download it
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/cpp/tutorial_code/ImgProc/Smoothing/Smoothing.cpp)
|
||||
@include samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
- The tutorial's code is shown below. You can also download it
|
||||
[here](https://raw.githubusercontent.com/opencv/opencv/master/samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py)
|
||||
@include samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py
|
||||
@end_toggle
|
||||
|
||||
Explanation
|
||||
-----------
|
||||
|
||||
- Load an image:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Load the image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Load the image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Load the image
|
||||
@end_toggle
|
||||
|
||||
- **Affine Transform:** As we explained in lines above, we need two sets of 3 points to derive the
|
||||
affine transform relation. Have a look:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Set your 3 points to calculate the Affine Transform
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Set your 3 points to calculate the Affine Transform
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Set your 3 points to calculate the Affine Transform
|
||||
@end_toggle
|
||||
You may want to draw these points to get a better idea on how they change. Their locations are
|
||||
approximately the same as the ones depicted in the example figure (in the Theory section). You
|
||||
may note that the size and orientation of the triangle defined by the 3 points change.
|
||||
|
||||
- Armed with both sets of points, we calculate the Affine Transform by using OpenCV function @ref
|
||||
cv::getAffineTransform :
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Get the Affine Transform
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Get the Affine Transform
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Get the Affine Transform
|
||||
@end_toggle
|
||||
We get a \f$2 \times 3\f$ matrix as an output (in this case **warp_mat**)
|
||||
|
||||
- We then apply the Affine Transform just found to the src image
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Apply the Affine Transform just found to the src image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Apply the Affine Transform just found to the src image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Apply the Affine Transform just found to the src image
|
||||
@end_toggle
|
||||
with the following arguments:
|
||||
|
||||
- **src**: Input image
|
||||
- **warp_dst**: Output image
|
||||
- **warp_mat**: Affine transform
|
||||
- **warp_dst.size()**: The desired size of the output image
|
||||
|
||||
We just got our first transformed image! We will display it in one bit. Before that, we also
|
||||
want to rotate it...
|
||||
|
||||
- **Rotate:** To rotate an image, we need to know two things:
|
||||
|
||||
-# The center with respect to which the image will rotate
|
||||
-# The angle to be rotated. In OpenCV a positive angle is counter-clockwise
|
||||
-# *Optional:* A scale factor
|
||||
|
||||
We define these parameters with the following snippet:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Compute a rotation matrix with respect to the center of the image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Compute a rotation matrix with respect to the center of the image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Compute a rotation matrix with respect to the center of the image
|
||||
@end_toggle
|
||||
|
||||
- We generate the rotation matrix with the OpenCV function @ref cv::getRotationMatrix2D , which
|
||||
returns a \f$2 \times 3\f$ matrix (in this case *rot_mat*)
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Get the rotation matrix with the specifications above
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Get the rotation matrix with the specifications above
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Get the rotation matrix with the specifications above
|
||||
@end_toggle
|
||||
|
||||
- We now apply the found rotation to the output of our previous Transformation:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Rotate the warped image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Rotate the warped image
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Rotate the warped image
|
||||
@end_toggle
|
||||
|
||||
- Finally, we display our results in two windows plus the original image for good measure:
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Show what you got
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Show what you got
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Show what you got
|
||||
@end_toggle
|
||||
|
||||
- We just have to wait until the user exits the program
|
||||
|
||||
@add_toggle_cpp
|
||||
@snippet samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp Wait until user exits the program
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_java
|
||||
@snippet samples/java/tutorial_code/ImgTrans/warp_affine/GeometricTransformsDemo.java Wait until user exits the program
|
||||
@end_toggle
|
||||
|
||||
@add_toggle_python
|
||||
@snippet samples/python/tutorial_code/ImgTrans/warp_affine/Geometric_Transforms_Demo.py Wait until user exits the program
|
||||
@end_toggle
|
||||
|
||||
Result
|
||||
------
|
||||
|
||||
- After compiling the code above, we can give it the path of an image as argument. For instance,
|
||||
for a picture like:
|
||||
|
||||

|
||||
|
||||
after applying the first Affine Transform we obtain:
|
||||
|
||||

|
||||
|
||||
and finally, after applying a negative rotation (remember negative means clockwise) and a scale
|
||||
factor, we get:
|
||||
|
||||

|
||||