From dc763e0250b94f6bccaa0873369aee361ae33a37 Mon Sep 17 00:00:00 2001 From: Alexey Spizhevoy Date: Tue, 11 Jan 2011 09:36:21 +0000 Subject: [PATCH] updated normalization routine in the matchTemplate to avoid division by zero on black images (ticket #798), added test --- modules/gpu/include/opencv2/gpu/gpu.hpp | 3 +- modules/gpu/src/cuda/match_template.cu | 10 +-- tests/gpu/src/match_template.cpp | 124 ++++++++++++++++---------------- 3 files changed, 71 insertions(+), 66 deletions(-) diff --git a/modules/gpu/include/opencv2/gpu/gpu.hpp b/modules/gpu/include/opencv2/gpu/gpu.hpp index b7e85a3..957299b 100644 --- a/modules/gpu/include/opencv2/gpu/gpu.hpp +++ b/modules/gpu/include/opencv2/gpu/gpu.hpp @@ -1180,7 +1180,6 @@ namespace cv size_t getBlockHistogramSize() const; void setSVMDetector(const vector& detector); - bool checkDetectorSize() const; static vector getDefaultPeopleDetector(); static vector getPeopleDetector_48x96(); @@ -1212,7 +1211,9 @@ namespace cv protected: void computeBlockHistograms(const GpuMat& img); void computeGradient(const GpuMat& img, GpuMat& grad, GpuMat& qangle); + double getWinSigma() const; + bool checkDetectorSize() const; static int numPartsWithin(int size, int part_size, int stride); static Size numPartsWithin(Size size, Size part_size, Size stride); diff --git a/modules/gpu/src/cuda/match_template.cu b/modules/gpu/src/cuda/match_template.cu index 3ac98c8..1765724 100644 --- a/modules/gpu/src/cuda/match_template.cu +++ b/modules/gpu/src/cuda/match_template.cu @@ -560,7 +560,7 @@ __global__ void matchTemplatePreparedKernel_CCOFF_NORMED_8U( (image_sqsum.ptr(y + h)[x + w] - image_sqsum.ptr(y)[x + w]) - (image_sqsum.ptr(y + h)[x] - image_sqsum.ptr(y)[x])); result.ptr(y)[x] = min(1.f, (ccorr - image_sum_ * templ_sum_scale) * - rsqrtf(templ_sqsum_scale * (image_sqsum_ - weight * image_sum_ * image_sum_))); + rsqrtf(templ_sqsum_scale * (image_sqsum_ - weight * image_sum_ * image_sum_ + 1.f))); } } @@ -611,7 +611,7 @@ __global__ void matchTemplatePreparedKernel_CCOFF_NORMED_8UC2( (image_sqsum_g.ptr(y + h)[x] - image_sqsum_g.ptr(y)[x])); float ccorr = result.ptr(y)[x]; float rdenom = rsqrtf(templ_sqsum_scale * (image_sqsum_r_ - weight * image_sum_r_ * image_sum_r_ - + image_sqsum_g_ - weight * image_sum_g_ * image_sum_g_)); + + image_sqsum_g_ - weight * image_sum_g_ * image_sum_g_ + 1.f)); result.ptr(y)[x] = min(1.f, (ccorr - image_sum_r_ * templ_sum_scale_r - image_sum_g_ * templ_sum_scale_g) * rdenom); } @@ -680,7 +680,7 @@ __global__ void matchTemplatePreparedKernel_CCOFF_NORMED_8UC3( float ccorr = result.ptr(y)[x]; float rdenom = rsqrtf(templ_sqsum_scale * (image_sqsum_r_ - weight * image_sum_r_ * image_sum_r_ + image_sqsum_g_ - weight * image_sum_g_ * image_sum_g_ - + image_sqsum_b_ - weight * image_sum_b_ * image_sum_b_)); + + image_sqsum_b_ - weight * image_sum_b_ * image_sum_b_ + 1.f)); result.ptr(y)[x] = min(1.f, (ccorr - image_sum_r_ * templ_sum_scale_r - image_sum_g_ * templ_sum_scale_g - image_sum_b_ * templ_sum_scale_b) * rdenom); @@ -763,7 +763,7 @@ __global__ void matchTemplatePreparedKernel_CCOFF_NORMED_8UC4( float rdenom = rsqrtf(templ_sqsum_scale * (image_sqsum_r_ - weight * image_sum_r_ * image_sum_r_ + image_sqsum_g_ - weight * image_sum_g_ * image_sum_g_ + image_sqsum_b_ - weight * image_sum_b_ * image_sum_b_ - + image_sqsum_a_ - weight * image_sum_a_ * image_sum_a_)); + + image_sqsum_a_ - weight * image_sum_a_ * image_sum_a_ + 1.f)); result.ptr(y)[x] = min(1.f, (ccorr - image_sum_r_ * templ_sum_scale_r - image_sum_g_ * templ_sum_scale_g - image_sum_b_ * templ_sum_scale_b @@ -822,7 +822,7 @@ __global__ void normalizeKernel_8U( float image_sqsum_ = (float)( (image_sqsum.ptr(y + h)[(x + w) * cn] - image_sqsum.ptr(y)[(x + w) * cn]) - (image_sqsum.ptr(y + h)[x * cn] - image_sqsum.ptr(y)[x * cn])); - result.ptr(y)[x] = min(1.f, result.ptr(y)[x] * rsqrtf(image_sqsum_ * templ_sqsum)); + result.ptr(y)[x] = min(1.f, result.ptr(y)[x] * rsqrtf((image_sqsum_ + 1.f) * templ_sqsum)); } } diff --git a/tests/gpu/src/match_template.cpp b/tests/gpu/src/match_template.cpp index e4ccd37..f29d5d7 100644 --- a/tests/gpu/src/match_template.cpp +++ b/tests/gpu/src/match_template.cpp @@ -124,7 +124,7 @@ struct CV_GpuMatchTemplateTest: CvTest F(t = clock();) gpu::matchTemplate(gpu::GpuMat(image), gpu::GpuMat(templ), dst, CV_TM_CCORR_NORMED); F(cout << "gpu_block: " << clock() - t << endl;) - if (!check(dst_gold, Mat(dst), h * w * 1e-5f)) return; + if (!check(dst_gold, Mat(dst), h * w * 1e-4f)) return; gen(image, n, m, CV_8U, cn); gen(templ, h, w, CV_8U, cn); @@ -146,7 +146,7 @@ struct CV_GpuMatchTemplateTest: CvTest F(t = clock();) gpu::matchTemplate(gpu::GpuMat(image), gpu::GpuMat(templ), dst, CV_TM_CCOEFF_NORMED); F(cout << "gpu_block: " << clock() - t << endl;) - if (!check(dst_gold, Mat(dst), h * w * 1e-6f)) return; + if (!check(dst_gold, Mat(dst), h * w * 1e-4f)) return; gen(image, n, m, CV_32F, cn); gen(templ, h, w, CV_32F, cn); @@ -207,66 +207,70 @@ struct CV_GpuMatchTemplateTest: CvTest return false; } - //// Debug check - //for (int i = 0; i < a.rows; ++i) - //{ - // for (int j = 0; j < a.cols; ++j) - // { - // float v1 = a.at(i, j); - // float v2 = b.at(i, j); - // if (fabs(v1 - v2) > max_err) - // { - // ts->printf(CvTS::CONSOLE, "%d %d %f %f\n", i, j, v1, v2); - // cin.get(); - // } - // } - //} - return true; } +} match_template_test; - //void match_template_naive_SQDIFF(const Mat& a, const Mat& b, Mat& c) - //{ - // c.create(a.rows - b.rows + 1, a.cols - b.cols + 1, CV_32F); - // for (int i = 0; i < c.rows; ++i) - // { - // for (int j = 0; j < c.cols; ++j) - // { - // float delta; - // float sum = 0.f; - // for (int y = 0; y < b.rows; ++y) - // { - // const unsigned char* arow = a.ptr(i + y); - // const unsigned char* brow = b.ptr(y); - // for (int x = 0; x < b.cols; ++x) - // { - // delta = (float)(arow[j + x] - brow[x]); - // sum += delta * delta; - // } - // } - // c.at(i, j) = sum; - // } - // } - //} +struct CV_GpuMatchTemplateFindPatternInBlackTest: CvTest +{ + CV_GpuMatchTemplateFindPatternInBlackTest() + : CvTest("GPU-MatchTemplateFindPatternInBlackTest", "matchTemplate") {} - //void match_template_naive_CCORR(const Mat& a, const Mat& b, Mat& c) - //{ - // c.create(a.rows - b.rows + 1, a.cols - b.cols + 1, CV_32F); - // for (int i = 0; i < c.rows; ++i) - // { - // for (int j = 0; j < c.cols; ++j) - // { - // float sum = 0.f; - // for (int y = 0; y < b.rows; ++y) - // { - // const float* arow = a.ptr(i + y); - // const float* brow = b.ptr(y); - // for (int x = 0; x < b.cols; ++x) - // sum += arow[j + x] * brow[x]; - // } - // c.at(i, j) = sum; - // } - // } - //} -} match_template_test; + void run(int) + { + try + { + Mat image = imread(std::string(ts->get_data_path()) + "matchtemplate/black.jpg"); + if (image.empty()) + { + ts->printf(CvTS::CONSOLE, "can't open file '%s'", (std::string(ts->get_data_path()) + + "matchtemplate/black.jpg").c_str()); + ts->set_failed_test_info(CvTS::FAIL_INVALID_TEST_DATA); + return; + } + + Mat pattern = imread(std::string(ts->get_data_path()) + "matchtemplate/cat.jpg"); + if (pattern.empty()) + { + ts->printf(CvTS::CONSOLE, "can't open file '%s'", (std::string(ts->get_data_path()) + + "matchtemplate/cat.jpg").c_str()); + ts->set_failed_test_info(CvTS::FAIL_INVALID_TEST_DATA); + return; + } + + gpu::GpuMat d_image(image); + gpu::GpuMat d_pattern(pattern); + gpu::GpuMat d_result; + double maxValue; + Point maxLoc; + Point maxLocGold(284, 12); + + gpu::matchTemplate(d_image, d_pattern, d_result, CV_TM_CCOEFF_NORMED); + gpu::minMaxLoc(d_result, NULL, &maxValue, NULL, &maxLoc ); + if (maxLoc != maxLocGold) + { + ts->printf(CvTS::CONSOLE, "bad match (CV_TM_CCOEFF_NORMED): %d %d, must be at: %d %d", + maxLoc.x, maxLoc.y, maxLocGold.x, maxLocGold.y); + ts->set_failed_test_info(CvTS::FAIL_INVALID_OUTPUT); + return; + } + + gpu::matchTemplate(d_image, d_pattern, d_result, CV_TM_CCORR_NORMED); + gpu::minMaxLoc(d_result, NULL, &maxValue, NULL, &maxLoc ); + if (maxLoc != maxLocGold) + { + ts->printf(CvTS::CONSOLE, "bad match (CV_TM_CCORR_NORMED): %d %d, must be at: %d %d", + maxLoc.x, maxLoc.y, maxLocGold.x, maxLocGold.y); + ts->set_failed_test_info(CvTS::FAIL_INVALID_OUTPUT); + return; + } + } + catch (const Exception& e) + { + ts->printf(CvTS::CONSOLE, e.what()); + if (!check_and_treat_gpu_exception(e, ts)) throw; + return; + } + } +} match_templet_find_bordered_pattern_test; \ No newline at end of file -- 2.7.4