Merge remote-tracking branch 'upstream/3.4' into merge-3.4
authorAlexander Alekhin <alexander.a.alekhin@gmail.com>
Sat, 2 Oct 2021 17:57:18 +0000 (17:57 +0000)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Sat, 2 Oct 2021 17:57:18 +0000 (17:57 +0000)
1  2 
doc/tutorials/app/video_input_psnr_ssim.markdown
modules/dnn/src/ocl4dnn/src/ocl4dnn_conv_spatial.cpp
modules/imgproc/include/opencv2/imgproc.hpp
modules/imgproc/src/hough.cpp
modules/java/android_sdk/build.gradle.in
modules/python/src2/hdr_parser.py
modules/videoio/src/cap_gstreamer.cpp

index e212c4e,0000000..1d53c70
mode 100644,000000..100644
--- /dev/null
@@@ -1,203 -1,0 +1,203 @@@
- costly, so while the PSNR may work in a real time like environment (24 frame per second) this will
 +Video Input with OpenCV and similarity measurement {#tutorial_video_input_psnr_ssim}
 +==================================================
 +
 +@tableofcontents
 +
 +@prev_tutorial{tutorial_raster_io_gdal}
 +@next_tutorial{tutorial_video_write}
 +
 +|    |    |
 +| -: | :- |
 +| Original author | Bernát Gábor |
 +| Compatibility | OpenCV >= 3.0 |
 +
 +Goal
 +----
 +
 +Today it is common to have a digital video recording system at your disposal. Therefore, you will
 +eventually come to the situation that you no longer process a batch of images, but video streams.
 +These may be of two kinds: real-time image feed (in the case of a webcam) or prerecorded and hard
 +disk drive stored files. Luckily OpenCV treats these two in the same manner, with the same C++
 +class. So here's what you'll learn in this tutorial:
 +
 +-   How to open and read video streams
 +-   Two ways for checking image similarity: PSNR and SSIM
 +
 +The source code
 +---------------
 +
 +As a test case where to show off these using OpenCV I've created a small program that reads in two
 +video files and performs a similarity check between them. This is something you could use to check
 +just how well a new video compressing algorithms works. Let there be a reference (original) video
 +like [this small Megamind clip
 +](https://github.com/opencv/opencv/tree/master/samples/data/Megamind.avi) and [a compressed
 +version of it ](https://github.com/opencv/opencv/tree/master/samples/data/Megamind_bugy.avi).
 +You may also find the source code and these video file in the
 +`samples/data` folder of the OpenCV source library.
 +
 +@add_toggle_cpp
 +@include cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp
 +@end_toggle
 +
 +@add_toggle_python
 +@include samples/python/tutorial_code/videoio/video-input-psnr-ssim.py
 +@end_toggle
 +
 +How to read a video stream (online-camera or offline-file)?
 +-----------------------------------------------------------
 +
 +Essentially, all the functionalities required for video manipulation is integrated in the @ref cv::VideoCapture
 +C++ class. This on itself builds on the FFmpeg open source library. This is a basic
 +dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession
 +of images, we refer to these in the literature as frames. In case of a video file there is a *frame
 +rate* specifying just how long is between two frames. While for the video cameras usually there is a
 +limit of just how many frames they can digitize per second, this property is less important as at
 +any time the camera sees the current snapshot of the world.
 +
 +The first task you need to do is to assign to a @ref cv::VideoCapture class its source. You can do
 +this either via the @ref cv::VideoCapture::VideoCapture or its @ref cv::VideoCapture::open function. If this argument is an
 +integer then you will bind the class to a camera, a device. The number passed here is the ID of the
 +device, assigned by the operating system. If you have a single camera attached to your system its ID
 +will probably be zero and further ones increasing from there. If the parameter passed to these is a
 +string it will refer to a video file, and the string points to the location and name of the file.
 +For example, to the upper source code a valid command line is:
 +@code{.bash}
 +video/Megamind.avi video/Megamind_bug.avi  35 10
 +@endcode
 +We do a similarity check. This requires a reference and a test case video file. The first two
 +arguments refer to this. Here we use a relative address. This means that the application will look
 +into its current working directory and open the video folder and try to find inside this the
 +*Megamind.avi* and the *Megamind_bug.avi*.
 +@code{.cpp}
 +const string sourceReference = argv[1],sourceCompareWith = argv[2];
 +
 +VideoCapture captRefrnc(sourceReference);
 +// or
 +VideoCapture captUndTst;
 +captUndTst.open(sourceCompareWith);
 +@endcode
 +To check if the binding of the class to a video source was successful or not use the @ref cv::VideoCapture::isOpened
 +function:
 +@code{.cpp}
 +if ( !captRefrnc.isOpened())
 +  {
 +  cout  << "Could not open reference " << sourceReference << endl;
 +  return -1;
 +  }
 +@endcode
 +Closing the video is automatic when the objects destructor is called. However, if you want to close
 +it before this you need to call its @ref cv::VideoCapture::release function. The frames of the video are just
 +simple images. Therefore, we just need to extract them from the @ref cv::VideoCapture object and put
 +them inside a *Mat* one. The video streams are sequential. You may get the frames one after another
 +by the @ref cv::VideoCapture::read or the overloaded \>\> operator:
 +@code{.cpp}
 +Mat frameReference, frameUnderTest;
 +captRefrnc >> frameReference;
 +captUndTst.read(frameUnderTest);
 +@endcode
 +The upper read operations will leave empty the *Mat* objects if no frame could be acquired (either
 +cause the video stream was closed or you got to the end of the video file). We can check this with a
 +simple if:
 +@code{.cpp}
 +if( frameReference.empty()  || frameUnderTest.empty())
 +{
 + // exit the program
 +}
 +@endcode
 +A read method is made of a frame grab and a decoding applied on that. You may call explicitly these
 +two by using the @ref cv::VideoCapture::grab and then the @ref cv::VideoCapture::retrieve functions.
 +
 +Videos have many-many information attached to them besides the content of the frames. These are
 +usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to
 +this to acquire these information there is a general function named @ref cv::VideoCapture::get that returns double
 +values containing these properties. Use bitwise operations to decode the characters from a double
 +type and conversions where valid values are only integers. Its single argument is the ID of the
 +queried property. For example, here we get the size of the frames in the reference and test case
 +video file; plus the number of frames inside the reference.
 +@code{.cpp}
 +Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),
 +                 (int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),
 +
 +cout << "Reference frame resolution: Width=" << refS.width << "  Height=" << refS.height
 +     << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
 +@endcode
 +When you are working with videos you may often want to control these values yourself. To do this
 +there is a @ref cv::VideoCapture::set function. Its first argument remains the name of the property you want to
 +change and there is a second of double type containing the value to be set. It will return true if
 +it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time
 +or frame:
 +@code{.cpp}
 +captRefrnc.set(CAP_PROP_POS_MSEC, 1.2);  // go to the 1.2 second in the video
 +captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
 +// now a read operation would read the frame at the set position
 +@endcode
 +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
 +
 +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 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]
 +
 +Then the PSNR is expressed as:
 +
 +\f[PSNR = 10 \cdot \log_{10} \left( \frac{MAX_I^2}{MSE} \right)\f]
 +
 +Here the \f$MAX_I\f$ is the maximum valid value for a pixel. In case of the simple single byte image
 +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 function looks
 +like:
 +
 +@add_toggle_cpp
 +@snippet cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp get-psnr
 +@end_toggle
 +
 +@add_toggle_python
 +@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
 +better. If the images significantly differ you'll get much lower ones like 15 and so. This
 +similarity check is easy and fast to calculate, however in practice it may turn out somewhat
 +inconsistent with human eye perception. The **structural similarity** algorithm aims to correct
 +this.
 +
 +Describing the methods goes well beyond the purpose of this tutorial. For that I invite you to read
 +the article introducing it. Nevertheless, you can get a good image of it by looking at the OpenCV
 +implementation below.
 +
 +@note
 +    SSIM is described more in-depth in the: "Z. Wang, A. C. Bovik, H. R. Sheikh and E. P.
 +    Simoncelli, "Image quality assessment: From error visibility to structural similarity," IEEE
 +    Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004." article.
 +
 +@add_toggle_cpp
 +@snippet samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp get-mssim
 +@end_toggle
 +
 +@add_toggle_python
 +@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
 +one, where one corresponds to perfect fit. Unfortunately, the many Gaussian blurring is quite
++costly, so while the PSNR may work in a real time like environment (24 frames per second) this will
 +take significantly more than to accomplish similar performance results.
 +
 +Therefore, the source code presented at the start of the tutorial will perform the PSNR measurement
 +for each frame, and the SSIM only for the frames where the PSNR falls below an input value. For
 +visualization purpose we show both images in an OpenCV window and print the PSNR and MSSIM values to
 +the console. Expect to see something like:
 +
 +![](images/outputVideoInput.png)
 +
 +You may observe a runtime instance of this on the [YouTube here](https://www.youtube.com/watch?v=iOcNljutOgg).
 +
 +@youtube{iOcNljutOgg}
Simple merge
Simple merge
@@@ -218,13 -214,12 +218,13 @@@ private
          isFailed(false)
      {
          call_deinit = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_GSTREAMER_CALL_DEINIT", false);
 +        start_loop = utils::getConfigurationParameterBool("OPENCV_VIDEOIO_GSTREAMER_START_MAINLOOP", false);
  
          GSafePtr<GError> err;
-         gst_init_check(NULL, NULL, err.getRef());
-         if (err)
+         gboolean gst_init_res = gst_init_check(NULL, NULL, err.getRef());
+         if (!gst_init_res)
          {
-             CV_WARN("Can't initialize GStreamer: " << err->message);
+             CV_WARN("Can't initialize GStreamer: " << (err ? err->message : "<unknown reason>"));
              isFailed = true;
              return;
          }