1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-29 15:23:05 +04:00

Merge remote-tracking branch 'upstream/master' into merge-4.x

This commit is contained in:
Alexander Alekhin
2020-11-27 18:14:53 +00:00
457 changed files with 30205 additions and 4172 deletions
@@ -32,7 +32,7 @@ automatically available with the platform (e.g. APPLE GCD) but chances are that
have access to a parallel framework either directly or by enabling the option in CMake and rebuild the library.
The second (weak) precondition is more related to the task you want to achieve as not all computations
are suitable / can be adatapted to be run in a parallel way. To remain simple, tasks that can be split
are suitable / can be adapted to be run in a parallel way. To remain simple, tasks that can be split
into multiple elementary operations with no memory dependency (no possible race condition) are easily
parallelizable. Computer vision processing are often easily parallelizable as most of the time the processing of
one pixel does not depend to the state of other pixels.
@@ -84,57 +84,198 @@ This tutorial's code is shown below. You can also download it
Explanation
-----------
-# Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in
previous sections). Let's check the general structure of the C++ program:
@add_toggle_cpp
Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in
previous sections). Let's check the general structure of the C++ program:
- Load an image (can be BGR or grayscale)
- Create two windows (one for dilation output, the other for erosion)
- Create a set of two Trackbars for each operation:
- The first trackbar "Element" returns either **erosion_elem** or **dilation_elem**
- The second trackbar "Kernel size" return **erosion_size** or **dilation_size** for the
corresponding operation.
- Every time we move any slider, the user's function **Erosion** or **Dilation** will be
called and it will update the output image based on the current trackbar values.
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp main
Let's analyze these two functions:
-# Load an image (can be BGR or grayscale)
-# Create two windows (one for dilation output, the other for erosion)
-# Create a set of two Trackbars for each operation:
- The first trackbar "Element" returns either **erosion_elem** or **dilation_elem**
- The second trackbar "Kernel size" return **erosion_size** or **dilation_size** for the
corresponding operation.
-# Call once erosion and dilation to show the initial image.
-# **erosion:**
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp erosion
- The function that performs the *erosion* operation is @ref cv::erode . As we can see, it
receives three arguments:
- *src*: The source image
- *erosion_dst*: The output image
- *element*: This is the kernel we will use to perform the operation. If we do not
specify, the default is a simple `3x3` matrix. Otherwise, we can specify its
shape. For this, we need to use the function cv::getStructuringElement :
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp kernel
Every time we move any slider, the user's function **Erosion** or **Dilation** will be
called and it will update the output image based on the current trackbar values.
We can choose any of three shapes for our kernel:
Let's analyze these two functions:
- Rectangular box: MORPH_RECT
- Cross: MORPH_CROSS
- Ellipse: MORPH_ELLIPSE
#### The erosion function
Then, we just have to specify the size of our kernel and the *anchor point*. If not
specified, it is assumed to be in the center.
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp erosion
- That is all. We are ready to perform the erosion of our image.
@note Additionally, there is another parameter that allows you to perform multiple erosions
(iterations) at once. However, We haven't used it in this simple tutorial. You can check out the
reference for more details.
The function that performs the *erosion* operation is @ref cv::erode . As we can see, it
receives three arguments:
- *src*: The source image
- *erosion_dst*: The output image
- *element*: This is the kernel we will use to perform the operation. If we do not
specify, the default is a simple `3x3` matrix. Otherwise, we can specify its
shape. For this, we need to use the function cv::getStructuringElement :
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp kernel
-# **dilation:**
We can choose any of three shapes for our kernel:
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**.
Here we also have the option of defining our kernel, its anchor point and the size of the operator
to be used.
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp dilation
- Rectangular box: MORPH_RECT
- Cross: MORPH_CROSS
- Ellipse: MORPH_ELLIPSE
Then, we just have to specify the size of our kernel and the *anchor point*. If not
specified, it is assumed to be in the center.
That is all. We are ready to perform the erosion of our image.
#### The dilation function
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**.
Here we also have the option of defining our kernel, its anchor point and the size of the operator
to be used.
@snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp dilation
@end_toggle
@add_toggle_java
Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in
previous sections). Let's check however the general structure of the java class. There are 4 main
parts in the java class:
- the class constructor which setups the window that will be filled with window components
- the `addComponentsToPane` method, which fills out the window
- the `update` method, which determines what happens when the user changes any value
- the `main` method, which is the entry point of the program
In this tutorial we will focus on the `addComponentsToPane` and `update` methods. However, for completion the
steps followed in the constructor are:
-# Load an image (can be BGR or grayscale)
-# Create a window
-# Add various control components with `addComponentsToPane`
-# show the window
The components were added by the following method:
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java components
In short we
-# create a panel for the sliders
-# create a combo box for the element types
-# create a slider for the kernel size
-# create a combo box for the morphology function to use (erosion or dilation)
The action and state changed listeners added call at the end the `update` method which updates
the image based on the current slider values. So every time we move any slider, the `update` method is triggered.
#### Updating the image
To update the image we used the following implementation:
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java update
In other words we
-# get the structuring element the user chose
-# execute the **erosion** or **dilation** function based on `doErosion`
-# reload the image with the morphology applied
-# repaint the frame
Let's analyze the `erode` and `dilate` methods:
#### The erosion method
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java erosion
The function that performs the *erosion* operation is @ref cv::erode . As we can see, it
receives three arguments:
- *src*: The source image
- *erosion_dst*: The output image
- *element*: This is the kernel we will use to perform the operation. For specifying the shape, we need to use
the function cv::getStructuringElement :
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java kernel
We can choose any of three shapes for our kernel:
- Rectangular box: CV_SHAPE_RECT
- Cross: CV_SHAPE_CROSS
- Ellipse: CV_SHAPE_ELLIPSE
Together with the shape we specify the size of our kernel and the *anchor point*. If the anchor point is not
specified, it is assumed to be in the center.
That is all. We are ready to perform the erosion of our image.
#### The dilation function
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**.
Here we also have the option of defining our kernel, its anchor point and the size of the operator
to be used.
@snippet java/tutorial_code/ImgProc/erosion_dilatation/MorphologyDemo1.java dilation
@end_toggle
@add_toggle_python
Most of the material shown here is trivial (if you have any doubt, please refer to the tutorials in
previous sections). Let's check the general structure of the python script:
@snippet python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py main
-# Load an image (can be BGR or grayscale)
-# Create two windows (one for erosion output, the other for dilation) with a set of trackbars each
- The first trackbar "Element" returns the value for the morphological type that will be mapped
(1 = rectangle, 2 = cross, 3 = ellipse)
- The second trackbar "Kernel size" returns the size of the element for the
corresponding operation
-# Call once erosion and dilation to show the initial image
Every time we move any slider, the user's function **erosion** or **dilation** will be
called and it will update the output image based on the current trackbar values.
Let's analyze these two functions:
#### The erosion function
@snippet python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py erosion
The function that performs the *erosion* operation is @ref cv::erode . As we can see, it
receives two arguments and returns the processed image:
- *src*: The source image
- *element*: The kernel we will use to perform the operation. We can specify its
shape by using the function cv::getStructuringElement :
@snippet python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py kernel
We can choose any of three shapes for our kernel:
- Rectangular box: MORPH_RECT
- Cross: MORPH_CROSS
- Ellipse: MORPH_ELLIPSE
Then, we just have to specify the size of our kernel and the *anchor point*. If the anchor point not
specified, it is assumed to be in the center.
That is all. We are ready to perform the erosion of our image.
#### The dilation function
The code is below. As you can see, it is completely similar to the snippet of code for **erosion**.
Here we also have the option of defining our kernel, its anchor point and the size of the operator
to be used.
@snippet python/tutorial_code/imgProc/erosion_dilatation/morphology_1.py dilation
@end_toggle
@note Additionally, there are further parameters that allow you to perform multiple erosions/dilations
(iterations) at once and also set the border type and value. However, We haven't used those
in this simple tutorial. You can check out the reference for more details.
Results
-------
Compile the code above and execute it with an image as argument. For instance, using this image:
Compile the code above and execute it (or run the script if using python) with an image as argument.
If you do not provide an image as argument the default sample image
([LinuxLogo.jpg](https://github.com/opencv/opencv/tree/master/samples/data/LinuxLogo.jpg)) will be used.
For instance, using this image:
![](images/Morphology_1_Tutorial_Original_Image.jpg)
@@ -143,3 +284,4 @@ naturally. Try them out! You can even try to add a third Trackbar to control the
iterations.
![](images/Morphology_1_Result.jpg)
(depending on the programming language the output might vary a little or be only 1 window)
@@ -247,15 +247,18 @@ When `WITH_` option is enabled:
`WITH_CUDA` (default: _OFF_)
Many algorithms have been implemented using CUDA acceleration, these functions are located in separate modules: @ref cuda. CUDA toolkit must be installed from the official NVIDIA site as a prerequisite. For cmake versions older than 3.9 OpenCV uses own `cmake/FindCUDA.cmake` script, for newer versions - the one packaged with CMake. Additional options can be used to control build process, e.g. `CUDA_GENERATION` or `CUDA_ARCH_BIN`. These parameters are not documented yet, please consult with the `cmake/OpenCVDetectCUDA.cmake` script for details.
Some tutorials can be found in the corresponding section: @ref tutorial_table_of_content_gpu
Many algorithms have been implemented using CUDA acceleration, these functions are located in separate modules. CUDA toolkit must be installed from the official NVIDIA site as a prerequisite. For cmake versions older than 3.9 OpenCV uses own `cmake/FindCUDA.cmake` script, for newer versions - the one packaged with CMake. Additional options can be used to control build process, e.g. `CUDA_GENERATION` or `CUDA_ARCH_BIN`. These parameters are not documented yet, please consult with the `cmake/OpenCVDetectCUDA.cmake` script for details.
@note Since OpenCV version 4.0 all CUDA-accelerated algorithm implementations have been moved to the _opencv_contrib_ repository. To build _opencv_ and _opencv_contrib_ together check @ref tutorial_config_reference_general_contrib.
@cond CUDA_MODULES
@note Some tutorials can be found in the corresponding section: @ref tutorial_table_of_content_gpu
@see @ref cuda
@endcond
@see https://en.wikipedia.org/wiki/CUDA
TODO: other options: `WITH_CUFFT`, `WITH_CUBLAS`, WITH_NVCUVID`?
TODO: other options: `WITH_CUFFT`, `WITH_CUBLAS`, `WITH_NVCUVID`?
### OpenCL support
@@ -32,8 +32,7 @@ In this tutorial you will learn how to:
-# Create and update the background model by using @ref cv::BackgroundSubtractor class;
-# Get and show the foreground mask by using @ref cv::imshow ;
Code
----
### Code
In the following you can find the source code. We will let the user choose to process either a video
file or a sequence of images.
+1 -1
View File
@@ -1,7 +1,7 @@
Using Creative Senz3D and other Intel RealSense SDK compatible depth sensors {#tutorial_intelperc}
=======================================================================================
@prev_tutorial{tutorial_kinect_openni}
@prev_tutorial{tutorial_orbbec_astra}
**Note**: This tutorial is partially obsolete since PerC SDK has been replaced with RealSense SDK
+1 -1
View File
@@ -2,7 +2,7 @@ Using Kinect and other OpenNI compatible depth sensors {#tutorial_kinect_openni}
======================================================
@prev_tutorial{tutorial_video_write}
@next_tutorial{tutorial_intelperc}
@next_tutorial{tutorial_orbbec_astra}
Depth sensors compatible with OpenNI (Kinect, XtionPRO, ...) are supported through VideoCapture
Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@@ -0,0 +1,150 @@
Using Orbbec Astra 3D cameras {#tutorial_orbbec_astra}
======================================================
@prev_tutorial{tutorial_kinect_openni}
@next_tutorial{tutorial_intelperc}
### Introduction
This tutorial is devoted to the Astra Series of Orbbec 3D cameras (https://orbbec3d.com/product-astra-pro/).
That cameras have a depth sensor in addition to a common color sensor. The depth sensors can be read using
the OpenNI interface with @ref cv::VideoCapture class. The video stream is provided through the regular camera
interface.
### Installation Instructions
In order to use a depth sensor with OpenCV you should do the following steps:
-# Download the latest version of Orbbec OpenNI SDK (from here <https://orbbec3d.com/develop/>).
Unzip the archive, choose the build according to your operating system and follow installation
steps provided in the Readme file. For instance, if you use 64bit GNU/Linux run:
@code{.bash}
$ cd Linux/OpenNI-Linux-x64-2.3.0.63/
$ sudo ./install.sh
@endcode
When you are done with the installation, make sure to replug your device for udev rules to take
effect. The camera should now work as a general camera device. Note that your current user should
belong to group `video` to have access to the camera. Also, make sure to source `OpenNIDevEnvironment` file:
@code{.bash}
$ source OpenNIDevEnvironment
@endcode
-# Run the following commands to verify that OpenNI library and header files can be found. You should see
something similar in your terminal:
@code{.bash}
$ echo $OPENNI2_INCLUDE
/home/user/OpenNI_2.3.0.63/Linux/OpenNI-Linux-x64-2.3.0.63/Include
$ echo $OPENNI2_REDIST
/home/user/OpenNI_2.3.0.63/Linux/OpenNI-Linux-x64-2.3.0.63/Redist
@endcode
If the above two variables are empty, then you need to source `OpenNIDevEnvironment` again. Now you can
configure OpenCV with OpenNI support enabled by setting the `WITH_OPENNI2` flag in CMake.
You may also like to enable the `BUILD_EXAMPLES` flag to get a code sample working with your Astra camera.
Run the following commands in the directory containing OpenCV source code to enable OpenNI support:
@code{.bash}
$ mkdir build
$ cd build
$ cmake -DWITH_OPENNI2=ON ..
@endcode
If the OpenNI library is found, OpenCV will be built with OpenNI2 support. You can see the status of OpenNI2
support in the CMake log:
@code{.text}
-- Video I/O:
-- DC1394: YES (2.2.6)
-- FFMPEG: YES
-- avcodec: YES (58.91.100)
-- avformat: YES (58.45.100)
-- avutil: YES (56.51.100)
-- swscale: YES (5.7.100)
-- avresample: NO
-- GStreamer: YES (1.18.1)
-- OpenNI2: YES (2.3.0)
-- v4l/v4l2: YES (linux/videodev2.h)
@endcode
-# Build OpenCV:
@code{.bash}
$ make
@endcode
### Code
To get both depth and color frames, two @ref cv::VideoCapture objects should be created:
@snippetlineno samples/cpp/tutorial_code/videoio/orbbec_astra/orbbec_astra.cpp Open streams
The first object will use the regular Video4Linux2 interface to access the color sensor. The second one
is using OpenNI2 API to retrieve depth data.
Before using the created VideoCapture objects you may want to setup stream parameters by setting
objects' properties. The most important parameters are frame width, frame height and fps:
@snippetlineno samples/cpp/tutorial_code/videoio/orbbec_astra/orbbec_astra.cpp Setup streams
For setting and getting some property of sensor data generators use @ref cv::VideoCapture::set and
@ref cv::VideoCapture::get methods respectively, e.g. :
@snippetlineno samples/cpp/tutorial_code/videoio/orbbec_astra/orbbec_astra.cpp Get properties
The following properties of cameras available through OpenNI interfaces are supported for the depth
generator:
- @ref cv::CAP_PROP_FRAME_WIDTH -- Frame width in pixels.
- @ref cv::CAP_PROP_FRAME_HEIGHT -- Frame height in pixels.
- @ref cv::CAP_PROP_FPS -- Frame rate in FPS.
- @ref cv::CAP_PROP_OPENNI_REGISTRATION -- Flag that registers the remapping depth map to image map
by changing the depth generator's viewpoint (if the flag is "on") or sets this view point to
its normal one (if the flag is "off"). The registration process resulting images are
pixel-aligned, which means that every pixel in the image is aligned to a pixel in the depth
image.
- @ref cv::CAP_PROP_OPENNI2_MIRROR -- Flag to enable or disable mirroring for this stream. Set to 0
to disable mirroring
Next properties are available for getting only:
- @ref cv::CAP_PROP_OPENNI_FRAME_MAX_DEPTH -- A maximum supported depth of the camera in mm.
- @ref cv::CAP_PROP_OPENNI_BASELINE -- Baseline value in mm.
After the VideoCapture objects are set up you can start reading frames from them.
@note
OpenCV's VideoCapture provides synchronous API, so you have to grab frames in a new thread
to avoid one stream blocking while another stream is being read. VideoCapture is not a
thread-safe class, so you need to be careful to avoid any possible deadlocks or data races.
Example implementation that gets frames from each sensor in a new thread and stores them
in a list along with their timestamps:
@snippetlineno samples/cpp/tutorial_code/videoio/orbbec_astra/orbbec_astra.cpp Read streams
VideoCapture can retrieve the following data:
-# data given from the depth generator:
- @ref cv::CAP_OPENNI_DEPTH_MAP - depth values in mm (CV_16UC1)
- @ref cv::CAP_OPENNI_POINT_CLOUD_MAP - XYZ in meters (CV_32FC3)
- @ref cv::CAP_OPENNI_DISPARITY_MAP - disparity in pixels (CV_8UC1)
- @ref cv::CAP_OPENNI_DISPARITY_MAP_32F - disparity in pixels (CV_32FC1)
- @ref cv::CAP_OPENNI_VALID_DEPTH_MASK - mask of valid pixels (not occluded, not shaded, etc.)
(CV_8UC1)
-# data given from the color sensor is a regular BGR image (CV_8UC3).
When new data is available a reading thread notifies the main thread. A frame is stored in the
ordered list -- the first frame is the latest one:
@snippetlineno samples/cpp/tutorial_code/videoio/orbbec_astra/orbbec_astra.cpp Show color frame
Depth frames can be picked the same way from the `depthFrames` list.
After that, you'll have two frames: one containing color information and another one -- depth
information. In the sample images below you can see the color frame and the depth frame showing
the same scene. Looking at the color frame it's hard to distinguish plant leaves from leaves painted
on a wall, but the depth data makes it easy.
![Color frame](images/astra_color.jpg)
![Depth frame](images/astra_depth.png)
The complete implementation can be found in
[orbbec_astra.cpp](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/videoio/orbbec_astra/orbbec_astra.cpp)
in `samples/cpp/tutorial_code/videoio` directory.
@@ -26,6 +26,10 @@ This section contains tutorials about how to read/save your video files.
*Languages:* C++
- @subpage tutorial_orbbec_astra
*Languages:* C++
- @subpage tutorial_intelperc
*Languages:* C++
*Languages:* C++
@@ -126,13 +126,12 @@ captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
For properties you can read and change look into the documentation of the @ref cv::VideoCapture::get and
@ref cv::VideoCapture::set functions.
Image similarity - PSNR and SSIM
--------------------------------
### Image similarity - PSNR and SSIM
We want to check just how imperceptible our video converting operation went, therefore we need a
system to check frame by frame the similarity or differences. The most common algorithm used for
this is the PSNR (aka **Peak signal-to-noise ratio**). The simplest definition of this starts out
from the *mean squad error*. Let there be two images: I1 and I2; with a two dimensional size i and
from the *mean squared error*. Let there be two images: I1 and I2; with a two dimensional size i and
j, composed of c number of channels.
\f[MSE = \frac{1}{c*i*j} \sum{(I_1-I_2)^2}\f]
@@ -145,15 +144,15 @@ Here the \f$MAX_I\f$ is the maximum valid value for a pixel. In case of the simp
per pixel per channel this is 255. When two images are the same the MSE will give zero, resulting in
an invalid divide by zero operation in the PSNR formula. In this case the PSNR is undefined and as
we'll need to handle this case separately. The transition to a logarithmic scale is made because the
pixel values have a very wide dynamic range. All this translated to OpenCV and a C++ function looks
pixel values have a very wide dynamic range. All this translated to OpenCV and a function looks
like:
@add_toggle_cpp
@include cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp get-psnr
@snippet cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp get-psnr
@end_toggle
@add_toggle_python
@include samples/python/tutorial_code/videoio/video-input-psnr-ssim.py get-psnr
@snippet samples/python/tutorial_code/videoio/video-input-psnr-ssim.py get-psnr
@end_toggle
Typically result values are anywhere between 30 and 50 for video compression, where higher is
@@ -172,11 +171,11 @@ implementation below.
Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004." article.
@add_toggle_cpp
@include cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp get-mssim
@snippet samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp get-mssim
@end_toggle
@add_toggle_python
@include samples/python/tutorial_code/videoio/video-input-psnr-ssim.py get-mssim
@snippet samples/python/tutorial_code/videoio/video-input-psnr-ssim.py get-mssim
@end_toggle
This will return a similarity index for each channel of the image. This value is between zero and
@@ -63,7 +63,7 @@ specialized video writing libraries such as *FFMpeg* or codecs as *HuffYUV*, *Co
an alternative, create the video track with OpenCV and expand it with sound tracks or convert it to
other formats by using video manipulation programs such as *VirtualDub* or *AviSynth*.
The *VideoWriter* class
The VideoWriter class
-----------------------
The content written here builds on the assumption you