diff --git a/doc/gpu_matrix_reductions.tex b/doc/gpu_matrix_reductions.tex index fd7867329..70b5c5f35 100644 --- a/doc/gpu_matrix_reductions.tex +++ b/doc/gpu_matrix_reductions.tex @@ -19,7 +19,7 @@ Returns norm of matrix (or of two matrices difference). \cvdefCpp{double norm(const GpuMat\& src1, int normType=NORM\_L2);} \begin{description} -\cvarg{src1}{Source matrix. \texttt{CV\_8UC1} matrices are supported for now.} +\cvarg{src1}{Source matrix. Any matrices except 64F are supported.} \cvarg{normType}{Norm type. \texttt{NORM\_L1}, \texttt{NORM\_L2} and \texttt{NORM\_INF} are supported for now.} \end{description} diff --git a/modules/gpu/src/matrix_reductions.cpp b/modules/gpu/src/matrix_reductions.cpp index 0c83271a6..3ef13f6e2 100644 --- a/modules/gpu/src/matrix_reductions.cpp +++ b/modules/gpu/src/matrix_reductions.cpp @@ -86,9 +86,25 @@ void cv::gpu::meanStdDev(const GpuMat& src, Scalar& mean, Scalar& stddev) //////////////////////////////////////////////////////////////////////// // norm -double cv::gpu::norm(const GpuMat& src1, int normType) +double cv::gpu::norm(const GpuMat& src, int normType) { - return norm(src1, GpuMat(src1.size(), src1.type(), Scalar::all(0.0)), normType); + GpuMat src_single_channel = src.reshape(1); + + if (normType == NORM_L1) + return absSum(src_single_channel)[0]; + + if (normType == NORM_L2) + return sqrt(sqrSum(src_single_channel)[0]); + + if (normType == NORM_INF) + { + double min_val, max_val; + minMax(src_single_channel, &min_val, &max_val); + return std::max(std::abs(min_val), std::abs(max_val)); + } + + CV_Error(CV_StsBadArg, "norm: unsupported norm type"); + return 0; } double cv::gpu::norm(const GpuMat& src1, const GpuMat& src2, int normType) diff --git a/tests/gpu/src/imgproc_gpu.cpp b/tests/gpu/src/imgproc_gpu.cpp index d941a00c4..1de3bd65d 100644 --- a/tests/gpu/src/imgproc_gpu.cpp +++ b/tests/gpu/src/imgproc_gpu.cpp @@ -825,6 +825,77 @@ struct CV_GpuColumnSumTest: CvTest } }; +struct CV_GpuNormTest : CvTest +{ + CV_GpuNormTest() : CvTest("GPU-Norm", "norm") {} + + void run(int) + { + try + { + RNG rng(0); + + int rows = rng.uniform(1, 500); + int cols = rng.uniform(1, 500); + + for (int cn = 1; cn <= 4; ++cn) + { + test(NORM_L1, rows, cols, CV_8U, cn, Scalar::all(0), Scalar::all(10)); + test(NORM_L1, rows, cols, CV_8S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_L1, rows, cols, CV_16U, cn, Scalar::all(0), Scalar::all(10)); + test(NORM_L1, rows, cols, CV_16S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_L1, rows, cols, CV_32S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_L1, rows, cols, CV_32F, cn, Scalar::all(0), Scalar::all(1)); + + test(NORM_L2, rows, cols, CV_8U, cn, Scalar::all(0), Scalar::all(10)); + test(NORM_L2, rows, cols, CV_8S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_L2, rows, cols, CV_16U, cn, Scalar::all(0), Scalar::all(10)); + test(NORM_L2, rows, cols, CV_16S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_L2, rows, cols, CV_32S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_L2, rows, cols, CV_32F, cn, Scalar::all(0), Scalar::all(1)); + + test(NORM_INF, rows, cols, CV_8U, cn, Scalar::all(0), Scalar::all(10)); + test(NORM_INF, rows, cols, CV_8S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_INF, rows, cols, CV_16U, cn, Scalar::all(0), Scalar::all(10)); + test(NORM_INF, rows, cols, CV_16S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_INF, rows, cols, CV_32S, cn, Scalar::all(-10), Scalar::all(10)); + test(NORM_INF, rows, cols, CV_32F, cn, Scalar::all(0), Scalar::all(1)); + } + } + catch (const cv::Exception& e) + { + ts->printf(CvTS::CONSOLE, e.what()); + if (!check_and_treat_gpu_exception(e, ts)) throw; + return; + } + } + + void gen(Mat& mat, int rows, int cols, int type, Scalar low, Scalar high) + { + mat.create(rows, cols, type); + RNG rng(0); + rng.fill(mat, RNG::UNIFORM, low, high); + } + + void test(int norm_type, int rows, int cols, int depth, int cn, Scalar low, Scalar high) + { + int type = CV_MAKE_TYPE(depth, cn); + + Mat src; + gen(src, rows, cols, type, low, high); + + double gold = norm(src, norm_type); + double mine = norm(GpuMat(src), norm_type); + + if (abs(gold - mine) > 1e-3) + { + ts->printf(CvTS::CONSOLE, "failed test: gold=%f, mine=%f, norm_type=%d, rows=%d, " + "cols=%d, depth=%d, cn=%d\n", gold, mine, norm_type, rows, cols, depth, cn); + ts->set_failed_test_info(CvTS::FAIL_INVALID_OUTPUT); + } + } +}; + ///////////////////////////////////////////////////////////////////////////// /////////////////// tests registration ///////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// @@ -845,4 +916,4 @@ CV_GpuHistogramsTest CV_GpuHistograms_test; CV_GpuCornerHarrisTest CV_GpuCornerHarris_test; CV_GpuCornerMinEigenValTest CV_GpuCornerMinEigenVal_test; CV_GpuColumnSumTest CV_GpuColumnSum_test; - +CV_GpuNormTest CV_GpuNormTest_test;