Merge pull request #13030 from dmatveev:tutorial

* G-API: First steps with tutorial

* G-API Tutorial: First iteration

* G-API port of anisotropic image segmentation tutorial;
* Currently works via OpenCV only;
* Some new kernels have been required.

* G-API Tutorial: added chapters on execution code, inspection, and profiling

* G-API Tutorial: make Fluid kernel headers public

For some reason, these headers were not moved to the public
headers subtree during the initial development. Somehow it even
worked for the existing workloads.

* G-API Tutorial: Fix a couple of issues found during the work

* Introduced Phase & Sqrt kernels, OCV & Fluid versions
* Extended GKernelPackage to allow kernel removal & policies on include()

All the above stuff needs to be tested, tests will be added later

* G-API Tutorial: added chapter on running Fluid backend

* G-API Tutorial: fix a number of issues in the text

* G-API Tutorial - some final updates

- Fixed post-merge issues after Sobel kernel renaming;
- Simplified G-API code a little bit;
- Put a conclusion note in text.

* G-API Tutorial - fix build issues in test/perf targets

Public headers were refactored but tests suites were not updated in time

* G-API Tutorial: Added tests & reference docs on new kernels

* Phase
* Sqrt

* G-API Tutorial: added link to the tutorial from the main module doc

* G-API Tutorial: Added tests on new GKernelPackage functionality

* G-API Tutorial: Extended InRange tests to cover 32F

* G-API Tutorial: Misc fixes

* Avoid building examples when gapi module is not there
* Added a volatile API disclaimer to G-API root documentation page

* G-API Tutorial: Fix perf tests build issue

This change came from master where Fluid kernels are still used
incorrectly.

* G-API Tutorial: Fixed channels support in Sqrt/Phase fluid kernels

Extended tests to cover this case

* G-API Tutorial: Fix text problems found on team review
This commit is contained in:
Dmitry Matveev
2018-11-15 18:12:36 +03:00
committed by Alexander Alekhin
parent 1d10d56651
commit 85fad1504a
35 changed files with 1051 additions and 49 deletions
@@ -10,7 +10,9 @@
using namespace cv;
using namespace std;
//! [calcGST_proto]
void calcGST(const Mat& inputImg, Mat& imgCoherencyOut, Mat& imgOrientationOut, int w);
//! [calcGST_proto]
int main()
{
@@ -26,6 +28,7 @@ int main()
return -1;
}
//! [main_extra]
//! [main]
Mat imgCoherency, imgOrientation;
calcGST(imgIn, imgCoherency, imgOrientation, W);
@@ -45,32 +48,36 @@ int main()
normalize(imgCoherency, imgCoherency, 0, 255, NORM_MINMAX);
normalize(imgOrientation, imgOrientation, 0, 255, NORM_MINMAX);
imwrite("result.jpg", 0.5*(imgIn + imgBin));
imwrite("Coherency.jpg", imgCoherency);
imwrite("Orientation.jpg", imgOrientation);
//! [main_extra]
return 0;
}
//! [calcGST]
//! [calcJ_header]
void calcGST(const Mat& inputImg, Mat& imgCoherencyOut, Mat& imgOrientationOut, int w)
{
Mat img;
inputImg.convertTo(img, CV_64F);
inputImg.convertTo(img, CV_32F);
// GST components calculation (start)
// J = (J11 J12; J12 J22) - GST
Mat imgDiffX, imgDiffY, imgDiffXY;
Sobel(img, imgDiffX, CV_64F, 1, 0, 3);
Sobel(img, imgDiffY, CV_64F, 0, 1, 3);
Sobel(img, imgDiffX, CV_32F, 1, 0, 3);
Sobel(img, imgDiffY, CV_32F, 0, 1, 3);
multiply(imgDiffX, imgDiffY, imgDiffXY);
//! [calcJ_header]
Mat imgDiffXX, imgDiffYY;
multiply(imgDiffX, imgDiffX, imgDiffXX);
multiply(imgDiffY, imgDiffY, imgDiffYY);
Mat J11, J22, J12; // J11, J22 and J12 are GST components
boxFilter(imgDiffXX, J11, CV_64F, Size(w, w));
boxFilter(imgDiffYY, J22, CV_64F, Size(w, w));
boxFilter(imgDiffXY, J12, CV_64F, Size(w, w));
boxFilter(imgDiffXX, J11, CV_32F, Size(w, w));
boxFilter(imgDiffYY, J22, CV_32F, Size(w, w));
boxFilter(imgDiffXY, J12, CV_32F, Size(w, w));
// GST components calculation (stop)
// eigenvalue calculation (start)
@@ -0,0 +1,107 @@
/**
* @brief You will learn how port an existing algorithm to G-API
* @author Dmitry Matveev, dmitry.matveev@intel.com, based
* on sample by Karpushin Vladislav, karpushin@ngs.ru
*/
#include "opencv2/opencv_modules.hpp"
#ifdef HAVE_OPENCV_GAPI
//! [full_sample]
#include <iostream>
#include <utility>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/gapi.hpp"
#include "opencv2/gapi/core.hpp"
#include "opencv2/gapi/imgproc.hpp"
//! [calcGST_proto]
void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w);
//! [calcGST_proto]
int main()
{
int W = 52; // window size is WxW
double C_Thr = 0.43; // threshold for coherency
int LowThr = 35; // threshold1 for orientation, it ranges from 0 to 180
int HighThr = 57; // threshold2 for orientation, it ranges from 0 to 180
cv::Mat imgIn = cv::imread("input.jpg", cv::IMREAD_GRAYSCALE);
if (imgIn.empty()) //check whether the image is loaded or not
{
std::cout << "ERROR : Image cannot be loaded..!!" << std::endl;
return -1;
}
//! [main]
// Calculate Gradient Structure Tensor and post-process it for output with G-API
cv::GMat in;
cv::GMat imgCoherency, imgOrientation;
calcGST(in, imgCoherency, imgOrientation, W);
cv::GMat imgCoherencyBin = imgCoherency > C_Thr;
cv::GMat imgOrientationBin = cv::gapi::inRange(imgOrientation, LowThr, HighThr);
cv::GMat imgBin = imgCoherencyBin & imgOrientationBin;
cv::GMat out = cv::gapi::addWeighted(in, 0.5, imgBin, 0.5, 0.0);
// Capture the graph into object segm
cv::GComputation segm(cv::GIn(in), cv::GOut(out, imgCoherency, imgOrientation));
// Define cv::Mats for output data
cv::Mat imgOut, imgOutCoherency, imgOutOrientation;
// Run the graph
segm.apply(cv::gin(imgIn), cv::gout(imgOut, imgOutCoherency, imgOutOrientation));
// Normalize extra outputs (out of the graph)
cv::normalize(imgOutCoherency, imgOutCoherency, 0, 255, cv::NORM_MINMAX);
cv::normalize(imgOutOrientation, imgOutOrientation, 0, 255, cv::NORM_MINMAX);
cv::imwrite("result.jpg", imgOut);
cv::imwrite("Coherency.jpg", imgOutCoherency);
cv::imwrite("Orientation.jpg", imgOutOrientation);
//! [main]
return 0;
}
//! [calcGST]
//! [calcGST_header]
void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w)
{
auto img = cv::gapi::convertTo(inputImg, CV_32F);
auto imgDiffX = cv::gapi::Sobel(img, CV_32F, 1, 0, 3);
auto imgDiffY = cv::gapi::Sobel(img, CV_32F, 0, 1, 3);
auto imgDiffXY = cv::gapi::mul(imgDiffX, imgDiffY);
//! [calcGST_header]
auto imgDiffXX = cv::gapi::mul(imgDiffX, imgDiffX);
auto imgDiffYY = cv::gapi::mul(imgDiffY, imgDiffY);
auto J11 = cv::gapi::boxFilter(imgDiffXX, CV_32F, cv::Size(w, w));
auto J22 = cv::gapi::boxFilter(imgDiffYY, CV_32F, cv::Size(w, w));
auto J12 = cv::gapi::boxFilter(imgDiffXY, CV_32F, cv::Size(w, w));
auto tmp1 = J11 + J22;
auto tmp2 = J11 - J22;
auto tmp22 = cv::gapi::mul(tmp2, tmp2);
auto tmp3 = cv::gapi::mul(J12, J12);
auto tmp4 = cv::gapi::sqrt(tmp22 + 4.0*tmp3);
auto lambda1 = tmp1 + tmp4;
auto lambda2 = tmp1 - tmp4;
imgCoherencyOut = (lambda1 - lambda2) / (lambda1 + lambda2);
imgOrientationOut = 0.5*cv::gapi::phase(J22 - J11, 2.0*J12, true);
}
//! [calcGST]
//! [full_sample]
#else
#include <iostream>
int main()
{
std::cerr << "This tutorial code requires G-API module to run" << std::endl;
}
#endif // HAVE_OPECV_GAPI
@@ -0,0 +1,128 @@
/**
* @brief You will learn how port an existing algorithm to G-API
* @author Dmitry Matveev, dmitry.matveev@intel.com, based
* on sample by Karpushin Vladislav, karpushin@ngs.ru
*/
#include "opencv2/opencv_modules.hpp"
#ifdef HAVE_OPENCV_GAPI
//! [full_sample]
#include <iostream>
#include <utility>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/gapi.hpp"
#include "opencv2/gapi/core.hpp"
#include "opencv2/gapi/imgproc.hpp"
//! [fluid_includes]
#include "opencv2/gapi/fluid/core.hpp" // Fluid Core kernel library
#include "opencv2/gapi/fluid/imgproc.hpp" // Fluid ImgProc kernel library
//! [fluid_includes]
#include "opencv2/gapi/fluid/gfluidkernel.hpp" // Fluid user kernel API
//! [calcGST_proto]
void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w);
//! [calcGST_proto]
int main()
{
int W = 52; // window size is WxW
double C_Thr = 0.43; // threshold for coherency
int LowThr = 35; // threshold1 for orientation, it ranges from 0 to 180
int HighThr = 57; // threshold2 for orientation, it ranges from 0 to 180
cv::Mat imgIn = cv::imread("input.jpg", cv::IMREAD_GRAYSCALE);
if (imgIn.empty()) //check whether the image is loaded or not
{
std::cout << "ERROR : Image cannot be loaded..!!" << std::endl;
return -1;
}
//! [main]
// Calculate Gradient Structure Tensor and post-process it for output with G-API
cv::GMat in;
cv::GMat imgCoherency, imgOrientation;
calcGST(in, imgCoherency, imgOrientation, W);
auto imgCoherencyBin = imgCoherency > C_Thr;
auto imgOrientationBin = cv::gapi::inRange(imgOrientation, LowThr, HighThr);
auto imgBin = imgCoherencyBin & imgOrientationBin;
cv::GMat out = cv::gapi::addWeighted(in, 0.5, imgBin, 0.5, 0.0);
// Capture the graph into object segm
cv::GComputation segm(cv::GIn(in), cv::GOut(out, imgCoherency, imgOrientation));
// Define cv::Mats for output data
cv::Mat imgOut, imgOutCoherency, imgOutOrientation;
//! [kernel_pkg_proper]
//! [kernel_pkg]
// Prepare the kernel package and run the graph
cv::gapi::GKernelPackage fluid_kernels = cv::gapi::combine // Define a custom kernel package:
(cv::gapi::core::fluid::kernels(), // ...with Fluid Core kernels
cv::gapi::imgproc::fluid::kernels(), // ...and Fluid ImgProc kernels
cv::unite_policy::KEEP);
//! [kernel_pkg]
//! [kernel_hotfix]
fluid_kernels.remove<cv::gapi::imgproc::GBoxFilter>(); // Remove Fluid Box filter as unsuitable,
// G-API will fall-back to OpenCV there.
//! [kernel_hotfix]
//! [kernel_pkg_use]
segm.apply(cv::gin(imgIn), // Input data vector
cv::gout(imgOut, imgOutCoherency, imgOutOrientation), // Output data vector
cv::compile_args(fluid_kernels)); // Kernel package to use
//! [kernel_pkg_use]
//! [kernel_pkg_proper]
// Normalize extra outputs (out of the graph)
cv::normalize(imgOutCoherency, imgOutCoherency, 0, 255, cv::NORM_MINMAX);
cv::normalize(imgOutOrientation, imgOutOrientation, 0, 255, cv::NORM_MINMAX);
cv::imwrite("result.jpg", imgOut);
cv::imwrite("Coherency.jpg", imgOutCoherency);
cv::imwrite("Orientation.jpg", imgOutOrientation);
//! [main]
return 0;
}
//! [calcGST]
//! [calcGST_header]
void calcGST(const cv::GMat& inputImg, cv::GMat& imgCoherencyOut, cv::GMat& imgOrientationOut, int w)
{
auto img = cv::gapi::convertTo(inputImg, CV_32F);
auto imgDiffX = cv::gapi::Sobel(img, CV_32F, 1, 0, 3);
auto imgDiffY = cv::gapi::Sobel(img, CV_32F, 0, 1, 3);
auto imgDiffXY = cv::gapi::mul(imgDiffX, imgDiffY);
//! [calcGST_header]
auto imgDiffXX = cv::gapi::mul(imgDiffX, imgDiffX);
auto imgDiffYY = cv::gapi::mul(imgDiffY, imgDiffY);
auto J11 = cv::gapi::boxFilter(imgDiffXX, CV_32F, cv::Size(w, w));
auto J22 = cv::gapi::boxFilter(imgDiffYY, CV_32F, cv::Size(w, w));
auto J12 = cv::gapi::boxFilter(imgDiffXY, CV_32F, cv::Size(w, w));
auto tmp1 = J11 + J22;
auto tmp2 = J11 - J22;
auto tmp22 = cv::gapi::mul(tmp2, tmp2);
auto tmp3 = cv::gapi::mul(J12, J12);
auto tmp4 = cv::gapi::sqrt(tmp22 + 4.0*tmp3);
auto lambda1 = tmp1 + tmp4;
auto lambda2 = tmp1 - tmp4;
imgCoherencyOut = (lambda1 - lambda2) / (lambda1 + lambda2);
imgOrientationOut = 0.5*cv::gapi::phase(J22 - J11, 2.0*J12, true);
}
//! [calcGST]
//! [full_sample]
#else
#include <iostream>
int main()
{
std::cerr << "This tutorial code requires G-API module to run" << std::endl;
}
#endif // HAVE_OPECV_GAPI