Path: blob/master/modules/imgproc/test/test_floodfill.cpp
16339 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_FloodFillTest : public cvtest::ArrayTest46{47public:48CV_FloodFillTest();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 fill_array( int test_case_idx, int i, int j, Mat& arr );5758/*int write_default_params(CvFileStorage* fs);59void get_timing_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types60CvSize** whole_sizes, bool *are_images );61void print_timing_params( int test_case_idx, char* ptr, int params_left );*/62Point seed_pt;63Scalar new_val;64Scalar l_diff, u_diff;65int connectivity;66bool use_mask, mask_only;67int range_type;68int new_mask_val;69bool test_cpp;70};717273CV_FloodFillTest::CV_FloodFillTest()74{75test_array[INPUT_OUTPUT].push_back(NULL);76test_array[INPUT_OUTPUT].push_back(NULL);77test_array[REF_INPUT_OUTPUT].push_back(NULL);78test_array[REF_INPUT_OUTPUT].push_back(NULL);79test_array[OUTPUT].push_back(NULL);80test_array[REF_OUTPUT].push_back(NULL);81optional_mask = false;82element_wise_relative_error = true;8384test_cpp = false;85}868788void CV_FloodFillTest::get_test_array_types_and_sizes( int test_case_idx,89vector<vector<Size> >& sizes,90vector<vector<int> >& types )91{92RNG& rng = ts->get_rng();93int depth, cn;94int i;95double buff[8];96cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );9798depth = cvtest::randInt(rng) % 3;99depth = depth == 0 ? CV_8U : depth == 1 ? CV_32S : CV_32F;100cn = cvtest::randInt(rng) & 1 ? 3 : 1;101102use_mask = (cvtest::randInt(rng) & 1) != 0;103connectivity = (cvtest::randInt(rng) & 1) ? 4 : 8;104mask_only = use_mask && (cvtest::randInt(rng) & 1) != 0;105new_mask_val = cvtest::randInt(rng) & 255;106range_type = cvtest::randInt(rng) % 3;107108types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn);109types[INPUT_OUTPUT][1] = types[REF_INPUT_OUTPUT][1] = CV_8UC1;110types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;111sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(9,1);112113if( !use_mask )114sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(0,0);115else116{117Size sz = sizes[INPUT_OUTPUT][0];118sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = Size(sz.width+2,sz.height+2);119}120121seed_pt.x = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].width;122seed_pt.y = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].height;123124if( range_type == 0 )125l_diff = u_diff = Scalar::all(0.);126else127{128Mat m( 1, 8, CV_16S, buff );129rng.fill( m, RNG::NORMAL, Scalar::all(0), Scalar::all(32) );130for( i = 0; i < 4; i++ )131{132l_diff.val[i] = fabs(m.at<short>(i)/16.);133u_diff.val[i] = fabs(m.at<short>(i+4)/16.);134}135}136137new_val = Scalar::all(0.);138for( i = 0; i < cn; i++ )139new_val.val[i] = cvtest::randReal(rng)*255;140141test_cpp = (cvtest::randInt(rng) & 256) == 0;142}143144145double CV_FloodFillTest::get_success_error_level( int /*test_case_idx*/, int i, int j )146{147return i == OUTPUT ? FLT_EPSILON : j == 0 ? FLT_EPSILON : 0;148}149150151void CV_FloodFillTest::fill_array( int test_case_idx, int i, int j, Mat& arr )152{153RNG& rng = ts->get_rng();154155if( i != INPUT && i != INPUT_OUTPUT )156{157cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );158return;159}160161if( j == 0 )162{163Mat tmp = arr;164Scalar m = Scalar::all(128);165Scalar s = Scalar::all(10);166167if( arr.depth() == CV_32FC1 )168tmp.create(arr.size(), CV_MAKETYPE(CV_8U, arr.channels()));169170if( range_type == 0 )171s = Scalar::all(2);172173rng.fill(tmp, RNG::NORMAL, m, s );174if( arr.data != tmp.data )175cvtest::convert(tmp, arr, arr.type());176}177else178{179Scalar l = Scalar::all(-2);180Scalar u = Scalar::all(2);181cvtest::randUni(rng, arr, l, u );182rectangle( arr, Point(0,0), Point(arr.cols-1,arr.rows-1), Scalar::all(1), 1, 8, 0 );183}184}185186187void CV_FloodFillTest::run_func()188{189int flags = connectivity + (mask_only ? CV_FLOODFILL_MASK_ONLY : 0) +190(range_type == 1 ? CV_FLOODFILL_FIXED_RANGE : 0) + (new_mask_val << 8);191double* odata = test_mat[OUTPUT][0].ptr<double>();192193if(!test_cpp)194{195CvConnectedComp comp;196cvFloodFill( test_array[INPUT_OUTPUT][0], cvPoint(seed_pt), cvScalar(new_val), cvScalar(l_diff), cvScalar(u_diff), &comp,197flags, test_array[INPUT_OUTPUT][1] );198odata[0] = comp.area;199odata[1] = comp.rect.x;200odata[2] = comp.rect.y;201odata[3] = comp.rect.width;202odata[4] = comp.rect.height;203odata[5] = comp.value.val[0];204odata[6] = comp.value.val[1];205odata[7] = comp.value.val[2];206odata[8] = comp.value.val[3];207}208else209{210cv::Mat img = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]),211mask = test_array[INPUT_OUTPUT][1] ? cv::cvarrToMat(test_array[INPUT_OUTPUT][1]) : cv::Mat();212cv::Rect rect;213int area;214if( mask.empty() )215area = cv::floodFill( img, seed_pt, new_val, &rect, l_diff, u_diff, flags );216else217area = cv::floodFill( img, mask, seed_pt, new_val, &rect, l_diff, u_diff, flags );218odata[0] = area;219odata[1] = rect.x;220odata[2] = rect.y;221odata[3] = rect.width;222odata[4] = rect.height;223odata[5] = odata[6] = odata[7] = odata[8] = 0;224}225}226227228typedef struct ff_offset_pair_t229{230int mofs, iofs;231}232ff_offset_pair_t;233234static void235cvTsFloodFill( CvMat* _img, CvPoint seed_pt, CvScalar new_val,236CvScalar l_diff, CvScalar u_diff, CvMat* _mask,237double* comp, int connectivity, int range_type,238int new_mask_val, bool mask_only )239{240CvMemStorage* st = cvCreateMemStorage();241ff_offset_pair_t p0, p;242CvSeq* seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(p0), st );243CvMat* tmp = _img;244CvMat* mask;245CvRect r = cvRect( 0, 0, -1, -1 );246int area = 0;247int i, j;248ushort* m;249float* img;250int mstep, step;251int cn = CV_MAT_CN(_img->type);252int mdelta[8], idelta[8], ncount;253int cols = _img->cols, rows = _img->rows;254int u0 = 0, u1 = 0, u2 = 0;255double s0 = 0, s1 = 0, s2 = 0;256257if( CV_MAT_DEPTH(_img->type) == CV_8U || CV_MAT_DEPTH(_img->type) == CV_32S )258{259tmp = cvCreateMat( rows, cols, CV_MAKETYPE(CV_32F,CV_MAT_CN(_img->type)) );260cvtest::convert(cvarrToMat(_img), cvarrToMat(tmp), -1);261}262263mask = cvCreateMat( rows + 2, cols + 2, CV_16UC1 );264265if( _mask )266cvtest::convert(cvarrToMat(_mask), cvarrToMat(mask), -1);267else268{269Mat m_mask = cvarrToMat(mask);270cvtest::set( m_mask, Scalar::all(0), Mat() );271cvRectangle( mask, cvPoint(0,0), cvPoint(mask->cols-1,mask->rows-1), cvScalar(Scalar::all(1.)), 1, 8, 0 );272}273274new_mask_val = (new_mask_val != 0 ? new_mask_val : 1) << 8;275276m = (ushort*)(mask->data.ptr + mask->step) + 1;277mstep = mask->step / sizeof(m[0]);278img = tmp->data.fl;279step = tmp->step / sizeof(img[0]);280281p0.mofs = seed_pt.y*mstep + seed_pt.x;282p0.iofs = seed_pt.y*step + seed_pt.x*cn;283284if( m[p0.mofs] )285goto _exit_;286287cvSeqPush( seq, &p0 );288m[p0.mofs] = (ushort)new_mask_val;289290if( connectivity == 4 )291{292ncount = 4;293mdelta[0] = -mstep; idelta[0] = -step;294mdelta[1] = -1; idelta[1] = -cn;295mdelta[2] = 1; idelta[2] = cn;296mdelta[3] = mstep; idelta[3] = step;297}298else299{300ncount = 8;301mdelta[0] = -mstep-1; mdelta[1] = -mstep; mdelta[2] = -mstep+1;302idelta[0] = -step-cn; idelta[1] = -step; idelta[2] = -step+cn;303304mdelta[3] = -1; mdelta[4] = 1;305idelta[3] = -cn; idelta[4] = cn;306307mdelta[5] = mstep-1; mdelta[6] = mstep; mdelta[7] = mstep+1;308idelta[5] = step-cn; idelta[6] = step; idelta[7] = step+cn;309}310311if( cn == 1 )312{313float a0 = (float)-l_diff.val[0];314float b0 = (float)u_diff.val[0];315316s0 = img[p0.iofs];317318if( range_type < 2 )319{320a0 += (float)s0; b0 += (float)s0;321}322323while( seq->total )324{325cvSeqPop( seq, &p0 );326float a = a0, b = b0;327float* ptr = img + p0.iofs;328ushort* mptr = m + p0.mofs;329330if( range_type == 2 )331a += ptr[0], b += ptr[0];332333for( i = 0; i < ncount; i++ )334{335int md = mdelta[i], id = idelta[i];336float v;337if( !mptr[md] && a <= (v = ptr[id]) && v <= b )338{339mptr[md] = (ushort)new_mask_val;340p.mofs = p0.mofs + md;341p.iofs = p0.iofs + id;342cvSeqPush( seq, &p );343}344}345}346}347else348{349float a0 = (float)-l_diff.val[0];350float a1 = (float)-l_diff.val[1];351float a2 = (float)-l_diff.val[2];352float b0 = (float)u_diff.val[0];353float b1 = (float)u_diff.val[1];354float b2 = (float)u_diff.val[2];355356s0 = img[p0.iofs];357s1 = img[p0.iofs + 1];358s2 = img[p0.iofs + 2];359360if( range_type < 2 )361{362a0 += (float)s0; b0 += (float)s0;363a1 += (float)s1; b1 += (float)s1;364a2 += (float)s2; b2 += (float)s2;365}366367while( seq->total )368{369cvSeqPop( seq, &p0 );370float _a0 = a0, _a1 = a1, _a2 = a2;371float _b0 = b0, _b1 = b1, _b2 = b2;372float* ptr = img + p0.iofs;373ushort* mptr = m + p0.mofs;374375if( range_type == 2 )376{377_a0 += ptr[0]; _b0 += ptr[0];378_a1 += ptr[1]; _b1 += ptr[1];379_a2 += ptr[2]; _b2 += ptr[2];380}381382for( i = 0; i < ncount; i++ )383{384int md = mdelta[i], id = idelta[i];385float v;386if( !mptr[md] &&387_a0 <= (v = ptr[id]) && v <= _b0 &&388_a1 <= (v = ptr[id+1]) && v <= _b1 &&389_a2 <= (v = ptr[id+2]) && v <= _b2 )390{391mptr[md] = (ushort)new_mask_val;392p.mofs = p0.mofs + md;393p.iofs = p0.iofs + id;394cvSeqPush( seq, &p );395}396}397}398}399400r.x = r.width = seed_pt.x;401r.y = r.height = seed_pt.y;402403if( !mask_only )404{405s0 = new_val.val[0];406s1 = new_val.val[1];407s2 = new_val.val[2];408409if( tmp != _img )410{411u0 = saturate_cast<uchar>(s0);412u1 = saturate_cast<uchar>(s1);413u2 = saturate_cast<uchar>(s2);414415s0 = u0;416s1 = u1;417s2 = u2;418}419}420else421s0 = s1 = s2 = 0;422423new_mask_val >>= 8;424425for( i = 0; i < rows; i++ )426{427float* ptr = img + i*step;428ushort* mptr = m + i*mstep;429uchar* dmptr = _mask ? _mask->data.ptr + (i+1)*_mask->step + 1 : 0;430double area0 = area;431432for( j = 0; j < cols; j++ )433{434if( mptr[j] > 255 )435{436if( dmptr )437dmptr[j] = (uchar)new_mask_val;438if( !mask_only )439{440if( cn == 1 )441ptr[j] = (float)s0;442else443{444ptr[j*3] = (float)s0;445ptr[j*3+1] = (float)s1;446ptr[j*3+2] = (float)s2;447}448}449else450{451if( cn == 1 )452s0 += ptr[j];453else454{455s0 += ptr[j*3];456s1 += ptr[j*3+1];457s2 += ptr[j*3+2];458}459}460461area++;462if( r.x > j )463r.x = j;464if( r.width < j )465r.width = j;466}467}468469if( area != area0 )470{471if( r.y > i )472r.y = i;473if( r.height < i )474r.height = i;475}476}477478_exit_:479cvReleaseMat( &mask );480if( tmp != _img )481{482if( !mask_only )483cvtest::convert(cvarrToMat(tmp), cvarrToMat(_img), -1);484cvReleaseMat( &tmp );485}486487comp[0] = area;488comp[1] = r.x;489comp[2] = r.y;490comp[3] = r.width - r.x + 1;491comp[4] = r.height - r.y + 1;492#if 0493if( mask_only )494{495double t = area ? 1./area : 0;496s0 *= t;497s1 *= t;498s2 *= t;499}500comp[5] = s0;501comp[6] = s1;502comp[7] = s2;503#else504comp[5] = new_val.val[0];505comp[6] = new_val.val[1];506comp[7] = new_val.val[2];507#endif508comp[8] = 0;509510cvReleaseMemStorage(&st);511}512513514void CV_FloodFillTest::prepare_to_validation( int /*test_case_idx*/ )515{516double* comp = test_mat[REF_OUTPUT][0].ptr<double>();517CvMat _input = cvMat(test_mat[REF_INPUT_OUTPUT][0]);518CvMat _mask = cvMat(test_mat[REF_INPUT_OUTPUT][1]);519cvTsFloodFill( &_input, cvPoint(seed_pt), cvScalar(new_val), cvScalar(l_diff), cvScalar(u_diff),520_mask.data.ptr ? &_mask : 0,521comp, connectivity, range_type,522new_mask_val, mask_only );523if(test_cpp)524comp[5] = comp[6] = comp[7] = comp[8] = 0;525}526527TEST(Imgproc_FloodFill, accuracy) { CV_FloodFillTest test; test.safe_run(); }528529TEST(Imgproc_FloodFill, maskValue)530{531const int n = 50;532Mat img = Mat::zeros(n, n, CV_8U);533Mat mask = Mat::zeros(n + 2, n + 2, CV_8U);534535circle(img, Point(n/2, n/2), 20, Scalar(100), 4);536537int flags = 4 + CV_FLOODFILL_MASK_ONLY;538floodFill(img, mask, Point(n/2 + 13, n/2), Scalar(100), NULL, Scalar(), Scalar(), flags);539540ASSERT_EQ(1, cvtest::norm(mask.rowRange(1, n-1).colRange(1, n-1), NORM_INF));541}542543}} // namespace544/* End of file. */545546547