From 384a28622d766c4ce302051152b40d7a1655ba85 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Wed, 29 Jan 2014 20:19:15 +0400 Subject: [PATCH 1/3] added cv::calcHist to T-API (only for CV_8UC1 with 256 bins) --- modules/core/src/matrix.cpp | 38 +++++++++ modules/imgproc/src/histogram.cpp | 93 +++++++++++++-------- modules/imgproc/test/ocl/test_histogram.cpp | 56 +++++++++++-- 3 files changed, 146 insertions(+), 41 deletions(-) diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 0f15ac1d6e..af2ca7d74f 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -1650,6 +1650,16 @@ int _InputArray::dims(int i) const return vv[i].dims; } + if( k == STD_VECTOR_UMAT ) + { + const std::vector& vv = *(const std::vector*)obj; + if( i < 0 ) + return 1; + CV_Assert( i < (int)vv.size() ); + + return vv[i].dims; + } + if( k == OPENGL_BUFFER ) { CV_Assert( i < 0 ); @@ -1701,6 +1711,16 @@ size_t _InputArray::total(int i) const return vv[i].total(); } + if( k == STD_VECTOR_UMAT ) + { + const std::vector& vv = *(const std::vector*)obj; + if( i < 0 ) + return vv.size(); + + CV_Assert( i < (int)vv.size() ); + return vv[i].total(); + } + return size(i).area(); } @@ -1723,6 +1743,18 @@ int _InputArray::type(int i) const if( k == NONE ) return -1; + if( k == STD_VECTOR_UMAT ) + { + const std::vector& vv = *(const std::vector*)obj; + if( vv.empty() ) + { + CV_Assert((flags & FIXED_TYPE) != 0); + return CV_MAT_TYPE(flags); + } + CV_Assert( i < (int)vv.size() ); + return vv[i >= 0 ? i : 0].type(); + } + if( k == STD_VECTOR_MAT ) { const std::vector& vv = *(const std::vector*)obj; @@ -1793,6 +1825,12 @@ bool _InputArray::empty() const return vv.empty(); } + if( k == STD_VECTOR_UMAT ) + { + const std::vector& vv = *(const std::vector*)obj; + return vv.empty(); + } + if( k == OPENGL_BUFFER ) return ((const ogl::Buffer*)obj)->empty(); diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp index 0533bbba2c..1a91119b9a 100644 --- a/modules/imgproc/src/histogram.cpp +++ b/modules/imgproc/src/histogram.cpp @@ -1399,6 +1399,57 @@ static void calcHist( const Mat* images, int nimages, const int* channels, } } +enum +{ + BINS = 256 +}; + +static bool ocl_calcHist1(InputArrayOfArrays _src, OutputArray _hist, int ddepth = CV_32S) +{ + int compunits = ocl::Device::getDefault().maxComputeUnits(); + size_t wgs = ocl::Device::getDefault().maxWorkGroupSize(); + + ocl::Kernel k1("calculate_histogram", ocl::imgproc::histogram_oclsrc, + format("-D BINS=%d -D HISTS_COUNT=%d -D WGS=%d", BINS, compunits, wgs)); + if (k1.empty()) + return false; + + _hist.create(1, BINS, ddepth); + UMat src = _src.getUMat(), ghist(1, BINS * compunits, CV_32SC1), + hist = ddepth == CV_32S ? _hist.getUMat() : UMat(BINS, 1, CV_32SC1); + + k1.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::PtrWriteOnly(ghist), + (int)src.total()); + + size_t globalsize = compunits * wgs; + if (!k1.run(1, &globalsize, &wgs, false)) + return false; + + ocl::Kernel k2("merge_histogram", ocl::imgproc::histogram_oclsrc, + format("-D BINS=%d -D HISTS_COUNT=%d -D WGS=%d", BINS, compunits, (int)wgs)); + if (k2.empty()) + return false; + + k2.args(ocl::KernelArg::PtrReadOnly(ghist), ocl::KernelArg::PtrWriteOnly(hist)); + if (!k2.run(1, &wgs, &wgs, false)) + return false; + + if (hist.depth() != ddepth) + hist.convertTo(_hist, ddepth); + else + _hist.getUMatRef() = hist; + + return true; +} + +static bool ocl_calcHist(InputArrayOfArrays images, OutputArray hist) +{ + std::vector v; + images.getUMatVector(v); + + return ocl_calcHist1(v[0], hist, CV_32F); +} + } void cv::calcHist( const Mat* images, int nimages, const int* channels, @@ -1417,6 +1468,12 @@ void cv::calcHist( InputArrayOfArrays images, const std::vector& channels, const std::vector& ranges, bool accumulate ) { + CV_OCL_RUN(images.total() == 1 && channels.size() == 1 && images.channels(0) == 1 && + channels[0] == 0 && images.isUMatVector() && mask.empty() && !accumulate && + histSize.size() == 1 && histSize[0] == BINS && ranges.size() == 2 && + ranges[0] == 0 && ranges[1] == 256, + ocl_calcHist(images, hist)) + int i, dims = (int)histSize.size(), rsz = (int)ranges.size(), csz = (int)channels.size(); int nimages = (int)images.total(); @@ -3290,47 +3347,13 @@ CV_IMPL void cvEqualizeHist( const CvArr* srcarr, CvArr* dstarr ) namespace cv { -enum -{ - BINS = 256 -}; - -static bool ocl_calcHist(InputArray _src, OutputArray _hist) -{ - int compunits = ocl::Device::getDefault().maxComputeUnits(); - size_t wgs = ocl::Device::getDefault().maxWorkGroupSize(); - - ocl::Kernel k1("calculate_histogram", ocl::imgproc::histogram_oclsrc, - format("-D BINS=%d -D HISTS_COUNT=%d -D WGS=%d", BINS, compunits, wgs)); - if (k1.empty()) - return false; - - _hist.create(1, BINS, CV_32SC1); - UMat src = _src.getUMat(), hist = _hist.getUMat(), ghist(1, BINS * compunits, CV_32SC1); - - k1.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::PtrWriteOnly(ghist), - (int)src.total()); - - size_t globalsize = compunits * wgs; - if (!k1.run(1, &globalsize, &wgs, false)) - return false; - - ocl::Kernel k2("merge_histogram", ocl::imgproc::histogram_oclsrc, - format("-D BINS=%d -D HISTS_COUNT=%d -D WGS=%d", BINS, compunits, (int)wgs)); - if (k2.empty()) - return false; - - k2.args(ocl::KernelArg::PtrReadOnly(ghist), ocl::KernelArg::PtrWriteOnly(hist)); - return k2.run(1, &wgs, &wgs, false); -} - static bool ocl_equalizeHist(InputArray _src, OutputArray _dst) { size_t wgs = std::min(ocl::Device::getDefault().maxWorkGroupSize(), BINS); // calculation of histogram UMat hist; - if (!ocl_calcHist(_src, hist)) + if (!ocl_calcHist1(_src, hist)) return false; UMat lut(1, 256, CV_8UC1); diff --git a/modules/imgproc/test/ocl/test_histogram.cpp b/modules/imgproc/test/ocl/test_histogram.cpp index d6cf6efa16..b0837eeaa2 100644 --- a/modules/imgproc/test/ocl/test_histogram.cpp +++ b/modules/imgproc/test/ocl/test_histogram.cpp @@ -144,11 +144,6 @@ PARAM_TEST_CASE(CalcBackProject, MatDepth, int, bool) scale = randomDouble(0.1, 1); } - - void Near() - { - OCL_EXPECT_MATS_NEAR(dst, 0.0) - } }; //////////////////////////////// CalcBackProject ////////////////////////////////////////////// @@ -162,13 +157,62 @@ OCL_TEST_P(CalcBackProject, Mat) OCL_OFF(cv::calcBackProject(images_roi, channels, hist_roi, dst_roi, ranges, scale)); OCL_ON(cv::calcBackProject(uimages_roi, channels, uhist_roi, udst_roi, ranges, scale)); - Near(); + OCL_EXPECT_MATS_NEAR(dst, 0.0) + } +} + +//////////////////////////////// CalcHist ////////////////////////////////////////////// + +PARAM_TEST_CASE(CalcHist, bool) +{ + bool useRoi; + + TEST_DECLARE_INPUT_PARAMETER(src) + TEST_DECLARE_OUTPUT_PARAMETER(hist) + + virtual void SetUp() + { + useRoi = GET_PARAM(0); + } + + virtual void random_roi() + { + Size roiSize = randomSize(1, MAX_VALUE); + + Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(src, src_roi, roiSize, srcBorder, CV_8UC1, 0, 256); + + Border histBorder = randomBorder(0, useRoi ? MAX_VALUE : 0); + randomSubMat(hist, hist_roi, Size(1, 256), histBorder, CV_32SC1, 0, MAX_VALUE); + + UMAT_UPLOAD_INPUT_PARAMETER(src) + UMAT_UPLOAD_OUTPUT_PARAMETER(hist) + } +}; + +OCL_TEST_P(CalcHist, Mat) +{ + const std::vector channels(1, 0); + std::vector ranges(2); + std::vector histSize(1, 256); + ranges[0] = 0; + ranges[1] = 256; + + for (int j = 0; j < test_loop_times; j++) + { + random_roi(); + + OCL_OFF(cv::calcHist(std::vector(1, src_roi), channels, noArray(), hist_roi, histSize, ranges, false)); + OCL_ON(cv::calcHist(std::vector(1, usrc_roi), channels, noArray(), uhist_roi, histSize, ranges, false)); + + OCL_EXPECT_MATS_NEAR(hist, 0.0) } } ///////////////////////////////////////////////////////////////////////////////////// OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CalcBackProject, Combine(Values((MatDepth)CV_8U), Values(1, 2), Bool())); +OCL_INSTANTIATE_TEST_CASE_P(Imgproc, CalcHist, Values(true, false)); } } // namespace cvtest::ocl From faa6074f3d19a7fb59b5eda937dcd45c0e0c5fce Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Wed, 29 Jan 2014 20:34:37 +0400 Subject: [PATCH 2/3] added performance test --- modules/imgproc/perf/opencl/perf_imgproc.cpp | 40 ++++++++++++++++++++ modules/imgproc/src/histogram.cpp | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/perf/opencl/perf_imgproc.cpp b/modules/imgproc/perf/opencl/perf_imgproc.cpp index 8d4b5c2cd3..7e5a817da5 100644 --- a/modules/imgproc/perf/opencl/perf_imgproc.cpp +++ b/modules/imgproc/perf/opencl/perf_imgproc.cpp @@ -61,6 +61,8 @@ OCL_PERF_TEST_P(EqualizeHistFixture, EqualizeHist, OCL_TEST_SIZES) const Size srcSize = GetParam(); const double eps = 1; + checkDeviceMaxMemoryAllocSize(srcSize, CV_8UC1); + UMat src(srcSize, CV_8UC1), dst(srcSize, CV_8UC1); declare.in(src, WARMUP_RNG).out(dst); @@ -69,6 +71,30 @@ OCL_PERF_TEST_P(EqualizeHistFixture, EqualizeHist, OCL_TEST_SIZES) SANITY_CHECK(dst, eps); } +///////////// calcHist //////////////////////// + +typedef TestBaseWithParam CalcHistFixture; + +OCL_PERF_TEST_P(CalcHistFixture, CalcHist, OCL_TEST_SIZES) +{ + const Size srcSize = GetParam(); + + const std::vector channels(1, 0); + std::vector ranges(2); + std::vector histSize(1, 256); + ranges[0] = 0; + ranges[1] = 256; + + checkDeviceMaxMemoryAllocSize(srcSize, CV_8UC1); + + UMat src(srcSize, CV_8UC1), hist(256, 1, CV_32FC1); + declare.in(src, WARMUP_RNG).out(hist); + + OCL_TEST_CYCLE() cv::calcHist(std::vector(1, src), channels, noArray(), hist, histSize, ranges, false); + + SANITY_CHECK(hist); +} + /////////// CopyMakeBorder ////////////////////// CV_ENUM(Border, BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT, BORDER_WRAP, BORDER_REFLECT_101) @@ -83,6 +109,8 @@ OCL_PERF_TEST_P(CopyMakeBorderFixture, CopyMakeBorder, const Size srcSize = get<0>(params); const int type = get<1>(params), borderType = get<2>(params); + checkDeviceMaxMemoryAllocSize(srcSize, type); + UMat src(srcSize, type), dst; const Size dstSize = srcSize + Size(12, 12); dst.create(dstSize, type); @@ -105,6 +133,8 @@ OCL_PERF_TEST_P(CornerMinEigenValFixture, CornerMinEigenVal, const int type = get<1>(params), borderType = BORDER_REFLECT; const int blockSize = 7, apertureSize = 1 + 2 * 3; + checkDeviceMaxMemoryAllocSize(srcSize, type); + UMat src(srcSize, type), dst(srcSize, CV_32FC1); declare.in(src, WARMUP_RNG).out(dst); @@ -124,6 +154,8 @@ OCL_PERF_TEST_P(CornerHarrisFixture, CornerHarris, const Size srcSize = get<0>(params); const int type = get<1>(params), borderType = BORDER_REFLECT; + checkDeviceMaxMemoryAllocSize(srcSize, type); + UMat src(srcSize, type), dst(srcSize, CV_32FC1); declare.in(src, WARMUP_RNG).out(dst); @@ -143,6 +175,8 @@ OCL_PERF_TEST_P(PreCornerDetectFixture, PreCornerDetect, const Size srcSize = get<0>(params); const int type = get<1>(params), borderType = BORDER_REFLECT; + checkDeviceMaxMemoryAllocSize(srcSize, type); + UMat src(srcSize, type), dst(srcSize, CV_32FC1); declare.in(src, WARMUP_RNG).out(dst); @@ -162,6 +196,8 @@ OCL_PERF_TEST_P(IntegralFixture, Integral1, ::testing::Combine(OCL_TEST_SIZES, O const Size srcSize = get<0>(params); const int ddepth = get<1>(params); + checkDeviceMaxMemoryAllocSize(srcSize, ddepth); + UMat src(srcSize, CV_8UC1), dst(srcSize + Size(1, 1), ddepth); declare.in(src, WARMUP_RNG).out(dst); @@ -186,6 +222,8 @@ OCL_PERF_TEST_P(ThreshFixture, Threshold, const int threshType = get<2>(params); const double maxValue = 220.0, threshold = 50; + checkDeviceMaxMemoryAllocSize(srcSize, srcType); + UMat src(srcSize, srcType), dst(srcSize, srcType); declare.in(src, WARMUP_RNG).out(dst); @@ -202,6 +240,8 @@ OCL_PERF_TEST_P(CLAHEFixture, CLAHE, OCL_TEST_SIZES) { const Size srcSize = GetParam(); + checkDeviceMaxMemoryAllocSize(srcSize, CV_8UC1); + UMat src(srcSize, CV_8UC1), dst(srcSize, CV_8UC1); const double clipLimit = 40.0; declare.in(src, WARMUP_RNG).out(dst); diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp index 1a91119b9a..e5b5cc76b7 100644 --- a/modules/imgproc/src/histogram.cpp +++ b/modules/imgproc/src/histogram.cpp @@ -1414,7 +1414,7 @@ static bool ocl_calcHist1(InputArrayOfArrays _src, OutputArray _hist, int ddepth if (k1.empty()) return false; - _hist.create(1, BINS, ddepth); + _hist.create(BINS, 1, ddepth); UMat src = _src.getUMat(), ghist(1, BINS * compunits, CV_32SC1), hist = ddepth == CV_32S ? _hist.getUMat() : UMat(BINS, 1, CV_32SC1); From 231bc17de79b773b001dc6dbf08e7ee533872c0b Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Wed, 29 Jan 2014 23:00:33 +0400 Subject: [PATCH 3/3] added conditional compilation --- modules/imgproc/src/histogram.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp index e5b5cc76b7..6fc23d2ce9 100644 --- a/modules/imgproc/src/histogram.cpp +++ b/modules/imgproc/src/histogram.cpp @@ -1399,12 +1399,14 @@ static void calcHist( const Mat* images, int nimages, const int* channels, } } +#ifdef HAVE_OPENCL + enum { BINS = 256 }; -static bool ocl_calcHist1(InputArrayOfArrays _src, OutputArray _hist, int ddepth = CV_32S) +static bool ocl_calcHist1(InputArray _src, OutputArray _hist, int ddepth = CV_32S) { int compunits = ocl::Device::getDefault().maxComputeUnits(); size_t wgs = ocl::Device::getDefault().maxWorkGroupSize(); @@ -1450,6 +1452,8 @@ static bool ocl_calcHist(InputArrayOfArrays images, OutputArray hist) return ocl_calcHist1(v[0], hist, CV_32F); } +#endif + } void cv::calcHist( const Mat* images, int nimages, const int* channels,