Path: blob/master/modules/imgproc/test/test_distancetransform.cpp
16344 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// Intel License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000, Intel Corporation, all rights reserved.13// Third party copyrights are property of their respective owners.14//15// Redistribution and use in source and binary forms, with or without modification,16// are permitted provided that the following conditions are met:17//18// * Redistribution's of source code must retain the above copyright notice,19// this list of conditions and the following disclaimer.20//21// * Redistribution's in binary form must reproduce the above copyright notice,22// this list of conditions and the following disclaimer in the documentation23// and/or other materials provided with the distribution.24//25// * The name of Intel Corporation may not be used to endorse or promote products26// derived from this software without specific prior written permission.27//28// This software is provided by the copyright holders and contributors "as is" and29// any express or implied warranties, including, but not limited to, the implied30// warranties of merchantability and fitness for a particular purpose are disclaimed.31// In no event shall the Intel Corporation or contributors be liable for any direct,32// indirect, incidental, special, exemplary, or consequential damages33// (including, but not limited to, procurement of substitute goods or services;34// loss of use, data, or profits; or business interruption) however caused35// and on any theory of liability, whether in contract, strict liability,36// or tort (including negligence or otherwise) arising in any way out of37// the use of this software, even if advised of the possibility of such damage.38//39//M*/4041#include "test_precomp.hpp"4243namespace opencv_test { namespace {4445class CV_DisTransTest : public cvtest::ArrayTest46{47public:48CV_DisTransTest();4950protected:51void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );52double get_success_error_level( int test_case_idx, int i, int j );53void run_func();54void prepare_to_validation( int );5556void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );57int prepare_test_case( int test_case_idx );5859int mask_size;60int dist_type;61int fill_labels;62float mask[3];63};646566CV_DisTransTest::CV_DisTransTest()67{68test_array[INPUT].push_back(NULL);69test_array[OUTPUT].push_back(NULL);70test_array[OUTPUT].push_back(NULL);71test_array[REF_OUTPUT].push_back(NULL);72test_array[REF_OUTPUT].push_back(NULL);73optional_mask = false;74element_wise_relative_error = true;75}767778void CV_DisTransTest::get_test_array_types_and_sizes( int test_case_idx,79vector<vector<Size> >& sizes, vector<vector<int> >& types )80{81RNG& rng = ts->get_rng();82cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );8384types[INPUT][0] = CV_8UC1;85types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1;86types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32SC1;8788if( cvtest::randInt(rng) & 1 )89{90mask_size = 3;91}92else93{94mask_size = 5;95}9697dist_type = cvtest::randInt(rng) % 3;98dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 : CV_DIST_L2;99100// for now, check only the "labeled" distance transform mode101fill_labels = 0;102103if( !fill_labels )104sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(0,0);105}106107108double CV_DisTransTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )109{110Size sz = test_mat[INPUT][0].size();111return dist_type == CV_DIST_C || dist_type == CV_DIST_L1 ? 0 : 0.01*MAX(sz.width, sz.height);112}113114115void CV_DisTransTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )116{117cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );118if( i == INPUT && CV_MAT_DEPTH(type) == CV_8U )119{120low = Scalar::all(0);121high = Scalar::all(10);122}123}124125int CV_DisTransTest::prepare_test_case( int test_case_idx )126{127int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );128if( code > 0 )129{130// the function's response to an "all-nonzeros" image is not determined,131// so put at least one zero point132Mat& mat = test_mat[INPUT][0];133RNG& rng = ts->get_rng();134int i = cvtest::randInt(rng) % mat.rows;135int j = cvtest::randInt(rng) % mat.cols;136mat.at<uchar>(i,j) = 0;137}138139return code;140}141142143void CV_DisTransTest::run_func()144{145cvDistTransform( test_array[INPUT][0], test_array[OUTPUT][0], dist_type, mask_size,146dist_type == CV_DIST_USER ? mask : 0, test_array[OUTPUT][1] );147}148149150static void151cvTsDistTransform( const CvMat* _src, CvMat* _dst, int dist_type,152int mask_size, float* _mask, CvMat* /*_labels*/ )153{154int i, j, k;155int width = _src->cols, height = _src->rows;156const float init_val = 1e6;157float mask[3];158CvMat* temp;159int ofs[16] = {0};160float delta[16];161int tstep, count;162163assert( mask_size == 3 || mask_size == 5 );164165if( dist_type == CV_DIST_USER )166memcpy( mask, _mask, sizeof(mask) );167else if( dist_type == CV_DIST_C )168{169mask_size = 3;170mask[0] = mask[1] = 1.f;171}172else if( dist_type == CV_DIST_L1 )173{174mask_size = 3;175mask[0] = 1.f;176mask[1] = 2.f;177}178else if( mask_size == 3 )179{180mask[0] = 0.955f;181mask[1] = 1.3693f;182}183else184{185mask[0] = 1.0f;186mask[1] = 1.4f;187mask[2] = 2.1969f;188}189190temp = cvCreateMat( height + mask_size-1, width + mask_size-1, CV_32F );191tstep = temp->step / sizeof(float);192193if( mask_size == 3 )194{195count = 4;196ofs[0] = -1; delta[0] = mask[0];197ofs[1] = -tstep-1; delta[1] = mask[1];198ofs[2] = -tstep; delta[2] = mask[0];199ofs[3] = -tstep+1; delta[3] = mask[1];200}201else202{203count = 8;204ofs[0] = -1; delta[0] = mask[0];205ofs[1] = -tstep-2; delta[1] = mask[2];206ofs[2] = -tstep-1; delta[2] = mask[1];207ofs[3] = -tstep; delta[3] = mask[0];208ofs[4] = -tstep+1; delta[4] = mask[1];209ofs[5] = -tstep+2; delta[5] = mask[2];210ofs[6] = -tstep*2-1; delta[6] = mask[2];211ofs[7] = -tstep*2+1; delta[7] = mask[2];212}213214for( i = 0; i < mask_size/2; i++ )215{216float* t0 = (float*)(temp->data.ptr + i*temp->step);217float* t1 = (float*)(temp->data.ptr + (temp->rows - i - 1)*temp->step);218219for( j = 0; j < width + mask_size - 1; j++ )220t0[j] = t1[j] = init_val;221}222223for( i = 0; i < height; i++ )224{225uchar* s = _src->data.ptr + i*_src->step;226float* tmp = (float*)(temp->data.ptr + temp->step*(i + (mask_size/2))) + (mask_size/2);227228for( j = 0; j < mask_size/2; j++ )229tmp[-j-1] = tmp[j + width] = init_val;230231for( j = 0; j < width; j++ )232{233if( s[j] == 0 )234tmp[j] = 0;235else236{237float min_dist = init_val;238for( k = 0; k < count; k++ )239{240float t = tmp[j+ofs[k]] + delta[k];241if( min_dist > t )242min_dist = t;243}244tmp[j] = min_dist;245}246}247}248249for( i = height - 1; i >= 0; i-- )250{251float* d = (float*)(_dst->data.ptr + i*_dst->step);252float* tmp = (float*)(temp->data.ptr + temp->step*(i + (mask_size/2))) + (mask_size/2);253254for( j = width - 1; j >= 0; j-- )255{256float min_dist = tmp[j];257if( min_dist > mask[0] )258{259for( k = 0; k < count; k++ )260{261float t = tmp[j-ofs[k]] + delta[k];262if( min_dist > t )263min_dist = t;264}265tmp[j] = min_dist;266}267d[j] = min_dist;268}269}270271cvReleaseMat( &temp );272}273274275void CV_DisTransTest::prepare_to_validation( int /*test_case_idx*/ )276{277CvMat _input = cvMat(test_mat[INPUT][0]), _output = cvMat(test_mat[REF_OUTPUT][0]);278279cvTsDistTransform( &_input, &_output, dist_type, mask_size, mask, 0 );280}281282283TEST(Imgproc_DistanceTransform, accuracy) { CV_DisTransTest test; test.safe_run(); }284285BIGDATA_TEST(Imgproc_DistanceTransform, large_image_12218)286{287const int lls_maxcnt = 79992000; // labels's maximum count288const int lls_mincnt = 1; // labels's minimum count289int i, j, nz;290Mat src(8000, 20000, CV_8UC1), dst, labels;291for( i = 0; i < src.rows; i++ )292for( j = 0; j < src.cols; j++ )293src.at<uchar>(i, j) = (j > (src.cols / 2)) ? 0 : 255;294295distanceTransform(src, dst, labels, cv::DIST_L2, cv::DIST_MASK_3, DIST_LABEL_PIXEL);296297double scale = (double)lls_mincnt / (double)lls_maxcnt;298labels.convertTo(labels, CV_32SC1, scale);299Size size = labels.size();300nz = cv::countNonZero(labels);301EXPECT_EQ(nz, (size.height*size.width / 2));302}303304}} // namespace305306307