Merge pull request #13723 from smirnov-alexey:gapi_add_sobelxy
* Add Sobel kernel which returns both dx and dy * Splice dx and dy and extend add_border function Also change some tests parameters * Add borderValue parameter in test * Introduces fluid kernel for sobelxy Adds tests (basic and performance) on new backend * Introduces BufHelper struct for some arithmetic
This commit is contained in:
parent
766fd20faa
commit
b1cc114b7b
@ -27,6 +27,7 @@
|
||||
namespace cv { namespace gapi {
|
||||
|
||||
namespace imgproc {
|
||||
using GMat2 = std::tuple<GMat,GMat>;
|
||||
using GMat3 = std::tuple<GMat,GMat,GMat>; // FIXME: how to avoid this?
|
||||
|
||||
G_TYPED_KERNEL(GFilter2D, <GMat(GMat,int,Mat,Point,Scalar,int,Scalar)>,"org.opencv.imgproc.filters.filter2D") {
|
||||
@ -83,6 +84,12 @@ namespace imgproc {
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL_M(GSobelXY, <GMat2(GMat,int,int,int,double,double,int,Scalar)>, "org.opencv.imgproc.filters.sobelxy") {
|
||||
static std::tuple<GMatDesc, GMatDesc> outMeta(GMatDesc in, int ddepth, int, int, double, double, int, Scalar) {
|
||||
return std::make_tuple(in.withDepth(ddepth), in.withDepth(ddepth));
|
||||
}
|
||||
};
|
||||
|
||||
G_TYPED_KERNEL(GEqHist, <GMat(GMat)>, "org.opencv.imgproc.equalizeHist"){
|
||||
static GMatDesc outMeta(GMatDesc in) {
|
||||
return in.withType(CV_8U, 1);
|
||||
@ -487,6 +494,58 @@ GAPI_EXPORTS GMat Sobel(const GMat& src, int ddepth, int dx, int dy, int ksize =
|
||||
int borderType = BORDER_DEFAULT,
|
||||
const Scalar& borderValue = Scalar(0));
|
||||
|
||||
/** @brief Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator.
|
||||
|
||||
In all cases except one, the \f$\texttt{ksize} \times \texttt{ksize}\f$ separable kernel is used to
|
||||
calculate the derivative. When \f$\texttt{ksize = 1}\f$, the \f$3 \times 1\f$ or \f$1 \times 3\f$
|
||||
kernel is used (that is, no Gaussian smoothing is done). `ksize = 1` can only be used for the first
|
||||
or the second x- or y- derivatives.
|
||||
|
||||
There is also the special value `ksize = FILTER_SCHARR (-1)` that corresponds to the \f$3\times3\f$ Scharr
|
||||
filter that may give more accurate results than the \f$3\times3\f$ Sobel. The Scharr aperture is
|
||||
|
||||
\f[\vecthreethree{-3}{0}{3}{-10}{0}{10}{-3}{0}{3}\f]
|
||||
|
||||
for the x-derivative, or transposed for the y-derivative.
|
||||
|
||||
The function calculates an image derivative by convolving the image with the appropriate kernel:
|
||||
|
||||
\f[\texttt{dst} = \frac{\partial^{xorder+yorder} \texttt{src}}{\partial x^{xorder} \partial y^{yorder}}\f]
|
||||
|
||||
The Sobel operators combine Gaussian smoothing and differentiation, so the result is more or less
|
||||
resistant to the noise. Most often, the function is called with ( xorder = 1, yorder = 0, ksize = 3)
|
||||
or ( xorder = 0, yorder = 1, ksize = 3) to calculate the first x- or y- image derivative. The first
|
||||
case corresponds to a kernel of:
|
||||
|
||||
\f[\vecthreethree{-1}{0}{1}{-2}{0}{2}{-1}{0}{1}\f]
|
||||
|
||||
The second case corresponds to a kernel of:
|
||||
|
||||
\f[\vecthreethree{-1}{-2}{-1}{0}{0}{0}{1}{2}{1}\f]
|
||||
|
||||
@note First returned matrix correspons to dx derivative while the second one to dy.
|
||||
|
||||
@note Rounding to nearest even is procedeed if hardware supports it, if not - to nearest.
|
||||
|
||||
@note Function textual ID is "org.opencv.imgproc.filters.sobelxy"
|
||||
|
||||
@param src input image.
|
||||
@param ddepth output image depth, see @ref filter_depths "combinations"; in the case of
|
||||
8-bit input images it will result in truncated derivatives.
|
||||
@param order order of the derivatives.
|
||||
@param ksize size of the extended Sobel kernel; it must be odd.
|
||||
@param scale optional scale factor for the computed derivative values; by default, no scaling is
|
||||
applied (see cv::getDerivKernels for details).
|
||||
@param delta optional delta value that is added to the results prior to storing them in dst.
|
||||
@param borderType pixel extrapolation method, see cv::BorderTypes
|
||||
@param borderValue border value in case of constant border type
|
||||
@sa filter2D, gaussianBlur, cartToPolar
|
||||
*/
|
||||
GAPI_EXPORTS std::tuple<GMat, GMat> SobelXY(const GMat& src, int ddepth, int order, int ksize = 3,
|
||||
double scale = 1, double delta = 0,
|
||||
int borderType = BORDER_DEFAULT,
|
||||
const Scalar& borderValue = Scalar(0));
|
||||
|
||||
/** @brief Finds edges in an image using the Canny algorithm.
|
||||
|
||||
The function finds edges in the input image and marks them in the output map edges using the
|
||||
|
||||
@ -31,6 +31,7 @@ class Erode3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType, cv::Siz
|
||||
class DilatePerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int, cv::GCompileArgs>> {};
|
||||
class Dilate3x3PerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,int, cv::GCompileArgs>> {};
|
||||
class SobelPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int,int, cv::GCompileArgs>> {};
|
||||
class SobelXYPerfTest : public TestPerfParams<tuple<compare_f, MatType,int,cv::Size,int,int, cv::GCompileArgs>> {};
|
||||
class CannyPerfTest : public TestPerfParams<tuple<compare_f, MatType,cv::Size,double,double,int,bool, cv::GCompileArgs>> {};
|
||||
class EqHistPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
|
||||
class RGB2GrayPerfTest : public TestPerfParams<tuple<compare_f, cv::Size, cv::GCompileArgs >> {};
|
||||
|
||||
@ -498,6 +498,52 @@ PERF_TEST_P_(SobelPerfTest, TestPerformance)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(SobelXYPerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF;
|
||||
MatType type = 0;
|
||||
int kernSize = 0, dtype = 0, order = 0;
|
||||
cv::Size sz;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, type, kernSize, sz, dtype, order, compile_args) = GetParam();
|
||||
|
||||
cv::Mat out_mat_ocv2 = cv::Mat(sz, dtype);
|
||||
cv::Mat out_mat_gapi2 = cv::Mat(sz, dtype);
|
||||
|
||||
initMatsRandN(type, sz, dtype, false);
|
||||
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{
|
||||
cv::Sobel(in_mat1, out_mat_ocv, dtype, order, 0, kernSize);
|
||||
cv::Sobel(in_mat1, out_mat_ocv2, dtype, 0, order, kernSize);
|
||||
}
|
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in;
|
||||
auto out = cv::gapi::SobelXY(in, dtype, order, kernSize);
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(std::get<0>(out), std::get<1>(out)));
|
||||
|
||||
// Warm-up graph engine:
|
||||
c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi, out_mat_gapi2), std::move(compile_args));
|
||||
|
||||
TEST_CYCLE()
|
||||
{
|
||||
c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi, out_mat_gapi2));
|
||||
}
|
||||
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi2, out_mat_ocv2));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
EXPECT_EQ(out_mat_gapi2.size(), sz);
|
||||
}
|
||||
|
||||
SANITY_CHECK_NOTHING();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PERF_TEST_P_(CannyPerfTest, TestPerformance)
|
||||
{
|
||||
compare_f cmpF;
|
||||
|
||||
@ -32,7 +32,7 @@ INSTANTIATE_TEST_CASE_P(SepFilterPerfTestFluid_other, SepFilterPerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(Filter2DPerfTestFluid, Filter2DPerfTest,
|
||||
Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(3), // add 4, 5, 7 when kernel is ready
|
||||
Values(3), // TODO: add 4, 5, 7 when kernel is ready
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::BORDER_DEFAULT),
|
||||
Values(-1, CV_32F),
|
||||
@ -41,7 +41,7 @@ INSTANTIATE_TEST_CASE_P(Filter2DPerfTestFluid, Filter2DPerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(BoxFilterPerfTestFluid, BoxFilterPerfTest,
|
||||
Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(3), // add size=5, when kernel is ready
|
||||
Values(3), // TODO: add size=5, when kernel is ready
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::BORDER_DEFAULT),
|
||||
Values(-1, CV_32F),
|
||||
@ -50,7 +50,7 @@ INSTANTIATE_TEST_CASE_P(BoxFilterPerfTestFluid, BoxFilterPerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(BlurPerfTestFluid, BlurPerfTest,
|
||||
Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(3), // add size=5, when kernel is ready
|
||||
Values(3), // TODO: add size=5, when kernel is ready
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::BORDER_DEFAULT),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
@ -58,21 +58,21 @@ INSTANTIATE_TEST_CASE_P(BlurPerfTestFluid, BlurPerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(GaussianBlurPerfTestFluid, GaussianBlurPerfTest,
|
||||
Combine(Values(ToleranceFilter(1e-3f, 0.01).to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(3), // add size=5, when kernel is ready
|
||||
Values(3), // TODO: add size=5, when kernel is ready
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(MedianBlurPerfTestFluid, MedianBlurPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(3), // add size=5, when kernel is ready
|
||||
Values(3), // TODO: add size=5, when kernel is ready
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(ErodePerfTestFluid, ErodePerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(3), // add size=5, when kernel is ready
|
||||
Values(3), // TODO: add size=5, when kernel is ready
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::MorphShapes::MORPH_RECT,
|
||||
cv::MorphShapes::MORPH_CROSS,
|
||||
@ -90,7 +90,7 @@ INSTANTIATE_TEST_CASE_P(DISABLED_Erode3x3PerfTestFluid, Erode3x3PerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(DilatePerfTestFluid, DilatePerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1),
|
||||
Values(3), // add size=5, when kernel is ready
|
||||
Values(3), // TODO: add size=5, when kernel is ready
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(cv::MorphShapes::MORPH_RECT,
|
||||
cv::MorphShapes::MORPH_CROSS,
|
||||
@ -108,7 +108,7 @@ INSTANTIATE_TEST_CASE_P(DISABLED_Dilate3x3PerfTestFluid, Dilate3x3PerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(SobelPerfTestFluid, SobelPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
|
||||
Values(3), // add 5x5 once supported
|
||||
Values(3), // TODO: add 5x5 once supported
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(-1, CV_16S, CV_32F),
|
||||
Values(0, 1),
|
||||
@ -118,13 +118,31 @@ INSTANTIATE_TEST_CASE_P(SobelPerfTestFluid, SobelPerfTest,
|
||||
INSTANTIATE_TEST_CASE_P(SobelPerfTestFluid32F, SobelPerfTest,
|
||||
Combine(Values(ToleranceFilter(1e-3f, 0.0).to_compare_f()),
|
||||
Values(CV_32FC1),
|
||||
Values(3), // add 5x5 once supported
|
||||
Values(3), // TODO: add 5x5 once supported
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(CV_32F),
|
||||
Values(0, 1),
|
||||
Values(1, 2),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SobelXYPerfTestFluid, SobelXYPerfTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
|
||||
Values(3), // TODO: add 5x5 once supported
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(-1, CV_16S, CV_32F),
|
||||
Values(1, 2),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SobelXYPerfTestFluid32F, SobelXYPerfTest,
|
||||
Combine(Values(ToleranceFilter(1e-3f, 0.0).to_compare_f()),
|
||||
Values(CV_32FC1),
|
||||
Values(3), // TODO: add 5x5 once supported
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
Values(CV_32F),
|
||||
Values(1, 2),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(RGB2GrayPerfTestFluid, RGB2GrayPerfTest,
|
||||
Combine(Values(ToleranceColor(1e-3).to_compare_f()),
|
||||
Values(szVGA, sz720p, sz1080p),
|
||||
|
||||
@ -80,6 +80,13 @@ GMat Sobel(const GMat& src, int ddepth, int dx, int dy, int ksize,
|
||||
return imgproc::GSobel::on(src, ddepth, dx, dy, ksize, scale, delta, borderType, bordVal);
|
||||
}
|
||||
|
||||
std::tuple<GMat, GMat> SobelXY(const GMat& src, int ddepth, int order, int ksize,
|
||||
double scale, double delta,
|
||||
int borderType, const Scalar& bordVal)
|
||||
{
|
||||
return imgproc::GSobelXY::on(src, ddepth, order, ksize, scale, delta, borderType, bordVal);
|
||||
}
|
||||
|
||||
GMat equalizeHist(const GMat& src)
|
||||
{
|
||||
return imgproc::GEqHist::on(src);
|
||||
|
||||
@ -11,6 +11,19 @@
|
||||
#include "opencv2/gapi/cpu/imgproc.hpp"
|
||||
#include "backends/cpu/gcpuimgproc.hpp"
|
||||
|
||||
namespace {
|
||||
cv::Mat add_border(const cv::Mat& in, const int ksize, const int borderType, const cv::Scalar& bordVal){
|
||||
if( borderType == cv::BORDER_CONSTANT )
|
||||
{
|
||||
cv::Mat temp_in;
|
||||
int add = (ksize - 1) / 2;
|
||||
cv::copyMakeBorder(in, temp_in, add, add, add, add, borderType, bordVal);
|
||||
return temp_in(cv::Rect(add, add, in.cols, in.rows));
|
||||
}
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUSepFilter, cv::gapi::imgproc::GSepFilter)
|
||||
{
|
||||
static void run(const cv::Mat& in, int ddepth, const cv::Mat& kernX, const cv::Mat& kernY, const cv::Point& anchor, const cv::Scalar& delta,
|
||||
@ -133,16 +146,19 @@ GAPI_OCV_KERNEL(GCPUSobel, cv::gapi::imgproc::GSobel)
|
||||
static void run(const cv::Mat& in, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType,
|
||||
const cv::Scalar& bordVal, cv::Mat &out)
|
||||
{
|
||||
if( borderType == cv::BORDER_CONSTANT )
|
||||
{
|
||||
cv::Mat temp_in;
|
||||
int add = (ksize - 1) / 2;
|
||||
cv::copyMakeBorder(in, temp_in, add, add, add, add, borderType, bordVal );
|
||||
cv::Rect rect = cv::Rect(add, add, in.cols, in.rows);
|
||||
cv::Sobel(temp_in(rect), out, ddepth, dx, dy, ksize, scale, delta, borderType);
|
||||
}
|
||||
else
|
||||
cv::Sobel(in, out, ddepth, dx, dy, ksize, scale, delta, borderType);
|
||||
cv::Mat temp_in = add_border(in, ksize, borderType, bordVal);
|
||||
cv::Sobel(temp_in, out, ddepth, dx, dy, ksize, scale, delta, borderType);
|
||||
}
|
||||
};
|
||||
|
||||
GAPI_OCV_KERNEL(GCPUSobelXY, cv::gapi::imgproc::GSobelXY)
|
||||
{
|
||||
static void run(const cv::Mat& in, int ddepth, int order, int ksize, double scale, double delta, int borderType,
|
||||
const cv::Scalar& bordVal, cv::Mat &out_dx, cv::Mat &out_dy)
|
||||
{
|
||||
cv::Mat temp_in = add_border(in, ksize, borderType, bordVal);
|
||||
cv::Sobel(temp_in, out_dx, ddepth, order, 0, ksize, scale, delta, borderType);
|
||||
cv::Sobel(temp_in, out_dy, ddepth, 0, order, ksize, scale, delta, borderType);
|
||||
}
|
||||
};
|
||||
|
||||
@ -256,6 +272,7 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::cpu::kernels()
|
||||
, GCPUErode
|
||||
, GCPUDilate
|
||||
, GCPUSobel
|
||||
, GCPUSobelXY
|
||||
, GCPUCanny
|
||||
, GCPUEqualizeHist
|
||||
, GCPURGB2YUV
|
||||
|
||||
@ -1022,6 +1022,168 @@ GAPI_FLUID_KERNEL(GFluidSobel, cv::gapi::imgproc::GSobel, true)
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------
|
||||
//
|
||||
// Fluid kernels: SobelXY
|
||||
//
|
||||
//---------------------
|
||||
|
||||
GAPI_FLUID_KERNEL(GFluidSobelXY, cv::gapi::imgproc::GSobelXY, true)
|
||||
{
|
||||
static const int Window = 3;
|
||||
|
||||
struct BufHelper
|
||||
{
|
||||
float *kx_dx, *ky_dx,
|
||||
*kx_dy, *ky_dy;
|
||||
float *buf_start;
|
||||
int buf_width, buf_chan;
|
||||
|
||||
static int length(int ksz, int width, int chan)
|
||||
{
|
||||
return ksz + ksz + ksz + ksz // kernels: kx_dx, ky_dx, kx_dy, ky_dy
|
||||
+ 2 * ksz * width * chan;
|
||||
}
|
||||
|
||||
BufHelper(int ksz, int width, int chan, Buffer& scratch)
|
||||
{
|
||||
kx_dx = scratch.OutLine<float>();
|
||||
ky_dx = kx_dx + ksz;
|
||||
kx_dy = ky_dx + ksz;
|
||||
ky_dy = kx_dy + ksz;
|
||||
buf_start = ky_dy + ksz;
|
||||
buf_width = width;
|
||||
buf_chan = chan;
|
||||
}
|
||||
|
||||
float* operator [](int i) {
|
||||
return buf_start + i * buf_width * buf_chan;
|
||||
}
|
||||
};
|
||||
|
||||
static void run(const View & in,
|
||||
int /* ddepth */,
|
||||
int /* order */,
|
||||
int ksize,
|
||||
double _scale,
|
||||
double _delta,
|
||||
int /* borderType */,
|
||||
const cv::Scalar& /* borderValue */,
|
||||
Buffer& out_x,
|
||||
Buffer& out_y,
|
||||
Buffer& scratch)
|
||||
{
|
||||
// TODO: support kernel height 3, 5, 7, 9, ...
|
||||
GAPI_Assert(ksize == 3 || ksize == FILTER_SCHARR);
|
||||
|
||||
int ksz = (ksize == FILTER_SCHARR)? 3: ksize;
|
||||
|
||||
GAPI_Assert(out_x.meta().size.width == out_y.meta().size.width);
|
||||
GAPI_Assert(out_x.meta().chan == out_y.meta().chan);
|
||||
|
||||
int width = out_x.meta().size.width;
|
||||
int chan = out_x.meta().chan;
|
||||
|
||||
BufHelper buf_helper(ksz, width, chan, scratch);
|
||||
|
||||
auto *kx_dx = buf_helper.kx_dx;
|
||||
auto *ky_dx = buf_helper.ky_dx;
|
||||
auto *kx_dy = buf_helper.kx_dy;
|
||||
auto *ky_dy = buf_helper.ky_dy;
|
||||
|
||||
// Scratch buffer layout:
|
||||
// |kx_dx|ky_dx|kx_dy|ky_dy|3 lines for horizontal kernel|3 lines for vertical kernel|
|
||||
float *buf[3];
|
||||
buf[0] = buf_helper[0];
|
||||
buf[1] = buf_helper[1];
|
||||
buf[2] = buf_helper[2];
|
||||
|
||||
auto scale = static_cast<float>(_scale);
|
||||
auto delta = static_cast<float>(_delta);
|
||||
|
||||
auto calc = [&](const View& src, Buffer& dst, float* kx, float* ky) {
|
||||
// DST SRC OP __VA_ARGS__
|
||||
UNARY_(uchar , uchar , run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
UNARY_(ushort, ushort, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
UNARY_( short, uchar , run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
UNARY_( short, ushort, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
UNARY_( short, short, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
UNARY_( float, uchar , run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
UNARY_( float, ushort, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
UNARY_( float, short, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
UNARY_( float, float, run_sobel, dst, src, kx, ky, ksz, scale, delta, buf);
|
||||
|
||||
CV_Error(cv::Error::StsBadArg, "unsupported combination of types");
|
||||
};
|
||||
|
||||
// calculate x-derivative
|
||||
calc(in, out_x, kx_dx, ky_dx);
|
||||
|
||||
// Move pointers to calculate dy(preventing buffer data corruption)
|
||||
buf[0] = buf_helper[3];
|
||||
buf[1] = buf_helper[4];
|
||||
buf[2] = buf_helper[5];
|
||||
|
||||
// calculate y-derivative
|
||||
calc(in, out_y, kx_dy, ky_dy);
|
||||
}
|
||||
|
||||
static void initScratch(const GMatDesc& in,
|
||||
int /* ddepth */,
|
||||
int order,
|
||||
int ksize,
|
||||
double /* scale */,
|
||||
double /* delta */,
|
||||
int /* borderType */,
|
||||
const Scalar & /* borderValue */,
|
||||
Buffer & scratch)
|
||||
{
|
||||
// TODO: support kernel height 3, 5, 7, 9, ...
|
||||
GAPI_Assert(ksize == 3 || ksize == FILTER_SCHARR);
|
||||
int ksz = (ksize == FILTER_SCHARR) ? 3 : ksize;
|
||||
|
||||
int width = in.size.width;
|
||||
int chan = in.chan;
|
||||
int buflen = BufHelper::length(ksz, width, chan);
|
||||
|
||||
cv::gapi::own::Size bufsize(buflen, 1);
|
||||
GMatDesc bufdesc = {CV_32F, 1, bufsize};
|
||||
Buffer buffer(bufdesc);
|
||||
scratch = std::move(buffer);
|
||||
|
||||
BufHelper buf_helper(ksz, width, chan, scratch);
|
||||
|
||||
auto *kx_dx = buf_helper.kx_dx;
|
||||
auto *ky_dx = buf_helper.ky_dx;
|
||||
auto *kx_dy = buf_helper.kx_dy;
|
||||
auto *ky_dy = buf_helper.ky_dy;
|
||||
|
||||
Mat kxmatX(1, ksize, CV_32FC1, kx_dx);
|
||||
Mat kymatX(ksize, 1, CV_32FC1, ky_dx);
|
||||
getDerivKernels(kxmatX, kymatX, order, 0, ksize);
|
||||
|
||||
Mat kxmatY(1, ksize, CV_32FC1, kx_dy);
|
||||
Mat kymatY(ksize, 1, CV_32FC1, ky_dy);
|
||||
getDerivKernels(kxmatY, kymatY, 0, order, ksize);
|
||||
}
|
||||
|
||||
static void resetScratch(Buffer& /* scratch */)
|
||||
{
|
||||
}
|
||||
|
||||
static Border getBorder(const cv::GMatDesc& /* src */,
|
||||
int /* ddepth */,
|
||||
int /* order */,
|
||||
int /* ksize */,
|
||||
double /* scale */,
|
||||
double /* delta */,
|
||||
int borderType,
|
||||
const cv::Scalar & borderValue)
|
||||
{
|
||||
return {borderType, borderValue};
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------
|
||||
//
|
||||
// Fluid kernels: filter2D
|
||||
@ -1546,6 +1708,7 @@ cv::gapi::GKernelPackage cv::gapi::imgproc::fluid::kernels()
|
||||
, GFluidMedianBlur
|
||||
, GFluidGaussBlur
|
||||
, GFluidSobel
|
||||
, GFluidSobelXY
|
||||
#if 0
|
||||
, GFluidCanny -- not fluid (?)
|
||||
, GFluidEqualizeHist -- not fluid
|
||||
|
||||
@ -26,6 +26,7 @@ struct Erode3x3Test : public TestParams <std::tuple<compare_f,MatType,cv::Size,b
|
||||
struct DilateTest : public TestParams <std::tuple<compare_f,MatType,int,cv::Size,int,bool,cv::GCompileArgs>> {};
|
||||
struct Dilate3x3Test : public TestParams <std::tuple<compare_f,MatType,cv::Size,bool,int,cv::GCompileArgs>> {};
|
||||
struct SobelTest : public TestParams <std::tuple<compare_f,MatType,int,cv::Size,int,int,int,bool,cv::GCompileArgs>> {};
|
||||
struct SobelXYTest : public TestParams <std::tuple<compare_f,MatType,int,cv::Size,int,int,int,int,cv::GCompileArgs>> {};
|
||||
struct EqHistTest : public TestParams <std::tuple<compare_f,cv::Size,bool,cv::GCompileArgs>> {};
|
||||
struct CannyTest : public TestParams <std::tuple<compare_f,MatType,cv::Size,double,double,int,bool,bool,cv::GCompileArgs>> {};
|
||||
struct RGB2GrayTest : public TestParams<std::tuple<compare_f,cv::Size,bool,cv::GCompileArgs>> {};
|
||||
|
||||
@ -353,6 +353,46 @@ TEST_P(SobelTest, AccuracyTest)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(SobelXYTest, AccuracyTest)
|
||||
{
|
||||
compare_f cmpF;
|
||||
MatType type = 0;
|
||||
int kernSize = 0, dtype = 0, order = 0, border_type = 0, border_val = 0;
|
||||
cv::Size sz;
|
||||
cv::GCompileArgs compile_args;
|
||||
std::tie(cmpF, type, kernSize, sz, dtype, order, border_type, border_val, compile_args) = GetParam();
|
||||
initMatsRandN(type, sz, dtype);
|
||||
cv::Mat out_mat_ocv2 = cv::Mat(sz, dtype);
|
||||
cv::Mat out_mat_gapi2 = cv::Mat(sz, dtype);
|
||||
|
||||
// G-API code //////////////////////////////////////////////////////////////
|
||||
cv::GMat in;
|
||||
auto out = cv::gapi::SobelXY(in, dtype, order, kernSize, 1, 0, border_type, border_val);
|
||||
|
||||
cv::GComputation c(cv::GIn(in), cv::GOut(std::get<0>(out), std::get<1>(out)));
|
||||
c.apply(cv::gin(in_mat1), cv::gout(out_mat_gapi, out_mat_gapi2), std::move(compile_args));
|
||||
// OpenCV code /////////////////////////////////////////////////////////////
|
||||
{
|
||||
// workaround for cv::Sobel
|
||||
cv::Mat temp_in;
|
||||
if(border_type == cv::BORDER_CONSTANT)
|
||||
{
|
||||
int n_pixels = (kernSize - 1) / 2;
|
||||
cv::copyMakeBorder(in_mat1, temp_in, n_pixels, n_pixels, n_pixels, n_pixels, border_type, border_val);
|
||||
in_mat1 = temp_in(cv::Rect(n_pixels, n_pixels, in_mat1.cols, in_mat1.rows));
|
||||
}
|
||||
cv::Sobel(in_mat1, out_mat_ocv, dtype, order, 0, kernSize, 1, 0, border_type);
|
||||
cv::Sobel(in_mat1, out_mat_ocv2, dtype, 0, order, kernSize, 1, 0, border_type);
|
||||
}
|
||||
// Comparison //////////////////////////////////////////////////////////////
|
||||
{
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi, out_mat_ocv));
|
||||
EXPECT_TRUE(cmpF(out_mat_gapi2, out_mat_ocv2));
|
||||
EXPECT_EQ(out_mat_gapi.size(), sz);
|
||||
EXPECT_EQ(out_mat_gapi2.size(), sz);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(EqHistTest, AccuracyTest)
|
||||
{
|
||||
compare_f cmpF;
|
||||
|
||||
@ -153,6 +153,30 @@ INSTANTIATE_TEST_CASE_P(SobelTestCPU32F, SobelTest,
|
||||
/*init output matrices or not*/ testing::Bool(),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SobelXYTestCPU, SobelXYTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
|
||||
Values(3, 5),
|
||||
Values(cv::Size(1280, 720),
|
||||
cv::Size(640, 480)),
|
||||
Values(-1, CV_16S, CV_32F),
|
||||
Values(1, 2),
|
||||
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT),
|
||||
Values(0, 1, 255),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SobelXYTestCPU32F, SobelXYTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_32FC1),
|
||||
Values(3, 5),
|
||||
Values(cv::Size(1280, 720),
|
||||
cv::Size(640, 480)),
|
||||
Values(CV_32F),
|
||||
Values(1, 2),
|
||||
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT),
|
||||
Values(0, 1, 255),
|
||||
Values(cv::compile_args(IMGPROC_CPU))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(EqHistTestCPU, EqHistTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(cv::Size(1280, 720),
|
||||
|
||||
@ -132,6 +132,30 @@ INSTANTIATE_TEST_CASE_P(SobelTestFluid32F, SobelTest,
|
||||
Values(true, false),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SobelXYTestFluid, SobelXYTest,
|
||||
Combine(Values(AbsExact().to_compare_f()),
|
||||
Values(CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1),
|
||||
Values(3),
|
||||
Values(cv::Size(1280, 720),
|
||||
cv::Size(640, 480)),
|
||||
Values(-1, CV_16S, CV_32F),
|
||||
Values(1, 2),
|
||||
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101),
|
||||
Values(0, 1, 255),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SobelXYTestFluid32F, SobelXYTest,
|
||||
Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()),
|
||||
Values(CV_32FC1),
|
||||
Values(3),
|
||||
Values(cv::Size(1280, 720),
|
||||
cv::Size(640, 480)),
|
||||
Values(CV_32F),
|
||||
Values(1, 2),
|
||||
Values(BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT_101),
|
||||
Values(0, 1, 255),
|
||||
Values(cv::compile_args(IMGPROC_FLUID))));
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(boxFilterTestFluid32, BoxFilterTest,
|
||||
Combine(Values(ToleranceFilter(1e-4f, 0.01).to_compare_f()),
|
||||
Values(CV_8UC1, CV_16UC1, CV_16SC1),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user