| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233 |
- // This file is part of OpenCV project.
- // It is subject to the license terms in the LICENSE file found in the top-level directory
- // of this distribution and at http://opencv.org/license.html.
- //////////////////////////////////////////////////////////////////////////////////////////
- /////////////////// tests for matrix operations and math functions ///////////////////////
- //////////////////////////////////////////////////////////////////////////////////////////
- #include "test_precomp.hpp"
- #include <float.h>
- #include <math.h>
- #include "opencv2/core/softfloat.hpp"
- namespace opencv_test { namespace {
- /// !!! NOTE !!! These tests happily avoid overflow cases & out-of-range arguments
- /// so that output arrays contain neigher Inf's nor Nan's.
- /// Handling such cases would require special modification of check function
- /// (validate_test_results) => TBD.
- /// Also, need some logarithmic-scale generation of input data. Right now it is done (in some tests)
- /// by generating min/max boundaries for random data in logarimithic scale, but
- /// within the same test case all the input array elements are of the same order.
- class Core_MathTest : public cvtest::ArrayTest
- {
- public:
- typedef cvtest::ArrayTest Base;
- Core_MathTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes,
- vector<vector<int> >& types);
- double get_success_error_level( int /*test_case_idx*/, int i, int j );
- bool test_nd;
- };
- Core_MathTest::Core_MathTest()
- {
- optional_mask = false;
- test_array[INPUT].push_back(NULL);
- test_array[OUTPUT].push_back(NULL);
- test_array[REF_OUTPUT].push_back(NULL);
- test_nd = false;
- }
- double Core_MathTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
- {
- return test_mat[i][j].depth() == CV_32F ? FLT_EPSILON*128 : DBL_EPSILON*1024;
- }
- void Core_MathTest::get_test_array_types_and_sizes( int test_case_idx,
- vector<vector<Size> >& sizes,
- vector<vector<int> >& types)
- {
- RNG& rng = ts->get_rng();
- int depth = cvtest::randInt(rng)%2 + CV_32F;
- int cn = cvtest::randInt(rng) % 4 + 1, type = CV_MAKETYPE(depth, cn);
- size_t i, j;
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- for( i = 0; i < test_array.size(); i++ )
- {
- size_t count = test_array[i].size();
- for( j = 0; j < count; j++ )
- types[i][j] = type;
- }
- test_nd = cvtest::randInt(rng)%3 == 0;
- }
- ////////// pow /////////////
- class Core_PowTest : public Core_MathTest
- {
- public:
- typedef Core_MathTest Base;
- Core_PowTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx,
- vector<vector<Size> >& sizes,
- vector<vector<int> >& types );
- void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- double get_success_error_level( int test_case_idx, int i, int j );
- double power;
- };
- Core_PowTest::Core_PowTest()
- {
- power = 0;
- }
- void Core_PowTest::get_test_array_types_and_sizes( int test_case_idx,
- vector<vector<Size> >& sizes,
- vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int depth = cvtest::randInt(rng) % (CV_64F+1);
- int cn = cvtest::randInt(rng) % 4 + 1;
- size_t i, j;
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- depth += depth == CV_8S;
- if( depth < CV_32F || cvtest::randInt(rng)%8 == 0 )
- // integer power
- power = (int)(cvtest::randInt(rng)%21 - 10);
- else
- {
- i = cvtest::randInt(rng)%17;
- power = i == 16 ? 1./3 : i == 15 ? 0.5 : i == 14 ? -0.5 : cvtest::randReal(rng)*10 - 5;
- }
- for( i = 0; i < test_array.size(); i++ )
- {
- size_t count = test_array[i].size();
- int type = CV_MAKETYPE(depth, cn);
- for( j = 0; j < count; j++ )
- types[i][j] = type;
- }
- test_nd = cvtest::randInt(rng)%3 == 0;
- }
- double Core_PowTest::get_success_error_level( int test_case_idx, int i, int j )
- {
- int depth = test_mat[i][j].depth();
- if( depth < CV_32F )
- return power == cvRound(power) && power >= 0 ? 0 : 1;
- else
- {
- return depth != CV_64F ? Base::get_success_error_level( test_case_idx, i, j ) : DBL_EPSILON*1024*1.11;
- }
- }
- void Core_PowTest::get_minmax_bounds( int /*i*/, int /*j*/, int type, Scalar& low, Scalar& high )
- {
- double l, u = cvtest::randInt(ts->get_rng())%1000 + 1;
- if( power > 0 )
- {
- double mval = cvtest::getMaxVal(type);
- double u1 = pow(mval,1./power)*2;
- u = MIN(u,u1);
- }
- l = power == cvRound(power) ? -u : FLT_EPSILON;
- low = Scalar::all(l);
- high = Scalar::all(u);
- }
- void Core_PowTest::run_func()
- {
- if(!test_nd)
- {
- if( fabs(power-1./3) <= DBL_EPSILON && test_mat[INPUT][0].depth() == CV_32F )
- {
- Mat a = test_mat[INPUT][0], b = test_mat[OUTPUT][0];
- a = a.reshape(1);
- b = b.reshape(1);
- for( int i = 0; i < a.rows; i++ )
- {
- b.at<float>(i,0) = (float)fabs(cvCbrt(a.at<float>(i,0)));
- for( int j = 1; j < a.cols; j++ )
- b.at<float>(i,j) = (float)fabs(cv::cubeRoot(a.at<float>(i,j)));
- }
- }
- else
- cvPow( test_array[INPUT][0], test_array[OUTPUT][0], power );
- }
- else
- {
- Mat& a = test_mat[INPUT][0];
- Mat& b = test_mat[OUTPUT][0];
- if(power == 0.5)
- cv::sqrt(a, b);
- else
- cv::pow(a, power, b);
- }
- }
- inline static int ipow( int a, int power )
- {
- int b = 1;
- while( power > 0 )
- {
- if( power&1 )
- b *= a, power--;
- else
- a *= a, power >>= 1;
- }
- return b;
- }
- inline static double ipow( double a, int power )
- {
- double b = 1.;
- while( power > 0 )
- {
- if( power&1 )
- b *= a, power--;
- else
- a *= a, power >>= 1;
- }
- return b;
- }
- void Core_PowTest::prepare_to_validation( int /*test_case_idx*/ )
- {
- const Mat& a = test_mat[INPUT][0];
- Mat& b = test_mat[REF_OUTPUT][0];
- int depth = a.depth();
- int ncols = a.cols*a.channels();
- int ipower = cvRound(power), apower = abs(ipower);
- int i, j;
- for( i = 0; i < a.rows; i++ )
- {
- const uchar* a_data = a.ptr(i);
- uchar* b_data = b.ptr(i);
- switch( depth )
- {
- case CV_8U:
- if( ipower < 0 )
- for( j = 0; j < ncols; j++ )
- {
- int val = ((uchar*)a_data)[j];
- ((uchar*)b_data)[j] = (uchar)(val == 0 ? 255 : val == 1 ? 1 :
- val == 2 && ipower == -1 ? 1 : 0);
- }
- else
- for( j = 0; j < ncols; j++ )
- {
- int val = ((uchar*)a_data)[j];
- val = ipow( val, ipower );
- ((uchar*)b_data)[j] = saturate_cast<uchar>(val);
- }
- break;
- case CV_8S:
- if( ipower < 0 )
- for( j = 0; j < ncols; j++ )
- {
- int val = ((schar*)a_data)[j];
- ((schar*)b_data)[j] = (schar)(val == 0 ? 127 : val == 1 ? 1 :
- val ==-1 ? 1-2*(ipower&1) :
- val == 2 && ipower == -1 ? 1 : 0);
- }
- else
- for( j = 0; j < ncols; j++ )
- {
- int val = ((schar*)a_data)[j];
- val = ipow( val, ipower );
- ((schar*)b_data)[j] = saturate_cast<schar>(val);
- }
- break;
- case CV_16U:
- if( ipower < 0 )
- for( j = 0; j < ncols; j++ )
- {
- int val = ((ushort*)a_data)[j];
- ((ushort*)b_data)[j] = (ushort)(val == 0 ? 65535 : val == 1 ? 1 :
- val ==-1 ? 1-2*(ipower&1) :
- val == 2 && ipower == -1 ? 1 : 0);
- }
- else
- for( j = 0; j < ncols; j++ )
- {
- int val = ((ushort*)a_data)[j];
- val = ipow( val, ipower );
- ((ushort*)b_data)[j] = saturate_cast<ushort>(val);
- }
- break;
- case CV_16S:
- if( ipower < 0 )
- for( j = 0; j < ncols; j++ )
- {
- int val = ((short*)a_data)[j];
- ((short*)b_data)[j] = (short)(val == 0 ? 32767 : val == 1 ? 1 :
- val ==-1 ? 1-2*(ipower&1) :
- val == 2 && ipower == -1 ? 1 : 0);
- }
- else
- for( j = 0; j < ncols; j++ )
- {
- int val = ((short*)a_data)[j];
- val = ipow( val, ipower );
- ((short*)b_data)[j] = saturate_cast<short>(val);
- }
- break;
- case CV_32S:
- if( ipower < 0 )
- for( j = 0; j < ncols; j++ )
- {
- int val = ((int*)a_data)[j];
- ((int*)b_data)[j] = val == 0 ? INT_MAX : val == 1 ? 1 :
- val ==-1 ? 1-2*(ipower&1) :
- val == 2 && ipower == -1 ? 1 : 0;
- }
- else
- for( j = 0; j < ncols; j++ )
- {
- int val = ((int*)a_data)[j];
- val = ipow( val, ipower );
- ((int*)b_data)[j] = val;
- }
- break;
- case CV_32F:
- if( power != ipower )
- for( j = 0; j < ncols; j++ )
- {
- double val = ((float*)a_data)[j];
- val = pow( fabs(val), power );
- ((float*)b_data)[j] = (float)val;
- }
- else
- for( j = 0; j < ncols; j++ )
- {
- double val = ((float*)a_data)[j];
- if( ipower < 0 )
- val = 1./val;
- val = ipow( val, apower );
- ((float*)b_data)[j] = (float)val;
- }
- break;
- case CV_64F:
- if( power != ipower )
- for( j = 0; j < ncols; j++ )
- {
- double val = ((double*)a_data)[j];
- val = pow( fabs(val), power );
- ((double*)b_data)[j] = (double)val;
- }
- else
- for( j = 0; j < ncols; j++ )
- {
- double val = ((double*)a_data)[j];
- if( ipower < 0 )
- val = 1./val;
- val = ipow( val, apower );
- ((double*)b_data)[j] = (double)val;
- }
- break;
- }
- }
- }
- ///////////////////////////////////////// matrix tests ////////////////////////////////////////////
- class Core_MatrixTest : public cvtest::ArrayTest
- {
- public:
- typedef cvtest::ArrayTest Base;
- Core_MatrixTest( int in_count, int out_count,
- bool allow_int, bool scalar_output, int max_cn );
- protected:
- void get_test_array_types_and_sizes( int test_case_idx,
- vector<vector<Size> >& sizes,
- vector<vector<int> >& types );
- double get_success_error_level( int test_case_idx, int i, int j );
- bool allow_int;
- bool scalar_output;
- int max_cn;
- };
- Core_MatrixTest::Core_MatrixTest( int in_count, int out_count,
- bool _allow_int, bool _scalar_output, int _max_cn )
- : allow_int(_allow_int), scalar_output(_scalar_output), max_cn(_max_cn)
- {
- int i;
- for( i = 0; i < in_count; i++ )
- test_array[INPUT].push_back(NULL);
- for( i = 0; i < out_count; i++ )
- {
- test_array[OUTPUT].push_back(NULL);
- test_array[REF_OUTPUT].push_back(NULL);
- }
- element_wise_relative_error = false;
- }
- void Core_MatrixTest::get_test_array_types_and_sizes( int test_case_idx,
- vector<vector<Size> >& sizes,
- vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int depth = cvtest::randInt(rng) % (allow_int ? CV_64F+1 : 2);
- int cn = cvtest::randInt(rng) % max_cn + 1;
- size_t i, j;
- if( allow_int )
- depth += depth == CV_8S;
- else
- depth += CV_32F;
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- for( i = 0; i < test_array.size(); i++ )
- {
- size_t count = test_array[i].size();
- int flag = (i == OUTPUT || i == REF_OUTPUT) && scalar_output;
- int type = !flag ? CV_MAKETYPE(depth, cn) : CV_64FC1;
- for( j = 0; j < count; j++ )
- {
- types[i][j] = type;
- if( flag )
- sizes[i][j] = Size( 4, 1 );
- }
- }
- }
- double Core_MatrixTest::get_success_error_level( int test_case_idx, int i, int j )
- {
- int input_depth = test_mat[INPUT][0].depth();
- double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? 5e-5 : 5e-10;
- double output_precision = Base::get_success_error_level( test_case_idx, i, j );
- return MAX(input_precision, output_precision);
- }
- ///////////////// Trace /////////////////////
- class Core_TraceTest : public Core_MatrixTest
- {
- public:
- Core_TraceTest();
- protected:
- void run_func();
- void prepare_to_validation( int test_case_idx );
- };
- Core_TraceTest::Core_TraceTest() : Core_MatrixTest( 1, 1, true, true, 4 )
- {
- }
- void Core_TraceTest::run_func()
- {
- test_mat[OUTPUT][0].at<Scalar>(0,0) = cvTrace(test_array[INPUT][0]);
- }
- void Core_TraceTest::prepare_to_validation( int )
- {
- Mat& mat = test_mat[INPUT][0];
- int count = MIN( mat.rows, mat.cols );
- Mat diag(count, 1, mat.type(), mat.ptr(), mat.step + mat.elemSize());
- Scalar r = cvtest::mean(diag);
- r *= (double)count;
- test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = r;
- }
- ///////// dotproduct //////////
- class Core_DotProductTest : public Core_MatrixTest
- {
- public:
- Core_DotProductTest();
- protected:
- void run_func() CV_OVERRIDE;
- void prepare_to_validation( int test_case_idx ) CV_OVERRIDE;
- double get_success_error_level( int test_case_idx, int i, int j ) CV_OVERRIDE;
- };
- Core_DotProductTest::Core_DotProductTest() : Core_MatrixTest( 2, 1, true, true, 4 )
- {
- }
- void Core_DotProductTest::run_func()
- {
- test_mat[OUTPUT][0].at<Scalar>(0,0) = Scalar(cvDotProduct( test_array[INPUT][0], test_array[INPUT][1] ));
- }
- void Core_DotProductTest::prepare_to_validation( int )
- {
- test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = Scalar(cvtest::crossCorr( test_mat[INPUT][0], test_mat[INPUT][1] ));
- }
- double Core_DotProductTest::get_success_error_level( int test_case_idx, int i, int j )
- {
- #ifdef __riscv
- const int depth = test_mat[i][j].depth();
- if (depth == CV_64F)
- return 2.5e-5;
- #endif
- return Core_MatrixTest::get_success_error_level( test_case_idx, i, j );
- }
- ///////// crossproduct //////////
- class Core_CrossProductTest : public Core_MatrixTest
- {
- public:
- Core_CrossProductTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx,
- vector<vector<Size> >& sizes,
- vector<vector<int> >& types );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- };
- Core_CrossProductTest::Core_CrossProductTest() : Core_MatrixTest( 2, 1, false, false, 1 )
- {
- }
- void Core_CrossProductTest::get_test_array_types_and_sizes( int,
- vector<vector<Size> >& sizes,
- vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int depth = cvtest::randInt(rng) % 2 + CV_32F;
- int cn = cvtest::randInt(rng) & 1 ? 3 : 1, type = CV_MAKETYPE(depth, cn);
- Size sz;
- types[INPUT][0] = types[INPUT][1] = types[OUTPUT][0] = types[REF_OUTPUT][0] = type;
- if( cn == 3 )
- sz = Size(1,1);
- else if( cvtest::randInt(rng) & 1 )
- sz = Size(3,1);
- else
- sz = Size(1,3);
- sizes[INPUT][0] = sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
- }
- void Core_CrossProductTest::run_func()
- {
- cvCrossProduct( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] );
- }
- void Core_CrossProductTest::prepare_to_validation( int )
- {
- cv::Scalar a, b, c;
- if( test_mat[INPUT][0].rows > 1 )
- {
- a.val[0] = cvGetReal2D( test_array[INPUT][0], 0, 0 );
- a.val[1] = cvGetReal2D( test_array[INPUT][0], 1, 0 );
- a.val[2] = cvGetReal2D( test_array[INPUT][0], 2, 0 );
- b.val[0] = cvGetReal2D( test_array[INPUT][1], 0, 0 );
- b.val[1] = cvGetReal2D( test_array[INPUT][1], 1, 0 );
- b.val[2] = cvGetReal2D( test_array[INPUT][1], 2, 0 );
- }
- else if( test_mat[INPUT][0].cols > 1 )
- {
- a.val[0] = cvGetReal1D( test_array[INPUT][0], 0 );
- a.val[1] = cvGetReal1D( test_array[INPUT][0], 1 );
- a.val[2] = cvGetReal1D( test_array[INPUT][0], 2 );
- b.val[0] = cvGetReal1D( test_array[INPUT][1], 0 );
- b.val[1] = cvGetReal1D( test_array[INPUT][1], 1 );
- b.val[2] = cvGetReal1D( test_array[INPUT][1], 2 );
- }
- else
- {
- a = cvGet1D( test_array[INPUT][0], 0 );
- b = cvGet1D( test_array[INPUT][1], 0 );
- }
- c.val[2] = a.val[0]*b.val[1] - a.val[1]*b.val[0];
- c.val[1] = -a.val[0]*b.val[2] + a.val[2]*b.val[0];
- c.val[0] = a.val[1]*b.val[2] - a.val[2]*b.val[1];
- if( test_mat[REF_OUTPUT][0].rows > 1 )
- {
- cvSetReal2D( test_array[REF_OUTPUT][0], 0, 0, c.val[0] );
- cvSetReal2D( test_array[REF_OUTPUT][0], 1, 0, c.val[1] );
- cvSetReal2D( test_array[REF_OUTPUT][0], 2, 0, c.val[2] );
- }
- else if( test_mat[REF_OUTPUT][0].cols > 1 )
- {
- cvSetReal1D( test_array[REF_OUTPUT][0], 0, c.val[0] );
- cvSetReal1D( test_array[REF_OUTPUT][0], 1, c.val[1] );
- cvSetReal1D( test_array[REF_OUTPUT][0], 2, c.val[2] );
- }
- else
- {
- cvSet1D( test_array[REF_OUTPUT][0], 0, cvScalar(c) );
- }
- }
- ///////////////// gemm /////////////////////
- class Core_GEMMTest : public Core_MatrixTest
- {
- public:
- typedef Core_MatrixTest Base;
- Core_GEMMTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- int tabc_flag;
- double alpha, beta;
- };
- Core_GEMMTest::Core_GEMMTest() : Core_MatrixTest( 5, 1, false, false, 2 )
- {
- test_case_count = 100;
- max_log_array_size = 10;
- tabc_flag = 0;
- alpha = beta = 0;
- }
- void Core_GEMMTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- Size sizeA;
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- sizeA = sizes[INPUT][0];
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- sizes[INPUT][0] = sizeA;
- sizes[INPUT][2] = sizes[INPUT][3] = Size(1,1);
- types[INPUT][2] = types[INPUT][3] &= ~CV_MAT_CN_MASK;
- tabc_flag = cvtest::randInt(rng) & 7;
- switch( tabc_flag & (CV_GEMM_A_T|CV_GEMM_B_T) )
- {
- case 0:
- sizes[INPUT][1].height = sizes[INPUT][0].width;
- sizes[OUTPUT][0].height = sizes[INPUT][0].height;
- sizes[OUTPUT][0].width = sizes[INPUT][1].width;
- break;
- case CV_GEMM_B_T:
- sizes[INPUT][1].width = sizes[INPUT][0].width;
- sizes[OUTPUT][0].height = sizes[INPUT][0].height;
- sizes[OUTPUT][0].width = sizes[INPUT][1].height;
- break;
- case CV_GEMM_A_T:
- sizes[INPUT][1].height = sizes[INPUT][0].height;
- sizes[OUTPUT][0].height = sizes[INPUT][0].width;
- sizes[OUTPUT][0].width = sizes[INPUT][1].width;
- break;
- case CV_GEMM_A_T | CV_GEMM_B_T:
- sizes[INPUT][1].width = sizes[INPUT][0].height;
- sizes[OUTPUT][0].height = sizes[INPUT][0].width;
- sizes[OUTPUT][0].width = sizes[INPUT][1].height;
- break;
- }
- sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
- if( cvtest::randInt(rng) & 1 )
- sizes[INPUT][4] = Size(0,0);
- else if( !(tabc_flag & CV_GEMM_C_T) )
- sizes[INPUT][4] = sizes[OUTPUT][0];
- else
- {
- sizes[INPUT][4].width = sizes[OUTPUT][0].height;
- sizes[INPUT][4].height = sizes[OUTPUT][0].width;
- }
- }
- int Core_GEMMTest::prepare_test_case( int test_case_idx )
- {
- int code = Base::prepare_test_case( test_case_idx );
- if( code > 0 )
- {
- alpha = cvGetReal2D( test_array[INPUT][2], 0, 0 );
- beta = cvGetReal2D( test_array[INPUT][3], 0, 0 );
- }
- return code;
- }
- void Core_GEMMTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
- {
- low = Scalar::all(-10.);
- high = Scalar::all(10.);
- }
- void Core_GEMMTest::run_func()
- {
- cvGEMM( test_array[INPUT][0], test_array[INPUT][1], alpha,
- test_array[INPUT][4], beta, test_array[OUTPUT][0], tabc_flag );
- }
- void Core_GEMMTest::prepare_to_validation( int )
- {
- cvtest::gemm( test_mat[INPUT][0], test_mat[INPUT][1], alpha,
- test_array[INPUT][4] ? test_mat[INPUT][4] : Mat(),
- beta, test_mat[REF_OUTPUT][0], tabc_flag );
- }
- ///////////////// multransposed /////////////////////
- class Core_MulTransposedTest : public Core_MatrixTest
- {
- public:
- Core_MulTransposedTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- int order;
- };
- Core_MulTransposedTest::Core_MulTransposedTest() : Core_MatrixTest( 2, 1, false, false, 1 )
- {
- test_case_count = 100;
- order = 0;
- test_array[TEMP].push_back(NULL);
- }
- void Core_MulTransposedTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- int src_type = cvtest::randInt(rng) % 5;
- int dst_type = cvtest::randInt(rng) % 2;
- src_type = src_type == 0 ? CV_8U : src_type == 1 ? CV_16U : src_type == 2 ? CV_16S :
- src_type == 3 ? CV_32F : CV_64F;
- dst_type = dst_type == 0 ? CV_32F : CV_64F;
- dst_type = MAX( dst_type, src_type );
- Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- if( bits & 1 )
- sizes[INPUT][1] = Size(0,0);
- else
- {
- sizes[INPUT][1] = sizes[INPUT][0];
- if( bits & 2 )
- sizes[INPUT][1].height = 1;
- if( bits & 4 )
- sizes[INPUT][1].width = 1;
- }
- sizes[TEMP][0] = sizes[INPUT][0];
- types[INPUT][0] = src_type;
- types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][1] = types[TEMP][0] = dst_type;
- order = (bits & 8) != 0;
- sizes[OUTPUT][0].width = sizes[OUTPUT][0].height = order == 0 ?
- sizes[INPUT][0].height : sizes[INPUT][0].width;
- sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
- }
- void Core_MulTransposedTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
- {
- low = cvScalarAll(-10.);
- high = cvScalarAll(10.);
- }
- void Core_MulTransposedTest::run_func()
- {
- cvMulTransposed( test_array[INPUT][0], test_array[OUTPUT][0],
- order, test_array[INPUT][1] );
- }
- void Core_MulTransposedTest::prepare_to_validation( int )
- {
- const Mat& src = test_mat[INPUT][0];
- Mat delta = test_mat[INPUT][1];
- Mat& temp = test_mat[TEMP][0];
- if( !delta.empty() )
- {
- if( delta.rows < src.rows || delta.cols < src.cols )
- {
- cv::repeat( delta, src.rows/delta.rows, src.cols/delta.cols, temp);
- delta = temp;
- }
- cvtest::add( src, 1, delta, -1, Scalar::all(0), temp, temp.type());
- }
- else
- src.convertTo(temp, temp.type());
- cvtest::gemm( temp, temp, 1., Mat(), 0, test_mat[REF_OUTPUT][0], order == 0 ? GEMM_2_T : GEMM_1_T );
- }
- ///////////////// Transform /////////////////////
- class Core_TransformTest : public Core_MatrixTest
- {
- public:
- typedef Core_MatrixTest Base;
- Core_TransformTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- double get_success_error_level( int test_case_idx, int i, int j );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- double scale;
- bool diagMtx;
- };
- Core_TransformTest::Core_TransformTest() : Core_MatrixTest( 3, 1, true, false, 4 )
- {
- scale = 1;
- diagMtx = false;
- }
- void Core_TransformTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- int depth, dst_cn, mat_cols, mattype;
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- mat_cols = CV_MAT_CN(types[INPUT][0]);
- depth = CV_MAT_DEPTH(types[INPUT][0]);
- dst_cn = cvtest::randInt(rng) % 4 + 1;
- types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn);
- mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
- types[INPUT][1] = mattype;
- types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn);
- scale = 1./((cvtest::randInt(rng)%4)*50+1);
- if( bits & 2 )
- {
- sizes[INPUT][2] = Size(0,0);
- mat_cols += (bits & 4) != 0;
- }
- else if( bits & 4 )
- sizes[INPUT][2] = Size(1,1);
- else
- {
- if( bits & 8 )
- sizes[INPUT][2] = Size(dst_cn,1);
- else
- sizes[INPUT][2] = Size(1,dst_cn);
- types[INPUT][2] &= ~CV_MAT_CN_MASK;
- }
- diagMtx = (bits & 16) != 0;
- sizes[INPUT][1] = Size(mat_cols,dst_cn);
- }
- int Core_TransformTest::prepare_test_case( int test_case_idx )
- {
- int code = Base::prepare_test_case( test_case_idx );
- if( code > 0 )
- {
- Mat& m = test_mat[INPUT][1];
- cvtest::add(m, scale, m, 0, Scalar::all(0), m, m.type() );
- if(diagMtx)
- {
- Mat mask = Mat::eye(m.rows, m.cols, CV_8U)*255;
- mask = ~mask;
- m.setTo(Scalar::all(0), mask);
- }
- }
- return code;
- }
- double Core_TransformTest::get_success_error_level( int test_case_idx, int i, int j )
- {
- int depth = test_mat[INPUT][0].depth();
- return depth <= CV_8S ? 1 : depth <= CV_32S ? 9 : Base::get_success_error_level( test_case_idx, i, j );
- }
- void Core_TransformTest::run_func()
- {
- CvMat _m = cvMat(test_mat[INPUT][1]), _shift = cvMat(test_mat[INPUT][2]);
- cvTransform( test_array[INPUT][0], test_array[OUTPUT][0], &_m, _shift.data.ptr ? &_shift : 0);
- }
- void Core_TransformTest::prepare_to_validation( int )
- {
- Mat transmat = test_mat[INPUT][1];
- Mat shift = test_mat[INPUT][2];
- cvtest::transform( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], transmat, shift );
- }
- class Core_TransformLargeTest : public Core_TransformTest
- {
- public:
- typedef Core_MatrixTest Base;
- protected:
- void get_test_array_types_and_sizes(int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types);
- };
- void Core_TransformLargeTest::get_test_array_types_and_sizes(int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types)
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- int depth, dst_cn, mat_cols, mattype;
- Base::get_test_array_types_and_sizes(test_case_idx, sizes, types);
- for (unsigned int j = 0; j < sizes.size(); j++)
- {
- for (unsigned int i = 0; i < sizes[j].size(); i++)
- {
- sizes[j][i].width *= 4;
- }
- }
- mat_cols = CV_MAT_CN(types[INPUT][0]);
- depth = CV_MAT_DEPTH(types[INPUT][0]);
- dst_cn = cvtest::randInt(rng) % 4 + 1;
- types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn);
- mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
- types[INPUT][1] = mattype;
- types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn);
- scale = 1. / ((cvtest::randInt(rng) % 4) * 50 + 1);
- if (bits & 2)
- {
- sizes[INPUT][2] = Size(0, 0);
- mat_cols += (bits & 4) != 0;
- }
- else if (bits & 4)
- sizes[INPUT][2] = Size(1, 1);
- else
- {
- if (bits & 8)
- sizes[INPUT][2] = Size(dst_cn, 1);
- else
- sizes[INPUT][2] = Size(1, dst_cn);
- types[INPUT][2] &= ~CV_MAT_CN_MASK;
- }
- diagMtx = (bits & 16) != 0;
- sizes[INPUT][1] = Size(mat_cols, dst_cn);
- }
- ///////////////// PerspectiveTransform /////////////////////
- class Core_PerspectiveTransformTest : public Core_MatrixTest
- {
- public:
- Core_PerspectiveTransformTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- double get_success_error_level( int test_case_idx, int i, int j );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- };
- Core_PerspectiveTransformTest::Core_PerspectiveTransformTest() : Core_MatrixTest( 2, 1, false, false, 2 )
- {
- }
- void Core_PerspectiveTransformTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- int depth, cn, mattype;
- Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- cn = CV_MAT_CN(types[INPUT][0]) + 1;
- depth = CV_MAT_DEPTH(types[INPUT][0]);
- types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
- mattype = depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
- types[INPUT][1] = mattype;
- sizes[INPUT][1] = Size(cn + 1, cn + 1);
- }
- double Core_PerspectiveTransformTest::get_success_error_level( int test_case_idx, int i, int j )
- {
- int depth = test_mat[INPUT][0].depth();
- return depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-8 :
- Core_MatrixTest::get_success_error_level(test_case_idx, i, j);
- }
- void Core_PerspectiveTransformTest::run_func()
- {
- CvMat _m = cvMat(test_mat[INPUT][1]);
- cvPerspectiveTransform( test_array[INPUT][0], test_array[OUTPUT][0], &_m );
- }
- static void cvTsPerspectiveTransform( const CvArr* _src, CvArr* _dst, const CvMat* transmat )
- {
- int i, j, cols;
- int cn, depth, mat_depth;
- CvMat astub, bstub, *a, *b;
- double mat[16] = {0.0};
- a = cvGetMat( _src, &astub, 0, 0 );
- b = cvGetMat( _dst, &bstub, 0, 0 );
- cn = CV_MAT_CN(a->type);
- depth = CV_MAT_DEPTH(a->type);
- mat_depth = CV_MAT_DEPTH(transmat->type);
- cols = transmat->cols;
- // prepare cn x (cn + 1) transform matrix
- if( mat_depth == CV_32F )
- {
- for( i = 0; i < transmat->rows; i++ )
- for( j = 0; j < cols; j++ )
- mat[i*cols + j] = ((float*)(transmat->data.ptr + transmat->step*i))[j];
- }
- else
- {
- CV_Assert( mat_depth == CV_64F );
- for( i = 0; i < transmat->rows; i++ )
- for( j = 0; j < cols; j++ )
- mat[i*cols + j] = ((double*)(transmat->data.ptr + transmat->step*i))[j];
- }
- // transform data
- cols = a->cols * cn;
- vector<double> buf(cols);
- for( i = 0; i < a->rows; i++ )
- {
- uchar* src = a->data.ptr + i*a->step;
- uchar* dst = b->data.ptr + i*b->step;
- switch( depth )
- {
- case CV_32F:
- for( j = 0; j < cols; j++ )
- buf[j] = ((float*)src)[j];
- break;
- case CV_64F:
- for( j = 0; j < cols; j++ )
- buf[j] = ((double*)src)[j];
- break;
- default:
- CV_Assert(0);
- }
- switch( cn )
- {
- case 2:
- for( j = 0; j < cols; j += 2 )
- {
- double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + mat[2];
- double t1 = buf[j]*mat[3] + buf[j+1]*mat[4] + mat[5];
- double w = buf[j]*mat[6] + buf[j+1]*mat[7] + mat[8];
- w = w ? 1./w : 0;
- buf[j] = t0*w;
- buf[j+1] = t1*w;
- }
- break;
- case 3:
- for( j = 0; j < cols; j += 3 )
- {
- double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + buf[j+2]*mat[2] + mat[3];
- double t1 = buf[j]*mat[4] + buf[j+1]*mat[5] + buf[j+2]*mat[6] + mat[7];
- double t2 = buf[j]*mat[8] + buf[j+1]*mat[9] + buf[j+2]*mat[10] + mat[11];
- double w = buf[j]*mat[12] + buf[j+1]*mat[13] + buf[j+2]*mat[14] + mat[15];
- w = w ? 1./w : 0;
- buf[j] = t0*w;
- buf[j+1] = t1*w;
- buf[j+2] = t2*w;
- }
- break;
- default:
- CV_Assert(0);
- }
- switch( depth )
- {
- case CV_32F:
- for( j = 0; j < cols; j++ )
- ((float*)dst)[j] = (float)buf[j];
- break;
- case CV_64F:
- for( j = 0; j < cols; j++ )
- ((double*)dst)[j] = buf[j];
- break;
- default:
- CV_Assert(0);
- }
- }
- }
- void Core_PerspectiveTransformTest::prepare_to_validation( int )
- {
- CvMat transmat = cvMat(test_mat[INPUT][1]);
- cvTsPerspectiveTransform( test_array[INPUT][0], test_array[REF_OUTPUT][0], &transmat );
- }
- ///////////////// Mahalanobis /////////////////////
- class Core_MahalanobisTest : public Core_MatrixTest
- {
- public:
- typedef Core_MatrixTest Base;
- Core_MahalanobisTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- };
- Core_MahalanobisTest::Core_MahalanobisTest() : Core_MatrixTest( 3, 1, false, true, 1 )
- {
- test_case_count = 100;
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- }
- void Core_MahalanobisTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- if( cvtest::randInt(rng) & 1 )
- sizes[INPUT][0].width = sizes[INPUT][1].width = 1;
- else
- sizes[INPUT][0].height = sizes[INPUT][1].height = 1;
- sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT][0];
- sizes[INPUT][2].width = sizes[INPUT][2].height = sizes[INPUT][0].width + sizes[INPUT][0].height - 1;
- sizes[TEMP][2] = sizes[INPUT][2];
- types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
- }
- int Core_MahalanobisTest::prepare_test_case( int test_case_idx )
- {
- int code = Base::prepare_test_case( test_case_idx );
- if( code > 0 )
- {
- // make sure that the inverted "covariation" matrix is symmetrix and positively defined.
- cvtest::gemm( test_mat[INPUT][2], test_mat[INPUT][2], 1., Mat(), 0., test_mat[TEMP][2], GEMM_2_T );
- cvtest::copy( test_mat[TEMP][2], test_mat[INPUT][2] );
- }
- return code;
- }
- void Core_MahalanobisTest::run_func()
- {
- test_mat[OUTPUT][0].at<Scalar>(0,0) =
- cvRealScalar(cvMahalanobis(test_array[INPUT][0], test_array[INPUT][1], test_array[INPUT][2]));
- }
- void Core_MahalanobisTest::prepare_to_validation( int )
- {
- cvtest::add( test_mat[INPUT][0], 1., test_mat[INPUT][1], -1.,
- Scalar::all(0), test_mat[TEMP][0], test_mat[TEMP][0].type() );
- if( test_mat[INPUT][0].rows == 1 )
- cvtest::gemm( test_mat[TEMP][0], test_mat[INPUT][2], 1.,
- Mat(), 0., test_mat[TEMP][1], 0 );
- else
- cvtest::gemm( test_mat[INPUT][2], test_mat[TEMP][0], 1.,
- Mat(), 0., test_mat[TEMP][1], 0 );
- test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(sqrt(cvtest::crossCorr(test_mat[TEMP][0], test_mat[TEMP][1])));
- }
- ///////////////// covarmatrix /////////////////////
- class Core_CovarMatrixTest : public Core_MatrixTest
- {
- public:
- Core_CovarMatrixTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- vector<void*> temp_hdrs;
- vector<uchar> hdr_data;
- int flags, t_flag, len, count;
- bool are_images;
- };
- Core_CovarMatrixTest::Core_CovarMatrixTest() : Core_MatrixTest( 1, 1, true, false, 1 ),
- flags(0), t_flag(0), len(0), count(0), are_images(false)
- {
- test_case_count = 100;
- test_array[INPUT_OUTPUT].push_back(NULL);
- test_array[REF_INPUT_OUTPUT].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- }
- void Core_CovarMatrixTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- int i, single_matrix;
- Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- flags = bits & (CV_COVAR_NORMAL | CV_COVAR_USE_AVG | CV_COVAR_SCALE | CV_COVAR_ROWS );
- single_matrix = flags & CV_COVAR_ROWS;
- t_flag = (bits & 256) != 0;
- const int min_count = 2;
- if( !t_flag )
- {
- len = sizes[INPUT][0].width;
- count = sizes[INPUT][0].height;
- count = MAX(count, min_count);
- sizes[INPUT][0] = Size(len, count);
- }
- else
- {
- len = sizes[INPUT][0].height;
- count = sizes[INPUT][0].width;
- count = MAX(count, min_count);
- sizes[INPUT][0] = Size(count, len);
- }
- if( single_matrix && t_flag )
- flags = (flags & ~CV_COVAR_ROWS) | CV_COVAR_COLS;
- if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32S )
- types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK) | CV_32F;
- sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = flags & CV_COVAR_NORMAL ? Size(len,len) : Size(count,count);
- sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = !t_flag ? Size(len,1) : Size(1,len);
- sizes[TEMP][0] = sizes[INPUT][0];
- types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] =
- types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] =
- CV_MAT_DEPTH(types[INPUT][0]) == CV_64F || (bits & 512) ? CV_64F : CV_32F;
- are_images = (bits & 1024) != 0;
- for( i = 0; i < (single_matrix ? 1 : count); i++ )
- temp_hdrs.push_back(NULL);
- }
- int Core_CovarMatrixTest::prepare_test_case( int test_case_idx )
- {
- int code = Core_MatrixTest::prepare_test_case( test_case_idx );
- if( code > 0 )
- {
- int i;
- int single_matrix = flags & (CV_COVAR_ROWS|CV_COVAR_COLS);
- int hdr_size = are_images ? sizeof(IplImage) : sizeof(CvMat);
- hdr_data.resize(count*hdr_size);
- uchar* _hdr_data = &hdr_data[0];
- if( single_matrix )
- {
- if( !are_images )
- *((CvMat*)_hdr_data) = cvMat(test_mat[INPUT][0]);
- else
- *((IplImage*)_hdr_data) = cvIplImage(test_mat[INPUT][0]);
- temp_hdrs[0] = _hdr_data;
- }
- else
- for( i = 0; i < count; i++ )
- {
- Mat part;
- void* ptr = _hdr_data + i*hdr_size;
- if( !t_flag )
- part = test_mat[INPUT][0].row(i);
- else
- part = test_mat[INPUT][0].col(i);
- if( !are_images )
- *((CvMat*)ptr) = cvMat(part);
- else
- *((IplImage*)ptr) = cvIplImage(part);
- temp_hdrs[i] = ptr;
- }
- }
- return code;
- }
- void Core_CovarMatrixTest::run_func()
- {
- cvCalcCovarMatrix( (const void**)&temp_hdrs[0], count,
- test_array[OUTPUT][0], test_array[INPUT_OUTPUT][0], flags );
- }
- void Core_CovarMatrixTest::prepare_to_validation( int )
- {
- Mat& avg = test_mat[REF_INPUT_OUTPUT][0];
- double scale = 1.;
- if( !(flags & CV_COVAR_USE_AVG) )
- {
- Mat hdrs0 = cvarrToMat(temp_hdrs[0]);
- int i;
- avg = Scalar::all(0);
- for( i = 0; i < count; i++ )
- {
- Mat vec;
- if( flags & CV_COVAR_ROWS )
- vec = hdrs0.row(i);
- else if( flags & CV_COVAR_COLS )
- vec = hdrs0.col(i);
- else
- vec = cvarrToMat(temp_hdrs[i]);
- cvtest::add(avg, 1, vec, 1, Scalar::all(0), avg, avg.type());
- }
- cvtest::add(avg, 1./count, avg, 0., Scalar::all(0), avg, avg.type());
- }
- if( flags & CV_COVAR_SCALE )
- {
- scale = 1./count;
- }
- Mat& temp0 = test_mat[TEMP][0];
- cv::repeat( avg, temp0.rows/avg.rows, temp0.cols/avg.cols, temp0 );
- cvtest::add( test_mat[INPUT][0], 1, temp0, -1, Scalar::all(0), temp0, temp0.type());
- cvtest::gemm( temp0, temp0, scale, Mat(), 0., test_mat[REF_OUTPUT][0],
- t_flag ^ ((flags & CV_COVAR_NORMAL) != 0) ? CV_GEMM_A_T : CV_GEMM_B_T );
- temp_hdrs.clear();
- }
- static void cvTsFloodWithZeros( Mat& mat, RNG& rng )
- {
- int k, total = mat.rows*mat.cols, type = mat.type();
- int zero_total = cvtest::randInt(rng) % total;
- CV_Assert( type == CV_32FC1 || type == CV_64FC1 );
- for( k = 0; k < zero_total; k++ )
- {
- int i = cvtest::randInt(rng) % mat.rows;
- int j = cvtest::randInt(rng) % mat.cols;
- if( type == CV_32FC1 )
- mat.at<float>(i,j) = 0.f;
- else
- mat.at<double>(i,j) = 0.;
- }
- }
- ///////////////// determinant /////////////////////
- class Core_DetTest : public Core_MatrixTest
- {
- public:
- typedef Core_MatrixTest Base;
- Core_DetTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- double get_success_error_level( int test_case_idx, int i, int j );
- void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- };
- Core_DetTest::Core_DetTest() : Core_MatrixTest( 1, 1, false, true, 1 )
- {
- test_case_count = 100;
- max_log_array_size = 7;
- test_array[TEMP].push_back(NULL);
- }
- void Core_DetTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- sizes[INPUT][0].width = sizes[INPUT][0].height;
- sizes[TEMP][0] = sizes[INPUT][0];
- types[TEMP][0] = CV_64FC1;
- }
- void Core_DetTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
- {
- low = cvScalarAll(-2.);
- high = cvScalarAll(2.);
- }
- double Core_DetTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
- {
- return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-2 : 1e-5;
- }
- int Core_DetTest::prepare_test_case( int test_case_idx )
- {
- int code = Core_MatrixTest::prepare_test_case( test_case_idx );
- if( code > 0 )
- cvTsFloodWithZeros( test_mat[INPUT][0], ts->get_rng() );
- return code;
- }
- void Core_DetTest::run_func()
- {
- test_mat[OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(cvDet(test_array[INPUT][0]));
- }
- // LU method that chooses the optimal in a column pivot element
- static double cvTsLU( CvMat* a, CvMat* b=NULL, CvMat* x=NULL, int* rank=0 )
- {
- int i, j, k, N = a->rows, N1 = a->cols, Nm = MIN(N, N1), step = a->step/sizeof(double);
- int M = b ? b->cols : 0, b_step = b ? b->step/sizeof(double) : 0;
- int x_step = x ? x->step/sizeof(double) : 0;
- double *a0 = a->data.db, *b0 = b ? b->data.db : 0;
- double *x0 = x ? x->data.db : 0;
- double t, det = 1.;
- CV_Assert( CV_MAT_TYPE(a->type) == CV_64FC1 &&
- (!b || CV_ARE_TYPES_EQ(a,b)) && (!x || CV_ARE_TYPES_EQ(a,x)));
- for( i = 0; i < Nm; i++ )
- {
- double max_val = fabs(a0[i*step + i]);
- double *a1, *a2, *b1 = 0, *b2 = 0;
- k = i;
- for( j = i+1; j < N; j++ )
- {
- t = fabs(a0[j*step + i]);
- if( max_val < t )
- {
- max_val = t;
- k = j;
- }
- }
- if( k != i )
- {
- for( j = i; j < N1; j++ )
- CV_SWAP( a0[i*step + j], a0[k*step + j], t );
- for( j = 0; j < M; j++ )
- CV_SWAP( b0[i*b_step + j], b0[k*b_step + j], t );
- det = -det;
- }
- if( max_val == 0 )
- {
- if( rank )
- *rank = i;
- return 0.;
- }
- a1 = a0 + i*step;
- a2 = a1 + step;
- b1 = b0 + i*b_step;
- b2 = b1 + b_step;
- for( j = i+1; j < N; j++, a2 += step, b2 += b_step )
- {
- t = a2[i]/a1[i];
- for( k = i+1; k < N1; k++ )
- a2[k] -= t*a1[k];
- for( k = 0; k < M; k++ )
- b2[k] -= t*b1[k];
- }
- det *= a1[i];
- }
- if( x )
- {
- CV_Assert( b );
- for( i = N-1; i >= 0; i-- )
- {
- double* a1 = a0 + i*step;
- double* b1 = b0 + i*b_step;
- for( j = 0; j < M; j++ )
- {
- t = b1[j];
- for( k = i+1; k < N1; k++ )
- t -= a1[k]*x0[k*x_step + j];
- x0[i*x_step + j] = t/a1[i];
- }
- }
- }
- if( rank )
- *rank = i;
- return det;
- }
- void Core_DetTest::prepare_to_validation( int )
- {
- test_mat[INPUT][0].convertTo(test_mat[TEMP][0], test_mat[TEMP][0].type());
- CvMat temp0 = cvMat(test_mat[TEMP][0]);
- test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(cvTsLU(&temp0, 0, 0));
- }
- ///////////////// invert /////////////////////
- class Core_InvertTest : public Core_MatrixTest
- {
- public:
- typedef Core_MatrixTest Base;
- Core_InvertTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
- double get_success_error_level( int test_case_idx, int i, int j );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- int method, rank;
- double result;
- };
- Core_InvertTest::Core_InvertTest()
- : Core_MatrixTest( 1, 1, false, false, 1 ), method(0), rank(0), result(0.)
- {
- test_case_count = 100;
- max_log_array_size = 7;
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- }
- void Core_InvertTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
- if( (bits & 3) == 0 )
- {
- method = CV_SVD;
- if( bits & 4 )
- {
- sizes[INPUT][0] = Size(min_size, min_size);
- if( bits & 16 )
- method = CV_CHOLESKY;
- }
- }
- else
- {
- method = CV_LU;
- sizes[INPUT][0] = Size(min_size, min_size);
- }
- sizes[TEMP][0].width = sizes[INPUT][0].height;
- sizes[TEMP][0].height = sizes[INPUT][0].width;
- sizes[TEMP][1] = sizes[INPUT][0];
- types[TEMP][0] = types[INPUT][0];
- types[TEMP][1] = CV_64FC1;
- sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size(min_size, min_size);
- }
- double Core_InvertTest::get_success_error_level( int /*test_case_idx*/, int, int )
- {
- return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 1e-2 : 1e-6;
- }
- int Core_InvertTest::prepare_test_case( int test_case_idx )
- {
- int code = Core_MatrixTest::prepare_test_case( test_case_idx );
- if( code > 0 )
- {
- cvTsFloodWithZeros( test_mat[INPUT][0], ts->get_rng() );
- if( method == CV_CHOLESKY )
- {
- cvtest::gemm( test_mat[INPUT][0], test_mat[INPUT][0], 1.,
- Mat(), 0., test_mat[TEMP][0], CV_GEMM_B_T );
- cvtest::copy( test_mat[TEMP][0], test_mat[INPUT][0] );
- }
- }
- return code;
- }
- void Core_InvertTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
- {
- low = cvScalarAll(-1.);
- high = cvScalarAll(1.);
- }
- void Core_InvertTest::run_func()
- {
- result = cvInvert(test_array[INPUT][0], test_array[TEMP][0], method);
- }
- static double cvTsSVDet( CvMat* mat, double* ratio )
- {
- int type = CV_MAT_TYPE(mat->type);
- int i, nm = MIN( mat->rows, mat->cols );
- CvMat* w = cvCreateMat( nm, 1, type );
- double det = 1.;
- cvSVD( mat, w, 0, 0, 0 );
- if( type == CV_32FC1 )
- {
- for( i = 0; i < nm; i++ )
- det *= w->data.fl[i];
- *ratio = w->data.fl[nm-1] < FLT_EPSILON ? 0 : w->data.fl[nm-1]/w->data.fl[0];
- }
- else
- {
- for( i = 0; i < nm; i++ )
- det *= w->data.db[i];
- *ratio = w->data.db[nm-1] < FLT_EPSILON ? 0 : w->data.db[nm-1]/w->data.db[0];
- }
- cvReleaseMat( &w );
- return det;
- }
- void Core_InvertTest::prepare_to_validation( int )
- {
- Mat& input = test_mat[INPUT][0];
- Mat& temp0 = test_mat[TEMP][0];
- Mat& temp1 = test_mat[TEMP][1];
- Mat& dst0 = test_mat[REF_OUTPUT][0];
- Mat& dst = test_mat[OUTPUT][0];
- CvMat _input = cvMat(input);
- double ratio = 0, det = cvTsSVDet( &_input, &ratio );
- double threshold = (input.depth() == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000;
- cvtest::convert( input, temp1, temp1.type() );
- if( det < threshold ||
- ((method == CV_LU || method == CV_CHOLESKY) && (result == 0 || ratio < threshold)) ||
- ((method == CV_SVD || method == CV_SVD_SYM) && result < threshold) )
- {
- dst = Scalar::all(0);
- dst0 = Scalar::all(0);
- return;
- }
- if( input.rows >= input.cols )
- cvtest::gemm( temp0, input, 1., Mat(), 0., dst, 0 );
- else
- cvtest::gemm( input, temp0, 1., Mat(), 0., dst, 0 );
- cv::setIdentity( dst0, Scalar::all(1) );
- }
- ///////////////// solve /////////////////////
- class Core_SolveTest : public Core_MatrixTest
- {
- public:
- typedef Core_MatrixTest Base;
- Core_SolveTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
- double get_success_error_level( int test_case_idx, int i, int j );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- int method, rank;
- double result;
- };
- Core_SolveTest::Core_SolveTest() : Core_MatrixTest( 2, 1, false, false, 1 ), method(0), rank(0), result(0.)
- {
- test_case_count = 100;
- max_log_array_size = 7;
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- }
- void Core_SolveTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- CvSize in_sz = cvSize(sizes[INPUT][0]);
- if( in_sz.width > in_sz.height )
- in_sz = cvSize(in_sz.height, in_sz.width);
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- sizes[INPUT][0] = in_sz;
- int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
- if( (bits & 3) == 0 )
- {
- method = CV_SVD;
- if( bits & 4 )
- {
- sizes[INPUT][0] = Size(min_size, min_size);
- /*if( bits & 8 )
- method = CV_SVD_SYM;*/
- }
- }
- else
- {
- method = CV_LU;
- sizes[INPUT][0] = Size(min_size, min_size);
- }
- sizes[INPUT][1].height = sizes[INPUT][0].height;
- sizes[TEMP][0].width = sizes[INPUT][1].width;
- sizes[TEMP][0].height = sizes[INPUT][0].width;
- sizes[TEMP][1] = sizes[INPUT][0];
- types[TEMP][0] = types[INPUT][0];
- types[TEMP][1] = CV_64FC1;
- sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size(sizes[INPUT][1].width, min_size);
- }
- int Core_SolveTest::prepare_test_case( int test_case_idx )
- {
- int code = Core_MatrixTest::prepare_test_case( test_case_idx );
- /*if( method == CV_SVD_SYM )
- {
- cvTsGEMM( test_array[INPUT][0], test_array[INPUT][0], 1.,
- 0, 0., test_array[TEMP][0], CV_GEMM_B_T );
- cvTsCopy( test_array[TEMP][0], test_array[INPUT][0] );
- }*/
- return code;
- }
- void Core_SolveTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
- {
- low = cvScalarAll(-1.);
- high = cvScalarAll(1.);
- }
- double Core_SolveTest::get_success_error_level( int /*test_case_idx*/, int, int )
- {
- return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 5e-2 : 1e-8;
- }
- void Core_SolveTest::run_func()
- {
- result = cvSolve(test_array[INPUT][0], test_array[INPUT][1], test_array[TEMP][0], method);
- }
- void Core_SolveTest::prepare_to_validation( int )
- {
- //int rank = test_mat[REF_OUTPUT][0].rows;
- Mat& input = test_mat[INPUT][0];
- Mat& dst = test_mat[OUTPUT][0];
- Mat& dst0 = test_mat[REF_OUTPUT][0];
- if( method == CV_LU )
- {
- if( result == 0 )
- {
- Mat& temp1 = test_mat[TEMP][1];
- cvtest::convert(input, temp1, temp1.type());
- dst = Scalar::all(0);
- CvMat _temp1 = cvMat(temp1);
- double det = cvTsLU( &_temp1, 0, 0 );
- dst0 = Scalar::all(det != 0);
- return;
- }
- double threshold = (input.type() == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000;
- CvMat _input = cvMat(input);
- double ratio = 0, det = cvTsSVDet( &_input, &ratio );
- if( det < threshold || ratio < threshold )
- {
- dst = Scalar::all(0);
- dst0 = Scalar::all(0);
- return;
- }
- }
- Mat* pdst = input.rows <= input.cols ? &test_mat[OUTPUT][0] : &test_mat[INPUT][1];
- cvtest::gemm( input, test_mat[TEMP][0], 1., test_mat[INPUT][1], -1., *pdst, 0 );
- if( pdst != &dst )
- cvtest::gemm( input, *pdst, 1., Mat(), 0., dst, CV_GEMM_A_T );
- dst0 = Scalar::all(0);
- }
- ///////////////// SVD /////////////////////
- class Core_SVDTest : public Core_MatrixTest
- {
- public:
- typedef Core_MatrixTest Base;
- Core_SVDTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- double get_success_error_level( int test_case_idx, int i, int j );
- void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- int flags;
- bool have_u, have_v, symmetric, compact, vector_w;
- };
- Core_SVDTest::Core_SVDTest() :
- Core_MatrixTest( 1, 4, false, false, 1 ),
- flags(0), have_u(false), have_v(false), symmetric(false), compact(false), vector_w(false)
- {
- test_case_count = 100;
- max_log_array_size = 8;
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- }
- void Core_SVDTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- int min_size, i, m, n;
- min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
- flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
- have_u = (bits & 8) != 0;
- have_v = (bits & 16) != 0;
- symmetric = (bits & 32) != 0;
- compact = (bits & 64) != 0;
- vector_w = (bits & 128) != 0;
- if( symmetric )
- sizes[INPUT][0] = Size(min_size, min_size);
- m = sizes[INPUT][0].height;
- n = sizes[INPUT][0].width;
- if( compact )
- sizes[TEMP][0] = Size(min_size, min_size);
- else
- sizes[TEMP][0] = sizes[INPUT][0];
- sizes[TEMP][3] = Size(0,0);
- if( vector_w )
- {
- sizes[TEMP][3] = sizes[TEMP][0];
- if( bits & 256 )
- sizes[TEMP][0] = Size(1, min_size);
- else
- sizes[TEMP][0] = Size(min_size, 1);
- }
- if( have_u )
- {
- sizes[TEMP][1] = compact ? Size(min_size, m) : Size(m, m);
- if( flags & CV_SVD_U_T )
- CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
- }
- else
- sizes[TEMP][1] = Size(0,0);
- if( have_v )
- {
- sizes[TEMP][2] = compact ? Size(n, min_size) : Size(n, n);
- if( !(flags & CV_SVD_V_T) )
- CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
- }
- else
- sizes[TEMP][2] = Size(0,0);
- types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[TEMP][3] = types[INPUT][0];
- types[OUTPUT][0] = types[OUTPUT][1] = types[OUTPUT][2] = types[INPUT][0];
- types[OUTPUT][3] = CV_8UC1;
- sizes[OUTPUT][0] = !have_u || !have_v ? Size(0,0) : sizes[INPUT][0];
- sizes[OUTPUT][1] = !have_u ? Size(0,0) : compact ? Size(min_size,min_size) : Size(m,m);
- sizes[OUTPUT][2] = !have_v ? Size(0,0) : compact ? Size(min_size,min_size) : Size(n,n);
- sizes[OUTPUT][3] = Size(min_size,1);
- for( i = 0; i < 4; i++ )
- {
- sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
- types[REF_OUTPUT][i] = types[OUTPUT][i];
- }
- }
- int Core_SVDTest::prepare_test_case( int test_case_idx )
- {
- int code = Core_MatrixTest::prepare_test_case( test_case_idx );
- if( code > 0 )
- {
- Mat& input = test_mat[INPUT][0];
- cvTsFloodWithZeros( input, ts->get_rng() );
- if( symmetric && (have_u || have_v) )
- {
- Mat& temp = test_mat[TEMP][have_u ? 1 : 2];
- cvtest::gemm( input, input, 1., Mat(), 0., temp, CV_GEMM_B_T );
- cvtest::copy( temp, input );
- }
- if( (flags & CV_SVD_MODIFY_A) && test_array[OUTPUT][0] )
- cvtest::copy( input, test_mat[OUTPUT][0] );
- }
- return code;
- }
- void Core_SVDTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
- {
- low = cvScalarAll(-2.);
- high = cvScalarAll(2.);
- }
- double Core_SVDTest::get_success_error_level( int test_case_idx, int i, int j )
- {
- int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] ));
- double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? 1e-5 : 5e-11;
- double output_precision = Base::get_success_error_level( test_case_idx, i, j );
- return MAX(input_precision, output_precision);
- }
- void Core_SVDTest::run_func()
- {
- CvArr* src = test_array[!(flags & CV_SVD_MODIFY_A) ? INPUT : OUTPUT][0];
- if( !src )
- src = test_array[INPUT][0];
- cvSVD( src, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
- }
- void Core_SVDTest::prepare_to_validation( int /*test_case_idx*/ )
- {
- Mat& input = test_mat[INPUT][0];
- int depth = input.depth();
- int i, m = input.rows, n = input.cols, min_size = MIN(m, n);
- Mat *src, *dst, *w;
- double prev = 0, threshold = depth == CV_32F ? FLT_EPSILON : DBL_EPSILON;
- if( have_u )
- {
- src = &test_mat[TEMP][1];
- dst = &test_mat[OUTPUT][1];
- cvtest::gemm( *src, *src, 1., Mat(), 0., *dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
- cv::setIdentity( test_mat[REF_OUTPUT][1], Scalar::all(1.) );
- }
- if( have_v )
- {
- src = &test_mat[TEMP][2];
- dst = &test_mat[OUTPUT][2];
- cvtest::gemm( *src, *src, 1., Mat(), 0., *dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
- cv::setIdentity( test_mat[REF_OUTPUT][2], Scalar::all(1.) );
- }
- w = &test_mat[TEMP][0];
- for( i = 0; i < min_size; i++ )
- {
- double normval = 0, aii;
- if( w->rows > 1 && w->cols > 1 )
- {
- normval = cvtest::norm( w->row(i), NORM_L1 );
- aii = depth == CV_32F ? w->at<float>(i,i) : w->at<double>(i,i);
- }
- else
- {
- normval = aii = depth == CV_32F ? w->at<float>(i) : w->at<double>(i);
- }
- normval = fabs(normval - aii);
- test_mat[OUTPUT][3].at<uchar>(i) = aii >= 0 && normval < threshold && (i == 0 || aii <= prev);
- prev = aii;
- }
- test_mat[REF_OUTPUT][3] = Scalar::all(1);
- if( have_u && have_v )
- {
- if( vector_w )
- {
- test_mat[TEMP][3] = Scalar::all(0);
- for( i = 0; i < min_size; i++ )
- {
- double val = depth == CV_32F ? w->at<float>(i) : w->at<double>(i);
- cvSetReal2D( test_array[TEMP][3], i, i, val );
- }
- w = &test_mat[TEMP][3];
- }
- if( m >= n )
- {
- cvtest::gemm( test_mat[TEMP][1], *w, 1., Mat(), 0., test_mat[REF_OUTPUT][0],
- flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
- cvtest::gemm( test_mat[REF_OUTPUT][0], test_mat[TEMP][2], 1., Mat(), 0.,
- test_mat[OUTPUT][0], flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
- }
- else
- {
- cvtest::gemm( *w, test_mat[TEMP][2], 1., Mat(), 0., test_mat[REF_OUTPUT][0],
- flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
- cvtest::gemm( test_mat[TEMP][1], test_mat[REF_OUTPUT][0], 1., Mat(), 0.,
- test_mat[OUTPUT][0], flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
- }
- cvtest::copy( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] );
- }
- }
- ///////////////// SVBkSb /////////////////////
- class Core_SVBkSbTest : public Core_MatrixTest
- {
- public:
- typedef Core_MatrixTest Base;
- Core_SVBkSbTest();
- protected:
- void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
- double get_success_error_level( int test_case_idx, int i, int j );
- void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
- int prepare_test_case( int test_case_idx );
- void run_func();
- void prepare_to_validation( int test_case_idx );
- int flags;
- bool have_b, symmetric, compact, vector_w;
- };
- Core_SVBkSbTest::Core_SVBkSbTest() : Core_MatrixTest( 2, 1, false, false, 1 ),
- flags(0), have_b(false), symmetric(false), compact(false), vector_w(false)
- {
- test_case_count = 100;
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- test_array[TEMP].push_back(NULL);
- }
- void Core_SVBkSbTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes,
- vector<vector<int> >& types )
- {
- RNG& rng = ts->get_rng();
- int bits = cvtest::randInt(rng);
- Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
- int min_size, i, m, n;
- cv::Size b_size;
- min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
- flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
- have_b = (bits & 16) != 0;
- symmetric = (bits & 32) != 0;
- compact = (bits & 64) != 0;
- vector_w = (bits & 128) != 0;
- if( symmetric )
- sizes[INPUT][0] = Size(min_size, min_size);
- m = sizes[INPUT][0].height;
- n = sizes[INPUT][0].width;
- sizes[INPUT][1] = Size(0,0);
- b_size = cvSize(m, m);
- if( have_b )
- {
- sizes[INPUT][1].height = sizes[INPUT][0].height;
- sizes[INPUT][1].width = cvtest::randInt(rng) % 100 + 1;
- b_size = sizes[INPUT][1];
- }
- if( compact )
- sizes[TEMP][0] = Size(min_size, min_size);
- else
- sizes[TEMP][0] = sizes[INPUT][0];
- if( vector_w )
- {
- if( bits & 256 )
- sizes[TEMP][0] = Size(1, min_size);
- else
- sizes[TEMP][0] = Size(min_size, 1);
- }
- sizes[TEMP][1] = compact ? Size(min_size, m) : Size(m, m);
- if( flags & CV_SVD_U_T )
- CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
- sizes[TEMP][2] = compact ? Size(n, min_size) : Size(n, n);
- if( !(flags & CV_SVD_V_T) )
- CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
- types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
- types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0];
- sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size( b_size.width, n );
- }
- int Core_SVBkSbTest::prepare_test_case( int test_case_idx )
- {
- int code = Base::prepare_test_case( test_case_idx );
- if( code > 0 )
- {
- Mat& input = test_mat[INPUT][0];
- cvTsFloodWithZeros( input, ts->get_rng() );
- if( symmetric )
- {
- Mat& temp = test_mat[TEMP][1];
- cvtest::gemm( input, input, 1., Mat(), 0., temp, CV_GEMM_B_T );
- cvtest::copy( temp, input );
- }
- CvMat _input = cvMat(input);
- cvSVD( &_input, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
- }
- return code;
- }
- void Core_SVBkSbTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
- {
- low = cvScalarAll(-2.);
- high = cvScalarAll(2.);
- }
- double Core_SVBkSbTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
- {
- return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-3 : 1e-7;
- }
- void Core_SVBkSbTest::run_func()
- {
- cvSVBkSb( test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2],
- test_array[INPUT][1], test_array[OUTPUT][0], flags );
- }
- void Core_SVBkSbTest::prepare_to_validation( int )
- {
- Mat& input = test_mat[INPUT][0];
- int i, m = input.rows, n = input.cols, min_size = MIN(m, n);
- bool is_float = input.type() == CV_32F;
- Size w_size = compact ? Size(min_size,min_size) : Size(m,n);
- Mat& w = test_mat[TEMP][0];
- Mat wdb( w_size.height, w_size.width, CV_64FC1 );
- CvMat _w = cvMat(w), _wdb = cvMat(wdb);
- // use exactly the same threshold as in icvSVD... ,
- // so the changes in the library and here should be synchronized.
- double threshold = cv::sum(w)[0]*(DBL_EPSILON*2);//(is_float ? FLT_EPSILON*10 : DBL_EPSILON*2);
- wdb = Scalar::all(0);
- for( i = 0; i < min_size; i++ )
- {
- double wii = vector_w ? cvGetReal1D(&_w,i) : cvGetReal2D(&_w,i,i);
- cvSetReal2D( &_wdb, i, i, wii > threshold ? 1./wii : 0. );
- }
- Mat u = test_mat[TEMP][1];
- Mat v = test_mat[TEMP][2];
- Mat b = test_mat[INPUT][1];
- if( is_float )
- {
- test_mat[TEMP][1].convertTo(u, CV_64F);
- test_mat[TEMP][2].convertTo(v, CV_64F);
- if( !b.empty() )
- test_mat[INPUT][1].convertTo(b, CV_64F);
- }
- Mat t0, t1;
- if( !b.empty() )
- cvtest::gemm( u, b, 1., Mat(), 0., t0, !(flags & CV_SVD_U_T) ? CV_GEMM_A_T : 0 );
- else if( flags & CV_SVD_U_T )
- cvtest::copy( u, t0 );
- else
- cvtest::transpose( u, t0 );
- cvtest::gemm( wdb, t0, 1, Mat(), 0, t1, 0 );
- cvtest::gemm( v, t1, 1, Mat(), 0, t0, flags & CV_SVD_V_T ? CV_GEMM_A_T : 0 );
- Mat& dst0 = test_mat[REF_OUTPUT][0];
- t0.convertTo(dst0, dst0.type() );
- }
- typedef std::complex<double> complex_type;
- struct pred_complex
- {
- bool operator() (const complex_type& lhs, const complex_type& rhs) const
- {
- return fabs(lhs.real() - rhs.real()) > fabs(rhs.real())*FLT_EPSILON ? lhs.real() < rhs.real() : lhs.imag() < rhs.imag();
- }
- };
- struct pred_double
- {
- bool operator() (const double& lhs, const double& rhs) const
- {
- return lhs < rhs;
- }
- };
- class Core_SolvePolyTest : public cvtest::BaseTest
- {
- public:
- Core_SolvePolyTest();
- ~Core_SolvePolyTest();
- protected:
- virtual void run( int start_from );
- };
- Core_SolvePolyTest::Core_SolvePolyTest() {}
- Core_SolvePolyTest::~Core_SolvePolyTest() {}
- void Core_SolvePolyTest::run( int )
- {
- RNG& rng = ts->get_rng();
- int fig = 100;
- double range = 50;
- double err_eps = 1e-4;
- for (int idx = 0, max_idx = 1000, progress = 0; idx < max_idx; ++idx)
- {
- progress = update_progress(progress, idx-1, max_idx, 0);
- int n = cvtest::randInt(rng) % 13 + 1;
- std::vector<complex_type> r(n), ar(n), c(n + 1, 0);
- std::vector<double> a(n + 1), u(n * 2), ar1(n), ar2(n);
- int rr_odds = 3; // odds that we get a real root
- for (int j = 0; j < n;)
- {
- if (cvtest::randInt(rng) % rr_odds == 0 || j == n - 1)
- r[j++] = cvtest::randReal(rng) * range;
- else
- {
- r[j] = complex_type(cvtest::randReal(rng) * range,
- cvtest::randReal(rng) * range + 1);
- r[j + 1] = std::conj(r[j]);
- j += 2;
- }
- }
- for (int j = 0, k = 1 << n, jj, kk; j < k; ++j)
- {
- int p = 0;
- complex_type v(1);
- for (jj = 0, kk = 1; jj < n && !(j & kk); ++jj, ++p, kk <<= 1)
- ;
- for (; jj < n; ++jj, kk <<= 1)
- {
- if (j & kk)
- v *= -r[jj];
- else
- ++p;
- }
- c[p] += v;
- }
- bool pass = false;
- double div = 0, s = 0;
- int cubic_case = idx & 1;
- for (int maxiter = 100; !pass && maxiter < 10000; maxiter *= 2, cubic_case = (cubic_case + 1) % 2)
- {
- for (int j = 0; j < n + 1; ++j)
- a[j] = c[j].real();
- CvMat amat, umat;
- cvInitMatHeader(&amat, n + 1, 1, CV_64FC1, &a[0]);
- cvInitMatHeader(&umat, n, 1, CV_64FC2, &u[0]);
- cvSolvePoly(&amat, &umat, maxiter, fig);
- for (int j = 0; j < n; ++j)
- ar[j] = complex_type(u[j * 2], u[j * 2 + 1]);
- std::sort(r.begin(), r.end(), pred_complex());
- std::sort(ar.begin(), ar.end(), pred_complex());
- pass = true;
- if( n == 3 )
- {
- ar2.resize(n);
- cv::Mat _umat2(3, 1, CV_64F, &ar2[0]), umat2 = _umat2;
- cvFlip(&amat, &amat, 0);
- int nr2;
- if( cubic_case == 0 )
- nr2 = cv::solveCubic(cv::cvarrToMat(&amat),umat2);
- else
- nr2 = cv::solveCubic(cv::Mat_<float>(cv::cvarrToMat(&amat)), umat2);
- cvFlip(&amat, &amat, 0);
- if(nr2 > 0)
- std::sort(ar2.begin(), ar2.begin()+nr2, pred_double());
- ar2.resize(nr2);
- int nr1 = 0;
- for(int j = 0; j < n; j++)
- if( fabs(r[j].imag()) < DBL_EPSILON )
- ar1[nr1++] = r[j].real();
- pass = pass && nr1 == nr2;
- if( nr2 > 0 )
- {
- div = s = 0;
- for(int j = 0; j < nr1; j++)
- {
- s += fabs(ar1[j]);
- div += fabs(ar1[j] - ar2[j]);
- }
- div /= s;
- pass = pass && div < err_eps;
- }
- }
- div = s = 0;
- for (int j = 0; j < n; ++j)
- {
- s += fabs(r[j].real()) + fabs(r[j].imag());
- div += sqrt(pow(r[j].real() - ar[j].real(), 2) + pow(r[j].imag() - ar[j].imag(), 2));
- }
- div /= s;
- pass = pass && div < err_eps;
- }
- //test x^3 = 0
- cv::Mat coeffs_5623(4, 1, CV_64FC1);
- cv::Mat r_5623(3, 1, CV_64FC2);
- coeffs_5623.at<double>(0) = 1;
- coeffs_5623.at<double>(1) = 0;
- coeffs_5623.at<double>(2) = 0;
- coeffs_5623.at<double>(3) = 0;
- double prec_5623 = cv::solveCubic(coeffs_5623, r_5623);
- pass = pass && r_5623.at<double>(0) == 0 && r_5623.at<double>(1) == 0 && r_5623.at<double>(2) == 0;
- pass = pass && prec_5623 == 1;
- if (!pass)
- {
- ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
- ts->printf( cvtest::TS::LOG, "too big diff = %g\n", div );
- for (size_t j=0;j<ar2.size();++j)
- ts->printf( cvtest::TS::LOG, "ar2[%d]=%g\n", j, ar2[j]);
- ts->printf(cvtest::TS::LOG, "\n");
- for (size_t j=0;j<r.size();++j)
- ts->printf( cvtest::TS::LOG, "r[%d]=(%g, %g)\n", j, r[j].real(), r[j].imag());
- ts->printf( cvtest::TS::LOG, "\n" );
- for (size_t j=0;j<ar.size();++j)
- ts->printf( cvtest::TS::LOG, "ar[%d]=(%g, %g)\n", j, ar[j].real(), ar[j].imag());
- break;
- }
- }
- }
- template<typename T>
- static void checkRoot(Mat& r, T re, T im)
- {
- for (int i = 0; i < r.cols*r.rows; i++)
- {
- Vec<T, 2>& v = *(Vec<T, 2>*)r.ptr(i);
- if (fabs(re - v[0]) < 1e-6 && fabs(im - v[1]) < 1e-6)
- {
- v[0] = std::numeric_limits<T>::quiet_NaN();
- v[1] = std::numeric_limits<T>::quiet_NaN();
- return;
- }
- }
- GTEST_NONFATAL_FAILURE_("Can't find root") << "(" << re << ", " << im << ")";
- }
- TEST(Core_SolveCubicConstant, accuracy)
- {
- {
- const std::vector<double> coeffs{0., 0., 0., 1.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 0);
- }
- {
- const std::vector<double> coeffs{0., 0., 0., 0.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, -1);
- }
- }
- TEST(Core_SolveCubicLinear, accuracy)
- {
- const std::vector<double> coeffs{0., 0., 2., -2.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 1);
- EXPECT_EQ(roots[0], 1.);
- }
- TEST(Core_SolveCubicQuadratic, accuracy)
- {
- {
- const std::vector<double> coeffs{0., 2., -4., 4.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 0);
- }
- {
- const std::vector<double> coeffs{0., 2., -4., 2.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 1);
- EXPECT_EQ(roots[0], 1.);
- }
- {
- const std::vector<double> coeffs{0., 2., -6., 4.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 2);
- EXPECT_EQ(roots[0], 2.);
- EXPECT_EQ(roots[1], 1.);
- }
- }
- TEST(Core_SolveCubicCubic, accuracy)
- {
- {
- const std::vector<double> coeffs{2., -6., 6., -2.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 1);
- EXPECT_EQ(roots[0], 1.);
- }
- {
- const std::vector<double> coeffs{2., -10., 24., -16.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 1);
- EXPECT_NEAR(roots[0], 1., 1e-8);
- }
- {
- const std::vector<double> coeffs{2., -10., 16., -8.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_TRUE(num_roots == 2 || num_roots == 3);
- EXPECT_NEAR(roots[0], 1., 1e-8);
- EXPECT_NEAR(roots[1], 2., 1e-8);
- if (num_roots == 3)
- {
- EXPECT_NEAR(roots[2], 2., 1e-8);
- }
- }
- {
- const std::vector<double> coeffs{2., -12., 22., -12.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 3);
- EXPECT_NEAR(roots[0], 1., 1e-8);
- EXPECT_NEAR(roots[1], 3., 1e-8);
- EXPECT_NEAR(roots[2], 2., 1e-8);
- }
- }
- TEST(Core_SolveCubicNormalizedCubic, accuracy)
- {
- {
- const std::vector<double> coeffs{-3., 3., -1.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 1);
- EXPECT_EQ(roots[0], 1.);
- }
- {
- const std::vector<double> coeffs{-5., 12., -8.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 1);
- EXPECT_NEAR(roots[0], 1., 1e-8);
- }
- {
- const std::vector<double> coeffs{-5., 8., -4.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_TRUE(num_roots == 2 || num_roots == 3);
- EXPECT_NEAR(roots[0], 1., 1e-8);
- EXPECT_NEAR(roots[1], 2., 1e-8);
- if (num_roots == 3)
- {
- EXPECT_NEAR(roots[2], 2., 1e-8);
- }
- }
- {
- const std::vector<double> coeffs{-6., 11., -6.};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 3);
- EXPECT_NEAR(roots[0], 1., 1e-8);
- EXPECT_NEAR(roots[1], 3., 1e-8);
- EXPECT_NEAR(roots[2], 2., 1e-8);
- }
- }
- TEST(Core_SolveCubic, regression_27323)
- {
- {
- const std::vector<double> coeffs{2e-13, 1, -2, 1};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 1);
- EXPECT_EQ(roots[0], -5e12 - 2.);
- }
- {
- const std::vector<double> coeffs{5e12, -1e13, 5e12};
- std::vector<double> roots;
- const auto num_roots = solveCubic(coeffs, roots);
- EXPECT_EQ(num_roots, 1);
- EXPECT_EQ(roots[0], -5e12 - 2.);
- }
- }
- TEST(Core_SolveCubic, regression_27748)
- {
- // a is extremely small relative to others (approx 1.8e-19 ratio),
- // causing instability in standard cubic formula.
- double a = 1.56041e-17;
- double b = 84.4504;
- double c = -96.795;
- double d = 13.6826;
- Mat coeffs = (Mat_<double>(1, 4) << a, b, c, d);
- Mat roots;
- int n = solveCubic(coeffs, roots);
- // Expecting quadratic behavior (2 roots)
- EXPECT_GE(n, 2);
- // Verify roots satisfy the FULL cubic equation
- for(int i = 0; i < n; i++)
- {
- double x = roots.at<double>(i);
- double val = a*x*x*x + b*x*x + c*x + d;
- // Check residual is small
- EXPECT_LE(fabs(val), 1e-6) << "Root " << x << " does not satisfy the equation";
- }
- }
- TEST(Core_SolvePoly, regression_5599)
- {
- // x^4 - x^2 = 0, roots: 1, -1, 0, 0
- cv::Mat coefs = (cv::Mat_<float>(1,5) << 0, 0, -1, 0, 1 );
- {
- cv::Mat r;
- double prec;
- prec = cv::solvePoly(coefs, r);
- EXPECT_LE(prec, 1e-6);
- EXPECT_EQ(4u, r.total());
- //std::cout << "Preciseness = " << prec << std::endl;
- //std::cout << "roots:\n" << r << "\n" << std::endl;
- ASSERT_EQ(CV_32FC2, r.type());
- checkRoot<float>(r, 1, 0);
- checkRoot<float>(r, -1, 0);
- checkRoot<float>(r, 0, 0);
- checkRoot<float>(r, 0, 0);
- }
- // x^2 - 2x + 1 = 0, roots: 1, 1
- coefs = (cv::Mat_<float>(1,3) << 1, -2, 1 );
- {
- cv::Mat r;
- double prec;
- prec = cv::solvePoly(coefs, r);
- EXPECT_LE(prec, 1e-6);
- EXPECT_EQ(2u, r.total());
- //std::cout << "Preciseness = " << prec << std::endl;
- //std::cout << "roots:\n" << r << "\n" << std::endl;
- ASSERT_EQ(CV_32FC2, r.type());
- checkRoot<float>(r, 1, 0);
- checkRoot<float>(r, 1, 0);
- }
- }
- class Core_PhaseTest : public cvtest::BaseTest
- {
- int t;
- public:
- Core_PhaseTest(int t_) : t(t_) {}
- ~Core_PhaseTest() {}
- protected:
- virtual void run(int)
- {
- const float maxAngleDiff = 0.5; //in degrees
- const int axisCount = 8;
- const int dim = theRNG().uniform(1,10);
- const float scale = theRNG().uniform(1.f, 100.f);
- Mat x(axisCount + 1, dim, t),
- y(axisCount + 1, dim, t);
- Mat anglesInDegrees(axisCount + 1, dim, t);
- // fill the data
- x.row(0).setTo(Scalar(0));
- y.row(0).setTo(Scalar(0));
- anglesInDegrees.row(0).setTo(Scalar(0));
- x.row(1).setTo(Scalar(scale));
- y.row(1).setTo(Scalar(0));
- anglesInDegrees.row(1).setTo(Scalar(0));
- x.row(2).setTo(Scalar(scale));
- y.row(2).setTo(Scalar(scale));
- anglesInDegrees.row(2).setTo(Scalar(45));
- x.row(3).setTo(Scalar(0));
- y.row(3).setTo(Scalar(scale));
- anglesInDegrees.row(3).setTo(Scalar(90));
- x.row(4).setTo(Scalar(-scale));
- y.row(4).setTo(Scalar(scale));
- anglesInDegrees.row(4).setTo(Scalar(135));
- x.row(5).setTo(Scalar(-scale));
- y.row(5).setTo(Scalar(0));
- anglesInDegrees.row(5).setTo(Scalar(180));
- x.row(6).setTo(Scalar(-scale));
- y.row(6).setTo(Scalar(-scale));
- anglesInDegrees.row(6).setTo(Scalar(225));
- x.row(7).setTo(Scalar(0));
- y.row(7).setTo(Scalar(-scale));
- anglesInDegrees.row(7).setTo(Scalar(270));
- x.row(8).setTo(Scalar(scale));
- y.row(8).setTo(Scalar(-scale));
- anglesInDegrees.row(8).setTo(Scalar(315));
- Mat resInRad, resInDeg;
- phase(x, y, resInRad, false);
- phase(x, y, resInDeg, true);
- CV_Assert(resInRad.size() == x.size());
- CV_Assert(resInRad.type() == x.type());
- CV_Assert(resInDeg.size() == x.size());
- CV_Assert(resInDeg.type() == x.type());
- // check the result
- int outOfRangeCount = countNonZero((resInDeg > 360) | (resInDeg < 0));
- if(outOfRangeCount > 0)
- {
- ts->printf(cvtest::TS::LOG, "There are result angles that are out of range [0, 360] (part of them is %f)\n",
- static_cast<float>(outOfRangeCount)/resInDeg.total());
- ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
- }
- Mat diff = abs(anglesInDegrees - resInDeg);
- size_t errDegCount = diff.total() - countNonZero((diff < maxAngleDiff) | ((360 - diff) < maxAngleDiff));
- if(errDegCount > 0)
- {
- ts->printf(cvtest::TS::LOG, "There are incorrect result angles (in degrees) (part of them is %f)\n",
- static_cast<float>(errDegCount)/resInDeg.total());
- ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
- }
- Mat convertedRes = resInRad * 180. / CV_PI;
- double normDiff = cvtest::norm(convertedRes - resInDeg, NORM_INF);
- if(normDiff > FLT_EPSILON * 180.)
- {
- ts->printf(cvtest::TS::LOG, "There are incorrect result angles (in radians)\n");
- ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
- }
- ts->set_failed_test_info(cvtest::TS::OK);
- }
- };
- TEST(Core_CheckRange_Empty, accuracy)
- {
- cv::Mat m;
- ASSERT_TRUE( cv::checkRange(m) );
- }
- TEST(Core_CheckRange_INT_MAX, accuracy)
- {
- cv::Mat m(3, 3, CV_32SC1, cv::Scalar(INT_MAX));
- ASSERT_FALSE( cv::checkRange(m, true, 0, 0, INT_MAX) );
- ASSERT_TRUE( cv::checkRange(m) );
- }
- TEST(Core_CheckRange_INT_MAX1, accuracy)
- {
- cv::Mat m(3, 3, CV_32SC1, cv::Scalar(INT_MAX));
- ASSERT_TRUE( cv::checkRange(m, true, 0, 0, (float)((double)INT_MAX+1.0f)) );
- ASSERT_TRUE( cv::checkRange(m) );
- }
- template <typename T> class Core_CheckRange : public testing::Test {};
- TYPED_TEST_CASE_P(Core_CheckRange);
- TYPED_TEST_P(Core_CheckRange, Negative)
- {
- double min_bound = 4.5;
- double max_bound = 16.0;
- TypeParam data[] = {5, 10, 15, 10, 10, 2, 8, 12, 14};
- cv::Mat src = cv::Mat(3,3, cv::DataDepth<TypeParam>::value, data);
- cv::Point bad_pt(0, 0);
- ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound));
- ASSERT_EQ(bad_pt.x, 2);
- ASSERT_EQ(bad_pt.y, 1);
- }
- TYPED_TEST_P(Core_CheckRange, Negative3CN)
- {
- double min_bound = 4.5;
- double max_bound = 16.0;
- TypeParam data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
- 10, 11, 12, 10, 11, 12, 2, 5, 6,
- 8, 8, 8, 12, 12, 12, 14, 14, 14};
- cv::Mat src = cv::Mat(3,3, CV_MAKETYPE(cv::DataDepth<TypeParam>::value, 3), data);
- cv::Point bad_pt(0, 0);
- ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound));
- ASSERT_EQ(bad_pt.x, 2);
- ASSERT_EQ(bad_pt.y, 1);
- }
- TYPED_TEST_P(Core_CheckRange, Positive)
- {
- double min_bound = -1;
- double max_bound = 16.0;
- TypeParam data[] = {5, 10, 15, 4, 10, 2, 8, 12, 14};
- cv::Mat src = cv::Mat(3,3, cv::DataDepth<TypeParam>::value, data);
- cv::Point bad_pt(0, 0);
- ASSERT_TRUE(checkRange(src, true, &bad_pt, min_bound, max_bound));
- ASSERT_EQ(bad_pt.x, 0);
- ASSERT_EQ(bad_pt.y, 0);
- }
- TYPED_TEST_P(Core_CheckRange, Bounds)
- {
- double min_bound = 24.5;
- double max_bound = 1.0;
- TypeParam data[] = {5, 10, 15, 4, 10, 2, 8, 12, 14};
- cv::Mat src = cv::Mat(3,3, cv::DataDepth<TypeParam>::value, data);
- cv::Point bad_pt(0, 0);
- ASSERT_FALSE(checkRange(src, true, &bad_pt, min_bound, max_bound));
- ASSERT_EQ(bad_pt.x, 0);
- ASSERT_EQ(bad_pt.y, 0);
- }
- TYPED_TEST_P(Core_CheckRange, Zero)
- {
- double min_bound = 0.0;
- double max_bound = 0.1;
- cv::Mat src1 = cv::Mat::zeros(3, 3, cv::DataDepth<TypeParam>::value);
- int sizes[] = {5, 6, 7};
- cv::Mat src2 = cv::Mat::zeros(3, sizes, cv::DataDepth<TypeParam>::value);
- ASSERT_TRUE( checkRange(src1, true, NULL, min_bound, max_bound) );
- ASSERT_TRUE( checkRange(src2, true, NULL, min_bound, max_bound) );
- }
- TYPED_TEST_P(Core_CheckRange, One)
- {
- double min_bound = 1.0;
- double max_bound = 1.1;
- cv::Mat src1 = cv::Mat::ones(3, 3, cv::DataDepth<TypeParam>::value);
- int sizes[] = {5, 6, 7};
- cv::Mat src2 = cv::Mat::ones(3, sizes, cv::DataDepth<TypeParam>::value);
- ASSERT_TRUE( checkRange(src1, true, NULL, min_bound, max_bound) );
- ASSERT_TRUE( checkRange(src2, true, NULL, min_bound, max_bound) );
- }
- TEST(Core_CheckRange, NaN)
- {
- float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
- 10, 11, 12, 10, 11, 12, 5, 5, std::numeric_limits<float>::quiet_NaN(),
- 8, 8, 8, 12, 12, 12, 14, 14, 14};
- cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
- cv::Point bad_pt(0, 0);
- ASSERT_FALSE(checkRange(src, true, &bad_pt));
- ASSERT_EQ(bad_pt.x, 2);
- ASSERT_EQ(bad_pt.y, 1);
- }
- TEST(Core_CheckRange, Inf)
- {
- float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
- 10, 11, 12, 10, 11, 12, 5, 5, std::numeric_limits<float>::infinity(),
- 8, 8, 8, 12, 12, 12, 14, 14, 14};
- cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
- cv::Point bad_pt(0, 0);
- ASSERT_FALSE(checkRange(src, true, &bad_pt));
- ASSERT_EQ(bad_pt.x, 2);
- ASSERT_EQ(bad_pt.y, 1);
- }
- TEST(Core_CheckRange, Inf_Minus)
- {
- float data[] = { 5, 6, 7, 10, 11, 12, 13, 14, 15,
- 10, 11, 12, 10, 11, 12, 5, 5, -std::numeric_limits<float>::infinity(),
- 8, 8, 8, 12, 12, 12, 14, 14, 14};
- cv::Mat src = cv::Mat(3,3, CV_32FC3, data);
- cv::Point bad_pt(0, 0);
- ASSERT_FALSE(checkRange(src, true, &bad_pt));
- ASSERT_EQ(bad_pt.x, 2);
- ASSERT_EQ(bad_pt.y, 1);
- }
- REGISTER_TYPED_TEST_CASE_P(Core_CheckRange, Negative, Negative3CN, Positive, Bounds, Zero, One);
- typedef ::testing::Types<signed char,unsigned char, signed short, unsigned short, signed int> mat_data_types;
- INSTANTIATE_TYPED_TEST_CASE_P(Negative_Test, Core_CheckRange, mat_data_types);
- TEST(Core_Invert, small)
- {
- cv::Mat a = (cv::Mat_<float>(3,3) << 2.42104644730331, 1.81444796521479, -3.98072565304758, 0, 7.08389214348967e-3, 5.55326770986007e-3, 0,0, 7.44556154284261e-3);
- //cv::randu(a, -1, 1);
- cv::Mat b = a.t()*a;
- cv::Mat c, i = Mat_<float>::eye(3, 3);
- cv::invert(b, c, cv::DECOMP_LU); //std::cout << b*c << std::endl;
- ASSERT_LT( cvtest::norm(b*c, i, CV_C), 0.1 );
- cv::invert(b, c, cv::DECOMP_SVD); //std::cout << b*c << std::endl;
- ASSERT_LT( cvtest::norm(b*c, i, CV_C), 0.1 );
- cv::invert(b, c, cv::DECOMP_CHOLESKY); //std::cout << b*c << std::endl;
- ASSERT_LT( cvtest::norm(b*c, i, CV_C), 0.1 );
- }
- /////////////////////////////////////////////////////////////////////////////////////////////////////
- TEST(Core_CovarMatrix, accuracy) { Core_CovarMatrixTest test; test.safe_run(); }
- TEST(Core_CrossProduct, accuracy) { Core_CrossProductTest test; test.safe_run(); }
- TEST(Core_Determinant, accuracy) { Core_DetTest test; test.safe_run(); }
- TEST(Core_DotProduct, accuracy) { Core_DotProductTest test; test.safe_run(); }
- TEST(Core_GEMM, accuracy) { Core_GEMMTest test; test.safe_run(); }
- TEST(Core_Invert, accuracy) { Core_InvertTest test; test.safe_run(); }
- TEST(Core_Mahalanobis, accuracy) { Core_MahalanobisTest test; test.safe_run(); }
- TEST(Core_MulTransposed, accuracy) { Core_MulTransposedTest test; test.safe_run(); }
- TEST(Core_Transform, accuracy) { Core_TransformTest test; test.safe_run(); }
- TEST(Core_TransformLarge, accuracy) { Core_TransformLargeTest test; test.safe_run(); }
- TEST(Core_PerspectiveTransform, accuracy) { Core_PerspectiveTransformTest test; test.safe_run(); }
- TEST(Core_Pow, accuracy) { Core_PowTest test; test.safe_run(); }
- TEST(Core_SolveLinearSystem, accuracy) { Core_SolveTest test; test.safe_run(); }
- TEST(Core_SVD, accuracy) { Core_SVDTest test; test.safe_run(); }
- TEST(Core_SVBkSb, accuracy) { Core_SVBkSbTest test; test.safe_run(); }
- TEST(Core_Trace, accuracy) { Core_TraceTest test; test.safe_run(); }
- TEST(Core_SolvePoly, accuracy) { Core_SolvePolyTest test; test.safe_run(); }
- TEST(Core_Phase, accuracy32f) { Core_PhaseTest test(CV_32FC1); test.safe_run(); }
- TEST(Core_Phase, accuracy64f) { Core_PhaseTest test(CV_64FC1); test.safe_run(); }
- TEST(Core_SVD, flt)
- {
- float a[] = {
- 1.23377746e+011f, -7.05490125e+010f, -4.18380882e+010f, -11693456.f,
- -39091328.f, 77492224.f, -7.05490125e+010f, 2.36211143e+011f,
- -3.51093473e+010f, 70773408.f, -4.83386156e+005f, -129560368.f,
- -4.18380882e+010f, -3.51093473e+010f, 9.25311222e+010f, -49052424.f,
- 43922752.f, 12176842.f, -11693456.f, 70773408.f, -49052424.f, 8.40836094e+004f,
- 5.17475293e+003f, -1.16122949e+004f, -39091328.f, -4.83386156e+005f,
- 43922752.f, 5.17475293e+003f, 5.16047969e+004f, 5.68887842e+003f, 77492224.f,
- -129560368.f, 12176842.f, -1.16122949e+004f, 5.68887842e+003f,
- 1.28060578e+005f
- };
- float b[] = {
- 283751232.f, 2.61604198e+009f, -745033216.f, 2.31125625e+005f,
- -4.52429188e+005f, -1.37596525e+006f
- };
- Mat A(6, 6, CV_32F, a);
- Mat B(6, 1, CV_32F, b);
- Mat X, B1;
- solve(A, B, X, DECOMP_SVD);
- B1 = A*X;
- EXPECT_LE(cvtest::norm(B1, B, NORM_L2 + NORM_RELATIVE), FLT_EPSILON*10);
- }
- // TODO: eigenvv, invsqrt, cbrt, fastarctan, (round, floor, ceil(?)),
- enum
- {
- MAT_N_DIM_C1,
- MAT_N_1_CDIM,
- MAT_1_N_CDIM,
- MAT_N_DIM_C1_NONCONT,
- MAT_N_1_CDIM_NONCONT,
- VECTOR
- };
- class CV_KMeansSingularTest : public cvtest::BaseTest
- {
- public:
- CV_KMeansSingularTest() {}
- ~CV_KMeansSingularTest() {}
- protected:
- void run(int inVariant)
- {
- RNG& rng = ts->get_rng();
- int i, iter = 0, N = 0, N0 = 0, K = 0, dims = 0;
- Mat labels;
- {
- const int MAX_DIM=5;
- int MAX_POINTS = 100, maxIter = 100;
- for( iter = 0; iter < maxIter; iter++ )
- {
- ts->update_context(this, iter, true);
- dims = rng.uniform(inVariant == MAT_1_N_CDIM ? 2 : 1, MAX_DIM+1);
- N = rng.uniform(2, MAX_POINTS+1);
- N0 = rng.uniform(1, MAX(N/10, 2));
- K = rng.uniform(1, N+1);
- Mat centers;
- if (inVariant == VECTOR)
- {
- dims = 2;
- std::vector<cv::Point2f> data0(N0);
- rng.fill(data0, RNG::UNIFORM, -1, 1);
- std::vector<cv::Point2f> data(N);
- for( i = 0; i < N; i++ )
- data[i] = data0[rng.uniform(0, N0)];
- kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0),
- 5, KMEANS_PP_CENTERS, centers);
- }
- else
- {
- Mat data0(N0, dims, CV_32F);
- rng.fill(data0, RNG::UNIFORM, -1, 1);
- Mat data;
- switch (inVariant)
- {
- case MAT_N_DIM_C1:
- data.create(N, dims, CV_32F);
- for( i = 0; i < N; i++ )
- data0.row(rng.uniform(0, N0)).copyTo(data.row(i));
- break;
- case MAT_N_1_CDIM:
- data.create(N, 1, CV_32FC(dims));
- for( i = 0; i < N; i++ )
- memcpy(data.ptr(i), data0.ptr(rng.uniform(0, N0)), dims * sizeof(float));
- break;
- case MAT_1_N_CDIM:
- data.create(1, N, CV_32FC(dims));
- for( i = 0; i < N; i++ )
- memcpy(data.ptr() + i * dims * sizeof(float), data0.ptr(rng.uniform(0, N0)), dims * sizeof(float));
- break;
- case MAT_N_DIM_C1_NONCONT:
- data.create(N, dims + 5, CV_32F);
- data = data(Range(0, N), Range(0, dims));
- for( i = 0; i < N; i++ )
- data0.row(rng.uniform(0, N0)).copyTo(data.row(i));
- break;
- case MAT_N_1_CDIM_NONCONT:
- data.create(N, 3, CV_32FC(dims));
- data = data.colRange(0, 1);
- for( i = 0; i < N; i++ )
- memcpy(data.ptr(i), data0.ptr(rng.uniform(0, N0)), dims * sizeof(float));
- break;
- }
- kmeans(data, K, labels, TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 0),
- 5, KMEANS_PP_CENTERS, centers);
- }
- ASSERT_EQ(centers.rows, K);
- ASSERT_EQ(labels.rows, N);
- Mat hist(K, 1, CV_32S, Scalar(0));
- for( i = 0; i < N; i++ )
- {
- int l = labels.at<int>(i);
- ASSERT_GE(l, 0);
- ASSERT_LT(l, K);
- hist.at<int>(l)++;
- }
- for( i = 0; i < K; i++ )
- ASSERT_GT(hist.at<int>(i), 0);
- }
- }
- }
- };
- TEST(Core_KMeans, singular) { CV_KMeansSingularTest test; test.safe_run(MAT_N_DIM_C1); }
- CV_ENUM(KMeansInputVariant, MAT_N_DIM_C1, MAT_N_1_CDIM, MAT_1_N_CDIM, MAT_N_DIM_C1_NONCONT, MAT_N_1_CDIM_NONCONT, VECTOR)
- typedef testing::TestWithParam<KMeansInputVariant> Core_KMeans_InputVariants;
- TEST_P(Core_KMeans_InputVariants, singular)
- {
- CV_KMeansSingularTest test;
- test.safe_run(GetParam());
- }
- INSTANTIATE_TEST_CASE_P(AllVariants, Core_KMeans_InputVariants, KMeansInputVariant::all());
- TEST(Core_KMeans, compactness)
- {
- const int N = 1024;
- const int attempts = 4;
- const TermCriteria crit = TermCriteria(TermCriteria::COUNT, 5, 0); // low number of iterations
- cvtest::TS& ts = *cvtest::TS::ptr();
- for (int K = 1; K <= N; K *= 2)
- {
- Mat data(N, 1, CV_32FC2);
- cvtest::randUni(ts.get_rng(), data, Scalar(-200, -200), Scalar(200, 200));
- Mat labels, centers;
- double compactness = kmeans(data, K, labels, crit, attempts, KMEANS_PP_CENTERS, centers);
- centers = centers.reshape(2);
- EXPECT_EQ(labels.rows, N);
- EXPECT_EQ(centers.rows, K);
- EXPECT_GE(compactness, 0.0);
- double expected = 0.0;
- for (int i = 0; i < N; ++i)
- {
- int l = labels.at<int>(i);
- Point2f d = data.at<Point2f>(i) - centers.at<Point2f>(l);
- expected += d.x * d.x + d.y * d.y;
- }
- EXPECT_NEAR(expected, compactness, expected * 1e-8);
- if (K == N)
- {
- EXPECT_DOUBLE_EQ(compactness, 0.0);
- }
- }
- }
- TEST(Core_KMeans, bad_input)
- {
- const int N = 100;
- const int attempts = 4;
- const TermCriteria crit = TermCriteria(TermCriteria::COUNT, 5, 0); // low number of iterations
- const int K = 3;
- Mat data(N, 1, CV_32FC2);
- cv::randu(data, Scalar(-200, -200), Scalar(200, 200));
- {
- SCOPED_TRACE("Huge value");
- data.at<Vec2f>(10, 0) = Vec2f(1e20f, 0);
- Mat labels, centers;
- EXPECT_ANY_THROW(kmeans(data, K, labels, crit, attempts, KMEANS_PP_CENTERS, centers));
- }
- {
- SCOPED_TRACE("Negative value");
- data.at<Vec2f>(10, 0) = Vec2f(0, -1e20f);
- Mat labels, centers;
- EXPECT_ANY_THROW(kmeans(data, K, labels, crit, attempts, KMEANS_PP_CENTERS, centers));
- }
- {
- SCOPED_TRACE("NaN");
- data.at<Vec2f>(10, 0) = Vec2f(0, std::numeric_limits<float>::quiet_NaN());
- Mat labels, centers;
- EXPECT_ANY_THROW(kmeans(data, K, labels, crit, attempts, KMEANS_PP_CENTERS, centers));
- }
- }
- TEST(CovariationMatrixVectorOfMat, accuracy)
- {
- unsigned int col_problem_size = 8, row_problem_size = 8, vector_size = 16;
- cv::Mat src(vector_size, col_problem_size * row_problem_size, CV_32F);
- int singleMatFlags = CV_COVAR_ROWS;
- cv::Mat gold;
- cv::Mat goldMean;
- cv::randu(src,cv::Scalar(-128), cv::Scalar(128));
- cv::calcCovarMatrix(src,gold,goldMean,singleMatFlags,CV_32F);
- std::vector<cv::Mat> srcVec;
- for(size_t i = 0; i < vector_size; i++)
- {
- srcVec.push_back(src.row(static_cast<int>(i)).reshape(0,col_problem_size));
- }
- cv::Mat actual;
- cv::Mat actualMean;
- cv::calcCovarMatrix(srcVec, actual, actualMean,singleMatFlags,CV_32F);
- cv::Mat diff;
- cv::absdiff(gold, actual, diff);
- cv::Scalar s = cv::sum(diff);
- ASSERT_EQ(s.dot(s), 0.0);
- cv::Mat meanDiff;
- cv::absdiff(goldMean, actualMean.reshape(0,1), meanDiff);
- cv::Scalar sDiff = cv::sum(meanDiff);
- ASSERT_EQ(sDiff.dot(sDiff), 0.0);
- }
- TEST(CovariationMatrixVectorOfMatWithMean, accuracy)
- {
- unsigned int col_problem_size = 8, row_problem_size = 8, vector_size = 16;
- cv::Mat src(vector_size, col_problem_size * row_problem_size, CV_32F);
- int singleMatFlags = CV_COVAR_ROWS | CV_COVAR_USE_AVG;
- cv::Mat gold;
- cv::randu(src,cv::Scalar(-128), cv::Scalar(128));
- cv::Mat goldMean;
- cv::reduce(src, goldMean, 0, REDUCE_AVG, CV_32F);
- cv::calcCovarMatrix(src,gold,goldMean,singleMatFlags,CV_32F);
- std::vector<cv::Mat> srcVec;
- for(size_t i = 0; i < vector_size; i++)
- {
- srcVec.push_back(src.row(static_cast<int>(i)).reshape(0,col_problem_size));
- }
- cv::Mat actual;
- cv::Mat actualMean = goldMean.reshape(0, row_problem_size);
- cv::calcCovarMatrix(srcVec, actual, actualMean,singleMatFlags,CV_32F);
- cv::Mat diff;
- cv::absdiff(gold, actual, diff);
- cv::Scalar s = cv::sum(diff);
- ASSERT_EQ(s.dot(s), 0.0);
- cv::Mat meanDiff;
- cv::absdiff(goldMean, actualMean.reshape(0,1), meanDiff);
- cv::Scalar sDiff = cv::sum(meanDiff);
- ASSERT_EQ(sDiff.dot(sDiff), 0.0);
- }
- TEST(Core_Pow, special)
- {
- for( int i = 0; i < 100; i++ )
- {
- int n = theRNG().uniform(1, 30);
- Mat mtx0(1, n, CV_8S), mtx, result;
- randu(mtx0, -5, 5);
- int type = theRNG().uniform(0, 2) ? CV_64F : CV_32F;
- double eps = type == CV_32F ? 1e-3 : 1e-10;
- mtx0.convertTo(mtx, type);
- // generate power from [-n, n] interval with 1/8 step - enough to check various cases.
- const int max_pf = 3;
- int pf = theRNG().uniform(0, max_pf*2+1);
- double power = ((1 << pf) - (1 << (max_pf*2-1)))/16.;
- int ipower = cvRound(power);
- bool is_ipower = ipower == power;
- cv::pow(mtx, power, result);
- for( int j = 0; j < n; j++ )
- {
- double val = type == CV_32F ? (double)mtx.at<float>(j) : mtx.at<double>(j);
- double r = type == CV_32F ? (double)result.at<float>(j) : result.at<double>(j);
- double r0;
- if( power == 0. )
- r0 = 1;
- else if( is_ipower )
- {
- r0 = 1;
- for( int k = 0; k < std::abs(ipower); k++ )
- r0 *= val;
- if( ipower < 0 )
- r0 = 1./r0;
- }
- else
- r0 = std::pow(val, power);
- if( cvIsInf(r0) )
- {
- ASSERT_TRUE(cvIsInf(r) != 0);
- }
- else if( cvIsNaN(r0) )
- {
- ASSERT_TRUE(cvIsNaN(r) != 0);
- }
- else
- {
- ASSERT_TRUE(cvIsInf(r) == 0 && cvIsNaN(r) == 0);
- ASSERT_LT(fabs(r - r0), eps);
- }
- }
- }
- }
- TEST(Core_Cholesky, accuracy64f)
- {
- const int n = 5;
- Mat A(n, n, CV_64F), refA;
- Mat mean(1, 1, CV_64F);
- *mean.ptr<double>() = 10.0;
- Mat dev(1, 1, CV_64F);
- *dev.ptr<double>() = 10.0;
- RNG rng(10);
- rng.fill(A, RNG::NORMAL, mean, dev);
- A = A*A.t();
- A.copyTo(refA);
- Cholesky(A.ptr<double>(), A.step, n, NULL, 0, 0);
- for (int i = 0; i < A.rows; i++)
- for (int j = i + 1; j < A.cols; j++)
- A.at<double>(i, j) = 0.0;
- EXPECT_LE(cvtest::norm(refA, A*A.t(), CV_RELATIVE_L2), FLT_EPSILON);
- }
- TEST(Core_QR_Solver, accuracy64f)
- {
- int m = 20, n = 18;
- Mat A(m, m, CV_64F);
- Mat B(m, n, CV_64F);
- Mat mean(1, 1, CV_64F);
- *mean.ptr<double>() = 10.0;
- Mat dev(1, 1, CV_64F);
- *dev.ptr<double>() = 10.0;
- RNG rng(10);
- rng.fill(A, RNG::NORMAL, mean, dev);
- rng.fill(B, RNG::NORMAL, mean, dev);
- A = A*A.t();
- Mat solutionQR;
- //solve system with square matrix
- solve(A, B, solutionQR, DECOMP_QR);
- EXPECT_LE(cvtest::norm(A*solutionQR, B, CV_RELATIVE_L2), FLT_EPSILON);
- A = Mat(m, n, CV_64F);
- B = Mat(m, n, CV_64F);
- rng.fill(A, RNG::NORMAL, mean, dev);
- rng.fill(B, RNG::NORMAL, mean, dev);
- //solve normal system
- solve(A, B, solutionQR, DECOMP_QR | DECOMP_NORMAL);
- EXPECT_LE(cvtest::norm(A.t()*(A*solutionQR), A.t()*B, CV_RELATIVE_L2), FLT_EPSILON);
- //solve overdeterminated system as a least squares problem
- Mat solutionSVD;
- solve(A, B, solutionQR, DECOMP_QR);
- solve(A, B, solutionSVD, DECOMP_SVD);
- EXPECT_LE(cvtest::norm(solutionQR, solutionSVD, CV_RELATIVE_L2), FLT_EPSILON);
- //solve system with singular matrix
- A = Mat(10, 10, CV_64F);
- B = Mat(10, 1, CV_64F);
- rng.fill(A, RNG::NORMAL, mean, dev);
- rng.fill(B, RNG::NORMAL, mean, dev);
- for (int i = 0; i < A.cols; i++)
- A.at<double>(0, i) = A.at<double>(1, i);
- ASSERT_FALSE(solve(A, B, solutionQR, DECOMP_QR));
- }
- TEST(Core_Solve, regression_11888)
- {
- cv::Matx<float, 3, 2> A(
- 2, 1,
- 3, 1,
- 6, 1
- );
- cv::Vec<float, 3> b(4, 5, 7);
- cv::Matx<float, 2, 1> xQR = A.solve(b, DECOMP_QR);
- cv::Matx<float, 2, 1> xSVD = A.solve(b, DECOMP_SVD);
- EXPECT_LE(cvtest::norm(xQR, xSVD, NORM_L2 | NORM_RELATIVE), 0.001);
- cv::Matx<float, 2, 3> iA = A.inv(DECOMP_SVD);
- EXPECT_LE(cvtest::norm(iA*A, Matx<float, 2, 2>::eye(), NORM_L2), 1e-3);
- EXPECT_ANY_THROW({
- /*cv::Matx<float, 2, 1> xLU =*/ A.solve(b, DECOMP_LU);
- std::cout << "FATAL ERROR" << std::endl;
- });
- }
- TEST(Core_Solve, Matx_2_2)
- {
- cv::Matx<float, 2, 2> A(
- 2, 1,
- 1, 1
- );
- cv::Vec<float, 2> b(4, 5);
- cv::Matx<float, 2, 1> xLU = A.solve(b, DECOMP_LU);
- cv::Matx<float, 2, 1> xQR = A.solve(b, DECOMP_QR);
- cv::Matx<float, 2, 1> xSVD = A.solve(b, DECOMP_SVD);
- EXPECT_LE(cvtest::norm(xQR, xSVD, NORM_L2 | NORM_RELATIVE), 1e-3);
- EXPECT_LE(cvtest::norm(xQR, xLU, NORM_L2 | NORM_RELATIVE), 1e-3);
- cv::Matx<float, 2, 2> iA = A.inv(DECOMP_SVD);
- EXPECT_LE(cvtest::norm(iA*A, Matx<float, 2, 2>::eye(), NORM_L2), 1e-3);
- }
- TEST(Core_Solve, Matx_3_3)
- {
- cv::Matx<float, 3, 3> A(
- 2, 1, 0,
- 0, 1, 1,
- 1, 0, 1
- );
- cv::Vec<float, 3> b(4, 5, 6);
- cv::Matx<float, 3, 1> xLU = A.solve(b, DECOMP_LU);
- cv::Matx<float, 3, 1> xQR = A.solve(b, DECOMP_QR);
- cv::Matx<float, 3, 1> xSVD = A.solve(b, DECOMP_SVD);
- EXPECT_LE(cvtest::norm(xQR, xSVD, NORM_L2 | NORM_RELATIVE), 1e-3);
- EXPECT_LE(cvtest::norm(xQR, xLU, NORM_L2 | NORM_RELATIVE), 1e-3);
- cv::Matx<float, 3, 3> iA = A.inv(DECOMP_SVD);
- EXPECT_LE(cvtest::norm(iA*A, Matx<float, 3, 3>::eye(), NORM_L2), 1e-3);
- }
- TEST(Core_Solve, Matx_4_4)
- {
- cv::Matx<float, 4, 4> A(
- 2, 1, 0, 4,
- 0, 1, 1, 3,
- 1, 0, 1, 2,
- 2, 2, 0, 1
- );
- cv::Vec<float, 4> b(4, 5, 6, 7);
- cv::Matx<float, 4, 1> xLU = A.solve(b, DECOMP_LU);
- cv::Matx<float, 4, 1> xQR = A.solve(b, DECOMP_QR);
- cv::Matx<float, 4, 1> xSVD = A.solve(b, DECOMP_SVD);
- EXPECT_LE(cvtest::norm(xQR, xSVD, NORM_L2 | NORM_RELATIVE), 1e-3);
- EXPECT_LE(cvtest::norm(xQR, xLU, NORM_L2 | NORM_RELATIVE), 1e-3);
- cv::Matx<float, 4, 4> iA = A.inv(DECOMP_SVD);
- EXPECT_LE(cvtest::norm(iA*A, Matx<float, 4, 4>::eye(), NORM_L2), 1e-3);
- }
- softdouble naiveExp(softdouble x)
- {
- int exponent = x.getExp();
- int sign = x.getSign() ? -1 : 1;
- if(sign < 0 && exponent >= 10) return softdouble::inf();
- softdouble mantissa = x.getFrac();
- //Taylor series for mantissa
- uint64 fac[20] = {1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800,
- 39916800, 479001600, 6227020800, 87178291200, 1307674368000,
- 20922789888000, 355687428096000, 6402373705728000, 121645100408832000,
- 2432902008176640000};
- softdouble sum = softdouble::one();
- // 21! > (2 ** 64)
- for(int i = 20; i > 0; i--)
- sum += pow(mantissa, softdouble(i))/softdouble(fac[i-1]);
- if(exponent >= 0)
- {
- exponent = (1 << exponent);
- return pow(sum, softdouble(exponent*sign));
- }
- else
- {
- if(sign < 0) sum = softdouble::one()/sum;
- exponent = -exponent;
- for(int j = 0; j < exponent; j++)
- sum = sqrt(sum);
- return sum;
- }
- }
- static float makeFP32(int sign, int exponent, int significand)
- {
- Cv32suf x;
- x.u = (unsigned)(((sign & 1) << 31) | ((exponent&255) << 23) | (significand & 0x7fffff));
- return x.f;
- }
- static float makeRandomFP32(RNG& rng, int sign, int exprange)
- {
- if( sign == -1 )
- sign = rng() % 2;
- int exponent = rng() % exprange;
- int significand = rng() % (1 << 23);
- return makeFP32(sign, exponent, significand);
- }
- TEST(Core_SoftFloat, exp32)
- {
- //special cases
- EXPECT_TRUE(exp( softfloat::nan()).isNaN());
- EXPECT_TRUE(exp( softfloat::inf()).isInf());
- EXPECT_EQ (exp(-softfloat::inf()), softfloat::zero());
- //ln(FLT_MAX) ~ 88.722
- const softfloat ln_max(88.722f);
- vector<softfloat> inputs;
- RNG rng(0);
- inputs.push_back(softfloat::zero());
- inputs.push_back(softfloat::one());
- inputs.push_back(softfloat::min());
- for(int i = 0; i < 50000; i++)
- {
- float x = makeRandomFP32(rng, -1, 10+127 //bigger exponent will produce inf
- );
- if(softfloat(x) > ln_max)
- x = rng.uniform(0.0f, (float)ln_max);
- inputs.push_back(softfloat(x));
- }
- for(size_t i = 0; i < inputs.size(); i++)
- {
- softfloat x(inputs[i]);
- softfloat y = exp(x);
- ASSERT_TRUE(!y.isNaN());
- ASSERT_TRUE(!y.isInf());
- ASSERT_GE(y, softfloat::zero());
- softfloat ygood = naiveExp(x);
- softfloat diff = abs(ygood - y);
- const softfloat eps = softfloat::eps();
- if(diff > eps)
- {
- ASSERT_LE(diff/max(abs(y), abs(ygood)), eps);
- }
- }
- }
- TEST(Core_SoftFloat, exp64)
- {
- //special cases
- EXPECT_TRUE(exp( softdouble::nan()).isNaN());
- EXPECT_TRUE(exp( softdouble::inf()).isInf());
- EXPECT_EQ (exp(-softdouble::inf()), softdouble::zero());
- //ln(DBL_MAX) ~ 709.7827
- const softdouble ln_max(709.7827);
- vector<softdouble> inputs;
- RNG rng(0);
- inputs.push_back(softdouble::zero());
- inputs.push_back(softdouble::one());
- inputs.push_back(softdouble::min());
- for(int i = 0; i < 50000; i++)
- {
- Cv64suf x;
- uint64 sign = rng() % 2;
- uint64 exponent = rng() % (10 + 1023); //bigger exponent will produce inf
- uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
- x.u = (sign << 63) | (exponent << 52) | mantissa;
- if(softdouble(x.f) > ln_max)
- x.f = rng.uniform(0.0, (double)ln_max);
- inputs.push_back(softdouble(x.f));
- }
- for(size_t i = 0; i < inputs.size(); i++)
- {
- softdouble x(inputs[i]);
- softdouble y = exp(x);
- ASSERT_TRUE(!y.isNaN());
- ASSERT_TRUE(!y.isInf());
- ASSERT_GE(y, softdouble::zero());
- softdouble ygood = naiveExp(x);
- softdouble diff = abs(ygood - y);
- const softdouble eps = softdouble::eps();
- if(diff > eps)
- {
- ASSERT_LE(diff/max(abs(y), abs(ygood)), softdouble(8192)*eps);
- }
- }
- }
- TEST(Core_SoftFloat, log32)
- {
- const int nValues = 50000;
- RNG rng(0);
- //special cases
- EXPECT_TRUE(log(softfloat::nan()).isNaN());
- for(int i = 0; i < nValues; i++)
- {
- softfloat x32(makeRandomFP32(rng, 1, 255));
- ASSERT_TRUE(log(x32).isNaN());
- }
- EXPECT_TRUE(log(softfloat::zero()).isInf());
- vector<softfloat> inputs;
- inputs.push_back(softfloat::one());
- inputs.push_back(softfloat(exp(softfloat::one())));
- inputs.push_back(softfloat::min());
- inputs.push_back(softfloat::max());
- for(int i = 0; i < nValues; i++)
- {
- inputs.push_back(softfloat(makeRandomFP32(rng, 0, 255)));
- }
- for(size_t i = 0; i < inputs.size(); i++)
- {
- softfloat x(inputs[i]);
- softfloat y = log(x);
- ASSERT_TRUE(!y.isNaN());
- ASSERT_TRUE(!y.isInf());
- softfloat ex = exp(y);
- softfloat diff = abs(ex - x);
- // 88 is approx estimate of max exp() argument
- ASSERT_TRUE(!ex.isInf() || (y > softfloat(88)));
- const softfloat eps2 = softfloat().setExp(-17);
- if(!ex.isInf() && diff > softfloat::eps())
- {
- ASSERT_LT(diff/max(abs(ex), x), eps2);
- }
- }
- }
- TEST(Core_SoftFloat, log64)
- {
- const int nValues = 50000;
- RNG rng(0);
- //special cases
- EXPECT_TRUE(log(softdouble::nan()).isNaN());
- for(int i = 0; i < nValues; i++)
- {
- Cv64suf x;
- uint64 sign = 1;
- uint64 exponent = rng() % 2047;
- uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
- x.u = (sign << 63) | (exponent << 52) | mantissa;
- softdouble x64(x.f);
- ASSERT_TRUE(log(x64).isNaN());
- }
- EXPECT_TRUE(log(softdouble::zero()).isInf());
- vector<softdouble> inputs;
- inputs.push_back(softdouble::one());
- inputs.push_back(exp(softdouble::one()));
- inputs.push_back(softdouble::min());
- inputs.push_back(softdouble::max());
- for(int i = 0; i < nValues; i++)
- {
- Cv64suf x;
- uint64 sign = 0;
- uint64 exponent = rng() % 2047;
- uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
- x.u = (sign << 63) | (exponent << 52) | mantissa;
- inputs.push_back(softdouble(x.f));
- }
- for(size_t i = 0; i < inputs.size(); i++)
- {
- softdouble x(inputs[i]);
- softdouble y = log(x);
- ASSERT_TRUE(!y.isNaN());
- ASSERT_TRUE(!y.isInf());
- softdouble ex = exp(y);
- softdouble diff = abs(ex - x);
- // 700 is approx estimate of max exp() argument
- ASSERT_TRUE(!ex.isInf() || (y > softdouble(700)));
- const softdouble eps2 = softdouble().setExp(-41);
- if(!ex.isInf() && diff > softdouble::eps())
- {
- ASSERT_LT(diff/max(abs(ex), x), eps2);
- }
- }
- }
- TEST(Core_SoftFloat, cbrt32)
- {
- vector<softfloat> inputs;
- RNG rng(0);
- inputs.push_back(softfloat::zero());
- inputs.push_back(softfloat::one());
- inputs.push_back(softfloat::max());
- inputs.push_back(softfloat::min());
- for(int i = 0; i < 50000; i++)
- {
- inputs.push_back(softfloat(makeRandomFP32(rng, -1, 255)));
- }
- for(size_t i = 0; i < inputs.size(); i++)
- {
- softfloat x(inputs[i]);
- softfloat y = cbrt(x);
- ASSERT_TRUE(!y.isNaN());
- ASSERT_TRUE(!y.isInf());
- softfloat cube = y*y*y;
- softfloat diff = abs(x - cube);
- const softfloat eps = softfloat::eps();
- if(diff > eps)
- {
- ASSERT_LT(diff/max(abs(x), abs(cube)), softfloat(4)*eps);
- }
- }
- }
- TEST(Core_SoftFloat, pow32)
- {
- const softfloat zero = softfloat::zero(), one = softfloat::one();
- const softfloat inf = softfloat::inf(), nan = softfloat::nan();
- const size_t nValues = 5000;
- RNG rng(0);
- //x ** nan == nan
- for(size_t i = 0; i < nValues; i++)
- {
- Cv32suf x;
- x.u = rng();
- ASSERT_TRUE(pow(softfloat(x.f), nan).isNaN());
- }
- //x ** inf check
- for(size_t i = 0; i < nValues; i++)
- {
- Cv32suf x;
- x.u = rng();
- softfloat x32(x.f);
- softfloat ax = abs(x32);
- if(x32.isNaN())
- {
- ASSERT_TRUE(pow(x32, inf).isNaN());
- }
- if(ax > one)
- {
- ASSERT_TRUE(pow(x32, inf).isInf());
- ASSERT_EQ (pow(x32, -inf), zero);
- }
- if(ax < one && ax > zero)
- {
- ASSERT_TRUE(pow(x32, -inf).isInf());
- ASSERT_EQ (pow(x32, inf), zero);
- }
- }
- //+-1 ** inf
- EXPECT_TRUE(pow( one, inf).isNaN());
- EXPECT_TRUE(pow(-one, inf).isNaN());
- // x ** 0 == 1
- for(size_t i = 0; i < nValues; i++)
- {
- Cv32suf x;
- x.u = rng();
- ASSERT_EQ(pow(softfloat(x.f), zero), one);
- }
- // x ** 1 == x
- for(size_t i = 0; i < nValues; i++)
- {
- Cv32suf x;
- x.u = rng();
- softfloat x32(x.f);
- softfloat val = pow(x32, one);
- // don't compare val and x32 directly because x != x if x is nan
- ASSERT_EQ(val.v, x32.v);
- }
- // nan ** y == nan, if y != 0
- for(size_t i = 0; i < nValues; i++)
- {
- unsigned u = rng();
- softfloat x32 = softfloat::fromRaw(u);
- x32 = (x32 != softfloat::zero()) ? x32 : softfloat::min();
- ASSERT_TRUE(pow(nan, x32).isNaN());
- }
- // nan ** 0 == 1
- EXPECT_EQ(pow(nan, zero), one);
- // inf ** y == 0, if y < 0
- // inf ** y == inf, if y > 0
- for(size_t i = 0; i < nValues; i++)
- {
- float x = makeRandomFP32(rng, 0, 255);
- softfloat x32 = softfloat(x);
- ASSERT_TRUE(pow( inf, x32).isInf());
- ASSERT_TRUE(pow(-inf, x32).isInf());
- ASSERT_EQ(pow( inf, -x32), zero);
- ASSERT_EQ(pow(-inf, -x32), zero);
- }
- // x ** y == (-x) ** y, if y % 2 == 0
- // x ** y == - (-x) ** y, if y % 2 == 1
- // x ** y == nan, if x < 0 and y is not integer
- for(size_t i = 0; i < nValues; i++)
- {
- softfloat x32(makeRandomFP32(rng, 1, 255));
- softfloat y32(makeRandomFP32(rng, -1, 23+127 //bigger exponent produces integer numbers only
- ));
- int yi = cvRound(y32);
- if(y32 != softfloat(yi))
- ASSERT_TRUE(pow(x32, y32).isNaN());
- else if(yi % 2)
- ASSERT_EQ(pow(-x32, y32), -pow(x32, y32));
- else
- ASSERT_EQ(pow(-x32, y32), pow(x32, y32));
- }
- // (0 ** 0) == 1
- EXPECT_EQ(pow(zero, zero), one);
- // 0 ** y == inf, if y < 0
- // 0 ** y == 0, if y > 0
- for(size_t i = 0; i < nValues; i++)
- {
- softfloat x32(makeRandomFP32(rng, 0, 255));
- ASSERT_TRUE(pow(zero, -x32).isInf());
- if(x32 != one)
- {
- ASSERT_EQ(pow(zero, x32), zero);
- }
- }
- }
- TEST(Core_SoftFloat, pow64)
- {
- const softdouble zero = softdouble::zero(), one = softdouble::one();
- const softdouble inf = softdouble::inf(), nan = softdouble::nan();
- const size_t nValues = 5000;
- RNG rng(0);
- //x ** nan == nan
- for(size_t i = 0; i < nValues; i++)
- {
- Cv64suf x;
- x.u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
- ASSERT_TRUE(pow(softdouble(x.f), nan).isNaN());
- }
- //x ** inf check
- for(size_t i = 0; i < nValues; i++)
- {
- Cv64suf x;
- x.u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
- softdouble x64(x.f);
- softdouble ax = abs(x64);
- if(x64.isNaN())
- {
- ASSERT_TRUE(pow(x64, inf).isNaN());
- }
- if(ax > one)
- {
- ASSERT_TRUE(pow(x64, inf).isInf());
- ASSERT_EQ(pow(x64, -inf), zero);
- }
- if(ax < one && ax > zero)
- {
- ASSERT_TRUE(pow(x64, -inf).isInf());
- ASSERT_EQ(pow(x64, inf), zero);
- }
- }
- //+-1 ** inf
- EXPECT_TRUE(pow( one, inf).isNaN());
- EXPECT_TRUE(pow(-one, inf).isNaN());
- // x ** 0 == 1
- for(size_t i = 0; i < nValues; i++)
- {
- Cv64suf x;
- x.u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
- ASSERT_EQ(pow(softdouble(x.f), zero), one);
- }
- // x ** 1 == x
- for(size_t i = 0; i < nValues; i++)
- {
- Cv64suf x;
- x.u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
- softdouble x64(x.f);
- softdouble val = pow(x64, one);
- // don't compare val and x64 directly because x != x if x is nan
- ASSERT_EQ(val.v, x64.v);
- }
- // nan ** y == nan, if y != 0
- for(size_t i = 0; i < nValues; i++)
- {
- uint64 u = ((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng);
- softdouble x64 = softdouble::fromRaw(u);
- x64 = (x64 != softdouble::zero()) ? x64 : softdouble::min();
- ASSERT_TRUE(pow(nan, x64).isNaN());
- }
- // nan ** 0 == 1
- EXPECT_EQ(pow(nan, zero), one);
- // inf ** y == 0, if y < 0
- // inf ** y == inf, if y > 0
- for(size_t i = 0; i < nValues; i++)
- {
- Cv64suf x;
- uint64 sign = 0;
- uint64 exponent = rng() % 2047;
- uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
- x.u = (sign << 63) | (exponent << 52) | mantissa;
- softdouble x64(x.f);
- ASSERT_TRUE(pow( inf, x64).isInf());
- ASSERT_TRUE(pow(-inf, x64).isInf());
- ASSERT_EQ(pow( inf, -x64), zero);
- ASSERT_EQ(pow(-inf, -x64), zero);
- }
- // x ** y == (-x) ** y, if y % 2 == 0
- // x ** y == - (-x) ** y, if y % 2 == 1
- // x ** y == nan, if x < 0 and y is not integer
- for(size_t i = 0; i < nValues; i++)
- {
- Cv64suf x;
- uint64 sign = 1;
- uint64 exponent = rng() % 2047;
- uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
- x.u = (sign << 63) | (exponent << 52) | mantissa;
- softdouble x64(x.f);
- Cv64suf y;
- sign = rng() % 2;
- //bigger exponent produces integer numbers only
- //exponent = rng() % (52 + 1023);
- //bigger exponent is too big
- exponent = rng() % (23 + 1023);
- mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
- y.u = (sign << 63) | (exponent << 52) | mantissa;
- softdouble y64(y.f);
- uint64 yi = cvRound(y64);
- if(y64 != softdouble(yi))
- ASSERT_TRUE(pow(x64, y64).isNaN());
- else if(yi % 2)
- ASSERT_EQ(pow(-x64, y64), -pow(x64, y64));
- else
- ASSERT_EQ(pow(-x64, y64), pow(x64, y64));
- }
- // (0 ** 0) == 1
- EXPECT_EQ(pow(zero, zero), one);
- // 0 ** y == inf, if y < 0
- // 0 ** y == 0, if y > 0
- for(size_t i = 0; i < nValues; i++)
- {
- Cv64suf x;
- uint64 sign = 0;
- uint64 exponent = rng() % 2047;
- uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
- x.u = (sign << 63) | (exponent << 52) | mantissa;
- softdouble x64(x.f);
- ASSERT_TRUE(pow(zero, -x64).isInf());
- if(x64 != one)
- {
- ASSERT_EQ(pow(zero, x64), zero);
- }
- }
- }
- TEST(Core_SoftFloat, sincos64)
- {
- static const softdouble
- two = softdouble(2), three = softdouble(3),
- half = softdouble::one()/two,
- zero = softdouble::zero(), one = softdouble::one(),
- pi = softdouble::pi(), piby2 = pi/two, eps = softdouble::eps(),
- sin45 = sqrt(two)/two, sin60 = sqrt(three)/two;
- softdouble vstdAngles[] =
- //x, sin(x), cos(x)
- {
- zero, zero, one,
- pi/softdouble(6), half, sin60,
- pi/softdouble(4), sin45, sin45,
- pi/three, sin60, half,
- };
- vector<softdouble> stdAngles;
- stdAngles.assign(vstdAngles, vstdAngles + 3*4);
- static const softdouble stdEps = eps.setExp(-39);
- const size_t nStdValues = 5000;
- for(size_t i = 0; i < nStdValues; i++)
- {
- for(size_t k = 0; k < stdAngles.size()/3; k++)
- {
- softdouble x = stdAngles[k*3] + pi*softdouble(2*((int)i-(int)nStdValues/2));
- softdouble s = stdAngles[k*3+1];
- softdouble c = stdAngles[k*3+2];
- ASSERT_LE(abs(sin(x) - s), stdEps);
- ASSERT_LE(abs(cos(x) - c), stdEps);
- //sin(x+pi/2) = cos(x)
- ASSERT_LE(abs(sin(x + piby2) - c), stdEps);
- //sin(x+pi) = -sin(x)
- ASSERT_LE(abs(sin(x + pi) + s), stdEps);
- //cos(x+pi/2) = -sin(x)
- ASSERT_LE(abs(cos(x+piby2) + s), stdEps);
- //cos(x+pi) = -cos(x)
- ASSERT_LE(abs(cos(x+pi) + c), stdEps);
- }
- }
- // sin(x) is NaN iff x ix NaN or Inf
- EXPECT_TRUE(sin(softdouble::inf()).isNaN());
- EXPECT_TRUE(sin(softdouble::nan()).isNaN());
- vector<int> exponents;
- exponents.push_back(0);
- for(int i = 1; i < 52; i++)
- {
- exponents.push_back( i);
- exponents.push_back(-i);
- }
- exponents.push_back(256); exponents.push_back(-256);
- exponents.push_back(512); exponents.push_back(-512);
- exponents.push_back(1022); exponents.push_back(-1022);
- vector<softdouble> inputs;
- RNG rng(0);
- static const size_t nValues = 1 << 18;
- for(size_t i = 0; i < nValues; i++)
- {
- softdouble x;
- uint64 mantissa = (((long long int)((unsigned int)(rng)) << 32 ) | (unsigned int)(rng)) & ((1LL << 52) - 1);
- x.v = mantissa;
- x = x.setSign((rng() % 2) != 0);
- x = x.setExp(exponents[rng() % exponents.size()]);
- inputs.push_back(x);
- }
- for(size_t i = 0; i < inputs.size(); i++)
- {
- softdouble x = inputs[i];
- int xexp = x.getExp();
- softdouble randEps = eps.setExp(std::max(xexp-52, -46));
- softdouble sx = sin(x);
- softdouble cx = cos(x);
- ASSERT_FALSE(sx.isInf()); ASSERT_FALSE(cx.isInf());
- ASSERT_FALSE(sx.isNaN()); ASSERT_FALSE(cx.isNaN());
- ASSERT_LE(abs(sx), one); ASSERT_LE(abs(cx), one);
- ASSERT_LE(abs((sx*sx + cx*cx) - one), eps);
- ASSERT_LE(abs(sin(x*two) - two*sx*cx), randEps);
- ASSERT_LE(abs(cos(x*two) - (cx*cx - sx*sx)), randEps);
- ASSERT_LE(abs(sin(-x) + sx), eps);
- ASSERT_LE(abs(cos(-x) - cx), eps);
- ASSERT_LE(abs(sin(x + piby2) - cx), randEps);
- ASSERT_LE(abs(sin(x + pi) + sx), randEps);
- ASSERT_LE(abs(cos(x+piby2) + sx), randEps);
- ASSERT_LE(abs(cos(x+pi) + cx), randEps);
- }
- }
- TEST(Core_SoftFloat, CvRound)
- {
- struct
- {
- uint64_t inVal;
- int64_t out64;
- int32_t out32;
- } _values[] =
- {
- { 0x0123456789abcdefU, 0, 0 }, // 3.51270056408850369812238561681E-303
- { 0x0000000000000000U, 0, 0 }, // 0
- { 0x8000000000000000U, 0, 0 }, // -0
- { 0x000123456789abcdU, 0, 0 }, // 1.5822747438273385725152200433E-309
- { 0x800123456789abcdU, 0, 0 }, // -1.5822747438273385725152200433E-309
- { 0x7ff0000000000000U, INT64_MAX, INT32_MAX }, // +inf
- { 0xfff0000000000000U, INT64_MIN, INT32_MIN }, // -inf
- { 0x7ff0000000000001U, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
- { 0xfff0000000000001U, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
- { 0x7ffa5a5a5a5a5a5aU, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
- { 0xfffa5a5a5a5a5a5aU, INT64_MAX, INT32_MAX }, // nan(casts to maximum value)
- { 0x7fe123456789abcdU, INT64_MAX, INT32_MAX }, // 9.627645455595956656406699747E307
- { 0xffe123456789abcdU, INT64_MIN, INT32_MIN }, // -9.627645455595956656406699747E307
- { 0x43ffffffffffffffU, INT64_MAX, INT32_MAX }, // (2^53-1)*2^12
- { 0xc3ffffffffffffffU, INT64_MIN, INT32_MIN }, // -(2^53-1)*2^12
- { 0x43f0000000000000U, INT64_MAX, INT32_MAX }, // 2^64
- { 0xc3f0000000000000U, INT64_MIN, INT32_MIN }, // -2^64
- { 0x43efffffffffffffU, INT64_MAX, INT32_MAX }, // (2^53-1)*2^11
- { 0xc3efffffffffffffU, INT64_MIN, INT32_MIN }, // -(2^53-1)*2^11
- { 0x43e0000000000000U, INT64_MAX, INT32_MAX }, // 2^63
- { 0xc3e0000000000000U, -0x7fffffffffffffff-1, INT32_MIN }, // -2^63
- { 0x43dfffffffffffffU, 0x7ffffffffffffc00, INT32_MAX }, // (2^53-1)*2^10
- { 0xc3dfffffffffffffU, -0x7ffffffffffffc00, INT32_MIN }, // -(2^53-1)*2^10
- { 0x433fffffffffffffU, 0x1fffffffffffff, INT32_MAX }, // (2^53-1)
- { 0xc33fffffffffffffU, -0x1fffffffffffff, INT32_MIN }, // -(2^53-1)
- { 0x432fffffffffffffU, 0x10000000000000, INT32_MAX }, // (2^52-1) + 0.5
- { 0xc32fffffffffffffU, -0x10000000000000, INT32_MIN }, // -(2^52-1) - 0.5
- { 0x431fffffffffffffU, 0x8000000000000, INT32_MAX }, // (2^51-1) + 0.75
- { 0xc31fffffffffffffU, -0x8000000000000, INT32_MIN }, // -(2^51-1) - 0.75
- { 0x431ffffffffffffeU, 0x8000000000000, INT32_MAX }, // (2^51-1) + 0.5
- { 0xc31ffffffffffffeU, -0x8000000000000, INT32_MIN }, // -(2^51-1) - 0.5
- { 0x431ffffffffffffdU, 0x7ffffffffffff, INT32_MAX }, // (2^51-1) + 0.25
- { 0xc31ffffffffffffdU, -0x7ffffffffffff, INT32_MIN }, // -(2^51-1) - 0.25
- { 0x41f0000000000000U, 0x100000000, INT32_MAX }, // 2^32 = 4294967296
- { 0xc1f0000000000000U, -0x100000000, INT32_MIN }, // -2^32 = -4294967296
- { 0x41efffffffffffffU, 0x100000000, INT32_MAX }, // 4294967295.99999952316284179688
- { 0xc1efffffffffffffU, -0x100000000, INT32_MIN }, // -4294967295.99999952316284179688
- { 0x41effffffff00000U, 0x100000000, INT32_MAX }, // (2^32-1) + 0.5 = 4294967295.5
- { 0xc1effffffff00000U, -0x100000000, INT32_MIN }, // -(2^32-1) - 0.5 = -4294967295.5
- { 0x41efffffffe00000U, 0xffffffffll, INT32_MAX }, // (2^32-1)
- { 0xc1efffffffe00000U, -0xffffffffll, INT32_MIN }, // -(2^32-1)
- { 0x41e0000000000000U, 0x80000000ll, INT32_MAX }, // 2^31 = 2147483648
- { 0xc1e0000000000000U, -0x80000000ll, -0x7fffffff-1 }, // -2^31 = -2147483648
- { 0x41dfffffffffffffU, 0x80000000ll, INT32_MAX }, // 2147483647.99999976158142089844
- { 0xc1dfffffffffffffU, -0x80000000ll, -0x7fffffff-1 }, // -2147483647.99999976158142089844
- { 0x41dffffffff00000U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.75
- { 0xc1dffffffff00000U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.75
- { 0x41dfffffffe00001U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.5 + 2^-22
- { 0xc1dfffffffe00001U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.5 - 2^-22
- { 0x41dfffffffe00000U, 0x80000000ll, INT32_MAX }, // (2^31-1) + 0.5
- { 0xc1dfffffffe00000U, -0x80000000ll, -0x7fffffff-1 }, // -(2^31-1) - 0.5
- { 0x41dfffffffdfffffU, 0x7fffffff, 0x7fffffff }, // (2^31-1) + 0.5 - 2^-22
- { 0xc1dfffffffdfffffU, -0x7fffffff, -0x7fffffff }, // -(2^31-1) - 0.5 + 2^-22
- { 0x41dfffffffd00000U, 0x7fffffff, 0x7fffffff }, // (2^31-1) + 0.25
- { 0xc1dfffffffd00000U, -0x7fffffff, -0x7fffffff }, // -(2^31-1) - 0.25
- { 0x41dfffffffc00000U, 0x7fffffff, 0x7fffffff }, // (2^31-1)
- { 0xc1dfffffffc00000U, -0x7fffffff, -0x7fffffff }, // -(2^31-1)
- { 0x41d0000000000000U, 0x40000000, 0x40000000 }, // 2^30 = 2147483648
- { 0xc1d0000000000000U, -0x40000000, -0x40000000 }, // -2^30 = -2147483648
- { 0x4006000000000000U, 3, 3 }, // 2.75
- { 0xc006000000000000U, -3, -3 }, // -2.75
- { 0x4004000000000001U, 3, 3 }, // 2.5 + 2^-51
- { 0xc004000000000001U, -3, -3 }, // -2.5 - 2^-51
- { 0x4004000000000000U, 2, 2 }, // 2.5
- { 0xc004000000000000U, -2, -2 }, // -2.5
- { 0x4003ffffffffffffU, 2, 2 }, // 2.5 - 2^-51
- { 0xc003ffffffffffffU, -2, -2 }, // -2.5 + 2^-51
- { 0x4002000000000000U, 2, 2 }, // 2.25
- { 0xc002000000000000U, -2, -2 }, // -2.25
- { 0x3ffc000000000000U, 2, 2 }, // 1.75
- { 0xbffc000000000000U, -2, -2 }, // -1.75
- { 0x3ff8000000000001U, 2, 2 }, // 1.5 + 2^-52
- { 0xbff8000000000001U, -2, -2 }, // -1.5 - 2^-52
- { 0x3ff8000000000000U, 2, 2 }, // 1.5
- { 0xbff8000000000000U, -2, -2 }, // -1.5
- { 0x3ff7ffffffffffffU, 1, 1 }, // 1.5 - 2^-52
- { 0xbff7ffffffffffffU, -1, -1 }, // -1.5 + 2^-52
- { 0x3ff4000000000000U, 1, 1 }, // 1.25
- { 0xbff4000000000000U, -1, -1 }, // -1.25
- { 0x3fe8000000000000U, 1, 1 }, // 0.75
- { 0xbfe8000000000000U, -1, -1 }, // -0.75
- { 0x3fe0000000000001U, 1, 1 }, // 0.5 + 2^-53
- { 0xbfe0000000000001U, -1, -1 }, // -0.5 - 2^-53
- { 0x3fe0000000000000U, 0, 0 }, // 0.5
- { 0xbfe0000000000000U, 0, 0 }, // -0.5
- { 0x3fd8000000000000U, 0, 0 }, // 0.375
- { 0xbfd8000000000000U, 0, 0 }, // -0.375
- { 0x3fd0000000000000U, 0, 0 }, // 0.25
- { 0xbfd0000000000000U, 0, 0 }, // -0.25
- { 0x0ff123456789abcdU, 0, 0 }, // 6.89918601543515033558134828315E-232
- { 0x8ff123456789abcdU, 0, 0 } // -6.89918601543515033558134828315E-232
- };
- struct testvalues
- {
- softdouble inVal;
- int64_t out64;
- int32_t out32;
- } *values = (testvalues*)_values;
- for (int i = 0, maxi = sizeof(_values) / sizeof(_values[0]); i < maxi; i++)
- {
- EXPECT_EQ(values[i].out64, cvRound64(values[i].inVal));
- EXPECT_EQ(values[i].out64, saturate_cast<int64_t>(values[i].inVal));
- EXPECT_EQ((uint64_t)(values[i].out64), saturate_cast<uint64_t>(values[i].inVal));
- EXPECT_EQ(values[i].out32, cvRound(values[i].inVal));
- EXPECT_EQ(values[i].out32, saturate_cast<int32_t>(values[i].inVal));
- EXPECT_EQ((uint32_t)(values[i].out32), saturate_cast<uint32_t>(values[i].inVal));
- }
- }
- template<typename T>
- static void checkRounding(T in, int outCeil, int outFloor)
- {
- EXPECT_EQ(outCeil,cvCeil(in));
- EXPECT_EQ(outFloor,cvFloor(in));
- /* cvRound is not expected to be IEEE compliant. The implementation
- should round to one of the above. */
- EXPECT_TRUE((cvRound(in) == outCeil) || (cvRound(in) == outFloor));
- }
- TEST(Core_FastMath, InlineRoundingOps)
- {
- struct
- {
- double in;
- int outCeil;
- int outFloor;
- } values[] =
- {
- // Values are chosen to convert to binary float 32/64 exactly
- { 1.0, 1, 1 },
- { 1.5, 2, 1 },
- { -1.5, -1, -2}
- };
- for (int i = 0, maxi = sizeof(values) / sizeof(values[0]); i < maxi; i++)
- {
- checkRounding<double>(values[i].in, values[i].outCeil, values[i].outFloor);
- checkRounding<float>((float)values[i].in, values[i].outCeil, values[i].outFloor);
- }
- }
- TEST(Core_FastMath, InlineNaN)
- {
- EXPECT_EQ( cvIsNaN((float) NAN), 1);
- EXPECT_EQ( cvIsNaN((float) -NAN), 1);
- EXPECT_EQ( cvIsNaN(0.0f), 0);
- EXPECT_EQ( cvIsNaN((double) NAN), 1);
- EXPECT_EQ( cvIsNaN((double) -NAN), 1);
- EXPECT_EQ( cvIsNaN(0.0), 0);
- // Regression: check the +/-Inf cases
- Cv64suf suf;
- suf.u = 0x7FF0000000000000UL;
- EXPECT_EQ( cvIsNaN(suf.f), 0);
- suf.u = 0xFFF0000000000000UL;
- EXPECT_EQ( cvIsNaN(suf.f), 0);
- }
- TEST(Core_FastMath, InlineIsInf)
- {
- // Assume HUGE_VAL is infinity. Strictly speaking, may not always be true.
- EXPECT_EQ( cvIsInf((float) HUGE_VAL), 1);
- EXPECT_EQ( cvIsInf((float) -HUGE_VAL), 1);
- EXPECT_EQ( cvIsInf(0.0f), 0);
- EXPECT_EQ( cvIsInf((double) HUGE_VAL), 1);
- EXPECT_EQ( cvIsInf((double) -HUGE_VAL), 1);
- EXPECT_EQ( cvIsInf(0.0), 0);
- // Regression: check the cases of 0x7FF00000xxxxxxxx
- Cv64suf suf;
- suf.u = 0x7FF0000000000001UL;
- EXPECT_EQ( cvIsInf(suf.f), 0);
- suf.u = 0x7FF0000012345678UL;
- EXPECT_EQ( cvIsInf(suf.f), 0);
- }
- }} // namespace
- /* End of file. */
|