From d0210f510e837ae3a4dd0d9a9ea505ae3f062751 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 14 Aug 2015 16:43:10 +0300 Subject: [PATCH 001/468] OpenCV version++. --- modules/core/include/opencv2/core/version.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/version.hpp b/modules/core/include/opencv2/core/version.hpp index 50562ec5ad..7457da76a9 100644 --- a/modules/core/include/opencv2/core/version.hpp +++ b/modules/core/include/opencv2/core/version.hpp @@ -50,7 +50,7 @@ #define CV_VERSION_EPOCH 2 #define CV_VERSION_MAJOR 4 #define CV_VERSION_MINOR 12 -#define CV_VERSION_REVISION 0 +#define CV_VERSION_REVISION 1 #define CVAUX_STR_EXP(__A) #__A #define CVAUX_STR(__A) CVAUX_STR_EXP(__A) From fc0e0239b8d6d3d65f59a2f062bd133d6cc845d9 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Fri, 14 Aug 2015 17:57:54 +0300 Subject: [PATCH 002/468] fixed valgrind warning in polylines (cherry picked from commit 855765986e9cd5c730730dd1f45175b182e737fa) --- modules/core/src/drawing.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/core/src/drawing.cpp b/modules/core/src/drawing.cpp index bd42ac5066..bd8f171b16 100644 --- a/modules/core/src/drawing.cpp +++ b/modules/core/src/drawing.cpp @@ -2216,6 +2216,7 @@ void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts, Mat p = pts.getMat(manyContours ? i : -1); if( p.total() == 0 ) { + ptsptr[i] = NULL; npts[i] = 0; continue; } From ecc53dd7a45f2573e35a897612100ece84dbc0f2 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sat, 15 Aug 2015 00:35:38 +0300 Subject: [PATCH 003/468] fixed memory leak in core ds tests (cherry picked from commit 7719da95526b81af0195a3576774eaac605cd045) --- modules/core/test/test_ds.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/modules/core/test/test_ds.cpp b/modules/core/test/test_ds.cpp index adc8f1a42c..ded52583a2 100644 --- a/modules/core/test/test_ds.cpp +++ b/modules/core/test/test_ds.cpp @@ -493,6 +493,7 @@ class Core_SeqBaseTest : public Core_DynStructBaseTest { public: Core_SeqBaseTest(); + virtual ~Core_SeqBaseTest(); void clear(); void run( int ); @@ -503,11 +504,14 @@ protected: int test_seq_ops( int iters ); }; - Core_SeqBaseTest::Core_SeqBaseTest() { } +Core_SeqBaseTest::~Core_SeqBaseTest() +{ + clear(); +} void Core_SeqBaseTest::clear() { @@ -1208,6 +1212,7 @@ class Core_SetTest : public Core_DynStructBaseTest { public: Core_SetTest(); + virtual ~Core_SetTest(); void clear(); void run( int ); @@ -1221,6 +1226,10 @@ Core_SetTest::Core_SetTest() { } +Core_SetTest::~Core_SetTest() +{ + clear(); +} void Core_SetTest::clear() { @@ -1419,6 +1428,7 @@ class Core_GraphTest : public Core_DynStructBaseTest { public: Core_GraphTest(); + virtual ~Core_GraphTest(); void clear(); void run( int ); @@ -1432,6 +1442,10 @@ Core_GraphTest::Core_GraphTest() { } +Core_GraphTest::~Core_GraphTest() +{ + clear(); +} void Core_GraphTest::clear() { @@ -2044,6 +2058,8 @@ void Core_GraphScanTest::run( int ) CV_TS_SEQ_CHECK_CONDITION( vtx_count == 0 && edge_count == 0, "Not every vertex/edge has been visited" ); update_progressbar(); + + cvReleaseGraphScanner( &scanner ); } // for a random graph the test just checks that every graph vertex and @@ -2108,8 +2124,6 @@ void Core_GraphScanTest::run( int ) catch(int) { } - - cvReleaseGraphScanner( &scanner ); } From bf94e6a91cea3bc4742aa04308855b4cbd0bed27 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sat, 15 Aug 2015 10:06:09 +0300 Subject: [PATCH 004/468] fixed memory leaks in cvtyuv tests (cherry picked from commit b2489d31d66599ac2aaa79af2b753a24649776aa) --- modules/imgproc/test/test_cvtyuv.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/test/test_cvtyuv.cpp b/modules/imgproc/test/test_cvtyuv.cpp index 0cce64cdba..7407523fe1 100644 --- a/modules/imgproc/test/test_cvtyuv.cpp +++ b/modules/imgproc/test/test_cvtyuv.cpp @@ -548,7 +548,7 @@ void referenceRGB2YUV(const Mat& rgb, Mat& yuv, RGBreader* rgbReader, YUVwriter* struct ConversionYUV { - ConversionYUV( const int code ) + explicit ConversionYUV( const int code ) { yuvReader_ = YUVreader :: getReader(code); yuvWriter_ = YUVwriter :: getWriter(code); @@ -557,6 +557,24 @@ struct ConversionYUV grayWriter_ = GRAYwriter:: getWriter(code); } + ~ConversionYUV() + { + if (yuvReader_) + delete yuvReader_; + + if (yuvWriter_) + delete yuvWriter_; + + if (rgbReader_) + delete rgbReader_; + + if (rgbReader_) + delete rgbReader_; + + if (grayWriter_) + delete grayWriter_; + } + int getDcn() { return (rgbWriter_ != 0) ? rgbWriter_->channels() : ((grayWriter_ != 0) ? grayWriter_->channels() : yuvWriter_->channels()); From ba3b902da7801fdae78a667c47e81f71f5d212b0 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sat, 15 Aug 2015 10:09:31 +0300 Subject: [PATCH 005/468] fixed memory leaks in floodfill tests (cherry picked from commit d1b882ddcf54e52ac70bb17540c84c4a93553add) --- modules/imgproc/test/test_floodfill.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/imgproc/test/test_floodfill.cpp b/modules/imgproc/test/test_floodfill.cpp index e46e9e120c..8293a12afd 100644 --- a/modules/imgproc/test/test_floodfill.cpp +++ b/modules/imgproc/test/test_floodfill.cpp @@ -501,6 +501,8 @@ _exit_: comp[6] = s1; comp[7] = s2; comp[8] = 0; + + cvReleaseMemStorage(&st); } From 08e38e9ff93b5e88dfe17b184f4e4527aa12c020 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sat, 15 Aug 2015 10:11:52 +0300 Subject: [PATCH 006/468] fixed memory leaks in warpAffine tests (cherry picked from commit b70e27e076a7eea6a1ccc6bb5f367e539e1aa51c) --- modules/imgproc/test/test_imgwarp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index 705bf0a7bc..99cffbc37d 100644 --- a/modules/imgproc/test/test_imgwarp.cpp +++ b/modules/imgproc/test/test_imgwarp.cpp @@ -1426,6 +1426,9 @@ TEST(Imgproc_cvWarpAffine, regression) int h = src->height; cv2DRotationMatrix(cvPoint2D32f(w*0.5f, h*0.5f), 45.0, 1.0, &M); cvWarpAffine(src, dst, &M); + + cvReleaseImage(&src); + cvReleaseImage(&dst); } TEST(Imgproc_fitLine_vector_3d, regression) From 486c40f578e5f8f4428c86eda083ee11212ae068 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sat, 15 Aug 2015 14:30:27 +0300 Subject: [PATCH 007/468] fixed uninitialized values warning in bad arg test class (cherry picked from commit 47cee8715bb086f6b0ca0f5b301d2eec87ce9f2a) --- modules/ts/src/ts.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/ts/src/ts.cpp b/modules/ts/src/ts.cpp index ee8f01171f..bfeae74bb2 100644 --- a/modules/ts/src/ts.cpp +++ b/modules/ts/src/ts.cpp @@ -323,6 +323,7 @@ BadArgTest::BadArgTest() progress = -1; test_case_idx = -1; freq = cv::getTickFrequency(); + t = -1; // oldErrorCbk = 0; // oldErrorCbkData = 0; } @@ -338,6 +339,7 @@ int BadArgTest::run_test_case( int expected_code, const string& _descr ) { test_case_idx = 0; progress = 0; + t = 0; dt = 0; } else From 69c50e01815346475c43407d97ea17fea8973632 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sat, 15 Aug 2015 16:25:25 +0300 Subject: [PATCH 008/468] fixed typo (cherry picked from commit 370d1ff21a99046021da39b74f4081a5b69ce57e) --- modules/features2d/test/test_nearestneighbors.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp index 8d1ecfd79a..2c64e648f2 100644 --- a/modules/features2d/test/test_nearestneighbors.cpp +++ b/modules/features2d/test/test_nearestneighbors.cpp @@ -65,13 +65,13 @@ protected: virtual void run( int start_from ); virtual void createModel( const Mat& data ) = 0; virtual int findNeighbors( Mat& points, Mat& neighbors ) = 0; - virtual int checkGetPoins( const Mat& data ); + virtual int checkGetPoints( const Mat& data ); virtual int checkFindBoxed(); virtual int checkFind( const Mat& data ); virtual void releaseModel() = 0; }; -int NearestNeighborTest::checkGetPoins( const Mat& ) +int NearestNeighborTest::checkGetPoints( const Mat& ) { return cvtest::TS::OK; } @@ -129,7 +129,7 @@ void NearestNeighborTest::run( int /*start_from*/ ) { createModel( desc ); - tempCode = checkGetPoins( desc ); + tempCode = checkGetPoints( desc ); if( tempCode != cvtest::TS::OK ) { ts->printf( cvtest::TS::LOG, "bad accuracy of GetPoints \n" ); @@ -162,7 +162,7 @@ public: CV_KDTreeTest_CPP() {} protected: virtual void createModel( const Mat& data ); - virtual int checkGetPoins( const Mat& data ); + virtual int checkGetPoints( const Mat& data ); virtual int findNeighbors( Mat& points, Mat& neighbors ); virtual int checkFindBoxed(); virtual void releaseModel(); @@ -175,7 +175,7 @@ void CV_KDTreeTest_CPP::createModel( const Mat& data ) tr = new KDTree( data, false ); } -int CV_KDTreeTest_CPP::checkGetPoins( const Mat& data ) +int CV_KDTreeTest_CPP::checkGetPoints( const Mat& data ) { Mat res1( data.size(), data.type() ), res3( data.size(), data.type() ); From 16bcc30e429321eeea995575ff9361e2cc4ef250 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sun, 16 Aug 2015 11:46:48 +0300 Subject: [PATCH 009/468] typo (cherry picked from commit 793bdaada7f170cf3fbaf3b421bb3054f37e8a63) --- modules/imgproc/test/test_cvtyuv.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/imgproc/test/test_cvtyuv.cpp b/modules/imgproc/test/test_cvtyuv.cpp index 7407523fe1..5db4972692 100644 --- a/modules/imgproc/test/test_cvtyuv.cpp +++ b/modules/imgproc/test/test_cvtyuv.cpp @@ -568,8 +568,8 @@ struct ConversionYUV if (rgbReader_) delete rgbReader_; - if (rgbReader_) - delete rgbReader_; + if (rgbWriter_) + delete rgbWriter_; if (grayWriter_) delete grayWriter_; From 3231c2f99562eb115296f1432a734fc23b333861 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Thu, 30 Jul 2015 18:03:48 +0300 Subject: [PATCH 010/468] NearestNeighborTest: use ts->get_rng() instead of (implicit) theRNG() This ensures that test data is not dependent on the order the tests are executed in. (cherry picked from commit 1245cd175283b11800bbbdc52287957cc3d76417) --- modules/features2d/test/test_nearestneighbors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp index 2c64e648f2..b63bc6433e 100644 --- a/modules/features2d/test/test_nearestneighbors.cpp +++ b/modules/features2d/test/test_nearestneighbors.cpp @@ -125,7 +125,7 @@ int NearestNeighborTest::checkFind( const Mat& data ) void NearestNeighborTest::run( int /*start_from*/ ) { int code = cvtest::TS::OK, tempCode; Mat desc( featuresCount, dims, CV_32FC1 ); - randu( desc, Scalar(minValue), Scalar(maxValue) ); + ts->get_rng().fill( desc, RNG::UNIFORM, minValue, maxValue ); createModel( desc ); From c16f465ff5b3379fb027f6256793d18cb7853d0d Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Thu, 20 Aug 2015 12:20:38 +0300 Subject: [PATCH 011/468] fixed "Conditional jump or move depends on uninitialised value" warning (cherry picked from commit f100cdb6d4373c93abc2b5613fae505ed3ce876d) --- modules/imgproc/test/test_imgwarp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index 99cffbc37d..a14ea532a9 100644 --- a/modules/imgproc/test/test_imgwarp.cpp +++ b/modules/imgproc/test/test_imgwarp.cpp @@ -1420,6 +1420,8 @@ TEST(Imgproc_cvWarpAffine, regression) IplImage* src = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 1); IplImage* dst = cvCreateImage(cvSize(100, 100), IPL_DEPTH_8U, 1); + cvZero(src); + float m[6]; CvMat M = cvMat( 2, 3, CV_32F, m ); int w = src->width; From d28e6c9b3693b02766031967dd5f0c7fd8056fc4 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Thu, 20 Aug 2015 13:28:10 +0300 Subject: [PATCH 012/468] fixed memory leak caused by illegal memory access (cherry picked from commit 4722b2d0e5b2caf053e53612ea277451c5cc53a0) --- modules/imgproc/test/test_imgwarp_strict.cpp | 34 +++++--------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/modules/imgproc/test/test_imgwarp_strict.cpp b/modules/imgproc/test/test_imgwarp_strict.cpp index c122d0b58b..365f851d5e 100644 --- a/modules/imgproc/test/test_imgwarp_strict.cpp +++ b/modules/imgproc/test/test_imgwarp_strict.cpp @@ -644,8 +644,7 @@ private: }; CV_Remap_Test::CV_Remap_Test() : - CV_ImageWarpBaseTest(), mapx(), mapy(), - borderType(-1), borderValue() + CV_ImageWarpBaseTest(), borderType(-1) { funcs[0] = &CV_Remap_Test::remap_nearest; funcs[1] = &CV_Remap_Test::remap_generic; @@ -666,7 +665,7 @@ void CV_Remap_Test::generate_test_data() // generating the mapx, mapy matrices static const int mapx_types[] = { CV_16SC2, CV_32FC1, CV_32FC2 }; mapx.create(dst.size(), mapx_types[rng.uniform(0, sizeof(mapx_types) / sizeof(int))]); - mapy = Mat(); + mapy.release(); const int n = std::min(std::min(src.cols, src.rows) / 10 + 1, 2); float _n = 0; //static_cast(-n); @@ -693,7 +692,7 @@ void CV_Remap_Test::generate_test_data() { MatIterator_ begin_y = mapy.begin(), end_y = mapy.end(); for ( ; begin_y != end_y; ++begin_y) - begin_y[0] = static_cast(rng.uniform(0, 1024)); + *begin_y = static_cast(rng.uniform(0, 1024)); } break; @@ -701,7 +700,7 @@ void CV_Remap_Test::generate_test_data() { MatIterator_ begin_y = mapy.begin(), end_y = mapy.end(); for ( ; begin_y != end_y; ++begin_y) - begin_y[0] = static_cast(rng.uniform(0, 1024)); + *begin_y = static_cast(rng.uniform(0, 1024)); } break; } @@ -718,8 +717,8 @@ void CV_Remap_Test::generate_test_data() MatIterator_ begin_y = mapy.begin(); for ( ; begin_x != end_x; ++begin_x, ++begin_y) { - begin_x[0] = rng.uniform(_n, fscols); - begin_y[0] = rng.uniform(_n, fsrows); + *begin_x = rng.uniform(_n, fscols); + *begin_y = rng.uniform(_n, fsrows); } } break; @@ -731,8 +730,8 @@ void CV_Remap_Test::generate_test_data() fsrows = static_cast(std::max(src.rows - 1 + n, 0)); for ( ; begin_x != end_x; ++begin_x) { - begin_x[0] = rng.uniform(_n, fscols); - begin_x[1] = rng.uniform(_n, fsrows); + (*begin_x)[0] = rng.uniform(_n, fscols); + (*begin_x)[1] = rng.uniform(_n, fsrows); } } break; @@ -777,23 +776,6 @@ void CV_Remap_Test::prepare_test_data_for_reference_func() { CV_ImageWarpBaseTest::prepare_test_data_for_reference_func(); convert_maps(); -/* - const int ksize = 3; - Mat kernel = getStructuringElement(CV_MOP_ERODE, Size(ksize, ksize)); - Mat mask(src.size(), CV_8UC1, Scalar::all(255)), dst_mask; - cv::erode(src, erode_src, kernel); - cv::erode(mask, dst_mask, kernel, Point(-1, -1), 1, BORDER_CONSTANT, Scalar::all(0)); - bitwise_not(dst_mask, mask); - src.copyTo(erode_src, mask); - dst_mask.release(); - - mask = Scalar::all(0); - kernel = getStructuringElement(CV_MOP_DILATE, kernel.size()); - cv::dilate(src, dilate_src, kernel); - cv::dilate(mask, dst_mask, kernel, Point(-1, -1), 1, BORDER_CONSTANT, Scalar::all(255)); - src.copyTo(dilate_src, dst_mask); - dst_mask.release(); -*/ } void CV_Remap_Test::run_reference_func() From 226ff9391724ae20250d77df2f4febd21fd3b9bf Mon Sep 17 00:00:00 2001 From: a-andre Date: Sun, 2 Aug 2015 13:13:58 +0200 Subject: [PATCH 013/468] install new headers like "opencv2/core.hpp" --- cmake/OpenCVModule.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index a70065750f..ec834d9090 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -488,7 +488,7 @@ macro(ocv_glob_module_sources) file(GLOB_RECURSE lib_srcs "src/*.cpp") file(GLOB_RECURSE lib_int_hdrs "src/*.hpp" "src/*.h") - file(GLOB lib_hdrs "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h") + file(GLOB lib_hdrs "include/opencv2/*.hpp" "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h") file(GLOB lib_hdrs_detail "include/opencv2/${name}/detail/*.hpp" "include/opencv2/${name}/detail/*.h") file(GLOB_RECURSE lib_srcs_apple "src/*.mm") if (APPLE) @@ -629,7 +629,7 @@ macro(ocv_create_module) if(OPENCV_MODULE_${the_module}_HEADERS AND ";${OPENCV_MODULES_PUBLIC};" MATCHES ";${the_module};") foreach(hdr ${OPENCV_MODULE_${the_module}_HEADERS}) string(REGEX REPLACE "^.*opencv2/" "opencv2/" hdr2 "${hdr}") - if(hdr2 MATCHES "^(opencv2/.*)/[^/]+.h(..)?$") + if(hdr2 MATCHES "^(opencv2/?.*)/[^/]+.h(..)?$") install(FILES ${hdr} DESTINATION "${OPENCV_INCLUDE_INSTALL_PATH}/${CMAKE_MATCH_1}" COMPONENT dev) endif() endforeach() From a14e524b32d9252b7c58181d9752804371c82e4f Mon Sep 17 00:00:00 2001 From: a-andre Date: Tue, 18 Aug 2015 18:48:32 +0200 Subject: [PATCH 014/468] fix documentation builder warnings --- modules/core/include/opencv2/core.hpp | 3 --- modules/core/include/opencv2/core/core.hpp | 3 --- modules/imgproc/include/opencv2/imgproc.hpp | 4 ---- modules/imgproc/include/opencv2/imgproc/imgproc.hpp | 4 ---- 4 files changed, 14 deletions(-) diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp index 98564c1a98..12773f8c1b 100644 --- a/modules/core/include/opencv2/core.hpp +++ b/modules/core/include/opencv2/core.hpp @@ -1,6 +1,3 @@ -/*! \file core.hpp - \brief The Core Functionality - */ /*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. diff --git a/modules/core/include/opencv2/core/core.hpp b/modules/core/include/opencv2/core/core.hpp index 67905ec466..3e9c92d097 100644 --- a/modules/core/include/opencv2/core/core.hpp +++ b/modules/core/include/opencv2/core/core.hpp @@ -1,6 +1,3 @@ -/*! \file core.hpp - \brief The Core Functionality - */ /*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index b07ece09b8..112f723274 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -1,7 +1,3 @@ -/*! \file imgproc.hpp - \brief The Image Processing - */ - /*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. diff --git a/modules/imgproc/include/opencv2/imgproc/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc/imgproc.hpp index 339476a633..f46cc643c8 100644 --- a/modules/imgproc/include/opencv2/imgproc/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc/imgproc.hpp @@ -1,7 +1,3 @@ -/*! \file imgproc.hpp - \brief The Image Processing - */ - /*M/////////////////////////////////////////////////////////////////////////////////////// // // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. From 6613d142617ab35db3fbc36f0ff40cb2d1068fef Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Tue, 25 Aug 2015 18:50:06 +0300 Subject: [PATCH 015/468] Add missing packages to the Debian conflict list And refactor the code to make sure that the dev and runtime package lists are in sync. --- cmake/OpenCVPackaging.cmake | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index bc59f00f8c..be52aee04b 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -115,15 +115,14 @@ if(HAVE_TBB AND NOT BUILD_TBB) endif() endif() -set(STD_OPENCV_LIBS opencv-data libopencv-calib3d2.4 libopencv-contrib2.4 libopencv-core2.4 - libopencv-features2d2.4 libopencv-flann2.4 libopencv-gpu2.4 libopencv-imgproc2.4 - libopencv-ml2.4 libopencv-ocl2.4 libopencv-stitching2.4 libopencv-ts2.4 libopencv-videostab2.4) +set(STD_OPENCV_LIBS opencv-data) +set(STD_OPENCV_DEV libopencv-dev) -set(STD_OPENCV_DEV libopencv-calib3d-dev libopencv-contrib-dev libopencv-core-dev - libopencv-dev libopencv-features2d-dev libopencv-flann-dev libopencv-gpu-dev - libopencv-highgui-dev libopencv-imgproc-dev libopencv-legacy-dev libopencv-ml-dev - libopencv-objdetect-dev libopencv-ocl-dev libopencv-photo-dev libopencv-stitching-dev - libopencv-superres-dev libopencv-ts-dev libopencv-video-dev libopencv-videostab-dev) +foreach(module calib3d contrib core features2d flann gpu highgui imgproc legacy + ml objdetect ocl photo stitching superres ts video videostab) + list(APPEND STD_OPENCV_LIBS "libopencv-${module}2.4") + list(APPEND STD_OPENCV_DEV "libopencv-${module}-dev") +endforeach() string(REPLACE ";" ", " CPACK_COMPONENT_LIBS_CONFLICTS "${STD_OPENCV_LIBS}") string(REPLACE ";" ", " CPACK_COMPONENT_LIBS_PROVIDES "${STD_OPENCV_LIBS}") From d122510c4f666a22e792a9b54044198f9c673f24 Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Wed, 26 Aug 2015 13:42:21 +0300 Subject: [PATCH 016/468] Only conflict with packages corresponding to modules that are built --- cmake/OpenCVPackaging.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index be52aee04b..f6d5bd04a0 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -120,8 +120,10 @@ set(STD_OPENCV_DEV libopencv-dev) foreach(module calib3d contrib core features2d flann gpu highgui imgproc legacy ml objdetect ocl photo stitching superres ts video videostab) - list(APPEND STD_OPENCV_LIBS "libopencv-${module}2.4") - list(APPEND STD_OPENCV_DEV "libopencv-${module}-dev") + if(HAVE_opencv_${module}) + list(APPEND STD_OPENCV_LIBS "libopencv-${module}2.4") + list(APPEND STD_OPENCV_DEV "libopencv-${module}-dev") + endif() endforeach() string(REPLACE ";" ", " CPACK_COMPONENT_LIBS_CONFLICTS "${STD_OPENCV_LIBS}") From 1d58e1a14a1c44a4c1b57c6a665acc7ea40d74ab Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 27 Aug 2015 16:09:37 +0300 Subject: [PATCH 017/468] fix potential out-of-border access in gpu StereoBeliefPropagation --- modules/gpu/src/stereobp.cpp | 8 ++++---- modules/gpu/test/test_calib3d.cpp | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/gpu/src/stereobp.cpp b/modules/gpu/src/stereobp.cpp index 1677f33446..3b827a3129 100644 --- a/modules/gpu/src/stereobp.cpp +++ b/modules/gpu/src/stereobp.cpp @@ -213,8 +213,8 @@ namespace if (rthis.levels > 1) { - int less_rows = (rows + 1) / 2; - int less_cols = (cols + 1) / 2; + int less_rows = rows / 2; + int less_cols = cols / 2; u2.create(less_rows * rthis.ndisp, less_cols, rthis.msg_type); d2.create(less_rows * rthis.ndisp, less_cols, rthis.msg_type); @@ -283,8 +283,8 @@ namespace for (int i = 1; i < rthis.levels; ++i) { - cols_all[i] = (cols_all[i-1] + 1) / 2; - rows_all[i] = (rows_all[i-1] + 1) / 2; + cols_all[i] = cols_all[i-1] / 2; + rows_all[i] = rows_all[i-1] / 2; datas[i].create(rows_all[i] * rthis.ndisp, cols_all[i], rthis.msg_type); diff --git a/modules/gpu/test/test_calib3d.cpp b/modules/gpu/test/test_calib3d.cpp index ea4039a0cd..80882d431d 100644 --- a/modules/gpu/test/test_calib3d.cpp +++ b/modules/gpu/test/test_calib3d.cpp @@ -114,7 +114,9 @@ GPU_TEST_P(StereoBeliefPropagation, Regression) cv::Mat h_disp(disp); h_disp.convertTo(h_disp, disp_gold.depth()); - EXPECT_MAT_NEAR(disp_gold, h_disp, 0.0); + cv::Rect roi(0, 0, disp_gold.cols - 20, disp_gold.rows - 20); + + EXPECT_MAT_NEAR(disp_gold(roi), h_disp(roi), 0.0); } INSTANTIATE_TEST_CASE_P(GPU_Calib3D, StereoBeliefPropagation, ALL_DEVICES); From 6dcd455ac4cf279b880458a24e055370b61bb1f5 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Mon, 31 Aug 2015 17:20:52 +0300 Subject: [PATCH 018/468] fixed memory leaks in modules/features2d/test/test_nearestneighbors.cpp --- .../test/test_lshindex_flannbased_matcher.cpp | 12 +++++++++++- modules/features2d/test/test_nearestneighbors.cpp | 13 ++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/modules/features2d/test/test_lshindex_flannbased_matcher.cpp b/modules/features2d/test/test_lshindex_flannbased_matcher.cpp index ddc81b0c5d..d1c6ea7e43 100644 --- a/modules/features2d/test/test_lshindex_flannbased_matcher.cpp +++ b/modules/features2d/test/test_lshindex_flannbased_matcher.cpp @@ -303,7 +303,8 @@ public: // // constructor // - CV_FeatureDetectorMatcherBaseTest(testparam* _tp, double _accuracy_margin, cv::Feature2D* _fe, cv::DescriptorMatcher *_flmatcher, string _flmatchername, int norm_type_for_bfmatcher) : + CV_FeatureDetectorMatcherBaseTest(testparam* _tp, double _accuracy_margin, cv::Feature2D* _fe, + cv::DescriptorMatcher *_flmatcher, string _flmatchername, int norm_type_for_bfmatcher) : tp(_tp), target_accuracy_margin_from_bfmatcher(_accuracy_margin), fe(_fe), @@ -318,6 +319,15 @@ public: bfmatcher = new cv::BFMatcher(norm_type_for_bfmatcher); } + virtual ~CV_FeatureDetectorMatcherBaseTest() + { + if (bfmatcher) + { + delete bfmatcher; + bfmatcher = NULL; + } + } + // // Main Test method // diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp index b63bc6433e..bb1d51bf60 100644 --- a/modules/features2d/test/test_nearestneighbors.cpp +++ b/modules/features2d/test/test_nearestneighbors.cpp @@ -159,7 +159,7 @@ void NearestNeighborTest::run( int /*start_from*/ ) { class CV_KDTreeTest_CPP : public NearestNeighborTest { public: - CV_KDTreeTest_CPP() {} + CV_KDTreeTest_CPP() : NearestNeighborTest(), tr(NULL) {} protected: virtual void createModel( const Mat& data ); virtual int checkGetPoints( const Mat& data ); @@ -244,7 +244,7 @@ void CV_KDTreeTest_CPP::releaseModel() class CV_FlannTest : public NearestNeighborTest { public: - CV_FlannTest() {} + CV_FlannTest() : NearestNeighborTest(), index(NULL) { } protected: void createIndex( const Mat& data, const IndexParams& params ); int knnSearch( Mat& points, Mat& neighbors ); @@ -255,6 +255,9 @@ protected: void CV_FlannTest::createIndex( const Mat& data, const IndexParams& params ) { + // release previously allocated index + releaseModel(); + index = new Index( data, params ); } @@ -321,7 +324,11 @@ int CV_FlannTest::radiusSearch( Mat& points, Mat& neighbors ) void CV_FlannTest::releaseModel() { - delete index; + if (index) + { + delete index; + index = NULL; + } } //--------------------------------------- From 7e4e8921bc0749c030ba3913ae23af2204fd58c4 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Mon, 31 Aug 2015 17:30:42 +0300 Subject: [PATCH 019/468] fixed memory leak in descriptor regression tests --- .../features2d/test/test_descriptors_regression.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/modules/features2d/test/test_descriptors_regression.cpp b/modules/features2d/test/test_descriptors_regression.cpp index 2185625ae9..a1c07f86bc 100644 --- a/modules/features2d/test/test_descriptors_regression.cpp +++ b/modules/features2d/test/test_descriptors_regression.cpp @@ -61,7 +61,7 @@ static void writeMatInBin( const Mat& mat, const string& filename ) fwrite( (void*)&mat.rows, sizeof(int), 1, f ); fwrite( (void*)&mat.cols, sizeof(int), 1, f ); fwrite( (void*)&type, sizeof(int), 1, f ); - int dataSize = (int)(mat.step * mat.rows * mat.channels()); + int dataSize = (int)(mat.step * mat.rows); fwrite( (void*)&dataSize, sizeof(int), 1, f ); fwrite( (void*)mat.data, 1, dataSize, f ); fclose(f); @@ -80,12 +80,15 @@ static Mat readMatFromBin( const string& filename ) size_t elements_read4 = fread( (void*)&dataSize, sizeof(int), 1, f ); CV_Assert(elements_read1 == 1 && elements_read2 == 1 && elements_read3 == 1 && elements_read4 == 1); - uchar* data = (uchar*)cvAlloc(dataSize); - size_t elements_read = fread( (void*)data, 1, dataSize, f ); + Mat returnMat(rows, cols, type); + CV_Assert(returnMat.step * returnMat.rows == (size_t)(dataSize)); + + size_t elements_read = fread( (void*)returnMat.data, 1, dataSize, f ); CV_Assert(elements_read == (size_t)(dataSize)); + fclose(f); - return Mat( rows, cols, type, data ); + return returnMat; } return Mat(); } From b5e42d8cc149796adb9cdc8400df6d6f1a9a324f Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 1 Sep 2015 11:26:25 +0300 Subject: [PATCH 020/468] fixed memory leak in ml module (cherry picked from commit d7bb1025f32ed268da7230cae3e8cb413dbab282) --- modules/ml/src/ertrees.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/ml/src/ertrees.cpp b/modules/ml/src/ertrees.cpp index d911834ee5..fe3e04ce90 100644 --- a/modules/ml/src/ertrees.cpp +++ b/modules/ml/src/ertrees.cpp @@ -537,6 +537,9 @@ void CvERTreeTrainData::set_data( const CvMat* _train_data, int _tflag, if( data ) delete data; + if ( pair16u32s_ptr ) + cvFree( &pair16u32s_ptr ); + if (_fdst) cvFree( &_fdst ); if (_idst) From ac33cd688cffd1c3fd541a67a758a84c90cf7bd7 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 1 Sep 2015 12:29:52 +0300 Subject: [PATCH 021/468] fixed memory leak in ANN (cherry picked from commit dfb49097e3013fa279d5882700601f5cabd6cbd8) --- modules/ml/src/ann_mlp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/ml/src/ann_mlp.cpp b/modules/ml/src/ann_mlp.cpp index 7323ab57a7..69e4448169 100644 --- a/modules/ml/src/ann_mlp.cpp +++ b/modules/ml/src/ann_mlp.cpp @@ -1535,6 +1535,10 @@ void CvANN_MLP::read( CvFileStorage* fs, CvFileNode* node ) _layer_sizes = (CvMat*)cvReadByName( fs, node, "layer_sizes" ); CV_CALL( create( _layer_sizes, SIGMOID_SYM, 0, 0 )); + + cvReleaseMat( &_layer_sizes ); + _layer_sizes = NULL; + l_count = layer_sizes->cols; CV_CALL( read_params( fs, node )); From 3c3bc123fc8508e1845d0a3e1ea85f66b1a36fc9 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 1 Sep 2015 13:04:33 +0300 Subject: [PATCH 022/468] release filestorage before exception (cherry picked from commit 3a1bb933401446b442348026b9cb680d35f3f449) --- modules/ml/src/svm.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/ml/src/svm.cpp b/modules/ml/src/svm.cpp index 0a5bfffa31..594a43a895 100644 --- a/modules/ml/src/svm.cpp +++ b/modules/ml/src/svm.cpp @@ -2315,7 +2315,12 @@ void CvSVM::write( CvFileStorage* fs, const char* name ) const params.svm_type == CvSVM::ONE_CLASS ? 1 : 0; const CvSVMDecisionFunc* df = decision_func; if( !isSvmModelApplicable(sv_total, var_all, var_count, class_count) ) + { + cvReleaseFileStorage( &fs ); + fs = NULL; + CV_ERROR( CV_StsParseError, "SVM model data is invalid, check sv_count, var_* and class_count tags" ); + } cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_ML_SVM ); From 54693b3fa70c90acffbf9e13d135c5cc0a4665bd Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 1 Sep 2015 11:40:23 +0300 Subject: [PATCH 023/468] fixed memory leak in GBTrees (cherry picked from commit 1b8c2589c057f862008cd1a3be5c8802b7bf1994) --- modules/ml/src/gbt.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/ml/src/gbt.cpp b/modules/ml/src/gbt.cpp index 131eb43fee..aeaf6695af 100644 --- a/modules/ml/src/gbt.cpp +++ b/modules/ml/src/gbt.cpp @@ -1292,13 +1292,18 @@ CvGBTrees::calc_error( CvMLData* _data, int type, std::vector *resp ) return -FLT_MAX; float* pred_resp = 0; + bool needsFreeing = false; + if (resp) { resp->resize(n); pred_resp = &((*resp)[0]); } else + { pred_resp = new float[n]; + needsFreeing = true; + } Sample_predictor predictor = Sample_predictor(this, pred_resp, _data->get_values(), _data->get_missing(), _sample_idx); @@ -1331,6 +1336,9 @@ CvGBTrees::calc_error( CvMLData* _data, int type, std::vector *resp ) err = err / (float)n; } + if (needsFreeing) + delete[]pred_resp; + return err; } From d50c07e303d5bacbdfc5cfdda4767e7485106beb Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 1 Sep 2015 13:22:49 +0300 Subject: [PATCH 024/468] fixed "Conditional jump or move depends on uninitialised value(s)" in GBD (cherry picked from commit 887736bcd4365cff0531e6f763b604a1c6e92e25) --- modules/ml/src/gbt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ml/src/gbt.cpp b/modules/ml/src/gbt.cpp index aeaf6695af..9ed6b4c986 100644 --- a/modules/ml/src/gbt.cpp +++ b/modules/ml/src/gbt.cpp @@ -259,7 +259,7 @@ CvGBTrees::train( const CvMat* _train_data, int _tflag, for (int i=1; idata.fl[i]) - class_labels->data.i[k]) && (kdata.fl[i]) - class_labels->data.i[k])) k++; if (k == j) { From c36582d2df34ed1da9bb04393b65124e37eee497 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Tue, 1 Sep 2015 16:17:18 +0300 Subject: [PATCH 025/468] fixed memory leak in flann index (cherry picked from commit 32d7c1950a562d038ff6f8b810ee46298a83fc39) --- modules/flann/src/miniflann.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/flann/src/miniflann.cpp b/modules/flann/src/miniflann.cpp index 5ce3e9051a..9bf503364d 100644 --- a/modules/flann/src/miniflann.cpp +++ b/modules/flann/src/miniflann.cpp @@ -318,12 +318,14 @@ buildIndex_(void*& index, const Mat& wholedata, const Mat& data, const IndexPara ::cvflann::Matrix dataset((ElementType*)data.data, data.rows, data.cols); - IndexType* _index = NULL; - if( !index || getParam(params, "algorithm", FLANN_INDEX_LINEAR) != FLANN_INDEX_LSH) // currently, additional index support is the lsh algorithm only. + // currently, additional index support is the lsh algorithm only. + if( !index || getParam(params, "algorithm", FLANN_INDEX_LINEAR) != FLANN_INDEX_LSH) { - _index = new IndexType(dataset, get_params(params), dist); + Ptr _index = makePtr(dataset, get_params(params), dist); _index->buildIndex(); index = _index; + // HACK to prevent object destruction + _index.obj = NULL; } else // build additional lsh index { From a81f0a51237b8772cfc350a9a91fb15a42215781 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Thu, 3 Sep 2015 13:25:29 +0300 Subject: [PATCH 026/468] fixed uninitialized memory writing/reading in flann (cherry picked from commit 3934d61de7d34e9ac8040cf5ced349a51ad2e520) --- modules/flann/include/opencv2/flann/kmeans_index.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/flann/include/opencv2/flann/kmeans_index.h b/modules/flann/include/opencv2/flann/kmeans_index.h index 9c0f4e2df8..e119ceb291 100644 --- a/modules/flann/include/opencv2/flann/kmeans_index.h +++ b/modules/flann/include/opencv2/flann/kmeans_index.h @@ -384,6 +384,8 @@ public: } root_ = pool_.allocate(); + std::memset(root_, 0, sizeof(KMeansNode)); + computeNodeStatistics(root_, indices_, (int)size_); computeClustering(root_, indices_, (int)size_, branching_,0); } @@ -823,11 +825,11 @@ private: variance -= distance_(centers[c], ZeroIterator(), veclen_); node->childs[c] = pool_.allocate(); + std::memset(node->childs[c], 0, sizeof(KMeansNode)); node->childs[c]->radius = radiuses[c]; node->childs[c]->pivot = centers[c]; node->childs[c]->variance = variance; node->childs[c]->mean_radius = mean_radius; - node->childs[c]->indices = NULL; computeClustering(node->childs[c],indices+start, end-start, branching, level+1); start=end; } From 0422054aa196347b706d682e223605d76ca38c64 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Thu, 3 Sep 2015 19:13:00 +0300 Subject: [PATCH 027/468] fixed warnings in gpu module (cherry picked from commit 6a05939e1ce552008ecf95451ddf362f2be7a4c3) --- modules/gpu/src/element_operations.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/gpu/src/element_operations.cpp b/modules/gpu/src/element_operations.cpp index 780745d733..280f85a36a 100644 --- a/modules/gpu/src/element_operations.cpp +++ b/modules/gpu/src/element_operations.cpp @@ -2804,7 +2804,7 @@ void cv::gpu::bitwise_not(const GpuMat& src, GpuMat& dst, const GpuMat& mask, St } else { - const int elem_size = src.elemSize1(); + const int elem_size = static_cast(src.elemSize1()); const int num_channels = src.channels(); const int bcols = src.cols * num_channels; @@ -2895,7 +2895,7 @@ void cv::gpu::bitwise_and(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, c } else { - const int elem_size = src1.elemSize1(); + const int elem_size = static_cast(src1.elemSize1()); const int num_channels = src1.channels(); const int bcols = src1.cols * num_channels; @@ -2979,7 +2979,7 @@ void cv::gpu::bitwise_or(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, co } else { - const int elem_size = src1.elemSize1(); + const int elem_size = static_cast(src1.elemSize1()); const int num_channels = src1.channels(); const int bcols = src1.cols * num_channels; @@ -3063,7 +3063,7 @@ void cv::gpu::bitwise_xor(const GpuMat& src1, const GpuMat& src2, GpuMat& dst, c } else { - const int elem_size = src1.elemSize1(); + const int elem_size = static_cast(src1.elemSize1()); const int num_channels = src1.channels(); const int bcols = src1.cols * num_channels; From f4ffcae8d98035cb79d64eb37de5eab6b55690e1 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Thu, 3 Sep 2015 17:21:04 +0300 Subject: [PATCH 028/468] initialize padding of CvString with zeros (cherry picked from commit 7b1eb3af7bb82dfd9258f6abdec350688cf65b51) --- modules/core/src/datastructs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/core/src/datastructs.cpp b/modules/core/src/datastructs.cpp index 76c3b2c371..ddadd39691 100644 --- a/modules/core/src/datastructs.cpp +++ b/modules/core/src/datastructs.cpp @@ -346,6 +346,7 @@ CV_IMPL CvString cvMemStorageAllocString( CvMemStorage* storage, const char* ptr, int len ) { CvString str; + memset(&str, 0, sizeof(CvString)); str.len = len >= 0 ? len : (int)strlen(ptr); str.ptr = (char*)cvMemStorageAlloc( storage, str.len + 1 ); From c7b471f10f41bfbb63309bce7378582f220e1593 Mon Sep 17 00:00:00 2001 From: Elena Shipunova Date: Mon, 7 Sep 2015 13:50:30 +0300 Subject: [PATCH 029/468] do not proceed with removing zero-length slice (cherry picked from commit 036c3b4e6d45dcf81181bb2658601f758c976088) --- modules/core/src/datastructs.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/core/src/datastructs.cpp b/modules/core/src/datastructs.cpp index ddadd39691..3e0bf47f4c 100644 --- a/modules/core/src/datastructs.cpp +++ b/modules/core/src/datastructs.cpp @@ -1689,6 +1689,9 @@ cvSeqRemoveSlice( CvSeq* seq, CvSlice slice ) slice.end_index = slice.start_index + length; + if ( slice.start_index == slice.end_index ) + return; + if( slice.end_index < total ) { CvSeqReader reader_to, reader_from; From 558054a53d9df34960b587b0bbeaeadcde1b729d Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 8 Sep 2015 16:04:28 +0300 Subject: [PATCH 030/468] fix for gpu::StereoBeliefPropogation: use continuous memory for internal buffers (cherry picked from commit e2a9df408f712f694206974a1f24a864881371c3) --- modules/gpu/src/stereobp.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/gpu/src/stereobp.cpp b/modules/gpu/src/stereobp.cpp index 3b827a3129..dde69d6d44 100644 --- a/modules/gpu/src/stereobp.cpp +++ b/modules/gpu/src/stereobp.cpp @@ -158,7 +158,7 @@ namespace init(stream); - datas[0].create(rows * rthis.ndisp, cols, rthis.msg_type); + createContinuous(rows * rthis.ndisp, cols, rthis.msg_type, datas[0]); comp_data_callers[rthis.msg_type == CV_32F][left.channels()](left, right, datas[0], StreamAccessor::getStream(stream)); @@ -187,10 +187,10 @@ namespace private: void init(Stream& stream) { - u.create(rows * rthis.ndisp, cols, rthis.msg_type); - d.create(rows * rthis.ndisp, cols, rthis.msg_type); - l.create(rows * rthis.ndisp, cols, rthis.msg_type); - r.create(rows * rthis.ndisp, cols, rthis.msg_type); + createContinuous(rows * rthis.ndisp, cols, rthis.msg_type, u); + createContinuous(rows * rthis.ndisp, cols, rthis.msg_type, d); + createContinuous(rows * rthis.ndisp, cols, rthis.msg_type, l); + createContinuous(rows * rthis.ndisp, cols, rthis.msg_type, r); if (rthis.levels & 1) { @@ -216,10 +216,10 @@ namespace int less_rows = rows / 2; int less_cols = cols / 2; - u2.create(less_rows * rthis.ndisp, less_cols, rthis.msg_type); - d2.create(less_rows * rthis.ndisp, less_cols, rthis.msg_type); - l2.create(less_rows * rthis.ndisp, less_cols, rthis.msg_type); - r2.create(less_rows * rthis.ndisp, less_cols, rthis.msg_type); + createContinuous(less_rows * rthis.ndisp, less_cols, rthis.msg_type, u2); + createContinuous(less_rows * rthis.ndisp, less_cols, rthis.msg_type, d2); + createContinuous(less_rows * rthis.ndisp, less_cols, rthis.msg_type, l2); + createContinuous(less_rows * rthis.ndisp, less_cols, rthis.msg_type, r2); if ((rthis.levels & 1) == 0) { @@ -286,7 +286,7 @@ namespace cols_all[i] = cols_all[i-1] / 2; rows_all[i] = rows_all[i-1] / 2; - datas[i].create(rows_all[i] * rthis.ndisp, cols_all[i], rthis.msg_type); + createContinuous(rows_all[i] * rthis.ndisp, cols_all[i], rthis.msg_type, datas[i]); data_step_down_callers[funcIdx](cols_all[i], rows_all[i], rows_all[i-1], datas[i-1], datas[i], cudaStream); } From c22cc67ba8b549e4883e2f6a40495ba3db465a77 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 10 Sep 2015 10:05:04 +0300 Subject: [PATCH 031/468] revert previous change in gpu::StereoBeliefPropogation (cherry picked from commit f903192c17b1c70182c0c25bb156900ea82b731b) --- modules/gpu/src/stereobp.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/gpu/src/stereobp.cpp b/modules/gpu/src/stereobp.cpp index dde69d6d44..0864fbcadc 100644 --- a/modules/gpu/src/stereobp.cpp +++ b/modules/gpu/src/stereobp.cpp @@ -213,8 +213,8 @@ namespace if (rthis.levels > 1) { - int less_rows = rows / 2; - int less_cols = cols / 2; + int less_rows = (rows + 1) / 2; + int less_cols = (cols + 1) / 2; createContinuous(less_rows * rthis.ndisp, less_cols, rthis.msg_type, u2); createContinuous(less_rows * rthis.ndisp, less_cols, rthis.msg_type, d2); @@ -283,8 +283,8 @@ namespace for (int i = 1; i < rthis.levels; ++i) { - cols_all[i] = cols_all[i-1] / 2; - rows_all[i] = rows_all[i-1] / 2; + cols_all[i] = (cols_all[i-1] + 1) / 2; + rows_all[i] = (rows_all[i-1] + 1) / 2; createContinuous(rows_all[i] * rthis.ndisp, cols_all[i], rthis.msg_type, datas[i]); From 3494d640df0a6f3df03f29fcfc059a25c365fba5 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 10 Sep 2015 10:05:25 +0300 Subject: [PATCH 032/468] add extra checks to data_step_down to prevent out-of-border access (cherry picked from commit 3ef067cc65cd548a968588f72d3b9ecc92a0e9bb) --- modules/gpu/src/cuda/stereobp.cu | 18 +++++++++--------- modules/gpu/src/stereobp.cpp | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/gpu/src/cuda/stereobp.cu b/modules/gpu/src/cuda/stereobp.cu index 05a19b4199..d011c7f4fe 100644 --- a/modules/gpu/src/cuda/stereobp.cu +++ b/modules/gpu/src/cuda/stereobp.cu @@ -255,7 +255,7 @@ namespace cv { namespace gpu { namespace device /////////////////////////////////////////////////////////////// template - __global__ void data_step_down(int dst_cols, int dst_rows, int src_rows, const PtrStep src, PtrStep dst) + __global__ void data_step_down(int dst_cols, int dst_rows, int src_cols, int src_rows, const PtrStep src, PtrStep dst) { const int x = blockIdx.x * blockDim.x + threadIdx.x; const int y = blockIdx.y * blockDim.y + threadIdx.y; @@ -264,10 +264,10 @@ namespace cv { namespace gpu { namespace device { for (int d = 0; d < cndisp; ++d) { - float dst_reg = src.ptr(d * src_rows + (2*y+0))[(2*x+0)]; - dst_reg += src.ptr(d * src_rows + (2*y+1))[(2*x+0)]; - dst_reg += src.ptr(d * src_rows + (2*y+0))[(2*x+1)]; - dst_reg += src.ptr(d * src_rows + (2*y+1))[(2*x+1)]; + float dst_reg = src.ptr(d * src_rows + ::min(2*y+0, src_rows-1))[::min(2*x+0, src_cols-1)]; + dst_reg += src.ptr(d * src_rows + ::min(2*y+1, src_rows-1))[::min(2*x+0, src_cols-1)]; + dst_reg += src.ptr(d * src_rows + ::min(2*y+0, src_rows-1))[::min(2*x+1, src_cols-1)]; + dst_reg += src.ptr(d * src_rows + ::min(2*y+1, src_rows-1))[::min(2*x+1, src_cols-1)]; dst.ptr(d * dst_rows + y)[x] = saturate_cast(dst_reg); } @@ -275,7 +275,7 @@ namespace cv { namespace gpu { namespace device } template - void data_step_down_gpu(int dst_cols, int dst_rows, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream) + void data_step_down_gpu(int dst_cols, int dst_rows, int src_cols, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream) { dim3 threads(32, 8, 1); dim3 grid(1, 1, 1); @@ -283,15 +283,15 @@ namespace cv { namespace gpu { namespace device grid.x = divUp(dst_cols, threads.x); grid.y = divUp(dst_rows, threads.y); - data_step_down<<>>(dst_cols, dst_rows, src_rows, (PtrStepSz)src, (PtrStepSz)dst); + data_step_down<<>>(dst_cols, dst_rows, src_cols, src_rows, (PtrStepSz)src, (PtrStepSz)dst); cudaSafeCall( cudaGetLastError() ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); } - template void data_step_down_gpu(int dst_cols, int dst_rows, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); - template void data_step_down_gpu(int dst_cols, int dst_rows, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); + template void data_step_down_gpu(int dst_cols, int dst_rows, int src_cols, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); + template void data_step_down_gpu(int dst_cols, int dst_rows, int src_cols, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); /////////////////////////////////////////////////////////////// /////////////////// level up messages //////////////////////// diff --git a/modules/gpu/src/stereobp.cpp b/modules/gpu/src/stereobp.cpp index 0864fbcadc..2bcefe3770 100644 --- a/modules/gpu/src/stereobp.cpp +++ b/modules/gpu/src/stereobp.cpp @@ -67,7 +67,7 @@ namespace cv { namespace gpu { namespace device template void comp_data_gpu(const PtrStepSzb& left, const PtrStepSzb& right, const PtrStepSzb& data, cudaStream_t stream); template - void data_step_down_gpu(int dst_cols, int dst_rows, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); + void data_step_down_gpu(int dst_cols, int dst_rows, int src_cols, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); template void level_up_messages_gpu(int dst_idx, int dst_cols, int dst_rows, int src_rows, PtrStepSzb* mus, PtrStepSzb* mds, PtrStepSzb* mls, PtrStepSzb* mrs, cudaStream_t stream); template @@ -253,7 +253,7 @@ namespace void calcBP(GpuMat& disp, Stream& stream) { - typedef void (*data_step_down_t)(int dst_cols, int dst_rows, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); + typedef void (*data_step_down_t)(int dst_cols, int dst_rows, int src_cols, int src_rows, const PtrStepSzb& src, const PtrStepSzb& dst, cudaStream_t stream); static const data_step_down_t data_step_down_callers[2] = { data_step_down_gpu, data_step_down_gpu @@ -288,7 +288,7 @@ namespace createContinuous(rows_all[i] * rthis.ndisp, cols_all[i], rthis.msg_type, datas[i]); - data_step_down_callers[funcIdx](cols_all[i], rows_all[i], rows_all[i-1], datas[i-1], datas[i], cudaStream); + data_step_down_callers[funcIdx](cols_all[i], rows_all[i], cols_all[i-1], rows_all[i-1], datas[i-1], datas[i], cudaStream); } PtrStepSzb mus[] = {u, u2}; From 7746d9b7ccfad2a7ae901aadd934f81b93eb701f Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Wed, 2 Sep 2015 18:15:05 +0300 Subject: [PATCH 033/468] fix for corrent modules dependencies (cherry picked from commit 1c3d83df54d2f39c9403126bf3c1374eaf749dee) --- cmake/OpenCVModule.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index ec834d9090..cae2a39c9d 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -49,6 +49,8 @@ foreach(mod ${OPENCV_MODULES_BUILD} ${OPENCV_MODULES_DISABLED_USER} ${OPENCV_MOD if(HAVE_${mod}) unset(HAVE_${mod} CACHE) endif() + unset(OPENCV_MODULE_${mod}_DEPS CACHE) + unset(OPENCV_MODULE_${mod}_DEPS_EXT CACHE) unset(OPENCV_MODULE_${mod}_REQ_DEPS CACHE) unset(OPENCV_MODULE_${mod}_OPT_DEPS CACHE) unset(OPENCV_MODULE_${mod}_PRIVATE_REQ_DEPS CACHE) From e6f3f3c029bc7cc5e5fe1aad072f96d08a8ebba0 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 17 Sep 2015 14:02:36 +0300 Subject: [PATCH 034/468] OpenCV version++. --- modules/core/include/opencv2/core/version.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/version.hpp b/modules/core/include/opencv2/core/version.hpp index 7457da76a9..096b66e97a 100644 --- a/modules/core/include/opencv2/core/version.hpp +++ b/modules/core/include/opencv2/core/version.hpp @@ -50,7 +50,7 @@ #define CV_VERSION_EPOCH 2 #define CV_VERSION_MAJOR 4 #define CV_VERSION_MINOR 12 -#define CV_VERSION_REVISION 1 +#define CV_VERSION_REVISION 2 #define CVAUX_STR_EXP(__A) #__A #define CVAUX_STR(__A) CVAUX_STR_EXP(__A) From 7d28541bbeed68647d0294a829f3d8dc9253cf2c Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Thu, 17 Sep 2015 18:17:06 +0300 Subject: [PATCH 035/468] test2.py: fail if a downloaded image can't be decoded (cherry picked from commit 56f17e4921a379317a0602d92d7ca3677cabe9d6) --- modules/python/test/test2.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/python/test/test2.py b/modules/python/test/test2.py index 9126160948..d0912cd618 100644 --- a/modules/python/test/test2.py +++ b/modules/python/test/test2.py @@ -22,7 +22,9 @@ class NewOpenCVTests(unittest.TestCase): def get_sample(self, filename, iscolor = cv.CV_LOAD_IMAGE_COLOR): if not filename in self.image_cache: filedata = urllib.urlopen("https://raw.github.com/Itseez/opencv/2.4/" + filename).read() - self.image_cache[filename] = cv2.imdecode(np.fromstring(filedata, dtype=np.uint8), iscolor) + image = cv2.imdecode(np.fromstring(filedata, dtype=np.uint8), iscolor) + self.assertFalse(image is None) + self.image_cache[filename] = image return self.image_cache[filename] def setUp(self): From c5d009d6c4ddf03f4b45acc544b436ca004a41f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hajo=20Nils=20Krabbenho=CC=88ft?= Date: Wed, 16 Sep 2015 22:04:42 +0200 Subject: [PATCH 036/468] fix crash for large BW tif images (cherry picked from commit d38fee759928d631ea2947c67e5ee9eb347693b6) --- modules/highgui/src/grfmt_tiff.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/highgui/src/grfmt_tiff.cpp b/modules/highgui/src/grfmt_tiff.cpp index eeee318c79..067f22de2f 100644 --- a/modules/highgui/src/grfmt_tiff.cpp +++ b/modules/highgui/src/grfmt_tiff.cpp @@ -221,6 +221,11 @@ bool TiffDecoder::readData( Mat& img ) (!is_tiled && tile_height0 == std::numeric_limits::max()) ) tile_height0 = m_height; + if(dst_bpp == 8) { + // we will use TIFFReadRGBA* functions, so allocate temporary buffer for 32bit RGBA + bpp = 8; + ncn = 4; + } const size_t buffer_size = bpp * ncn * tile_height0 * tile_width0; AutoBuffer _buffer( buffer_size ); uchar* buffer = _buffer; From 2fc0ce5c246a70c83691e7f1afd689457e25e70f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hajo=20Nils=20Krabbenho=CC=88ft?= Date: Wed, 16 Sep 2015 22:19:51 +0200 Subject: [PATCH 037/468] buffer_size should be in bytes, not bits (cherry picked from commit 7825cbeb7d70c2e1e558808d7433ece414394177) --- modules/highgui/src/grfmt_tiff.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/highgui/src/grfmt_tiff.cpp b/modules/highgui/src/grfmt_tiff.cpp index 067f22de2f..c7639fe345 100644 --- a/modules/highgui/src/grfmt_tiff.cpp +++ b/modules/highgui/src/grfmt_tiff.cpp @@ -226,7 +226,7 @@ bool TiffDecoder::readData( Mat& img ) bpp = 8; ncn = 4; } - const size_t buffer_size = bpp * ncn * tile_height0 * tile_width0; + const size_t buffer_size = (bpp/bitsPerByte) * ncn * tile_height0 * tile_width0; AutoBuffer _buffer( buffer_size ); uchar* buffer = _buffer; ushort* buffer16 = (ushort*)buffer; From 33cd7f38a8f19b308cc72fc141eab5b5df798ad3 Mon Sep 17 00:00:00 2001 From: robertxwu Date: Mon, 21 Sep 2015 13:57:25 -0700 Subject: [PATCH 038/468] re-submit (cherry picked from commit 4a68cc1675990c46cf53a66f137cb8da09022e4b) --- modules/calib3d/src/calibinit.cpp | 35 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/modules/calib3d/src/calibinit.cpp b/modules/calib3d/src/calibinit.cpp index 5e6ea1d289..000ac5435d 100644 --- a/modules/calib3d/src/calibinit.cpp +++ b/modules/calib3d/src/calibinit.cpp @@ -152,7 +152,7 @@ struct CvCBQuad //static CvMat* debug_img = 0; static int icvGenerateQuads( CvCBQuad **quads, CvCBCorner **corners, - CvMemStorage *storage, CvMat *image, int flags ); + CvMemStorage *storage, CvMat *image, int flags, int *max_quad_buf_size); /*static int icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners, @@ -172,7 +172,7 @@ static int icvCleanFoundConnectedQuads( int quad_count, static int icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads, int *all_count, CvCBQuad **all_quads, CvCBCorner **corners, - CvSize pattern_size, CvMemStorage* storage ); + CvSize pattern_size, int max_quad_buf_size, CvMemStorage* storage ); static void icvOrderQuad(CvCBQuad *quad, CvCBCorner *corner, int common); @@ -183,7 +183,7 @@ static int icvTrimRow(CvCBQuad **quads, int count, int row, int dir); #endif static int icvAddOuterQuad(CvCBQuad *quad, CvCBQuad **quads, int quad_count, - CvCBQuad **all_quads, int all_count, CvCBCorner **corners); + CvCBQuad **all_quads, int all_count, CvCBCorner **corners, int max_quad_buf_size); static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0); @@ -313,6 +313,7 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size, // making it difficult to detect smaller squares. for( k = 0; k < 6; k++ ) { + int max_quad_buf_size = 0; for( dilations = min_dilations; dilations <= max_dilations; dilations++ ) { if (found) @@ -368,7 +369,7 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size, cvRectangle( thresh_img, cvPoint(0,0), cvPoint(thresh_img->cols-1, thresh_img->rows-1), CV_RGB(255,255,255), 3, 8); - quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags ); + quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags, &max_quad_buf_size); PRINTF("Quad count: %d/%d\n", quad_count, expected_corners_num); } @@ -408,8 +409,8 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size, // allocate extra for adding in icvOrderFoundQuads cvFree(&quad_group); cvFree(&corner_group); - quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * (quad_count+quad_count / 2)); - corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * (quad_count+quad_count / 2)*4 ); + quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * max_quad_buf_size); + corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * max_quad_buf_size * 4 ); for( group_idx = 0; ; group_idx++ ) { @@ -424,7 +425,7 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size, // maybe delete or add some PRINTF("Starting ordering of inner quads\n"); count = icvOrderFoundConnectedQuads(count, quad_group, &quad_count, &quads, &corners, - pattern_size, storage ); + pattern_size, max_quad_buf_size, storage ); PRINTF("Orig count: %d After ordering: %d\n", icount, count); @@ -623,7 +624,7 @@ icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size ) static int icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads, int *all_count, CvCBQuad **all_quads, CvCBCorner **corners, - CvSize pattern_size, CvMemStorage* storage ) + CvSize pattern_size, int max_quad_buf_size, CvMemStorage* storage ) { cv::Ptr temp_storage = cvCreateChildMemStorage( storage ); CvSeq* stack = cvCreateSeq( 0, sizeof(*stack), sizeof(void*), temp_storage ); @@ -803,15 +804,18 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads, if (found > 0) { PRINTF("Found %d inner quads not connected to outer quads, repairing\n", found); - for (int i=0; icount < 4 && quads[i]->ordered) { - int added = icvAddOuterQuad(quads[i],quads,quad_count,all_quads,*all_count,corners); + int added = icvAddOuterQuad(quads[i],quads,quad_count,all_quads,*all_count,corners, max_quad_buf_size); *all_count += added; quad_count += added; } } + + if (*all_count >= max_quad_buf_size) + return 0; } @@ -854,11 +858,11 @@ icvOrderFoundConnectedQuads( int quad_count, CvCBQuad **quads, static int icvAddOuterQuad( CvCBQuad *quad, CvCBQuad **quads, int quad_count, - CvCBQuad **all_quads, int all_count, CvCBCorner **corners ) + CvCBQuad **all_quads, int all_count, CvCBCorner **corners, int max_quad_buf_size ) { int added = 0; - for (int i=0; i<4; i++) // find no-neighbor corners + for (int i=0; i<4 && all_count < max_quad_buf_size; i++) // find no-neighbor corners { if (!quad->neighbors[i]) // ok, create and add neighbor { @@ -1649,7 +1653,7 @@ static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count ) static int icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners, - CvMemStorage *storage, CvMat *image, int flags ) + CvMemStorage *storage, CvMat *image, int flags, int *max_quad_buf_size ) { int quad_count = 0; cv::Ptr temp_storage; @@ -1754,8 +1758,9 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners, cvEndFindContours( &scanner ); // allocate quad & corner buffers - *out_quads = (CvCBQuad*)cvAlloc((root->total+root->total / 2) * sizeof((*out_quads)[0])); - *out_corners = (CvCBCorner*)cvAlloc((root->total+root->total / 2) * 4 * sizeof((*out_corners)[0])); + *max_quad_buf_size = MAX(1, (root->total+root->total / 2)) * 2; + *out_quads = (CvCBQuad*)cvAlloc(*max_quad_buf_size * sizeof((*out_quads)[0])); + *out_corners = (CvCBCorner*)cvAlloc(*max_quad_buf_size * 4 * sizeof((*out_corners)[0])); // Create array of quads structures for( idx = 0; idx < root->total; idx++ ) From 2243bfa181dec54bf6cecca4f99a94296f807127 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sat, 15 Aug 2015 18:30:08 +0300 Subject: [PATCH 039/468] repaired gstreamer camera capture: 1. Enabled property retrieval: height, width, FPS 2. Fixed issue when isOpened returns always true even for non-existing devices 3. Ability to work with non-0 device. Camera capture index is taken into account (cherry picked from commit dbd7912b88e36a045d1086d54f77467de5ab006f) --- modules/highgui/src/cap.cpp | 6 +- modules/highgui/src/cap_gstreamer.cpp | 130 ++++++++++++++++---------- 2 files changed, 83 insertions(+), 53 deletions(-) diff --git a/modules/highgui/src/cap.cpp b/modules/highgui/src/cap.cpp index 491e388559..5c17848e8d 100644 --- a/modules/highgui/src/cap.cpp +++ b/modules/highgui/src/cap.cpp @@ -238,10 +238,12 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index) #endif #ifdef HAVE_GSTREAMER - capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L2, 0); + capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L2, + reinterpret_cast(index)); if (capture) return capture; - capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L, 0); + capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L, + reinterpret_cast(index)); if (capture) return capture; #endif diff --git a/modules/highgui/src/cap_gstreamer.cpp b/modules/highgui/src/cap_gstreamer.cpp index cae719996e..fe4eaf25e3 100644 --- a/modules/highgui/src/cap_gstreamer.cpp +++ b/modules/highgui/src/cap_gstreamer.cpp @@ -371,9 +371,7 @@ void CvCapture_GStreamer::startPipeline() if (status == GST_STATE_CHANGE_ASYNC) { // wait for status update - GstState st1; - GstState st2; - status = gst_element_get_state(pipeline, &st1, &st2, GST_CLOCK_TIME_NONE); + status = gst_element_get_state(pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); } if (status == GST_STATE_CHANGE_FAILURE) { @@ -568,21 +566,39 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) GstElementFactory * testfac; GstStateChangeReturn status; - if (type == CV_CAP_GSTREAMER_V4L){ + int cameraID = -1; + if (type == CV_CAP_GSTREAMER_V4L || + type == CV_CAP_GSTREAMER_V4L2) + { + cameraID = static_cast(reinterpret_cast(filename)); + } + + std::stringstream stdstream; + std::string stdfilename; + + if (type == CV_CAP_GSTREAMER_V4L) + { testfac = gst_element_factory_find("v4lsrc"); if (!testfac){ return false; } g_object_unref(G_OBJECT(testfac)); - filename = "v4lsrc ! "COLOR_ELEM" ! appsink"; + + stdstream << "v4lsrc device=/dev/video" << cameraID << " ! " << COLOR_ELEM << " ! appsink"; + stdfilename = stdstream.str(); + filename = stdfilename.c_str(); } - if (type == CV_CAP_GSTREAMER_V4L2){ + else if (type == CV_CAP_GSTREAMER_V4L2) + { testfac = gst_element_factory_find("v4l2src"); if (!testfac){ return false; } g_object_unref(G_OBJECT(testfac)); - filename = "v4l2src ! "COLOR_ELEM" ! appsink"; + + stdstream << "v4l2src device=/dev/video" << cameraID << " ! " << COLOR_ELEM << " ! appsink"; + stdfilename = stdstream.str(); + filename = stdfilename.c_str(); } @@ -620,7 +636,9 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) stream = true; manualpipeline = true; } - } else { + } + else + { stream = true; uri = g_strdup(filename); } @@ -641,64 +659,77 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) uridecodebin = gst_element_make_from_uri(GST_URI_SRC, uri, "src", NULL); #endif element_from_uri = true; - }else{ + } + else + { uridecodebin = gst_element_factory_make("uridecodebin", NULL); g_object_set(G_OBJECT(uridecodebin), "uri", uri, NULL); } g_free(protocol); - if(!uridecodebin) { + if(!uridecodebin) + { //fprintf(stderr, "GStreamer: Error opening bin: %s\n", err->message); close(); return false; } } - if(manualpipeline) + if (manualpipeline) { GstIterator *it = NULL; #if GST_VERSION_MAJOR == 0 it = gst_bin_iterate_sinks(GST_BIN(uridecodebin)); - if(gst_iterator_next(it, (gpointer *)&sink) != GST_ITERATOR_OK) { + if (gst_iterator_next(it, (gpointer *)&sink) != GST_ITERATOR_OK) + { CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n"); return false; } #else - it = gst_bin_iterate_sinks (GST_BIN(uridecodebin)); + it = gst_bin_iterate_elements(GST_BIN(uridecodebin)); - gboolean done = FALSE; + gboolean done = false; GstElement *element = NULL; gchar* name = NULL; GValue value = G_VALUE_INIT; - while (!done) { - switch (gst_iterator_next (it, &value)) { + while (!done) + { + switch (gst_iterator_next (it, &value)) + { case GST_ITERATOR_OK: - element = GST_ELEMENT (g_value_get_object (&value)); - name = gst_element_get_name(element); - if (name){ - if(strstr(name, "opencvsink") != NULL || strstr(name, "appsink") != NULL) { - sink = GST_ELEMENT ( gst_object_ref (element) ); - done = TRUE; + element = GST_ELEMENT (g_value_get_object (&value)); + name = gst_element_get_name(element); + if (name) + { + if (strstr(name, "opencvsink") != NULL || strstr(name, "appsink") != NULL) + { + sink = GST_ELEMENT ( gst_object_ref (element) ); + done = sink && color; + } + else if (strstr(name, COLOR_ELEM) != NULL) + { + color = GST_ELEMENT ( gst_object_ref (element) ); + done = sink && color; + } + g_free(name); } - g_free(name); - } - g_value_unset (&value); + g_value_unset (&value); - break; + break; case GST_ITERATOR_RESYNC: - gst_iterator_resync (it); - break; + gst_iterator_resync (it); + break; case GST_ITERATOR_ERROR: case GST_ITERATOR_DONE: - done = TRUE; - break; - } + done = TRUE; + break; + } } gst_iterator_free (it); - - if (!sink){ + if (!sink) + { CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n"); return false; } @@ -715,18 +746,23 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) gst_bin_add_many(GST_BIN(pipeline), uridecodebin, color, sink, NULL); - if(element_from_uri) { - if(!gst_element_link(uridecodebin, color)) { + if(element_from_uri) + { + if(!gst_element_link(uridecodebin, color)) + { CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n"); gst_object_unref(pipeline); pipeline = NULL; return false; } - }else{ + } + else + { g_signal_connect(uridecodebin, "pad-added", G_CALLBACK(newPad), color); } - if(!gst_element_link(color, sink)) { + if(!gst_element_link(color, sink)) + { CV_ERROR(CV_StsError, "GStreamer: cannot link color -> sink\n"); gst_object_unref(pipeline); pipeline = NULL; @@ -754,16 +790,13 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) gst_app_sink_set_caps(GST_APP_SINK(sink), caps); gst_caps_unref(caps); - // For video files only: set pipeline to PAUSED state to get its duration - if (file) { - status = gst_element_set_state(GST_ELEMENT(pipeline), GST_STATE_PAUSED); + status = gst_element_set_state(GST_ELEMENT(pipeline), + file ? GST_STATE_PAUSED : GST_STATE_PLAYING); if (status == GST_STATE_CHANGE_ASYNC) { // wait for status update - GstState st1; - GstState st2; - status = gst_element_get_state(pipeline, &st1, &st2, GST_CLOCK_TIME_NONE); + status = gst_element_get_state(pipeline, NULL, NULL, GST_CLOCK_TIME_NONE); } if (status == GST_STATE_CHANGE_FAILURE) { @@ -814,14 +847,9 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) fps = (double)num/(double)denom; - // GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline"); - } - else - { - duration = -1; - width = -1; - height = -1; - fps = -1; + // GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline") + + stopPipeline(); } __END__; From 9a3e53e7386b7a94976d216dae41ddb48600db3d Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sun, 16 Aug 2015 21:01:22 +0300 Subject: [PATCH 040/468] repaired GStreamer 0.10 version (cherry picked from commit c19ed39a785d7ac9e39c117cfacc3827024619f7) --- cmake/OpenCVFindLibsVideo.cmake | 6 +++--- modules/highgui/src/cap_gstreamer.cpp | 30 +++++++++++++++------------ 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake index 1654df73ca..514aa5cd3d 100644 --- a/cmake/OpenCVFindLibsVideo.cmake +++ b/cmake/OpenCVFindLibsVideo.cmake @@ -12,8 +12,8 @@ endif(WITH_VFW) # --- GStreamer --- ocv_clear_vars(HAVE_GSTREAMER) -# try to find gstreamer 1.x first -if(WITH_GSTREAMER) +# try to find gstreamer 1.x first if 0.10 was not requested +if(WITH_GSTREAMER AND NOT WITH_GSTREAMER_0_10) CHECK_MODULE(gstreamer-base-1.0 HAVE_GSTREAMER_BASE) CHECK_MODULE(gstreamer-video-1.0 HAVE_GSTREAMER_VIDEO) CHECK_MODULE(gstreamer-app-1.0 HAVE_GSTREAMER_APP) @@ -29,7 +29,7 @@ if(WITH_GSTREAMER) set(GSTREAMER_PBUTILS_VERSION ${ALIASOF_gstreamer-pbutils-1.0_VERSION}) endif() -endif(WITH_GSTREAMER) +endif() # gstreamer support was requested but could not find gstreamer 1.x, # so fallback/try to find gstreamer 0.10 diff --git a/modules/highgui/src/cap_gstreamer.cpp b/modules/highgui/src/cap_gstreamer.cpp index fe4eaf25e3..957587c219 100644 --- a/modules/highgui/src/cap_gstreamer.cpp +++ b/modules/highgui/src/cap_gstreamer.cpp @@ -75,10 +75,13 @@ #if GST_VERSION_MAJOR == 0 #define COLOR_ELEM "ffmpegcolorspace" +#define COLOR_ELEM_NAME "ffmpegcsp" #elif FULL_GST_VERSION < VERSION_NUM(1,5,0) #define COLOR_ELEM "videoconvert" +#define COLOR_ELEM_NAME COLOR_ELEM #else #define COLOR_ELEM "autovideoconvert" +#define COLOR_ELEM_NAME COLOR_ELEM #endif void toFraction(double decimal, double &numerator, double &denominator); @@ -677,28 +680,27 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) if (manualpipeline) { - GstIterator *it = NULL; -#if GST_VERSION_MAJOR == 0 - it = gst_bin_iterate_sinks(GST_BIN(uridecodebin)); - if (gst_iterator_next(it, (gpointer *)&sink) != GST_ITERATOR_OK) - { - CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n"); - return false; - } -#else - it = gst_bin_iterate_elements(GST_BIN(uridecodebin)); + GstIterator *it = gst_bin_iterate_elements(GST_BIN(uridecodebin)); - gboolean done = false; GstElement *element = NULL; + gboolean done = false; gchar* name = NULL; +#if GST_VERSION_MAJOR > 0 GValue value = G_VALUE_INIT; +#endif while (!done) { +#if GST_VERSION_MAJOR > 0 switch (gst_iterator_next (it, &value)) { case GST_ITERATOR_OK: element = GST_ELEMENT (g_value_get_object (&value)); +#else + switch (gst_iterator_next (it, (gpointer *)&element)) + { + case GST_ITERATOR_OK: +#endif name = gst_element_get_name(element); if (name) { @@ -707,14 +709,16 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) sink = GST_ELEMENT ( gst_object_ref (element) ); done = sink && color; } - else if (strstr(name, COLOR_ELEM) != NULL) + else if (strstr(name, COLOR_ELEM_NAME) != NULL) { color = GST_ELEMENT ( gst_object_ref (element) ); done = sink && color; } g_free(name); } +#if GST_VERSION_MAJOR > 0 g_value_unset (&value); +#endif break; case GST_ITERATOR_RESYNC: @@ -733,7 +737,7 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) CV_ERROR(CV_StsError, "GStreamer: cannot find appsink in manual pipeline\n"); return false; } -#endif + pipeline = uridecodebin; } else From 56654ae360b7ecdb658398fd5efd5a0c76ada71d Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Sun, 16 Aug 2015 21:25:36 +0300 Subject: [PATCH 041/468] added some property setting and getting (cherry picked from commit 75fcedf0edbc83a900918de1a25195eaefc214f5) --- modules/highgui/src/cap_gstreamer.cpp | 50 +++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/modules/highgui/src/cap_gstreamer.cpp b/modules/highgui/src/cap_gstreamer.cpp index 957587c219..cab652dfd2 100644 --- a/modules/highgui/src/cap_gstreamer.cpp +++ b/modules/highgui/src/cap_gstreamer.cpp @@ -145,6 +145,7 @@ protected: gpointer data); GstElement* pipeline; GstElement* uridecodebin; + GstElement* v4l2src; GstElement* color; GstElement* sink; #if GST_VERSION_MAJOR > 0 @@ -168,6 +169,7 @@ void CvCapture_GStreamer::init() { pipeline = NULL; uridecodebin = NULL; + v4l2src = NULL; color = NULL; sink = NULL; #if GST_VERSION_MAJOR > 0 @@ -707,14 +709,18 @@ bool CvCapture_GStreamer::open( int type, const char* filename ) if (strstr(name, "opencvsink") != NULL || strstr(name, "appsink") != NULL) { sink = GST_ELEMENT ( gst_object_ref (element) ); - done = sink && color; } else if (strstr(name, COLOR_ELEM_NAME) != NULL) { color = GST_ELEMENT ( gst_object_ref (element) ); - done = sink && color; + } + else if (strstr(name, "v4l") != NULL) + { + v4l2src = GST_ELEMENT ( gst_object_ref (element) ); } g_free(name); + + done = sink && color && v4l2src; } #if GST_VERSION_MAJOR > 0 g_value_unset (&value); @@ -884,7 +890,7 @@ double CvCapture_GStreamer::getProperty( int propId ) if(!pipeline) { CV_WARN("GStreamer: no pipeline"); - return false; + return 0; } switch(propId) { @@ -893,7 +899,7 @@ double CvCapture_GStreamer::getProperty( int propId ) status = gst_element_query_position(sink, FORMAT, &value); if(!status) { CV_WARN("GStreamer: unable to query position of stream"); - return false; + return 0; } return value * 1e-6; // nano seconds to milli seconds case CV_CAP_PROP_POS_FRAMES: @@ -901,7 +907,7 @@ double CvCapture_GStreamer::getProperty( int propId ) status = gst_element_query_position(sink, FORMAT, &value); if(!status) { CV_WARN("GStreamer: unable to query position of stream"); - return false; + return 0; } return value; case CV_CAP_PROP_POS_AVI_RATIO: @@ -909,7 +915,7 @@ double CvCapture_GStreamer::getProperty( int propId ) status = gst_element_query_position(sink, FORMAT, &value); if(!status) { CV_WARN("GStreamer: unable to query position of stream"); - return false; + return 0; } return ((double) value) / GST_FORMAT_PERCENT_MAX; case CV_CAP_PROP_FRAME_WIDTH: @@ -928,6 +934,21 @@ double CvCapture_GStreamer::getProperty( int propId ) case CV_CAP_PROP_CONTRAST: case CV_CAP_PROP_SATURATION: case CV_CAP_PROP_HUE: + if (v4l2src) + { + const gchar * propName = + propId == CV_CAP_PROP_BRIGHTNESS ? "brightness" : + propId == CV_CAP_PROP_CONTRAST ? "contrast" : + propId == CV_CAP_PROP_SATURATION ? "saturation" : + propId == CV_CAP_PROP_HUE ? "hue" : NULL; + + if (propName) + { + gint32 value32 = 0; + g_object_get(G_OBJECT(v4l2src), propName, &value32, NULL); + return value32; + } + } case CV_CAP_PROP_GAIN: case CV_CAP_PROP_CONVERT_RGB: break; @@ -944,7 +965,7 @@ double CvCapture_GStreamer::getProperty( int propId ) #undef FORMAT - return false; + return 0; } /*! @@ -1023,6 +1044,21 @@ bool CvCapture_GStreamer::setProperty( int propId, double value ) case CV_CAP_PROP_CONTRAST: case CV_CAP_PROP_SATURATION: case CV_CAP_PROP_HUE: + if (v4l2src) + { + const gchar * propName = + propId == CV_CAP_PROP_BRIGHTNESS ? "brightness" : + propId == CV_CAP_PROP_CONTRAST ? "contrast" : + propId == CV_CAP_PROP_SATURATION ? "saturation" : + propId == CV_CAP_PROP_HUE ? "hue" : NULL; + + if (propName) + { + gint32 value32 = cv::saturate_cast(value); + g_object_set(G_OBJECT(v4l2src), propName, &value32, NULL); + return true; + } + } case CV_CAP_PROP_GAIN: case CV_CAP_PROP_CONVERT_RGB: break; From 1ea65689519c1f907d6ff2a01f46485be0ee6076 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Thu, 24 Sep 2015 15:52:17 +0300 Subject: [PATCH 042/468] Fixed wrong-name-for-changelog-of-native-package warning for deb packages. (cherry picked from commit cb1dc7cb6e8886f02864467aeae6c584a7eccc76) --- cmake/OpenCVPackaging.cmake | 13 +++++++++++++ cmake/templates/changelog.Debian.in | 3 ++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index f6d5bd04a0..a1151c1cf3 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -201,6 +201,19 @@ if(CPACK_GENERATOR STREQUAL "DEB") install(FILES "${DEBIAN_CHANGELOG_OUT_FILE_GZ}" DESTINATION "share/doc/${CPACK_DEBIAN_COMPONENT_${comp_upcase}_NAME}" COMPONENT "${comp}") + + set(CHANGELOG_OUT_FILE "${CMAKE_BINARY_DIR}/deb-packages-gen/${comp}/changelog") + set(CHANGELOG_OUT_FILE_GZ "${CMAKE_BINARY_DIR}/deb-packages-gen/${comp}/changelog.gz") + file(WRITE ${CHANGELOG_OUT_FILE} "Upstream changelog stub. See https://github.com/Itseez/opencv/wiki/ChangeLog") + + execute_process(COMMAND "${GZIP_TOOL}" "-cf9" "${CHANGELOG_OUT_FILE}" + OUTPUT_FILE "${CHANGELOG_OUT_FILE_GZ}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") + + install(FILES "${CHANGELOG_OUT_FILE_GZ}" + DESTINATION "share/doc/${CPACK_DEBIAN_COMPONENT_${comp_upcase}_NAME}" + COMPONENT "${comp}") + endforeach() endif() diff --git a/cmake/templates/changelog.Debian.in b/cmake/templates/changelog.Debian.in index 70486e8090..a47ec42bc8 100644 --- a/cmake/templates/changelog.Debian.in +++ b/cmake/templates/changelog.Debian.in @@ -1,4 +1,5 @@ @CHANGELOG_PACKAGE_NAME@ (@CPACK_PACKAGE_VERSION@) unstable; urgency=low - * Debian changelog stub. See upstream changelog or release notes in user + * Debian changelog stub. See https://github.com/Itseez/opencv/wiki/ChangeLog + or release notes in user documentation for more details. -- @CPACK_PACKAGE_CONTACT@ @CHANGELOG_PACKAGE_DATE@ From 15b313ce4bd08cb380dba6a569eb816e31ceb084 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Mon, 12 Oct 2015 00:11:45 +0300 Subject: [PATCH 043/468] fixed memory leak in findHomography tests (cherry picked from commit ec5244a73abf36014fdd2763ff1f16e5e986cbb4) --- modules/calib3d/test/test_homography.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/calib3d/test/test_homography.cpp b/modules/calib3d/test/test_homography.cpp index f68af1d7c1..2db0a3c1ab 100644 --- a/modules/calib3d/test/test_homography.cpp +++ b/modules/calib3d/test/test_homography.cpp @@ -12,6 +12,7 @@ // // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. // Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Copyright (C) 2015, Itseez Inc., all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -562,6 +563,9 @@ void CV_HomographyTest::run(int) default: continue; } } + + delete[]src_data; + src_data = NULL; } } From 96a2edb3756af078d8d7752e2911687df6d1bf0f Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Mon, 12 Oct 2015 00:37:46 +0300 Subject: [PATCH 044/468] delete video readers (cherry picked from commit 0d5b739d35e7a0c2d2b88db58994397ae969f468) --- modules/highgui/test/test_ffmpeg.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/highgui/test/test_ffmpeg.cpp b/modules/highgui/test/test_ffmpeg.cpp index 09de119ac6..31108f857c 100644 --- a/modules/highgui/test/test_ffmpeg.cpp +++ b/modules/highgui/test/test_ffmpeg.cpp @@ -396,6 +396,10 @@ TEST(Highgui_Video_parallel_writers_and_readers, accuracy) if (code == 1) std::cerr << "Couldn't delete " << *i << std::endl; } + + // delete the readers + for (std::vector::iterator i = readers.begin(), end = readers.end(); i != end; ++i) + delete *i; } #endif From a5c20f859281a93689cb6f1b46006c2233e8bd44 Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Mon, 12 Oct 2015 11:37:26 +0300 Subject: [PATCH 045/468] Debian formatted copyright file added to all debian packages. (cherry picked from commit 9d24b3c3b0133c29a642aa5a0d2a0634333287f3) --- cmake/OpenCVPackaging.cmake | 9 +++++++- cmake/templates/copyright | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 cmake/templates/copyright diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index a1151c1cf3..e64d447bfa 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -19,6 +19,7 @@ OpenCV makes it easy for businesses to utilize and modify the code.") set(CPACK_PACKAGE_VERSION_MINOR "${OPENCV_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${OPENCV_VERSION_PATCH}") set(CPACK_PACKAGE_VERSION "${OPENCV_VCSVERSION}") + set(OPENCV_DEBIAN_COPYRIGHT_FILE "") endif(NOT OPENCV_CUSTOM_PACKAGE_INFO) set(CPACK_STRIP_FILES 1) @@ -192,7 +193,7 @@ if(CPACK_GENERATOR STREQUAL "DEB") set(DEBIAN_CHANGELOG_OUT_FILE "${CMAKE_BINARY_DIR}/deb-packages-gen/${comp}/changelog.Debian") set(DEBIAN_CHANGELOG_OUT_FILE_GZ "${CMAKE_BINARY_DIR}/deb-packages-gen/${comp}/changelog.Debian.gz") set(CHANGELOG_PACKAGE_NAME "${CPACK_DEBIAN_COMPONENT_${comp_upcase}_NAME}") - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/changelog.Debian.in" "${DEBIAN_CHANGELOG_OUT_FILE}" @ONLY) + configure_file("${CMAKE_SOURCE_DIR}/cmake/templates/changelog.Debian.in" "${DEBIAN_CHANGELOG_OUT_FILE}" @ONLY) execute_process(COMMAND "${GZIP_TOOL}" "-cf9" "${DEBIAN_CHANGELOG_OUT_FILE}" OUTPUT_FILE "${DEBIAN_CHANGELOG_OUT_FILE_GZ}" @@ -214,6 +215,12 @@ if(CPACK_GENERATOR STREQUAL "DEB") DESTINATION "share/doc/${CPACK_DEBIAN_COMPONENT_${comp_upcase}_NAME}" COMPONENT "${comp}") + if(OPENCV_DEBIAN_COPYRIGHT_FILE) + install(FILES "${OPENCV_DEBIAN_COPYRIGHT_FILE}" + DESTINATION "share/doc/${CPACK_DEBIAN_COMPONENT_${comp_upcase}_NAME}" + COMPONENT "${comp}") + endif() + endforeach() endif() diff --git a/cmake/templates/copyright b/cmake/templates/copyright new file mode 100644 index 0000000000..5e66dab7fc --- /dev/null +++ b/cmake/templates/copyright @@ -0,0 +1,43 @@ +Format: http://dep.debian.net/deps/dep5 + +Files: * +Copyright: 2000-2015, Intel Corporation + 2009-2011, Willow Garage Inc. + 2009-2015, NVIDIA Corporation + 2010-2013, Advanced Micro Devices, Inc. + 2015, OpenCV Foundation + 2015, Itseez Inc. +License: BSD-3-clause + By downloading, copying, installing or using the software you agree to this + license. If you do not agree to this license, do not download, install, copy + or use the software. +. +. + License Agreement + For Open Source Computer Vision Library + (3-clause BSD License) + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: +. + \* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +. + \* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +. + \* Neither the names of the copyright holders nor the names of the + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + + This software is provided by the copyright holders and contributors "as is" + and any express or implied warranties, including, but not limited to, the + implied warranties of merchantability and fitness for a particular purpose are + disclaimed. In no event shall copyright holders or contributors be liable for + any direct, indirect, incidental, special, exemplary, or consequential damages + (including, but not limited to, procurement of substitute goods or services; + loss of use, data, or profits; or business interruption) however caused + and on any theory of liability, whether in contract, strict liability, + or tort (including negligence or otherwise) arising in any way out of + the use of this software, even if advised of the possibility of such damage. From 8a37fc82238a8ade347ea1af483227db28737f0d Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 13 Oct 2015 15:02:38 +0300 Subject: [PATCH 046/468] Added missing copyright headers. (cherry picked from commit 408107ce6d16ae118167ffe22fda6bdcdb9514cb) --- include/opencv/cxmisc.h | 42 +++++++++++++++++++++ modules/flann/include/opencv2/flann/dummy.h | 29 ++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/include/opencv/cxmisc.h b/include/opencv/cxmisc.h index 6446944643..3a76656290 100644 --- a/include/opencv/cxmisc.h +++ b/include/opencv/cxmisc.h @@ -1,3 +1,45 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// + * // + * // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + * // + * // By downloading, copying, installing or using the software you agree to this license. + * // If you do not agree to this license, do not download, install, + * // copy or use the software. + * // + * // + * // License Agreement + * // For Open Source Computer Vision Library + * // + * // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. + * // Copyright (C) 2009, Willow Garage Inc., all rights reserved. + * // Third party copyrights are property of their respective owners. + * // + * // Redistribution and use in source and binary forms, with or without modification, + * // are permitted provided that the following conditions are met: + * // + * // * Redistribution's of source code must retain the above copyright notice, + * // this list of conditions and the following disclaimer. + * // + * // * Redistribution's in binary form must reproduce the above copyright notice, + * // this list of conditions and the following disclaimer in the documentation + * // and/or other materials provided with the distribution. + * // + * // * The name of the copyright holders may not be used to endorse or promote products + * // derived from this software without specific prior written permission. + * // + * // This software is provided by the copyright holders and contributors "as is" and + * // any express or implied warranties, including, but not limited to, the implied + * // warranties of merchantability and fitness for a particular purpose are disclaimed. + * // In no event shall the Intel Corporation or contributors be liable for any direct, + * // indirect, incidental, special, exemplary, or consequential damages + * // (including, but not limited to, procurement of substitute goods or services; + * // loss of use, data, or profits; or business interruption) however caused + * // and on any theory of liability, whether in contract, strict liability, + * // or tort (including negligence or otherwise) arising in any way out of + * // the use of this software, even if advised of the possibility of such damage. + * // + * //M*/ + #ifndef __OPENCV_OLD_CXMISC_H__ #define __OPENCV_OLD_CXMISC_H__ diff --git a/modules/flann/include/opencv2/flann/dummy.h b/modules/flann/include/opencv2/flann/dummy.h index 26bd3fa5dd..339098180c 100644 --- a/modules/flann/include/opencv2/flann/dummy.h +++ b/modules/flann/include/opencv2/flann/dummy.h @@ -1,3 +1,32 @@ +/*********************************************************************** + * Software License Agreement (BSD License) + * + * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. + * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. + * + * THE BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *************************************************************************/ #ifndef OPENCV_FLANN_DUMMY_H_ #define OPENCV_FLANN_DUMMY_H_ From 2d3e1703707a0734de106759ecce4bd5275eb825 Mon Sep 17 00:00:00 2001 From: a-andre Date: Tue, 13 Oct 2015 18:16:14 +0200 Subject: [PATCH 047/468] install opencv2/highgui.hpp header (cherry picked from commit d16fb3051296feebd04cdd7a372e0049629c155f) --- modules/highgui/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index 7905872b80..44cf98c613 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -64,7 +64,7 @@ set(highgui_srcs src/window.cpp ) -file(GLOB highgui_ext_hdrs "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h") +file(GLOB highgui_ext_hdrs "include/opencv2/*.hpp" "include/opencv2/${name}/*.hpp" "include/opencv2/${name}/*.h") if(HAVE_QT5) set(CMAKE_AUTOMOC ON) From ca50969c2b9bd71f2f6ce7569f8ad595b1bf5244 Mon Sep 17 00:00:00 2001 From: Aaron Simmons Date: Tue, 13 Oct 2015 17:42:40 -0600 Subject: [PATCH 048/468] brining over fix in master (#4140) for libz import on 64-bit android (cherry picked from commit 55a9fdf0512a6bd3fd82591f48db0942cbd4fc38) --- cmake/OpenCVFindLibsGrfmt.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/OpenCVFindLibsGrfmt.cmake b/cmake/OpenCVFindLibsGrfmt.cmake index f27a302ab7..43c3b16cc1 100644 --- a/cmake/OpenCVFindLibsGrfmt.cmake +++ b/cmake/OpenCVFindLibsGrfmt.cmake @@ -8,7 +8,8 @@ if(BUILD_ZLIB) else() include(FindZLIB) if(ZLIB_FOUND AND ANDROID) - if(ZLIB_LIBRARY STREQUAL "${ANDROID_SYSROOT}/usr/lib/libz.so") + if(ZLIB_LIBRARIES STREQUAL "${ANDROID_SYSROOT}/usr/lib/libz.so" OR + ZLIB_LIBRARIES STREQUAL "${ANDROID_SYSROOT}/usr/lib64/libz.so") set(ZLIB_LIBRARY z) set(ZLIB_LIBRARIES z) endif() From 42447a7610af61e07e3ee210fcfd62920319751e Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Tue, 13 Oct 2015 16:32:53 +0300 Subject: [PATCH 049/468] Set of lintain warning fixes for -samples debian package. (cherry picked from commit ff002203029220cd63bbb383b3f286a1ee7c35f3) --- samples/CMakeLists.txt | 2 +- samples/c/CMakeLists.txt | 7 ++++--- samples/cpp/CMakeLists.txt | 4 ++-- samples/gpu/CMakeLists.txt | 4 ++-- samples/gpu/performance/CMakeLists.txt | 4 ++-- samples/ocl/CMakeLists.txt | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index d2089de768..1754649f10 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -22,7 +22,7 @@ endif() if(INSTALL_C_EXAMPLES) install(FILES "CMakeLists.txt" DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH} - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT samples) endif() if(INSTALL_PYTHON_EXAMPLES) diff --git a/samples/c/CMakeLists.txt b/samples/c/CMakeLists.txt index 61f23666f3..cb653c752c 100644 --- a/samples/c/CMakeLists.txt +++ b/samples/c/CMakeLists.txt @@ -52,8 +52,9 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) endif() if (OCV_DEPENDENCIES_FOUND AND INSTALL_C_EXAMPLES AND NOT WIN32) - file(GLOB C_SAMPLES *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd *.txt) + file(GLOB C_SAMPLES *.c *.cpp *.jpg *.png *.data makefile.* *.cmd *.txt) install(FILES ${C_SAMPLES} - DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/c - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + DESTINATION "${OPENCV_SAMPLES_SRC_INSTALL_PATH}/c" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT samples) + install(PROGRAMS build_all.sh DESTINATION "${OPENCV_SAMPLES_SRC_INSTALL_PATH}/c" COMPONENT samples) endif () diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 65e402bc13..fa52ac4860 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -93,6 +93,6 @@ endif() if (OCV_DEPENDENCIES_FOUND AND INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB C_SAMPLES *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd *.txt) install(FILES ${C_SAMPLES} - DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/cpp - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + DESTINATION "${OPENCV_SAMPLES_SRC_INSTALL_PATH}/cpp" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT samples) endif() diff --git a/samples/gpu/CMakeLists.txt b/samples/gpu/CMakeLists.txt index dc7464f942..cdf9ee8562 100644 --- a/samples/gpu/CMakeLists.txt +++ b/samples/gpu/CMakeLists.txt @@ -112,6 +112,6 @@ if (OCV_DEPENDENCIES_FOUND AND INSTALL_C_EXAMPLES AND NOT WIN32) list_filterout(install_list ".*driver_api_stereo_multi.cpp") endif() install(FILES ${install_list} - DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/gpu - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + DESTINATION "${OPENCV_SAMPLES_SRC_INSTALL_PATH}/gpu" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT samples) endif() diff --git a/samples/gpu/performance/CMakeLists.txt b/samples/gpu/performance/CMakeLists.txt index 4a1603a916..d0810af22d 100644 --- a/samples/gpu/performance/CMakeLists.txt +++ b/samples/gpu/performance/CMakeLists.txt @@ -29,7 +29,7 @@ endif() if(INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB GPU_FILES performance/*.cpp performance/*.h performance/CMakeLists.txt) install(FILES ${GPU_FILES} - DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/gpu/performance - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ + DESTINATION "${OPENCV_SAMPLES_SRC_INSTALL_PATH}/gpu/performance" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT samples) endif() diff --git a/samples/ocl/CMakeLists.txt b/samples/ocl/CMakeLists.txt index 10db9b10fb..706c4ae0bd 100644 --- a/samples/ocl/CMakeLists.txt +++ b/samples/ocl/CMakeLists.txt @@ -54,6 +54,6 @@ endif() if (OCV_DEPENDENCIES_FOUND AND INSTALL_C_EXAMPLES AND NOT WIN32) file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd *.txt) install(FILES ${install_list} - DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/ocl - PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples) + DESTINATION "${OPENCV_SAMPLES_SRC_INSTALL_PATH}/ocl" + PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT samples) endif() From 966d35a9fbd5102605c6742f493c405190b8a6cc Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 14 Oct 2015 12:52:32 +0300 Subject: [PATCH 050/468] Made samples build independent from nonfree module. (cherry picked from commit bba8c0beacf34143509b60aaf5321c56b2a21013) --- samples/CMakeLists.txt | 10 +++- samples/c/CMakeLists.txt | 2 +- samples/c/find_obj.cpp | 34 +++++++---- samples/c/find_obj_calonder.cpp | 31 +++++++--- samples/c/one_way_sample.cpp | 30 +++++++--- samples/cpp/CMakeLists.txt | 5 +- samples/cpp/bagofwords_classification.cpp | 58 ++++++++++++------- samples/cpp/descriptor_extractor_matcher.cpp | 13 ++++- samples/cpp/fabmap_sample.cpp | 18 +++++- samples/cpp/freak_demo.cpp | 28 ++++++--- samples/cpp/generic_descriptor_match.cpp | 26 +++++++-- samples/cpp/matcher_simple.cpp | 22 +++++-- .../features2D/SURF_FlannMatcher.cpp | 27 ++++++--- .../features2D/SURF_Homography.cpp | 29 +++++++--- .../features2D/SURF_descriptor.cpp | 23 ++++++-- .../features2D/SURF_detector.cpp | 23 ++++++-- samples/ocl/CMakeLists.txt | 5 +- samples/ocl/surf_matcher.cpp | 27 ++++++--- 18 files changed, 301 insertions(+), 110 deletions(-) diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 1754649f10..df01dc76b6 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -68,8 +68,14 @@ endif() add_subdirectory(c) add_subdirectory(cpp) -add_subdirectory(ocl) -add_subdirectory(gpu) +ocv_check_dependencies(opencv_ocl) +if (OCV_DEPENDENCIES_FOUND) + add_subdirectory(ocl) +endif() +ocv_check_dependencies(opencv_gpu) +if (OCV_DEPENDENCIES_FOUND) + add_subdirectory(gpu) +endif() # # END OF BUILD CASE 2: Build samples with library binaries diff --git a/samples/c/CMakeLists.txt b/samples/c/CMakeLists.txt index cb653c752c..b26e4ab662 100644 --- a/samples/c/CMakeLists.txt +++ b/samples/c/CMakeLists.txt @@ -4,7 +4,7 @@ # ---------------------------------------------------------------------------- SET(OPENCV_C_SAMPLES_REQUIRED_DEPS opencv_core opencv_flann opencv_imgproc - opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_photo opencv_nonfree + opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_photo opencv_features2d opencv_calib3d opencv_legacy opencv_contrib) ocv_check_dependencies(${OPENCV_C_SAMPLES_REQUIRED_DEPS}) diff --git a/samples/c/find_obj.cpp b/samples/c/find_obj.cpp index e0431fc6d4..e0ae60cacc 100644 --- a/samples/c/find_obj.cpp +++ b/samples/c/find_obj.cpp @@ -4,19 +4,31 @@ * Author: Liu Liu * liuliu.1987+opencv@gmail.com */ -#include "opencv2/objdetect/objdetect.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/calib3d/calib3d.hpp" -#include "opencv2/nonfree/nonfree.hpp" -#include "opencv2/imgproc/imgproc_c.h" -#include "opencv2/legacy/legacy.hpp" -#include "opencv2/legacy/compat.hpp" -#include -#include +#include "opencv2/opencv_modules.hpp" #include +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + printf("The sample requires nonfree module that is not available in your OpenCV distribution.\n"); + return -1; +} + +#else + +# include "opencv2/objdetect/objdetect.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/calib3d/calib3d.hpp" +# include "opencv2/nonfree/nonfree.hpp" +# include "opencv2/imgproc/imgproc_c.h" +# include "opencv2/legacy/legacy.hpp" +# include "opencv2/legacy/compat.hpp" + +# include + using namespace std; static void help() { @@ -320,3 +332,5 @@ int main(int argc, char** argv) return 0; } + +#endif diff --git a/samples/c/find_obj_calonder.cpp b/samples/c/find_obj_calonder.cpp index 02cd266526..685e703c54 100644 --- a/samples/c/find_obj_calonder.cpp +++ b/samples/c/find_obj_calonder.cpp @@ -1,12 +1,25 @@ -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/core/core.hpp" -#include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/nonfree/nonfree.hpp" -#include "opencv2/legacy/legacy.hpp" - +#include "opencv2/opencv_modules.hpp" #include -#include + +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + std::cout << "The sample requires nonfree module that is not available in your OpenCV distribution." << std::endl; + return -1; +} + +#else + +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/core/core.hpp" +# include "opencv2/imgproc/imgproc.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/nonfree/nonfree.hpp" +# include "opencv2/legacy/legacy.hpp" + +# include +# include using namespace std; using namespace cv; @@ -164,3 +177,5 @@ int main( int argc, char **argv ) return 0; } + +#endif diff --git a/samples/c/one_way_sample.cpp b/samples/c/one_way_sample.cpp index ad0153ba0c..6db28baf36 100644 --- a/samples/c/one_way_sample.cpp +++ b/samples/c/one_way_sample.cpp @@ -7,16 +7,28 @@ * */ -#include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/imgproc/imgproc_c.h" -#include "opencv2/nonfree/nonfree.hpp" -#include "opencv2/legacy/legacy.hpp" -#include "opencv2/legacy/compat.hpp" +#include "opencv2/opencv_modules.hpp" +#include + +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + printf("The sample requires nonfree module that is not available in your OpenCV distribution.\n"); + return -1; +} + +#else + +# include "opencv2/imgproc/imgproc.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/imgproc/imgproc_c.h" +# include "opencv2/nonfree/nonfree.hpp" +# include "opencv2/legacy/legacy.hpp" +# include "opencv2/legacy/compat.hpp" #include -#include static void help() { @@ -116,3 +128,5 @@ Mat DrawCorrespondences(const Mat& img1, const vector& features1, cons return img_corr; } + +#endif diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index fa52ac4860..5eff52a90f 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -4,8 +4,9 @@ # ---------------------------------------------------------------------------- SET(OPENCV_CPP_SAMPLES_REQUIRED_DEPS opencv_core opencv_flann opencv_imgproc - opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_photo opencv_nonfree - opencv_features2d opencv_calib3d opencv_legacy opencv_contrib opencv_stitching opencv_videostab) + opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_photo + opencv_features2d opencv_calib3d opencv_legacy opencv_contrib + opencv_stitching opencv_videostab) ocv_check_dependencies(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS}) diff --git a/samples/cpp/bagofwords_classification.cpp b/samples/cpp/bagofwords_classification.cpp index db194b536c..d351baaa96 100644 --- a/samples/cpp/bagofwords_classification.cpp +++ b/samples/cpp/bagofwords_classification.cpp @@ -1,29 +1,41 @@ #include "opencv2/opencv_modules.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/nonfree/nonfree.hpp" -#include "opencv2/ml/ml.hpp" -#ifdef HAVE_OPENCV_OCL -#define _OCL_SVM_ 1 //select whether using ocl::svm method or not, default is using -#include "opencv2/ocl/ocl.hpp" -#endif - -#include #include -#include -#include -#if defined WIN32 || defined _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#undef min -#undef max -#include "sys/types.h" -#endif -#include +#ifndef HAVE_OPENCV_NONFREE -#define DEBUG_DESC_PROGRESS +int main(int, char**) +{ + std::cout << "The sample requires nonfree module that is not available in your OpenCV distribution." << std::endl; + return -1; +} + +#else + +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/imgproc/imgproc.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/nonfree/nonfree.hpp" +# include "opencv2/ml/ml.hpp" +# ifdef HAVE_OPENCV_OCL +# define _OCL_SVM_ 1 //select whether using ocl::svm method or not, default is using +# include "opencv2/ocl/ocl.hpp" +# endif + +# include +# include +# include + + +# if defined WIN32 || defined _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# undef min +# undef max +# include "sys/types.h" +# endif +# include + +# define DEBUG_DESC_PROGRESS using namespace cv; using namespace std; @@ -2623,3 +2635,5 @@ int main(int argc, char** argv) } return 0; } + +#endif diff --git a/samples/cpp/descriptor_extractor_matcher.cpp b/samples/cpp/descriptor_extractor_matcher.cpp index 98c6452234..4a9a63403a 100644 --- a/samples/cpp/descriptor_extractor_matcher.cpp +++ b/samples/cpp/descriptor_extractor_matcher.cpp @@ -1,8 +1,11 @@ +#include "opencv2/opencv_modules.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/calib3d/calib3d.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/features2d/features2d.hpp" -#include "opencv2/nonfree/nonfree.hpp" +#ifdef HAVE_OPENCV_NONFREE +# include "opencv2/nonfree/nonfree.hpp" +#endif #include @@ -17,14 +20,14 @@ static void help(char** argv) << "Case1: second image is obtained from the first (given) image using random generated homography matrix\n" << argv[0] << " [detectorType] [descriptorType] [matcherType] [matcherFilterType] [image] [evaluate(0 or 1)]\n" << "Example of case1:\n" - << "./descriptor_extractor_matcher SURF SURF FlannBased NoneFilter cola.jpg 0\n" + << "./descriptor_extractor_matcher ORB ORB FlannBased NoneFilter cola.jpg 0\n" << "\n" << "Case2: both images are given. If ransacReprojThreshold>=0 then homography matrix are calculated\n" << argv[0] << " [detectorType] [descriptorType] [matcherType] [matcherFilterType] [image1] [image2] [ransacReprojThreshold]\n" << "\n" << "Matches are filtered using homography matrix in case1 and case2 (if ransacReprojThreshold>=0)\n" << "Example of case2:\n" - << "./descriptor_extractor_matcher SURF SURF BruteForce CrossCheckFilter cola1.jpg cola2.jpg 3\n" + << "./descriptor_extractor_matcher ORB ORB BruteForce CrossCheckFilter cola1.jpg cola2.jpg 3\n" << "\n" << "Possible detectorType values: see in documentation on createFeatureDetector().\n" << "Possible descriptorType values: see in documentation on createDescriptorExtractor().\n" @@ -239,7 +242,11 @@ int main(int argc, char** argv) return -1; } +#ifdef HAVE_OPENCV_NONFREE cv::initModule_nonfree(); +#else + cout << "Warning: OpenCV is built without nonfree support SIFT, SURF and some other algorithms are not available." << endl; +#endif bool isWarpPerspective = argc == 7; double ransacReprojThreshold = -1; diff --git a/samples/cpp/fabmap_sample.cpp b/samples/cpp/fabmap_sample.cpp index bbe5f2b4c5..25b9dbd241 100644 --- a/samples/cpp/fabmap_sample.cpp +++ b/samples/cpp/fabmap_sample.cpp @@ -49,9 +49,21 @@ // //M*/ +#include "opencv2/opencv_modules.hpp" +#include -#include "opencv2/opencv.hpp" -#include "opencv2/nonfree/nonfree.hpp" +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + std::cout << "The sample requires nonfree module that is not available in your OpenCV distribution." << std::endl; + return -1; +} + +#else + +# include "opencv2/opencv.hpp" +# include "opencv2/nonfree/nonfree.hpp" using namespace cv; using namespace std; @@ -212,3 +224,5 @@ int main(int argc, char * argv[]) { return 0; } + +#endif diff --git a/samples/cpp/freak_demo.cpp b/samples/cpp/freak_demo.cpp index 6dbd9215ba..6a941598c3 100644 --- a/samples/cpp/freak_demo.cpp +++ b/samples/cpp/freak_demo.cpp @@ -34,15 +34,27 @@ // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. +#include "opencv2/opencv_modules.hpp" #include -#include -#include -#include -#include -#include -#include -#include +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + std::cout << "The sample requires nonfree module that is not available in your OpenCV distribution." << std::endl; + return -1; +} + +#else + +# include +# include + +# include +# include +# include +# include +# include using namespace cv; @@ -126,3 +138,5 @@ int main( int argc, char** argv ) { imshow("matches", imgMatch); waitKey(0); } + +#endif diff --git a/samples/cpp/generic_descriptor_match.cpp b/samples/cpp/generic_descriptor_match.cpp index 1cb03c6a9c..198f4046a8 100644 --- a/samples/cpp/generic_descriptor_match.cpp +++ b/samples/cpp/generic_descriptor_match.cpp @@ -1,11 +1,23 @@ -#include "opencv2/calib3d/calib3d.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/imgproc/imgproc.hpp" -#include "opencv2/nonfree/nonfree.hpp" - +#include "opencv2/opencv_modules.hpp" #include +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + printf("The sample requires nonfree module that is not available in your OpenCV distribution.\n"); + return -1; +} + +#else + +# include "opencv2/opencv_modules.hpp" +# include "opencv2/calib3d/calib3d.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/imgproc/imgproc.hpp" +# include "opencv2/nonfree/nonfree.hpp" + using namespace cv; static void help() @@ -91,3 +103,5 @@ Mat DrawCorrespondences(const Mat& img1, const vector& features1, cons return img_corr; } + +#endif diff --git a/samples/cpp/matcher_simple.cpp b/samples/cpp/matcher_simple.cpp index 42e89fbaa6..2df32eb4b7 100644 --- a/samples/cpp/matcher_simple.cpp +++ b/samples/cpp/matcher_simple.cpp @@ -1,8 +1,20 @@ +#include "opencv2/opencv_modules.hpp" #include -#include "opencv2/core/core.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/nonfree/nonfree.hpp" + +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + printf("The sample requires nonfree module that is not available in your OpenCV distribution.\n"); + return -1; +} + +#else + +# include "opencv2/core/core.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/nonfree/nonfree.hpp" using namespace cv; @@ -56,3 +68,5 @@ int main(int argc, char** argv) return 0; } + +#endif diff --git a/samples/cpp/tutorial_code/features2D/SURF_FlannMatcher.cpp b/samples/cpp/tutorial_code/features2D/SURF_FlannMatcher.cpp index 09346309ec..9cc17768aa 100644 --- a/samples/cpp/tutorial_code/features2D/SURF_FlannMatcher.cpp +++ b/samples/cpp/tutorial_code/features2D/SURF_FlannMatcher.cpp @@ -4,12 +4,23 @@ * @author A. Huaman */ +#include "opencv2/opencv_modules.hpp" #include -#include -#include "opencv2/core/core.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/nonfree/features2d.hpp" + +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + printf("The sample requires nonfree module that is not available in your OpenCV distribution.\n"); + return -1; +} + +#else + +# include "opencv2/core/core.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/nonfree/features2d.hpp" using namespace cv; @@ -28,7 +39,7 @@ int main( int argc, char** argv ) Mat img_2 = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE ); if( !img_1.data || !img_2.data ) - { std::cout<< " --(!) Error reading images " << std::endl; return -1; } + { printf(" --(!) Error reading images \n"); return -1; } //-- Step 1: Detect the keypoints using SURF Detector int minHessian = 400; @@ -97,4 +108,6 @@ int main( int argc, char** argv ) * @function readme */ void readme() -{ std::cout << " Usage: ./SURF_FlannMatcher " << std::endl; } +{ printf(" Usage: ./SURF_FlannMatcher \n"); } + +#endif \ No newline at end of file diff --git a/samples/cpp/tutorial_code/features2D/SURF_Homography.cpp b/samples/cpp/tutorial_code/features2D/SURF_Homography.cpp index 4b29638a5f..11dd074951 100644 --- a/samples/cpp/tutorial_code/features2D/SURF_Homography.cpp +++ b/samples/cpp/tutorial_code/features2D/SURF_Homography.cpp @@ -4,13 +4,24 @@ * @author A. Huaman */ +#include "opencv2/opencv_modules.hpp" #include -#include -#include "opencv2/core/core.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/calib3d/calib3d.hpp" -#include "opencv2/nonfree/features2d.hpp" + +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + printf("The sample requires nonfree module that is not available in your OpenCV distribution.\n"); + return -1; +} + +#else + +# include "opencv2/core/core.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/calib3d/calib3d.hpp" +# include "opencv2/nonfree/features2d.hpp" using namespace cv; @@ -29,7 +40,7 @@ int main( int argc, char** argv ) Mat img_scene = imread( argv[2], CV_LOAD_IMAGE_GRAYSCALE ); if( !img_object.data || !img_scene.data ) - { std::cout<< " --(!) Error reading images " << std::endl; return -1; } + { printf(" --(!) Error reading images \n"); return -1; } //-- Step 1: Detect the keypoints using SURF Detector int minHessian = 400; @@ -121,4 +132,6 @@ int main( int argc, char** argv ) * @function readme */ void readme() -{ std::cout << " Usage: ./SURF_Homography " << std::endl; } +{ printf(" Usage: ./SURF_Homography \n"); } + +#endif \ No newline at end of file diff --git a/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp b/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp index 527e5dd951..2fcd884ce8 100644 --- a/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp +++ b/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp @@ -4,12 +4,23 @@ * @author A. Huaman */ +#include "opencv2/opencv_modules.hpp" #include -#include -#include "opencv2/core/core.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/nonfree/features2d.hpp" + +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + printf("The sample requires nonfree module that is not available in your OpenCV distribution.\n"); + return -1; +} + +#else + +# include "opencv2/core/core.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/nonfree/features2d.hpp" using namespace cv; @@ -70,3 +81,5 @@ int main( int argc, char** argv ) */ void readme() { std::cout << " Usage: ./SURF_descriptor " << std::endl; } + +#endif \ No newline at end of file diff --git a/samples/cpp/tutorial_code/features2D/SURF_detector.cpp b/samples/cpp/tutorial_code/features2D/SURF_detector.cpp index 2625f1df3b..21dc45a949 100644 --- a/samples/cpp/tutorial_code/features2D/SURF_detector.cpp +++ b/samples/cpp/tutorial_code/features2D/SURF_detector.cpp @@ -4,12 +4,23 @@ * @author A. Huaman */ -#include +#include "opencv2/opencv_modules.hpp" #include -#include "opencv2/core/core.hpp" -#include "opencv2/features2d/features2d.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/nonfree/features2d.hpp" + +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + std::cout << "The sample requires nonfree module that is not available in your OpenCV distribution." << std::endl; + return -1; +} + +#else + +# include "opencv2/core/core.hpp" +# include "opencv2/features2d/features2d.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/nonfree/features2d.hpp" using namespace cv; @@ -60,3 +71,5 @@ int main( int argc, char** argv ) */ void readme() { std::cout << " Usage: ./SURF_detector " << std::endl; } + +#endif diff --git a/samples/ocl/CMakeLists.txt b/samples/ocl/CMakeLists.txt index 706c4ae0bd..90856f7ca1 100644 --- a/samples/ocl/CMakeLists.txt +++ b/samples/ocl/CMakeLists.txt @@ -1,7 +1,6 @@ SET(OPENCV_OCL_SAMPLES_REQUIRED_DEPS opencv_core opencv_flann opencv_imgproc opencv_highgui opencv_ml opencv_video opencv_objdetect opencv_features2d - opencv_calib3d opencv_legacy opencv_contrib opencv_ocl - opencv_nonfree) + opencv_calib3d opencv_legacy opencv_contrib opencv_ocl) ocv_check_dependencies(${OPENCV_OCL_SAMPLES_REQUIRED_DEPS}) @@ -52,7 +51,7 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) endif() if (OCV_DEPENDENCIES_FOUND AND INSTALL_C_EXAMPLES AND NOT WIN32) - file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd *.txt) + file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* *.txt) install(FILES ${install_list} DESTINATION "${OPENCV_SAMPLES_SRC_INSTALL_PATH}/ocl" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT samples) diff --git a/samples/ocl/surf_matcher.cpp b/samples/ocl/surf_matcher.cpp index 6023de9039..19b7f564a8 100644 --- a/samples/ocl/surf_matcher.cpp +++ b/samples/ocl/surf_matcher.cpp @@ -1,11 +1,22 @@ +#include "opencv2/opencv_modules.hpp" #include -#include -#include "opencv2/core/core.hpp" -#include "opencv2/highgui/highgui.hpp" -#include "opencv2/ocl/ocl.hpp" -#include "opencv2/nonfree/ocl.hpp" -#include "opencv2/calib3d/calib3d.hpp" -#include "opencv2/nonfree/nonfree.hpp" + +#ifndef HAVE_OPENCV_NONFREE + +int main(int, char**) +{ + std::cout << "The sample requires nonfree module that is not available in your OpenCV distribution." << std::endl; + return -1; +} + +#else + +# include "opencv2/core/core.hpp" +# include "opencv2/highgui/highgui.hpp" +# include "opencv2/ocl/ocl.hpp" +# include "opencv2/nonfree/ocl.hpp" +# include "opencv2/calib3d/calib3d.hpp" +# include "opencv2/nonfree/nonfree.hpp" using namespace cv; using namespace cv::ocl; @@ -326,3 +337,5 @@ int main(int argc, char* argv[]) waitKey(0); return EXIT_SUCCESS; } + +#endif From 2e78a3e5e94f21f6488734bc992cf5a8a7a5a27a Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 14 Oct 2015 16:19:37 +0300 Subject: [PATCH 051/468] Fixed samples build with nonfree. (cherry picked from commit 341e7b3be24f921cdf0a63793afc2e694b4e98b6) --- samples/c/CMakeLists.txt | 2 +- samples/cpp/CMakeLists.txt | 2 +- samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp | 2 +- samples/ocl/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/samples/c/CMakeLists.txt b/samples/c/CMakeLists.txt index b26e4ab662..bd82ba2637 100644 --- a/samples/c/CMakeLists.txt +++ b/samples/c/CMakeLists.txt @@ -16,7 +16,7 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function") endif() - ocv_include_modules(${OPENCV_C_SAMPLES_REQUIRED_DEPS}) + ocv_include_modules(${OPENCV_C_SAMPLES_REQUIRED_DEPS} opencv_nonfree) # --------------------------------------------- # Define executable targets diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt index 5eff52a90f..6433d1fd30 100644 --- a/samples/cpp/CMakeLists.txt +++ b/samples/cpp/CMakeLists.txt @@ -15,7 +15,7 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) project(cpp_samples) ocv_include_directories("${OpenCV_SOURCE_DIR}/include")#for opencv.hpp - ocv_include_modules(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS}) + ocv_include_modules(${OPENCV_CPP_SAMPLES_REQUIRED_DEPS} opencv_nonfree) if(HAVE_opencv_gpu) ocv_include_directories("${OpenCV_SOURCE_DIR}/modules/gpu/include") diff --git a/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp b/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp index 2fcd884ce8..aeabd8e346 100644 --- a/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp +++ b/samples/cpp/tutorial_code/features2D/SURF_descriptor.cpp @@ -80,6 +80,6 @@ int main( int argc, char** argv ) * @function readme */ void readme() -{ std::cout << " Usage: ./SURF_descriptor " << std::endl; } +{ printf(" Usage: ./SURF_descriptor \n"); } #endif \ No newline at end of file diff --git a/samples/ocl/CMakeLists.txt b/samples/ocl/CMakeLists.txt index 90856f7ca1..ee6d4f618c 100644 --- a/samples/ocl/CMakeLists.txt +++ b/samples/ocl/CMakeLists.txt @@ -10,7 +10,7 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) project("${project}_samples") - ocv_include_modules(${OPENCV_OCL_SAMPLES_REQUIRED_DEPS}) + ocv_include_modules(${OPENCV_OCL_SAMPLES_REQUIRED_DEPS} opencv_nonfree) if(HAVE_OPENCL) ocv_include_directories(${OPENCL_INCLUDE_DIR}) From 60eda6f25c93b37f620b9e12d7a95d753d30ef46 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Mon, 19 Oct 2015 13:36:44 +0300 Subject: [PATCH 052/468] export simple libs from OPENCV_LINKER_LIBS (fix #5541) (cherry picked from commit 937a096bf10bedd2d10803f67716393f9065abe8) --- cmake/OpenCVModule.cmake | 5 ++++- cmake/OpenCVUtils.cmake | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index cae2a39c9d..88ebe54f79 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -576,7 +576,10 @@ macro(ocv_create_module) if(NOT "${ARGN}" STREQUAL "SKIP_LINK") target_link_libraries(${the_module} ${OPENCV_MODULE_${the_module}_DEPS}) target_link_libraries(${the_module} LINK_INTERFACE_LIBRARIES ${OPENCV_MODULE_${the_module}_DEPS}) - target_link_libraries(${the_module} ${OPENCV_MODULE_${the_module}_DEPS_EXT} ${OPENCV_LINKER_LIBS} ${IPP_LIBS} ${ARGN}) + set(extra_deps ${OPENCV_MODULE_${the_module}_DEPS_EXT} ${OPENCV_LINKER_LIBS} ${IPP_LIBS} ${ARGN}) + ocv_extract_simple_libs(extra_deps _simple_deps _other_deps) + target_link_libraries(${the_module} LINK_INTERFACE_LIBRARIES ${_simple_deps}) # this list goes to "export" + target_link_libraries(${the_module} ${extra_deps}) endif() add_dependencies(opencv_modules ${the_module}) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index c23ddccebe..0692b763d5 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -630,3 +630,21 @@ function(ocv_source_group group) file(GLOB srcs ${OCV_SOURCE_GROUP_GLOB}) source_group(${group} FILES ${srcs}) endfunction() + +# build the list of simple dependencies, that links via "-l" +# _all_libs - name of variable with input list +# _simple - name of variable with output list of simple libs +# _other - name of variable with _all_libs - _simple +macro(ocv_extract_simple_libs _all_libs _simple _other) + set(${_simple} "") + set(${_other} "") + foreach(_l ${${_all_libs}}) + if(TARGET ${_l}) + list(APPEND ${_other} ${_l}) + elseif(EXISTS "${_l}") + list(APPEND ${_other} ${_l}) + else() + list(APPEND ${_simple} ${_l}) + endif() + endforeach() +endmacro() From 8e40becab12c642e7bbafb9fe87698e8b6bf28da Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 23 Oct 2015 12:28:09 +0300 Subject: [PATCH 053/468] Debian packages with legacy C headers added to list of conflicts, relpaces, etc. (cherry picked from commit e245aed6bbebd69a63a00d45a66b358df4153888) --- cmake/OpenCVPackaging.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index e64d447bfa..4e4b4d42c9 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -127,6 +127,8 @@ foreach(module calib3d contrib core features2d flann gpu highgui imgproc legacy endif() endforeach() +list(APPEND STD_OPENCV_DEV "libhighgui-dev" "libcv-dev" "libcvaux-dev") + string(REPLACE ";" ", " CPACK_COMPONENT_LIBS_CONFLICTS "${STD_OPENCV_LIBS}") string(REPLACE ";" ", " CPACK_COMPONENT_LIBS_PROVIDES "${STD_OPENCV_LIBS}") string(REPLACE ";" ", " CPACK_COMPONENT_LIBS_REPLACES "${STD_OPENCV_LIBS}") From b9b40a73bab744e9605773b0983ea3a3bc7644d6 Mon Sep 17 00:00:00 2001 From: "Anton V. Shokurov" Date: Wed, 28 Oct 2015 07:37:51 -0400 Subject: [PATCH 054/468] Exposure and autofocus properties fixed/added. Exposure can now be manually controlled (implemented only in libv4l). Will work only with a kernel version >= 4.5. Autofocus can be enabled/disabled. --- modules/videoio/src/cap_libv4l.cpp | 74 +++++++++++++++--------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/modules/videoio/src/cap_libv4l.cpp b/modules/videoio/src/cap_libv4l.cpp index 46fac95288..e6b80ba72d 100644 --- a/modules/videoio/src/cap_libv4l.cpp +++ b/modules/videoio/src/cap_libv4l.cpp @@ -1352,6 +1352,29 @@ static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) { return(&capture->frame); } +static int zeroPropertyQuietly(CvCaptureCAM_V4L* capture, int property_id, int value) +{ + struct v4l2_control c; + int v4l2_min; + int v4l2_max; + //we need to make sure that the autocontrol is switch off, if available. + capture->control.id = property_id; + v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id); + v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id); + if ( !((v4l2_min == -1) && (v4l2_max == -1)) ) { + //autocontrol capability is supported, switch it off. + c.id = capture->control.id; + c.value = value; + if( v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0 ){ + if (errno != ERANGE) { + fprintf(stderr, "VIDEOIO ERROR: V4L2: Failed to set autocontrol \"%d\": %s (value %d)\n", c.id, strerror(errno), c.value); + return -1; + } + } + }//lack of support should not be considerred an error. + return 0; +} + /* TODO: review this adaptation */ static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture, int property_id ) { @@ -1431,32 +1454,15 @@ static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture, break; case CV_CAP_PROP_EXPOSURE: sprintf(name, "Exposure"); - capture->control.id = V4L2_CID_EXPOSURE; + capture->control.id = V4L2_CID_EXPOSURE_ABSOLUTE; break; - case CV_CAP_PROP_FOCUS: { - struct v4l2_control c; - int v4l2_min; - int v4l2_max; - //we need to make sure that the autofocus is switch off, if available. - capture->control.id = V4L2_CID_FOCUS_AUTO; - v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id); - v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id); - if ( !((v4l2_min == -1) && (v4l2_max == -1)) ) { - //autofocus capability is supported, switch it off. - c.id = capture->control.id; - c.value = 0;//off - if( v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0 ){ - if (errno != ERANGE) { - fprintf(stderr, "VIDEOIO ERROR: V4L2: Failed to set control \"%d\"(FOCUS_AUTO): %s (value %d)\n", c.id, strerror(errno), c.value); - return -1; - } - } - }//lack of support should not be considerred an error. - + case CV_CAP_PROP_FOCUS: sprintf(name, "Focus"); capture->control.id = V4L2_CID_FOCUS_ABSOLUTE; break; - } + case CV_CAP_PROP_AUTOFOCUS: + sprintf(name, "Autofocus"); + capture->control.id = V4L2_CID_FOCUS_AUTO; default: sprintf(name, ""); capture->control.id = property_id; @@ -1671,30 +1677,22 @@ static int icvSetControl (CvCaptureCAM_V4L* capture, int property_id, double val capture->control.id = V4L2_CID_GAIN; break; case CV_CAP_PROP_EXPOSURE: + //we need to make sure that the autoexposure is switch off, if available. + zeroPropertyQuietly(capture, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL); + //now get the manual exposure value sprintf(name, "Exposure"); - capture->control.id = V4L2_CID_EXPOSURE; + capture->control.id = V4L2_CID_EXPOSURE_ABSOLUTE; break; case CV_CAP_PROP_FOCUS: //we need to make sure that the autofocus is switch off, if available. - capture->control.id = V4L2_CID_FOCUS_AUTO; - v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id); - v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id); - if ( !((v4l2_min == -1) && (v4l2_max == -1)) ) { - //autofocus capability is supported, switch it off. - c.id = capture->control.id; - c.value = 0;//off - if( v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0 ){ - if (errno != ERANGE) { - fprintf(stderr, "VIDEOIO ERROR: V4L2: Failed to set control \"%d\"(FOCUS_AUTO): %s (value %d)\n", c.id, strerror(errno), c.value); - return -1; - } - } - }//lack of support should not be considerred an error. - + zeroPropertyQuietly(capture, V4L2_CID_FOCUS_AUTO, 0 /*off*/); //now set the manual focus sprintf(name, "Focus"); capture->control.id = V4L2_CID_FOCUS_ABSOLUTE; break; + case CV_CAP_PROP_AUTOFOCUS: + sprintf(name, "Autofocus"); + capture->control.id = V4L2_CID_FOCUS_AUTO; default: sprintf(name, ""); capture->control.id = property_id; From 07a58c47cb75e2cd875595e01afe33d2c7881971 Mon Sep 17 00:00:00 2001 From: Teng Cao Date: Wed, 2 Dec 2015 17:31:17 +0800 Subject: [PATCH 055/468] Update cascadeclassifier.cpp minor fix since predict() returun int --- apps/traincascade/cascadeclassifier.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/traincascade/cascadeclassifier.cpp b/apps/traincascade/cascadeclassifier.cpp index aa97708338..1c09a96bc0 100644 --- a/apps/traincascade/cascadeclassifier.cpp +++ b/apps/traincascade/cascadeclassifier.cpp @@ -336,7 +336,7 @@ int CvCascadeClassifier::fillPassedSamples( int first, int count, bool isPositiv consumed++; featureEvaluator->setImage( img, isPositive ? 1 : 0, i ); - if( predict( i ) == 1.0F ) + if( predict( i ) == 1 ) { getcount++; printf("%s current samples: %d\r", isPositive ? "POS":"NEG", getcount); From 4fa14f75b850b86796fafe8f2ef678f730e613ac Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Mon, 7 Dec 2015 13:21:51 +0300 Subject: [PATCH 056/468] suppress lintian warning in opencv.pc --- cmake/OpenCVPackaging.cmake | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index f7fbcfaaa2..775605c4f8 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -227,6 +227,32 @@ function(ocv_generate_lintian_overrides_file comp) endif() endfunction() +function(ocv_get_lintian_version version) + find_program(LINTIAN_EXECUTABLE lintian) + + if(NOT LINTIAN_EXECUTABLE) + return() + endif() + + execute_process(COMMAND ${LINTIAN_EXECUTABLE} --version + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE LINTIAN_EXITCODE + OUTPUT_VARIABLE LINTIAN_VERSION + ERROR_QUIET) + + if(NOT LINTIAN_EXITCODE EQUAL 0) + return() + endif() + + if(LINTIAN_VERSION MATCHES "([0-9]+\\.[0-9]+\\.[0-9]+)") + set(LINTIAN_VERSION "${CMAKE_MATCH_1}" CACHE INTERNAL "Lintian version") + endif() + + set("${version}" "${LINTIAN_VERSION}" PARENT_SCOPE) +endfunction() + +ocv_get_lintian_version(LINTIAN_VERSION) + set(LIBS_LINTIAN_OVERRIDES "binary-or-shlib-defines-rpath" # usr/lib/libopencv_core.so.2.4.12 "package-name-doesnt-match-sonames") # libopencv-calib3d2.4 libopencv-contrib2.4 @@ -246,6 +272,11 @@ endif() set(DEV_LINTIAN_OVERRIDES "binary-or-shlib-defines-rpath" # usr/bin/opencv_traincascade "binary-without-manpage") # usr/bin/opencv_traincascade +if(LINTIAN_VERSION VERSION_GREATER "2.5.30" OR + LINTIAN_VERSION VERSION_EQUAL "2.5.30") + list(APPEND DEV_LINTIAN_OVERRIDES "pkg-config-bad-directive") # usr/lib/pkgconfig/opencv.pc -L/usr/local/cuda-7.0/lib64 +endif() + if(NOT INSTALL_C_EXAMPLES) set(SAMPLES_LINTIAN_OVERRIDES "empty-binary-package") # samples are not installed endif() From 7cb78451d10955ff3e7030758c909c1c455a5039 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Fri, 27 Feb 2015 18:59:55 +0300 Subject: [PATCH 057/468] Backported several changes from master branch: - #3771 - inline round on ARM - #5633 - documentation for MSER - #5666 - run.py fixes --- modules/core/include/opencv2/core/types_c.h | 26 +++++++++++++ .../doc/feature_detection_and_description.rst | 39 +++++++++++++++++-- modules/ts/misc/run.py | 6 +-- modules/ts/misc/run_suite.py | 34 ++++++++-------- modules/ts/misc/run_utils.py | 13 +++---- 5 files changed, 89 insertions(+), 29 deletions(-) diff --git a/modules/core/include/opencv2/core/types_c.h b/modules/core/include/opencv2/core/types_c.h index 989b799fdf..9e9231db08 100644 --- a/modules/core/include/opencv2/core/types_c.h +++ b/modules/core/include/opencv2/core/types_c.h @@ -305,6 +305,30 @@ enum { #define CV_CMP(a,b) (((a) > (b)) - ((a) < (b))) #define CV_SIGN(a) CV_CMP((a),0) +#if defined __GNUC__ && defined __arm__ && (defined __ARM_PCS_VFP || defined __ARM_VFPV3__) +# define CV_VFP 1 +#else +# define CV_VFP 0 +#endif + + +#if CV_VFP +// 1. general scheme +#define ARM_ROUND(_value, _asm_string) \ + int res; \ + float temp; \ + asm(_asm_string : [res] "=r" (res), [temp] "=w" (temp) : [value] "w" (_value)); \ + return res; +// 2. version for double +#ifdef __clang__ +#define ARM_ROUND_DBL(value) ARM_ROUND(value, "vcvtr.s32.f64 %[temp], %[value] \n vmov %[res], %[temp]") +#else +#define ARM_ROUND_DBL(value) ARM_ROUND(value, "vcvtr.s32.f64 %[temp], %P[value] \n vmov %[res], %[temp]") +#endif +// 3. version for float +#define ARM_ROUND_FLT(value) ARM_ROUND(value, "vcvtr.s32.f32 %[temp], %[value]\n vmov %[res], %[temp]") +#endif // CV_VFP + CV_INLINE int cvRound( double value ) { #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__ && defined __SSE2__ && !defined __APPLE__) @@ -323,6 +347,8 @@ CV_INLINE int cvRound( double value ) #elif defined CV_ICC || defined __GNUC__ # ifdef HAVE_TEGRA_OPTIMIZATION TEGRA_ROUND(value); +# elif CV_VFP + ARM_ROUND_DBL(value) # else return (int)lrint(value); # endif diff --git a/modules/features2d/doc/feature_detection_and_description.rst b/modules/features2d/doc/feature_detection_and_description.rst index c05a71d34a..effaed73d7 100644 --- a/modules/features2d/doc/feature_detection_and_description.rst +++ b/modules/features2d/doc/feature_detection_and_description.rst @@ -52,13 +52,46 @@ Maximally stable extremal region extractor. :: void operator()( const Mat& image, vector >& msers, const Mat& mask ) const; }; -The class encapsulates all the parameters of the MSER extraction algorithm (see -http://en.wikipedia.org/wiki/Maximally_stable_extremal_regions). Also see http://code.opencv.org/projects/opencv/wiki/MSER for useful comments and parameters description. +The class encapsulates all the parameters of the MSER extraction algorithm (see [wiki]_ article). .. note:: - * (Python) A complete example showing the use of the MSER detector can be found at opencv_source_code/samples/python2/mser.py + * there are two different implementation of MSER: one for grey image, one for color image the grey image algorithm is taken from: [nister2008linear]_ ; the paper claims to be faster than union-find method; it actually get 1.5~2m/s on my centrino L7200 1.2GHz laptop. + * the color image algorithm is taken from: [forssen2007maximally]_ ; it should be much slower than grey image method ( 3~4 times ); the chi_table.h file is taken directly from paper's source code which is distributed under GPL. + + * (Python) A complete example showing the use of the MSER detector can be found at opencv_source_code/samples/python2/mser.py + +.. [wiki] http://en.wikipedia.org/wiki/Maximally_stable_extremal_regions +.. [nister2008linear] David Nistér and Henrik Stewénius. Linear time maximally stable extremal regions. In Computer Vision–ECCV 2008, pages 183–196. Springer, 2008. +.. [forssen2007maximally] Per-Erik Forssén. Maximally stable colour regions for recognition and matching. In Computer Vision and Pattern Recognition, 2007. CVPR'07. IEEE Conference on, pages 1–8. IEEE, 2007. + +MSER::MSER +---------- +The MSER constructor + +.. ocv:function:: MSER::MSER(int _delta=5, int _min_area=60, int _max_area=14400, double _max_variation=0.25, double _min_diversity=.2, int _max_evolution=200, double _area_threshold=1.01, double _min_margin=0.003, int _edge_blur_size=5) + + :param _delta: Compares (sizei - sizei-delta)/sizei-delta + :param _min_area: Prune the area which smaller than minArea + :param _max_area: Prune the area which bigger than maxArea + :param _max_variation: Prune the area have simliar size to its children + :param _min_diversity: For color image, trace back to cut off mser with diversity less than min_diversity + :param _max_evolution: For color image, the evolution steps + :param _area_threshold: For color image, the area threshold to cause re-initialize + :param _min_margin: For color image, ignore too small margin + :param _edge_blur_size: For color image, the aperture size for edge blur + +MSER::operator() +---------------- + +Detect MSER regions + +.. ocv:function:: void MSER::operator()(const Mat& image, vector >& msers, const Mat& mask=Mat() ) const + + :param image: Input image (8UC1, 8UC3 or 8UC4) + :param msers: Resulting list of point sets + :param mask: The operation mask ORB --- diff --git a/modules/ts/misc/run.py b/modules/ts/misc/run.py index a3a13145a1..ad6a38ddb8 100755 --- a/modules/ts/misc/run.py +++ b/modules/ts/misc/run.py @@ -31,7 +31,7 @@ if __name__ == "__main__": parser.add_argument("--list", action="store_true", default=False, help="List available tests (executables)") parser.add_argument("--list_short", action="store_true", default=False, help="List available tests (aliases)") parser.add_argument("--list_short_main", action="store_true", default=False, help="List available tests (main repository, aliases)") - parser.add_argument("--configuration", metavar="CFG", default="", help="Visual Studio: force Debug or Release configuration") + parser.add_argument("--configuration", metavar="CFG", default=None, help="Force Debug or Release configuration (for Visual Studio and Java tests build)") parser.add_argument("-n", "--dry_run", action="store_true", help="Do not run the tests") parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Print more debug information") @@ -95,12 +95,12 @@ if __name__ == "__main__": try: if not os.path.isdir(path): raise Err("Not a directory (should contain CMakeCache.txt ot test executables)") - cache = CMakeCache() + cache = CMakeCache(args.configuration) fname = os.path.join(path, "CMakeCache.txt") if os.path.isfile(fname): log.debug("Reading cmake cache file: %s", fname) - cache.read(path, fname, args.configuration) + cache.read(path, fname) else: log.debug("Assuming folder contains tests: %s", path) cache.setDummy(path) diff --git a/modules/ts/misc/run_suite.py b/modules/ts/misc/run_suite.py index c3d715e168..280c21caa6 100644 --- a/modules/ts/misc/run_suite.py +++ b/modules/ts/misc/run_suite.py @@ -48,22 +48,27 @@ class TestSuite(object): return sorted(self.getAliases(fname), key = len)[0] def getAliases(self, fname): + def getCuts(fname, prefix): + # filename w/o extension (opencv_test_core) + noext = re.sub(r"\.(exe|apk)$", '', fname) + # filename w/o prefix (core.exe) + nopref = fname + if fname.startswith(prefix): + nopref = fname[len(prefix):] + # filename w/o prefix and extension (core) + noprefext = noext + if noext.startswith(prefix): + noprefext = noext[len(prefix):] + return noext, nopref, noprefext # input is full path ('/home/.../bin/opencv_test_core') or 'java' res = [fname] fname = os.path.basename(fname) res.append(fname) # filename (opencv_test_core.exe) - noext = re.sub(r"\.(exe|apk)$", '', fname) - res.append(noext) # filename w/o extension (opencv_test_core) - nopref = None - if fname.startswith(self.nameprefix): - nopref = fname[len(self.nameprefix):] - res.append(nopref) # filename w/o prefix (core) - if noext.startswith(self.nameprefix): - res.append(noext[len(self.nameprefix):]) - if self.options.configuration == "Debug": - res.append(re.sub(r"d$", '', noext)) # MSVC debug config, remove 'd' suffix - if nopref: - res.append(re.sub(r"d$", '', nopref)) # MSVC debug config, remove 'd' suffix + for s in getCuts(fname, self.nameprefix): + res.append(s) + if self.cache.build_type == "Debug" and "Visual Studio" in self.cache.cmake_generator: + res.append(re.sub(r"d$", '', s)) # MSVC debug config, remove 'd' suffix + log.debug("Aliases: %s", set(res)) return set(res) def getTest(self, name): @@ -101,10 +106,7 @@ class TestSuite(object): args = args[:] exe = os.path.abspath(path) if path == "java": - cfg = self.cache.build_type - if self.options.configuration: - cfg = self.options.configuration - cmd = [self.cache.ant_executable, "-Dopencv.build.type=%s" % cfg, "buildAndTest"] + cmd = [self.cache.ant_executable, "-Dopencv.build.type=%s" % self.cache.build_type, "buildAndTest"] ret = execute(cmd, cwd = self.cache.java_test_binary_dir + "/.build") return None, ret else: diff --git a/modules/ts/misc/run_utils.py b/modules/ts/misc/run_utils.py index dca951d17a..5841631a7c 100644 --- a/modules/ts/misc/run_utils.py +++ b/modules/ts/misc/run_utils.py @@ -152,7 +152,7 @@ parse_patterns = ( {'name': "opencv_home", 'default': None, 'pattern': re.compile(r"^OpenCV_SOURCE_DIR:STATIC=(.+)$")}, {'name': "opencv_build", 'default': None, 'pattern': re.compile(r"^OpenCV_BINARY_DIR:STATIC=(.+)$")}, {'name': "tests_dir", 'default': None, 'pattern': re.compile(r"^EXECUTABLE_OUTPUT_PATH:PATH=(.+)$")}, - {'name': "build_type", 'default': "Release", 'pattern': re.compile(r"^CMAKE_BUILD_TYPE:STRING=(.*)$")}, + {'name': "build_type", 'default': "Release", 'pattern': re.compile(r"^CMAKE_BUILD_TYPE:\w+=(.*)$")}, {'name': "git_executable", 'default': None, 'pattern': re.compile(r"^GIT_EXECUTABLE:FILEPATH=(.*)$")}, {'name': "cxx_flags", 'default': "", 'pattern': re.compile(r"^CMAKE_CXX_FLAGS:STRING=(.*)$")}, {'name': "cxx_flags_debug", 'default': "", 'pattern': re.compile(r"^CMAKE_CXX_FLAGS_DEBUG:STRING=(.*)$")}, @@ -174,17 +174,19 @@ parse_patterns = ( ) class CMakeCache: - def __init__(self): + def __init__(self, cfg = None): self.setDefaultAttrs() self.cmake_home_vcver = None self.opencv_home_vcver = None self.featuresSIMD = None self.main_modules = [] + if cfg: + self.build_type = cfg def setDummy(self, path): self.tests_dir = os.path.normpath(path) - def read(self, path, fname, cfg): + def read(self, path, fname): rx = re.compile(r'^opencv_(\w+)_SOURCE_DIR:STATIC=(.*)$') module_paths = {} # name -> path with open(fname, "rt") as cachefile: @@ -213,10 +215,7 @@ class CMakeCache: # fix VS test binary path (add Debug or Release) if "Visual Studio" in self.cmake_generator: - if cfg: - self.tests_dir = os.path.join(self.tests_dir, self.options.configuration) - else: - self.tests_dir = os.path.join(self.tests_dir, self.build_type) + self.tests_dir = os.path.join(self.tests_dir, self.build_type) self.cmake_home_vcver = readGitVersion(self.git_executable, self.cmake_home) if self.opencv_home == self.cmake_home: From 46edb54ac380a15559271c70b493825a7933ae70 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Tue, 22 Dec 2015 15:58:39 +0300 Subject: [PATCH 058/468] Fixed PCH warning during ARM crosscompilation --- cmake/OpenCVPCHSupport.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVPCHSupport.cmake b/cmake/OpenCVPCHSupport.cmake index ad2bc8ba2c..13619daf27 100644 --- a/cmake/OpenCVPCHSupport.cmake +++ b/cmake/OpenCVPCHSupport.cmake @@ -169,9 +169,9 @@ MACRO(_PCH_GET_TARGET_COMPILE_FLAGS _cflags _header_name _pch_path _dowarn ) # if you have different versions of the headers for different build types # you may set _pch_dowarn IF (_dowarn) - SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include \"${CMAKE_CURRENT_BINARY_DIR}/${_header_name}\" -Winvalid-pch " ) + SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -Winvalid-pch " ) ELSE (_dowarn) - SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include \"${CMAKE_CURRENT_BINARY_DIR}/${_header_name}\" " ) + SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} " ) ENDIF (_dowarn) ELSE(CMAKE_COMPILER_IS_GNUCXX) From b3bbe7704d160ca9678b57dc17c4a9074122fdfd Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Wed, 23 Dec 2015 13:06:56 +0100 Subject: [PATCH 059/468] add jaccardDistance measure for rectangle overlap computes the complement of the Jaccard Index as described in https://en.wikipedia.org/wiki/Jaccard_index. For rectangles this reduces to computing the intersection over the union. --- modules/core/include/opencv2/core/types.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/modules/core/include/opencv2/core/types.hpp b/modules/core/include/opencv2/core/types.hpp index e166556af7..6909676dc3 100644 --- a/modules/core/include/opencv2/core/types.hpp +++ b/modules/core/include/opencv2/core/types.hpp @@ -51,6 +51,7 @@ #include #include #include +#include #include "opencv2/core/cvdef.h" #include "opencv2/core/cvstd.hpp" @@ -1832,7 +1833,26 @@ Rect_<_Tp> operator | (const Rect_<_Tp>& a, const Rect_<_Tp>& b) return c |= b; } +/** + * @brief measure dissimilarity between two sample sets + * + * computes the complement of the Jaccard Index as described in . + * For rectangles this reduces to computing the intersection over the union. + */ +template static inline +double jaccardDistance(const Rect_<_Tp>& a, const Rect_<_Tp>& b) { + _Tp Aa = a.area(); + _Tp Ab = b.area(); + if ((Aa + Ab) <= std::numeric_limits<_Tp>::epsilon()) { + // jaccard_index = 1 -> distance = 0 + return 0.0; + } + + double Aab = (a & b).area(); + // distance = 1 - jaccard_index + return 1.0 - Aab / (Aa + Ab - Aab); +} ////////////////////////////// RotatedRect ////////////////////////////// From c4e80952ced54978e8e6294a93d28ede251e8e9d Mon Sep 17 00:00:00 2001 From: atinfinity Date: Wed, 23 Dec 2015 23:43:01 +0900 Subject: [PATCH 060/468] changed to find TBB library(VS2015) --- cmake/OpenCVDetectTBB.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/OpenCVDetectTBB.cmake b/cmake/OpenCVDetectTBB.cmake index 8ff78bb3d4..be40b476b6 100644 --- a/cmake/OpenCVDetectTBB.cmake +++ b/cmake/OpenCVDetectTBB.cmake @@ -65,6 +65,8 @@ if(NOT HAVE_TBB) set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/vc11") elseif(MSVC12) set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/vc12") + elseif(MSVC14) + set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/vc14") endif() set(TBB_LIB_DIR "${_TBB_LIB_PATH}" CACHE PATH "Full path of TBB library directory") link_directories("${TBB_LIB_DIR}") From e607a85df61581db88202a40f69f646d7237c9d6 Mon Sep 17 00:00:00 2001 From: Ishank gulati Date: Wed, 23 Dec 2015 23:37:32 +0530 Subject: [PATCH 061/468] png-image-compatibility --- modules/videoio/src/cap_images.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/videoio/src/cap_images.cpp b/modules/videoio/src/cap_images.cpp index 00d5af47d1..e379561593 100644 --- a/modules/videoio/src/cap_images.cpp +++ b/modules/videoio/src/cap_images.cpp @@ -124,7 +124,7 @@ bool CvCapture_Images::grabFrame() } cvReleaseImage(&frame); - frame = cvLoadImage(str, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR); + frame = cvLoadImage(str, CV_LOAD_IMAGE_UNCHANGED); if( frame ) currentframe++; From 24da1ba3dcb0d63c28fa48f99677dd76eb31151a Mon Sep 17 00:00:00 2001 From: Ishank gulati Date: Thu, 17 Dec 2015 10:16:10 +0530 Subject: [PATCH 062/468] added videoio docs and tutorials --- .../highgui/table_of_content_highgui.markdown | 18 ----------------- doc/tutorials/tutorials.markdown | 4 ++++ .../images/video-input-psnr-ssim.png | Bin .../images/video-write.png | Bin .../videoio/table_of_content_videoio.markdown | 19 ++++++++++++++++++ .../images/outputVideoInput.png | Bin .../video_input_psnr_ssim.markdown | 8 ++++---- .../images/resultOutputWideoWrite.png | Bin .../images/videoCompressSelect.png | Bin .../video-write/images/videoFileStructure.png | Bin .../video-write/video_write.markdown | 6 +++--- .../video-input-psnr-ssim.cpp | 0 .../video-input-psnr-ssim/video/Megamind.avi | Bin .../video/Megamind_bugy.avi | Bin .../video-write/video-write.cpp | 0 15 files changed, 30 insertions(+), 25 deletions(-) rename doc/tutorials/{highgui => videoio}/images/video-input-psnr-ssim.png (100%) rename doc/tutorials/{highgui => videoio}/images/video-write.png (100%) create mode 100644 doc/tutorials/videoio/table_of_content_videoio.markdown rename doc/tutorials/{highgui => videoio}/video-input-psnr-ssim/images/outputVideoInput.png (100%) rename doc/tutorials/{highgui => videoio}/video-input-psnr-ssim/video_input_psnr_ssim.markdown (97%) rename doc/tutorials/{highgui => videoio}/video-write/images/resultOutputWideoWrite.png (100%) rename doc/tutorials/{highgui => videoio}/video-write/images/videoCompressSelect.png (100%) rename doc/tutorials/{highgui => videoio}/video-write/images/videoFileStructure.png (100%) rename doc/tutorials/{highgui => videoio}/video-write/video_write.markdown (97%) rename samples/cpp/tutorial_code/{HighGUI => videoio}/video-input-psnr-ssim/video-input-psnr-ssim.cpp (100%) rename samples/cpp/tutorial_code/{HighGUI => videoio}/video-input-psnr-ssim/video/Megamind.avi (100%) rename samples/cpp/tutorial_code/{HighGUI => videoio}/video-input-psnr-ssim/video/Megamind_bugy.avi (100%) rename samples/cpp/tutorial_code/{HighGUI => videoio}/video-write/video-write.cpp (100%) diff --git a/doc/tutorials/highgui/table_of_content_highgui.markdown b/doc/tutorials/highgui/table_of_content_highgui.markdown index 3ff0e0322d..8f8b28f428 100644 --- a/doc/tutorials/highgui/table_of_content_highgui.markdown +++ b/doc/tutorials/highgui/table_of_content_highgui.markdown @@ -12,24 +12,6 @@ use the built-in graphical user interface of the library. We will learn how to add a Trackbar to our applications -- @subpage tutorial_video_input_psnr_ssim - - *Compatibility:* \> OpenCV 2.0 - - *Author:* Bernát Gábor - - You will learn how to read video streams, and how to calculate similarity values such as PSNR - or SSIM. - -- @subpage tutorial_video_write - - *Compatibility:* \> OpenCV 2.0 - - *Author:* Bernát Gábor - - Whenever you work with video feeds you may eventually want to save your image processing - result in a form of a new video file. Here's how to do it. - - @subpage tutorial_raster_io_gdal *Compatibility:* \> OpenCV 2.0 diff --git a/doc/tutorials/tutorials.markdown b/doc/tutorials/tutorials.markdown index 552420c3c9..035c69a290 100644 --- a/doc/tutorials/tutorials.markdown +++ b/doc/tutorials/tutorials.markdown @@ -71,6 +71,10 @@ As always, we would be happy to hear your comments and receive your contribution Run OpenCV and your vision apps on an iDevice +- @subpage tutorial_table_of_content_videoio + + These tutorials show how to read and write videos using videio module. + - @subpage tutorial_table_of_content_viz These tutorials show how to use Viz module effectively. diff --git a/doc/tutorials/highgui/images/video-input-psnr-ssim.png b/doc/tutorials/videoio/images/video-input-psnr-ssim.png similarity index 100% rename from doc/tutorials/highgui/images/video-input-psnr-ssim.png rename to doc/tutorials/videoio/images/video-input-psnr-ssim.png diff --git a/doc/tutorials/highgui/images/video-write.png b/doc/tutorials/videoio/images/video-write.png similarity index 100% rename from doc/tutorials/highgui/images/video-write.png rename to doc/tutorials/videoio/images/video-write.png diff --git a/doc/tutorials/videoio/table_of_content_videoio.markdown b/doc/tutorials/videoio/table_of_content_videoio.markdown new file mode 100644 index 0000000000..b1b669ded7 --- /dev/null +++ b/doc/tutorials/videoio/table_of_content_videoio.markdown @@ -0,0 +1,19 @@ +Video Input and Output (videoio module) {#tutorial_table_of_content_videoio} +========================================= + +This section contains tutorials about how to read/save your video files. + +- @subpage tutorial_video_input_psnr_ssim + + *Compatibility:* \> OpenCV 2.0 + + *Author:* Bernát Gábor + + You will learn how to read video streams, and how to calculate similarity values such as PSNR + or SSIM. + +- @subpage tutorial_video_write + + *Compatibility:* \> OpenCV 2.0 + + *Author:* Bernát Gábor \ No newline at end of file diff --git a/doc/tutorials/highgui/video-input-psnr-ssim/images/outputVideoInput.png b/doc/tutorials/videoio/video-input-psnr-ssim/images/outputVideoInput.png similarity index 100% rename from doc/tutorials/highgui/video-input-psnr-ssim/images/outputVideoInput.png rename to doc/tutorials/videoio/video-input-psnr-ssim/images/outputVideoInput.png diff --git a/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown b/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown similarity index 97% rename from doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown rename to doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown index 1e61a87753..ef82b67236 100644 --- a/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown +++ b/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown @@ -20,12 +20,12 @@ As a test case where to show off these using OpenCV I've created a small program video files and performs a similarity check between them. This is something you could use to check just how well a new video compressing algorithms works. Let there be a reference (original) video like [this small Megamind clip -](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi) and [a compressed -version of it ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi). +](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind.avi) and [a compressed +version of it ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind_bugy.avi). You may also find the source code and these video file in the -`samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/` folder of the OpenCV source library. +`samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/` folder of the OpenCV source library. -@include cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp +@include cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp How to read a video stream (online-camera or offline-file)? ----------------------------------------------------------- diff --git a/doc/tutorials/highgui/video-write/images/resultOutputWideoWrite.png b/doc/tutorials/videoio/video-write/images/resultOutputWideoWrite.png similarity index 100% rename from doc/tutorials/highgui/video-write/images/resultOutputWideoWrite.png rename to doc/tutorials/videoio/video-write/images/resultOutputWideoWrite.png diff --git a/doc/tutorials/highgui/video-write/images/videoCompressSelect.png b/doc/tutorials/videoio/video-write/images/videoCompressSelect.png similarity index 100% rename from doc/tutorials/highgui/video-write/images/videoCompressSelect.png rename to doc/tutorials/videoio/video-write/images/videoCompressSelect.png diff --git a/doc/tutorials/highgui/video-write/images/videoFileStructure.png b/doc/tutorials/videoio/video-write/images/videoFileStructure.png similarity index 100% rename from doc/tutorials/highgui/video-write/images/videoFileStructure.png rename to doc/tutorials/videoio/video-write/images/videoFileStructure.png diff --git a/doc/tutorials/highgui/video-write/video_write.markdown b/doc/tutorials/videoio/video-write/video_write.markdown similarity index 97% rename from doc/tutorials/highgui/video-write/video_write.markdown rename to doc/tutorials/videoio/video-write/video_write.markdown index d10f6d051f..399ac7a1e2 100644 --- a/doc/tutorials/highgui/video-write/video_write.markdown +++ b/doc/tutorials/videoio/video-write/video_write.markdown @@ -30,10 +30,10 @@ The source code --------------- You may also find the source code and these video file in the -`samples/cpp/tutorial_code/highgui/video-write/` folder of the OpenCV source library or [download it -from here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp). +`samples/cpp/tutorial_code/videoio/video-write/` folder of the OpenCV source library or [download it +from here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/videoio/video-write/video-write.cpp). -@include cpp/tutorial_code/HighGUI/video-write/video-write.cpp +@include cpp/tutorial_code/videoio/video-write/video-write.cpp The structure of a video ------------------------ diff --git a/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp b/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp similarity index 100% rename from samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp rename to samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp diff --git a/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi b/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind.avi similarity index 100% rename from samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi rename to samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind.avi diff --git a/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi b/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind_bugy.avi similarity index 100% rename from samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi rename to samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind_bugy.avi diff --git a/samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp b/samples/cpp/tutorial_code/videoio/video-write/video-write.cpp similarity index 100% rename from samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp rename to samples/cpp/tutorial_code/videoio/video-write/video-write.cpp From 64a57f7c387f201094076120bfecf59719a95aea Mon Sep 17 00:00:00 2001 From: Dan Moodie Date: Mon, 28 Dec 2015 10:27:10 -0500 Subject: [PATCH 063/468] Support for opengl2 in vtk 7.1 --- cmake/OpenCVDetectVTK.cmake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/OpenCVDetectVTK.cmake b/cmake/OpenCVDetectVTK.cmake index 66dcdd0112..e75aef8a0c 100644 --- a/cmake/OpenCVDetectVTK.cmake +++ b/cmake/OpenCVDetectVTK.cmake @@ -3,7 +3,14 @@ if(NOT WITH_VTK) endif() # VTK 6.x components -find_package(VTK QUIET COMPONENTS vtkRenderingOpenGL vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE) +find_package(VTK QUIET COMPONENTS vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE) +IF(VTK_FOUND) + IF(VTK_RENDERING_BACKEND) #in vtk 7, the rendering backend is exported as a var. + find_package(VTK QUIET COMPONENTS vtkRendering${VTK_RENDERING_BACKEND} vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE) + ELSE(VTK_RENDERING_BACKEND) + find_package(VTK QUIET COMPONENTS vtkRenderingOpenGL vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE) + ENDIF(VTK_RENDERING_BACKEND) +ENDIF(VTK_FOUND) # VTK 5.x components if(NOT VTK_FOUND) From a7aa198b4caa07895b41593fdd9adf480a40c5c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Sp=C3=B6rk?= Date: Mon, 4 Jan 2016 15:47:26 +0100 Subject: [PATCH 064/468] fixing issue #4969 of Itseez/opencv. Someone forgot to wrap the load function for SVMs in the corresponding ml python module. Fixed that. --- modules/ml/include/opencv2/ml.hpp | 4 ++++ modules/ml/src/svm.cpp | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 862f3f950c..013d9187fe 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -719,6 +719,10 @@ public: Use StatModel::train to train the model. Since %SVM has several parameters, you may want to find the best parameters for your problem, it can be done with SVM::trainAuto. */ CV_WRAP static Ptr create(); + + CV_WRAP virtual void read( const FileNode& fn ) = 0; + + CV_WRAP static Ptr load(const String& fs); }; /****************************************************************************************\ diff --git a/modules/ml/src/svm.cpp b/modules/ml/src/svm.cpp index 757bb7a171..639f6e2168 100644 --- a/modules/ml/src/svm.cpp +++ b/modules/ml/src/svm.cpp @@ -2261,6 +2261,17 @@ Ptr SVM::create() return makePtr(); } +Ptr SVM::load(const String& filename) +{ + FileStorage fs; + fs.open(filename, FileStorage::READ); + + Ptr svm = makePtr(); + + svm->read(fs.getFirstTopLevelNode()); + return svm; +} + Mat SVM::getUncompressedSupportVectors() const { const SVMImpl* this_ = dynamic_cast(this); From 6c8bc6a25b1fb433a198520455a5a5c27a03cc5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Sp=C3=B6rk?= Date: Thu, 7 Jan 2016 08:00:01 +0100 Subject: [PATCH 065/468] fixed ABI incompatibilities as proposed by alalek related to issue 4969 fixes issue 5891 fixes issue 5922 --- modules/ml/include/opencv2/ml.hpp | 11 ++++++++--- modules/ml/src/svm.cpp | 6 +++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 013d9187fe..cfd95a5240 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -720,9 +720,14 @@ public: find the best parameters for your problem, it can be done with SVM::trainAuto. */ CV_WRAP static Ptr create(); - CV_WRAP virtual void read( const FileNode& fn ) = 0; - - CV_WRAP static Ptr load(const String& fs); + /** @brief Loads and creates a serialized svm from a file + * + * Use SVM::save to serialize and store an SVM to disk. + * Load the SVM from this file again, by calling this function with the path to the file. + * + * @param fs Filename + */ + CV_WRAP static Ptr load(const String& filepath); }; /****************************************************************************************\ diff --git a/modules/ml/src/svm.cpp b/modules/ml/src/svm.cpp index 639f6e2168..34acebb991 100644 --- a/modules/ml/src/svm.cpp +++ b/modules/ml/src/svm.cpp @@ -2261,14 +2261,14 @@ Ptr SVM::create() return makePtr(); } -Ptr SVM::load(const String& filename) +Ptr SVM::load(const String& filepath) { FileStorage fs; - fs.open(filename, FileStorage::READ); + fs.open(filepath, FileStorage::READ); Ptr svm = makePtr(); - svm->read(fs.getFirstTopLevelNode()); + ((SVMImpl*)svm.get())->read(fs.getFirstTopLevelNode()); return svm; } From 66eda72f668e9ab0740a0bd4432af4f4566915c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Sp=C3=B6rk?= Date: Thu, 7 Jan 2016 08:19:06 +0100 Subject: [PATCH 066/468] fixed a doxygen issue --- modules/ml/include/opencv2/ml.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index cfd95a5240..4f99bf4b36 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -725,7 +725,7 @@ public: * Use SVM::save to serialize and store an SVM to disk. * Load the SVM from this file again, by calling this function with the path to the file. * - * @param fs Filename + * @param filepath path to serialized svm */ CV_WRAP static Ptr load(const String& filepath); }; From 551b5d3e1af5891959d797f947c850dbe9055ccd Mon Sep 17 00:00:00 2001 From: Kai Hugo Hustoft Endresen Date: Fri, 8 Jan 2016 00:32:52 +0100 Subject: [PATCH 067/468] StereoSGBM.cpp - use SSE2 for pass 2 using MODE_HH With a test image set of 2800x1400 bytes on a Intel Core i7 5960X this improves runtime of MODE_HH with about 10%. (this particular replaced code segment is approx 3 times faster than the non-SSE2 variant). I was able to reduce runtime by 130 ms by this simple fix. The second part of the SSE2 optimized part could probably be optimized further by using shift SSE2 operations, but I imagine this would improve performance 10-20 ms at best. --- modules/calib3d/src/stereosgbm.cpp | 50 +++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp index 1c085f9b3a..9b783e9d65 100644 --- a/modules/calib3d/src/stereosgbm.cpp +++ b/modules/calib3d/src/stereosgbm.cpp @@ -759,14 +759,50 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2, } else { - for( d = 0; d < D; d++ ) + #if CV_SSE2 + if( useSIMD ) { - int Sval = Sp[d]; - if( Sval < minS ) - { - minS = Sval; - bestDisp = d; - } + __m128i _minS = _mm_set1_epi16(MAX_COST), _bestDisp = _mm_set1_epi16(-1); + __m128i _d8 = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7), _8 = _mm_set1_epi16(8); + + for( d = 0; d < D; d+= 8 ) + { + __m128i L0 = _mm_load_si128((const __m128i*)( Sp + d )); + __m128i mask = _mm_cmplt_epi16( L0, _minS ); + _minS = _mm_min_epi16( L0, _minS ); + _bestDisp = _mm_xor_si128(_bestDisp, _mm_and_si128(_mm_xor_si128( _bestDisp, _d8), mask)); + _d8 = _mm_adds_epi16(_d8, _8 ); + } + short CV_DECL_ALIGNED(16) bestDispBuf[8]; + _mm_store_si128((__m128i*)bestDispBuf, _bestDisp); + short CV_DECL_ALIGNED(16) minSBuf[8]; + _mm_store_si128((__m128i*)minSBuf, _minS ); + + for( int i = 0; i < 8; i++ ) + { + int Sval = minSBuf[ i ]; + if( Sval <= minS ) + { + if( ( Sval < minS ) || ( bestDispBuf[i] < bestDisp ) ) + { + bestDisp = bestDispBuf[i]; + } + minS = Sval; + } + } + } + else + #endif + { + for( d = 0; d < D; d++ ) + { + int Sval = Sp[d]; + if( Sval < minS ) + { + minS = Sval; + bestDisp = d; + } + } } } From 6e22020dadb3743884494e92386b90143dea90e6 Mon Sep 17 00:00:00 2001 From: Alexander Karsakov Date: Mon, 11 Jan 2016 11:39:18 +0300 Subject: [PATCH 068/468] Fixed pnpTask: don't copy inliers vector in case it's empty. --- modules/calib3d/src/solvepnp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/calib3d/src/solvepnp.cpp b/modules/calib3d/src/solvepnp.cpp index be587031ec..3c1e50e6b2 100644 --- a/modules/calib3d/src/solvepnp.cpp +++ b/modules/calib3d/src/solvepnp.cpp @@ -197,7 +197,7 @@ namespace cv } resultsMutex.lock(); - if ( (localInliers.size() > inliers.size()) || (localInliers.size() == inliers.size() && curIndex > bestIndex)) + if ( (localInliers.size() > inliers.size()) || (localInliers.size() == inliers.size() && inliers.size() > 0 && curIndex > bestIndex)) { inliers.clear(); inliers.resize(localInliers.size()); From 3f172731b20e4e646b89985154b34a0532cd7b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20Sp=C3=B6rk?= Date: Mon, 11 Jan 2016 10:59:15 +0100 Subject: [PATCH 069/468] added wrapped load function for python as suggested by gat3way --- modules/ml/include/opencv2/ml.hpp | 10 ++++++++++ modules/ml/src/ann_mlp.cpp | 14 +++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 4f99bf4b36..7acce7f33c 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1398,6 +1398,16 @@ public: Note that the train method has optional flags: ANN_MLP::TrainFlags. */ CV_WRAP static Ptr create(); + + /** @brief Loads and creates a serialized ANN from a file + * + * Use ANN::save to serialize and store an ANN to disk. + * Load the ANN from this file again, by calling this function with the path to the file. + * + * @param filepath path to serialized ANN + */ + CV_WRAP static Ptr load(const String& filepath); + }; /****************************************************************************************\ diff --git a/modules/ml/src/ann_mlp.cpp b/modules/ml/src/ann_mlp.cpp index ff6512dedd..19ee913320 100644 --- a/modules/ml/src/ann_mlp.cpp +++ b/modules/ml/src/ann_mlp.cpp @@ -1317,6 +1317,18 @@ Ptr ANN_MLP::create() return makePtr(); } -}} +Ptr ANN_MLP::load(const String& filepath) +{ + FileStorage fs; + fs.open(filepath, FileStorage::READ); + + Ptr ann = makePtr(); + + ((ANN_MLPImpl*)ann.get())->read(fs.getFirstTopLevelNode()); + return ann; +} + + + }} /* End of file. */ From 537d1322b469daff93432621d0c7fae3ec7f2546 Mon Sep 17 00:00:00 2001 From: takacsd Date: Mon, 11 Jan 2016 16:05:22 +0100 Subject: [PATCH 070/468] Add missing implementation to one of the Mat_<_Tp> constructor. (#5945) --- modules/core/include/opencv2/core/mat.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index e10cd9587d..631c698081 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -821,6 +821,9 @@ template inline Mat_<_Tp>::Mat_(int _dims, const int* _sz) template inline Mat_<_Tp>::Mat_(int _dims, const int* _sz, const _Tp& _s) : Mat(_dims, _sz, DataType<_Tp>::type, Scalar(_s)) {} +template inline Mat_<_Tp>::Mat_(int _dims, const int* _sz, _Tp* _data, const size_t* _steps) + : Mat(_dims, _sz, DataType<_Tp>::type, _data, _steps) {} + template inline Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const Range* ranges) : Mat(m, ranges) {} From c7ccde69a828c493d0cb291d5151c0cc493a29f1 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 14 Jan 2016 14:38:37 +0300 Subject: [PATCH 071/468] fix TLS implementation (closes #5967) --- modules/core/src/system.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index 5fbb453742..768280e1a6 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -1085,11 +1085,14 @@ public: for(size_t i = 0; i < threads.size(); i++) { - std::vector& thread_slots = threads[i]->slots; - if (thread_slots.size() > slotIdx && thread_slots[slotIdx]) + if(threads[i]) { - dataVec.push_back(thread_slots[slotIdx]); - threads[i]->slots[slotIdx] = 0; + std::vector& thread_slots = threads[i]->slots; + if (thread_slots.size() > slotIdx && thread_slots[slotIdx]) + { + dataVec.push_back(thread_slots[slotIdx]); + threads[i]->slots[slotIdx] = 0; + } } } @@ -1116,9 +1119,12 @@ public: for(size_t i = 0; i < threads.size(); i++) { - std::vector& thread_slots = threads[i]->slots; - if (thread_slots.size() > slotIdx && thread_slots[slotIdx]) - dataVec.push_back(thread_slots[slotIdx]); + if(threads[i]) + { + std::vector& thread_slots = threads[i]->slots; + if (thread_slots.size() > slotIdx && thread_slots[slotIdx]) + dataVec.push_back(thread_slots[slotIdx]); + } } } From c8ff7a486735f45f9dd4060111b71957c78142c6 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 14 Jan 2016 16:59:33 +0300 Subject: [PATCH 072/468] build: fix opencv_world with CUDA --- CMakeLists.txt | 2 +- cmake/OpenCVUtils.cmake | 20 +++++--------------- modules/cudev/CMakeLists.txt | 2 +- modules/world/CMakeLists.txt | 4 ++-- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bf9d85feb0..5cdc849f02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,7 +253,7 @@ OCV_OPTION(INSTALL_TESTS "Install accuracy and performance test binar # OpenCV build options # =================================================== -OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers" ON IF (NOT IOS) ) +OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers" ON IF (NOT IOS AND NOT CMAKE_CROSSCOMPILING AND NOT ((HAVE_CUDA OR WITH_CUDA) AND BUILD_opencv_world)) ) OCV_OPTION(ENABLE_SOLUTION_FOLDERS "Solution folder in Visual Studio or in other IDEs" (MSVC_IDE OR CMAKE_GENERATOR MATCHES Xcode) ) OCV_OPTION(ENABLE_PROFILING "Enable profiling in the GCC compiler (Add flags: -g -pg)" OFF IF CMAKE_COMPILER_IS_GNUCXX ) OCV_OPTION(ENABLE_COVERAGE "Enable coverage collection with GCov" OFF IF CMAKE_COMPILER_IS_GNUCXX ) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 75412ebc83..b60f357d40 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -747,20 +747,9 @@ function(ocv_add_executable target) endfunction() function(ocv_add_library target) - set(cuda_objs "") - if(HAVE_CUDA) - set(cuda_srcs "") - - foreach(var ${ARGN}) - if(var MATCHES ".cu") - list(APPEND cuda_srcs ${var}) - endif() - endforeach() - - if(cuda_srcs) - ocv_include_directories(${CUDA_INCLUDE_DIRS}) - ocv_cuda_compile(cuda_objs ${lib_cuda_srcs} ${lib_cuda_hdrs}) - endif() + if(HAVE_CUDA AND ARGN MATCHES "\\.cu") + ocv_include_directories(${CUDA_INCLUDE_DIRS}) + ocv_cuda_compile(cuda_objs ${ARGN}) set(OPENCV_MODULE_${target}_CUDA_OBJECTS ${cuda_objs} CACHE INTERNAL "Compiled CUDA object files") endif() @@ -771,9 +760,10 @@ function(ocv_add_library target) AND NOT OPENCV_MODULE_${target}_CHILDREN AND NOT OPENCV_MODULE_${target}_CLASS STREQUAL "BINDINGS" AND NOT ${target} STREQUAL "opencv_ts" + AND (NOT BUILD_opencv_world OR NOT HAVE_CUDA) ) set(sources ${ARGN}) - ocv_list_filterout(sources "\\\\.(cl|inc)$") + ocv_list_filterout(sources "\\\\.(cl|inc|cu)$") add_library(${target}_object OBJECT ${sources}) set_target_properties(${target}_object PROPERTIES EXCLUDE_FROM_ALL True diff --git a/modules/cudev/CMakeLists.txt b/modules/cudev/CMakeLists.txt index 257572951e..f9f1d0bb98 100644 --- a/modules/cudev/CMakeLists.txt +++ b/modules/cudev/CMakeLists.txt @@ -17,6 +17,6 @@ ocv_set_module_sources(HEADERS ${lib_hdrs} SOURCES ${lib_srcs}) ocv_create_module() -if(BUILD_TESTS) +if(BUILD_TESTS AND NOT BUILD_opencv_world) add_subdirectory(test) endif() diff --git a/modules/world/CMakeLists.txt b/modules/world/CMakeLists.txt index 7783151faa..6fa10d0b5c 100644 --- a/modules/world/CMakeLists.txt +++ b/modules/world/CMakeLists.txt @@ -20,13 +20,13 @@ if(NOT OPENCV_INITIAL_PASS) foreach(m ${OPENCV_MODULES_BUILD}) if(OPENCV_MODULE_${m}_IS_PART_OF_WORLD) message(STATUS " module ${m}...") - set(CMAKE_CURRENT_SOURCE_DIR ${OPENCV_MODULE_${m}_LOCATION}) + set(CMAKE_CURRENT_SOURCE_DIR "${OPENCV_MODULE_${m}_LOCATION}") #add_subdirectory("${OPENCV_MODULE_${m}_LOCATION}" ${CMAKE_CURRENT_BINARY_DIR}/${m}) include_one_module(${m}) endif() endforeach() message(STATUS "Processing WORLD modules... DONE") - set(CMAKE_CURRENT_SOURCE_DIR OPENCV_MODULE_${opencv_world}_LOCATION) + set(CMAKE_CURRENT_SOURCE_DIR "${OPENCV_MODULE_opencv_world_LOCATION}") endif() ocv_add_module(world opencv_core) From fcbb57a63f4e51ab12294eaed55afaebdf56fafd Mon Sep 17 00:00:00 2001 From: AlexeyAB Date: Thu, 14 Jan 2016 19:02:18 +0300 Subject: [PATCH 073/468] Added ability to disable lighting in the viz-module. When I reconstructed the 3D scene I want to show it as viz::WMesh with an initial value of lighting. For this I disable lighting and shadows: cv::viz::Viz3d viz_3d_window("3D"); viz_3d_window.setRenderingProperty("mesh", cv::viz::LIGHTING, 0); Most of the examples show the 3D reconstruction using the point cloud, but using the mesh one part of it creates a shadow on other parts of it if lighting ON. Using a 3D mesh with disabled lighting gives the most realistic picture of the reconstructed 3D scene. --- modules/viz/include/opencv2/viz/widgets.hpp | 3 ++- modules/viz/src/widget.cpp | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp index fde4fc2c7d..47b655424f 100644 --- a/modules/viz/include/opencv2/viz/widgets.hpp +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -67,7 +67,8 @@ namespace cv REPRESENTATION, IMMEDIATE_RENDERING, SHADING, - AMBIENT + AMBIENT, + LIGHTING }; enum RepresentationValues diff --git a/modules/viz/src/widget.cpp b/modules/viz/src/widget.cpp index 698f21c9ae..3423ba8de6 100644 --- a/modules/viz/src/widget.cpp +++ b/modules/viz/src/widget.cpp @@ -115,6 +115,14 @@ void cv::viz::Widget::setRenderingProperty(int property, double value) case LINE_WIDTH: actor->GetProperty()->SetLineWidth(float(value)); break; case IMMEDIATE_RENDERING: actor->GetMapper()->SetImmediateModeRendering(int(value)); break; case AMBIENT: actor->GetProperty()->SetAmbient(float(value)); break; + case LIGHTING: + { + if (value == 0) + actor->GetProperty()->LightingOff(); + else + actor->GetProperty()->LightingOn(); + break; + } case FONT_SIZE: { vtkTextActor* text_actor = vtkTextActor::SafeDownCast(actor); From 4f5d5851843a1a6f4bbe0bc6d761f24a04fa7b45 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Fri, 4 Dec 2015 14:31:24 +0300 Subject: [PATCH 074/468] Update call to Tegra optimized morphology filtering --- modules/imgproc/src/morph.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/imgproc/src/morph.cpp b/modules/imgproc/src/morph.cpp index 1cf4a625dd..118d4efedd 100644 --- a/modules/imgproc/src/morph.cpp +++ b/modules/imgproc/src/morph.cpp @@ -584,19 +584,11 @@ typedef MorphFVec DilateVec32f; #else -#ifdef HAVE_TEGRA_OPTIMIZATION -using tegra::ErodeRowVec8u; -using tegra::DilateRowVec8u; - -using tegra::ErodeColumnVec8u; -using tegra::DilateColumnVec8u; -#else typedef MorphRowNoVec ErodeRowVec8u; typedef MorphRowNoVec DilateRowVec8u; typedef MorphColumnNoVec ErodeColumnVec8u; typedef MorphColumnNoVec DilateColumnVec8u; -#endif typedef MorphRowNoVec ErodeRowVec16u; typedef MorphRowNoVec DilateRowVec16u; @@ -1114,6 +1106,17 @@ public: Mat srcStripe = src.rowRange(row0, row1); Mat dstStripe = dst.rowRange(row0, row1); + +#if defined HAVE_TEGRA_OPTIMIZATION + //Iterative separable filters are converted to single iteration filters + //But anyway check that we really get 1 iteration prior to processing + if( countNonZero(kernel) == kernel.rows*kernel.cols && iterations == 1 && + src.depth() == CV_8U && ( op == MORPH_ERODE || op == MORPH_DILATE ) && + tegra::morphology(srcStripe, dstStripe, op, kernel, anchor, + rowBorderType, columnBorderType, borderValue) ) + return; +#endif + Ptr f = createMorphologyFilter(op, src.type(), kernel, anchor, rowBorderType, columnBorderType, borderValue ); From c35ddcba1a99409aa5bb01e83fa2c1d667d8e085 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 15 Jan 2016 12:42:22 +0300 Subject: [PATCH 075/468] cmake: refactor OpenCL detection, allow custom configurations --- CMakeLists.txt | 11 +++++------ cmake/OpenCVDetectOpenCL.cmake | 34 +++++++++++++--------------------- cmake/OpenCVModule.cmake | 1 - modules/core/CMakeLists.txt | 2 +- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cdc849f02..3c64442263 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1138,14 +1138,13 @@ endif() if(HAVE_OPENCL) status("") - status(" OpenCL:") if(HAVE_OPENCL_STATIC) - set(__opencl_ver "static") + set(__opencl_type "") else() - set(__opencl_ver "dynamic") + set(__opencl_type "") endif() - status(" Version:" ${__opencl_ver}) - if(OPENCL_INCLUDE_DIR) + status(" OpenCL:" ${__opencl_type}) + if(OPENCL_INCLUDE_DIRS) status(" Include path:" ${OPENCL_INCLUDE_DIRS}) endif() if(OPENCL_LIBRARIES) @@ -1162,7 +1161,7 @@ if(HAVE_OPENCL) list(APPEND __libs "${l}") endif() endforeach() - status(" libraries:" ${__libs}) + status(" Link libraries:" ${__libs}) endif() status(" Use AMDFFT:" HAVE_CLAMDFFT THEN YES ELSE NO) status(" Use AMDBLAS:" HAVE_CLAMDBLAS THEN YES ELSE NO) diff --git a/cmake/OpenCVDetectOpenCL.cmake b/cmake/OpenCVDetectOpenCL.cmake index 67e10ede89..433f244fe6 100644 --- a/cmake/OpenCVDetectOpenCL.cmake +++ b/cmake/OpenCVDetectOpenCL.cmake @@ -1,21 +1,21 @@ +set(OPENCL_FOUND ON CACHE BOOL "OpenCL library is found") if(APPLE) - set(OPENCL_FOUND YES) set(OPENCL_LIBRARY "-framework OpenCL" CACHE STRING "OpenCL library") - set(OPENCL_INCLUDE_DIR "" CACHE STRING "OpenCL include directory") - mark_as_advanced(OPENCL_INCLUDE_DIR OPENCL_LIBRARY) - set(HAVE_OPENCL_STATIC ON) + set(OPENCL_INCLUDE_DIR "" CACHE PATH "OpenCL include directory") else(APPLE) - set(OPENCL_FOUND YES) - set(HAVE_OPENCL_STATIC OFF) - set(OPENCL_INCLUDE_DIR "${OpenCV_SOURCE_DIR}/3rdparty/include/opencl/1.2") + set(OPENCL_LIBRARY "" CACHE STRING "OpenCL library") + set(OPENCL_INCLUDE_DIR "${OpenCV_SOURCE_DIR}/3rdparty/include/opencl/1.2" CACHE PATH "OpenCL include directory") endif(APPLE) - -if(WINRT) - set(OPENCL_FOUND NO) - set(HAVE_OPENCL_STATIC OFF) -endif(WINRT) +mark_as_advanced(OPENCL_INCLUDE_DIR OPENCL_LIBRARY) if(OPENCL_FOUND) + if(OPENCL_LIBRARY) + set(HAVE_OPENCL_STATIC ON) + set(OPENCL_LIBRARIES "${OPENCL_LIBRARY}") + else() + set(HAVE_OPENCL_STATIC OFF) + endif() + if(NOT HAVE_OPENCL_STATIC) try_compile(__VALID_OPENCL "${OpenCV_BINARY_DIR}" @@ -29,20 +29,12 @@ if(OPENCL_FOUND) endif() endif() - if(NOT WINRT) - set(HAVE_OPENCL 1) - endif() + set(HAVE_OPENCL 1) if(WITH_OPENCL_SVM) set(HAVE_OPENCL_SVM 1) endif() - if(HAVE_OPENCL_STATIC) - set(OPENCL_LIBRARIES "${OPENCL_LIBRARY}") - else() - unset(OPENCL_LIBRARIES) - endif() - set(OPENCL_INCLUDE_DIRS ${OPENCL_INCLUDE_DIR}) if(WITH_OPENCLAMDFFT) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 3385385c5f..23a637a25a 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -701,7 +701,6 @@ macro(ocv_glob_module_sources) ) if(cl_kernels) set(OCL_NAME opencl_kernels_${name}) - ocv_include_directories(${OPENCL_INCLUDE_DIRS}) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OCL_NAME}.cpp" "${CMAKE_CURRENT_BINARY_DIR}/${OCL_NAME}.hpp" COMMAND ${CMAKE_COMMAND} "-DMODULE_NAME=${name}" "-DCL_DIR=${CMAKE_CURRENT_LIST_DIR}/src/opencl" "-DOUTPUT=${CMAKE_CURRENT_BINARY_DIR}/${OCL_NAME}.cpp" -P "${OpenCV_SOURCE_DIR}/cmake/cl2cpp.cmake" diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt index 44085d4edf..8a68c90289 100644 --- a/modules/core/CMakeLists.txt +++ b/modules/core/CMakeLists.txt @@ -27,7 +27,7 @@ source_group("Cuda Headers\\Detail" FILES ${lib_cuda_hdrs_detail}) ocv_glob_module_sources(SOURCES "${OPENCV_MODULE_opencv_core_BINARY_DIR}/version_string.inc" HEADERS ${lib_cuda_hdrs} ${lib_cuda_hdrs_detail}) -ocv_module_include_directories(${the_module} ${ZLIB_INCLUDE_DIRS}) +ocv_module_include_directories(${the_module} ${ZLIB_INCLUDE_DIRS} ${OPENCL_INCLUDE_DIRS}) ocv_create_module(${extra_libs}) ocv_add_accuracy_tests() From 9d4ee2f54d5a3823e8d3f2af320efb805543bd37 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 25 Dec 2015 17:35:38 +0300 Subject: [PATCH 076/468] cmake: added generation of CMakeVars.txt related: #5845 --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cdc849f02..166feef793 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1255,3 +1255,6 @@ endif() # ---------------------------------------------------------------------------- include(cmake/OpenCVPackaging.cmake) + +# This should be the last command +ocv_cmake_dump_vars("" TOFILE "CMakeVars.txt") From 9cd67318947d801dea558dcd9ac119e941aeef63 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 15 Jan 2016 14:03:48 +0300 Subject: [PATCH 077/468] cmake: add DEBUG_PRE/DEBUG_POST commands handling Useful for debug purposes: cmake -DDEBUG_POST="ocv_cmake_dump_vars(CUDA)" . cmake -DCMAKE_PRE="ocv_cmake_dump_vars(\"OPENCL|opencl\")" . --- CMakeLists.txt | 3 +++ cmake/OpenCVUtils.cmake | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 166feef793..fc0c415c4b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,8 @@ endif() include(cmake/OpenCVUtils.cmake) +ocv_cmake_eval(DEBUG_PRE ONCE) + ocv_clear_vars(OpenCVModules_TARGETS) # ---------------------------------------------------------------------------- @@ -1258,3 +1260,4 @@ include(cmake/OpenCVPackaging.cmake) # This should be the last command ocv_cmake_dump_vars("" TOFILE "CMakeVars.txt") +ocv_cmake_eval(DEBUG_POST ONCE) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index b60f357d40..75073f5a85 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -1,3 +1,5 @@ +include(CMakeParseArguments) + # Debugging function function(ocv_cmake_dump_vars) cmake_parse_arguments(DUMP "" "TOFILE" "" ${ARGN}) @@ -16,6 +18,15 @@ function(ocv_cmake_dump_vars) endif() endfunction() +function(ocv_cmake_eval var_name) + if(DEFINED ${var_name}) + file(WRITE "${CMAKE_BINARY_DIR}/CMakeCommand-${var_name}.cmake" ${${var_name}}) + include("${CMAKE_BINARY_DIR}/CMakeCommand-${var_name}.cmake") + endif() + if(";${ARGN};" MATCHES ";ONCE;") + unset(${var_name} CACHE) + endif() +endfunction() # Search packages for host system instead of packages for target system # in case of cross compilation thess macro should be defined by toolchain file From 8f37a3a37c34c6f3af93ed16278bf4f44bdd6098 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 15 Jan 2016 14:38:25 +0300 Subject: [PATCH 078/468] cmake: make ocv_cmake_dump_vars() case insensitive --- cmake/OpenCVUtils.cmake | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index 75073f5a85..765ee71090 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -2,12 +2,14 @@ include(CMakeParseArguments) # Debugging function function(ocv_cmake_dump_vars) + set(VARS "") + get_cmake_property(_variableNames VARIABLES) cmake_parse_arguments(DUMP "" "TOFILE" "" ${ARGN}) set(regex "${DUMP_UNPARSED_ARGUMENTS}") - get_cmake_property(_variableNames VARIABLES) - set(VARS "") + string(TOLOWER "${regex}" regex_lower) foreach(_variableName ${_variableNames}) - if(_variableName MATCHES "${regex}") + string(TOLOWER "${_variableName}" _variableName_lower) + if(_variableName MATCHES "${regex}" OR _variableName_lower MATCHES "${regex_lower}") set(VARS "${VARS}${_variableName}=${${_variableName}}\n") endif() endforeach() From c75f9c80c72cc9957856ba6c4da34339d1150b6f Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 15 Jan 2016 19:43:24 +0300 Subject: [PATCH 079/468] cmake: turn off precompiled headers in case of opencv_world builds --- CMakeLists.txt | 2 +- modules/world/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5cdc849f02..f8c6537373 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -253,7 +253,7 @@ OCV_OPTION(INSTALL_TESTS "Install accuracy and performance test binar # OpenCV build options # =================================================== -OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers" ON IF (NOT IOS AND NOT CMAKE_CROSSCOMPILING AND NOT ((HAVE_CUDA OR WITH_CUDA) AND BUILD_opencv_world)) ) +OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers" ON IF (NOT IOS AND NOT CMAKE_CROSSCOMPILING) ) OCV_OPTION(ENABLE_SOLUTION_FOLDERS "Solution folder in Visual Studio or in other IDEs" (MSVC_IDE OR CMAKE_GENERATOR MATCHES Xcode) ) OCV_OPTION(ENABLE_PROFILING "Enable profiling in the GCC compiler (Add flags: -g -pg)" OFF IF CMAKE_COMPILER_IS_GNUCXX ) OCV_OPTION(ENABLE_COVERAGE "Enable coverage collection with GCov" OFF IF CMAKE_COMPILER_IS_GNUCXX ) diff --git a/modules/world/CMakeLists.txt b/modules/world/CMakeLists.txt index 6fa10d0b5c..db8928d69c 100644 --- a/modules/world/CMakeLists.txt +++ b/modules/world/CMakeLists.txt @@ -14,6 +14,7 @@ function(include_one_module m) endfunction() if(NOT OPENCV_INITIAL_PASS) + set(ENABLE_PRECOMPILED_HEADERS OFF CACHE INTERNAL "" FORCE) project(opencv_world) message(STATUS "Processing WORLD modules...") From 5312db93b4af9cdade4a7d0ba0f1f7c3f7413344 Mon Sep 17 00:00:00 2001 From: Ishank gulati Date: Sun, 17 Jan 2016 09:46:23 +0530 Subject: [PATCH 080/468] added equality --- .../features2d/feature_homography/feature_homography.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorials/features2d/feature_homography/feature_homography.markdown b/doc/tutorials/features2d/feature_homography/feature_homography.markdown index dd96302baf..ec7913c330 100644 --- a/doc/tutorials/features2d/feature_homography/feature_homography.markdown +++ b/doc/tutorials/features2d/feature_homography/feature_homography.markdown @@ -75,7 +75,7 @@ int main( int argc, char** argv ) std::vector< DMatch > good_matches; for( int i = 0; i < descriptors_object.rows; i++ ) - { if( matches[i].distance < 3*min_dist ) + { if( matches[i].distance <= 3*min_dist ) { good_matches.push_back( matches[i]); } } From 9a783d2a8eddc16d11c816c78830fa3fd0670ed6 Mon Sep 17 00:00:00 2001 From: Prayag Verma Date: Mon, 18 Jan 2016 10:11:01 +0530 Subject: [PATCH 081/468] Update license year range to 2016 --- LICENSE | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index ab58eebcad..fce70d7135 100644 --- a/LICENSE +++ b/LICENSE @@ -7,12 +7,12 @@ copy or use the software. For Open Source Computer Vision Library (3-clause BSD License) -Copyright (C) 2000-2015, Intel Corporation, all rights reserved. +Copyright (C) 2000-2016, Intel Corporation, all rights reserved. Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. -Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved. +Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved. Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. -Copyright (C) 2015, OpenCV Foundation, all rights reserved. -Copyright (C) 2015, Itseez Inc., all rights reserved. +Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved. +Copyright (C) 2015-2016, Itseez Inc., all rights reserved. Third party copyrights are property of their respective owners. Redistribution and use in source and binary forms, with or without modification, From 389f176a67741b403275a4e16e1dc2f26a3e64fa Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Mon, 18 Jan 2016 12:54:53 +0300 Subject: [PATCH 082/468] Removed ioctl calls to query for VIDIOC_G_INPUT and VIDIOC_ENUMINPUT since information returned by the calls is never used. Fixed icvCaptureFromCAM_V4L return value in case of V4L2 camera initialization failure. --- modules/highgui/src/cap_v4l.cpp | 47 +++------------------------------ 1 file changed, 3 insertions(+), 44 deletions(-) diff --git a/modules/highgui/src/cap_v4l.cpp b/modules/highgui/src/cap_v4l.cpp index d09c8f88cf..2599cada80 100644 --- a/modules/highgui/src/cap_v4l.cpp +++ b/modules/highgui/src/cap_v4l.cpp @@ -491,8 +491,6 @@ static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName) // 0 then detected nothing // 1 then V4L2 device - int deviceIndex; - /* Open and test V4L2 device */ capture->deviceHandle = open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0); if (-1 == capture->deviceHandle) @@ -514,28 +512,6 @@ static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName) return 0; } - /* Query channels number */ - if (-1 == ioctl (capture->deviceHandle, VIDIOC_G_INPUT, &deviceIndex)) - { -#ifndef NDEBUG - fprintf(stderr, "(DEBUG) try_init_v4l2 VIDIOC_G_INPUT \"%s\": %s\n", deviceName, strerror(errno)); -#endif - icvCloseCAM_V4L(capture); - return 0; - } - - /* Query information about current input */ - CLEAR (capture->inp); - capture->inp.index = deviceIndex; - if (-1 == ioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp)) - { -#ifndef NDEBUG - fprintf(stderr, "(DEBUG) try_init_v4l2 VIDIOC_ENUMINPUT \"%s\": %s\n", deviceName, strerror(errno)); -#endif - icvCloseCAM_V4L(capture); - return 0; - } - return 1; } @@ -834,26 +810,6 @@ static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName) return -1; } - /* The following code sets the CHANNEL_NUMBER of the video input. Some video sources - have sub "Channel Numbers". For a typical V4L TV capture card, this is usually 1. - I myself am using a simple NTSC video input capture card that uses the value of 1. - If you are not in North America or have a different video standard, you WILL have to change - the following settings and recompile/reinstall. This set of settings is based on - the most commonly encountered input video source types (like my bttv card) */ - - if(capture->inp.index > 0) { - CLEAR (capture->inp); - capture->inp.index = CHANNEL_NUMBER; - /* Set only channel number to CHANNEL_NUMBER */ - /* V4L2 have a status field from selected video mode */ - if (-1 == ioctl (capture->deviceHandle, VIDIOC_ENUMINPUT, &capture->inp)) - { - fprintf (stderr, "HIGHGUI ERROR: V4L2: Aren't able to set channel number\n"); - icvCloseCAM_V4L (capture); - return -1; - } - } /* End if */ - /* Find Window info */ CLEAR (capture->form); capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -1157,6 +1113,9 @@ static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index) } #endif /* HAVE_CAMV4L */ #ifdef HAVE_CAMV4L2 +#ifndef HAVE_CAMV4L + return NULL; +#endif /* !HAVE_CAMV4L */ } else { V4L2_SUPPORT = 1; } From 474c53ac710bd61224443258b6e0f7c595b08fae Mon Sep 17 00:00:00 2001 From: Alexander Fedorov Date: Mon, 18 Jan 2016 15:34:41 +0300 Subject: [PATCH 083/468] Fixed parser for img1_filename and img2_filename. Without fixes after 68 line (img1_filename = parser.get(0);) OpenCV Error: ./stereo_matching im0.png im1.png --max-disparity=16 --blocksize=17 OpenCV Error: Bad argument (undeclared position 0 requested) in getByIndex, file /home/entodi/opencv/modules/core/src/command_line_parser.cpp, line 169 terminate called after throwing an instance of 'cv::Exception' what(): /home/entodi/opencv/modules/core/src/command_line_parser.cpp:169: error: (-5) undeclared position 0 requested in function getByIndex --- samples/cpp/stereo_match.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/cpp/stereo_match.cpp b/samples/cpp/stereo_match.cpp index e3ebb5ddf0..e88b139a16 100644 --- a/samples/cpp/stereo_match.cpp +++ b/samples/cpp/stereo_match.cpp @@ -59,7 +59,7 @@ int main(int argc, char** argv) Ptr bm = StereoBM::create(16,9); Ptr sgbm = StereoSGBM::create(0,16,3); cv::CommandLineParser parser(argc, argv, - "{help h||}{algorithm||}{max-disparity|0|}{blocksize|0|}{no-display||}{scale|1|}{i||}{e||}{o||}{p||}"); + "{@arg1||}{@arg2||}{help h||}{algorithm||}{max-disparity|0|}{blocksize|0|}{no-display||}{scale|1|}{i||}{e||}{o||}{p||}"); if(parser.has("help")) { print_help(); From cc3b2f619740c933a1d8376045e2b455966f9a69 Mon Sep 17 00:00:00 2001 From: emiswelt Date: Tue, 19 Jan 2016 15:39:07 +0000 Subject: [PATCH 084/468] Added a helpful comment on the scale parameter of the spherical warper. --- .../stitching/include/opencv2/stitching/detail/warpers.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp index ee8e824cbf..2327699f8f 100644 --- a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp @@ -214,7 +214,8 @@ struct CV_EXPORTS SphericalProjector : ProjectorBase /** @brief Warper that maps an image onto the unit sphere located at the origin. - Projects image onto unit sphere with origin at (0, 0, 0). + Projects image onto unit sphere with origin at (0, 0, 0) and radius scale, measured in pixels. + A 360° panorama would therefore have a resulting width of 2 * scale * PI pixels. Poles are located at (0, -1, 0) and (0, 1, 0) points. */ class CV_EXPORTS SphericalWarper : public RotationWarperBase @@ -222,7 +223,8 @@ class CV_EXPORTS SphericalWarper : public RotationWarperBase public: /** @brief Construct an instance of the spherical warper class. - @param scale Projected image scale multiplier + @param scale Radius of the projected sphere, in pixels. An image spanning the + whole sphere will have a width of 2 * scale * PI pixels. */ SphericalWarper(float scale) { projector_.scale = scale; } From bb1c2d71a8714be1b31ee31424ac7dbef1ef36d8 Mon Sep 17 00:00:00 2001 From: Elena Gvozdeva Date: Wed, 20 Jan 2016 13:07:07 +0300 Subject: [PATCH 085/468] fix bug on border at pyrUp --- modules/imgproc/src/pyramids.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/modules/imgproc/src/pyramids.cpp b/modules/imgproc/src/pyramids.cpp index 4000167497..acf507248e 100644 --- a/modules/imgproc/src/pyramids.cpp +++ b/modules/imgproc/src/pyramids.cpp @@ -349,7 +349,7 @@ pyrUp_( const Mat& _src, Mat& _dst, int) for( ; sy <= y + 1; sy++ ) { WT* row = buf + ((sy - sy0) % PU_SZ)*bufstep; - int _sy = borderInterpolate(sy*2, dsize.height, BORDER_REFLECT_101)/2; + int _sy = borderInterpolate(sy*2, ssize.height*2, BORDER_REFLECT_101)/2; const T* src = (const T*)(_src.data + _src.step*_sy); if( ssize.width == cn ) @@ -370,6 +370,11 @@ pyrUp_( const Mat& _src, Mat& _dst, int) t0 = src[sx - cn] + src[sx]*7; t1 = src[sx]*8; row[dx] = t0; row[dx + cn] = t1; + + if (dsize.width > ssize.width*2) + { + row[(_dst.cols-1) + x] = row[dx + cn]; + } } for( x = cn; x < ssize.width - cn; x++ ) @@ -395,6 +400,17 @@ pyrUp_( const Mat& _src, Mat& _dst, int) dst1[x] = t1; dst0[x] = t0; } } + + if (dsize.height > ssize.height*2) + { + T* dst0 = _dst.ptr(ssize.height*2-2); + T* dst2 = _dst.ptr(ssize.height*2); + + for(x = 0; x < dsize.width ; x++ ) + { + dst2[x] = dst0[x]; + } + } } typedef void (*PyrFunc)(const Mat&, Mat&, int); From 24bbdeb0c859a874aa529e564bf627035197b58f Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 20 Jan 2016 13:06:51 +0300 Subject: [PATCH 086/468] include available modules only --- include/opencv2/opencv.hpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/opencv2/opencv.hpp b/include/opencv2/opencv.hpp index fd9ca5898e..49b6a6691f 100644 --- a/include/opencv2/opencv.hpp +++ b/include/opencv2/opencv.hpp @@ -43,16 +43,38 @@ #ifndef __OPENCV_ALL_HPP__ #define __OPENCV_ALL_HPP__ +#include "opencv2/opencv_modules.hpp" + #include "opencv2/core.hpp" +#ifdef HAVE_OPENCV_IMGPROC #include "opencv2/imgproc.hpp" +#endif +#ifdef HAVE_OPENCV_PHOTO #include "opencv2/photo.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEO #include "opencv2/video.hpp" +#endif +#ifdef HAVE_OPENCV_FEATURES2D #include "opencv2/features2d.hpp" +#endif +#ifdef HAVE_OPENCV_OBJDETECT #include "opencv2/objdetect.hpp" +#endif +#ifdef HAVE_OPENCV_CALIB3D #include "opencv2/calib3d.hpp" +#endif +#ifdef HAVE_OPENCV_IMGCODECS #include "opencv2/imgcodecs.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEOIO #include "opencv2/videoio.hpp" +#endif +#ifdef HAVE_OPENCV_HIGHGUI #include "opencv2/highgui.hpp" +#endif +#ifdef HAVE_OPENCV_ML #include "opencv2/ml.hpp" +#endif #endif From 4a8d1147c224214336ddd8bd8671ab7fed95fcab Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 20 Jan 2016 13:06:51 +0300 Subject: [PATCH 087/468] include available modules only --- include/opencv2/opencv.hpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/include/opencv2/opencv.hpp b/include/opencv2/opencv.hpp index f89547c9be..f76da92fef 100644 --- a/include/opencv2/opencv.hpp +++ b/include/opencv2/opencv.hpp @@ -43,19 +43,41 @@ #ifndef __OPENCV_ALL_HPP__ #define __OPENCV_ALL_HPP__ +#include "opencv2/opencv_modules.hpp" + #include "opencv2/core/core_c.h" #include "opencv2/core/core.hpp" +#ifdef HAVE_OPENCV_FLANN #include "opencv2/flann/miniflann.hpp" +#endif +#ifdef HAVE_OPENCV_IMGPROC #include "opencv2/imgproc/imgproc_c.h" #include "opencv2/imgproc/imgproc.hpp" +#endif +#ifdef HAVE_OPENCV_PHOTO #include "opencv2/photo/photo.hpp" +#endif +#ifdef HAVE_OPENCV_VIDEO #include "opencv2/video/video.hpp" +#endif +#ifdef HAVE_OPENCV_FEATURES2D #include "opencv2/features2d/features2d.hpp" +#endif +#ifdef HAVE_OPENCV_OBJDETECT #include "opencv2/objdetect/objdetect.hpp" +#endif +#ifdef HAVE_OPENCV_CALIB3D #include "opencv2/calib3d/calib3d.hpp" +#endif +#ifdef HAVE_OPENCV_ML #include "opencv2/ml/ml.hpp" +#endif +#ifdef HAVE_OPENCV_HIGHGUI #include "opencv2/highgui/highgui_c.h" #include "opencv2/highgui/highgui.hpp" +#endif +#ifdef HAVE_OPENCV_CONTRIB #include "opencv2/contrib/contrib.hpp" +#endif #endif From b6c5936704bc663d253f665d7b95481528547f85 Mon Sep 17 00:00:00 2001 From: emiswelt Date: Wed, 20 Jan 2016 10:21:36 +0000 Subject: [PATCH 088/468] Removed trailing whitespace. Note: Force push to force a re-run of build tests. The previous tests failed in an unrelated module. I assume it's a bug that occured randomly. --- .../stitching/include/opencv2/stitching/detail/warpers.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp index 2327699f8f..0cb9e42e87 100644 --- a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp @@ -214,8 +214,8 @@ struct CV_EXPORTS SphericalProjector : ProjectorBase /** @brief Warper that maps an image onto the unit sphere located at the origin. - Projects image onto unit sphere with origin at (0, 0, 0) and radius scale, measured in pixels. - A 360° panorama would therefore have a resulting width of 2 * scale * PI pixels. + Projects image onto unit sphere with origin at (0, 0, 0) and radius scale, measured in pixels. + A 360° panorama would therefore have a resulting width of 2 * scale * PI pixels. Poles are located at (0, -1, 0) and (0, 1, 0) points. */ class CV_EXPORTS SphericalWarper : public RotationWarperBase @@ -224,7 +224,7 @@ public: /** @brief Construct an instance of the spherical warper class. @param scale Radius of the projected sphere, in pixels. An image spanning the - whole sphere will have a width of 2 * scale * PI pixels. + whole sphere will have a width of 2 * scale * PI pixels. */ SphericalWarper(float scale) { projector_.scale = scale; } From 9bee835daca44b894c5c9689641bf639090fc9d3 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 20 Jan 2016 19:01:00 +0300 Subject: [PATCH 089/468] cmake: fix python detection --- cmake/OpenCVDetectPython.cmake | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/cmake/OpenCVDetectPython.cmake b/cmake/OpenCVDetectPython.cmake index 9493133eb4..64054d1efa 100644 --- a/cmake/OpenCVDetectPython.cmake +++ b/cmake/OpenCVDetectPython.cmake @@ -26,7 +26,7 @@ function(find_python preferred_version min_version library_env include_dir_env libs_found libs_version_string libraries library debug_libraries debug_library include_path include_dir include_dir2 packages_path numpy_include_dirs numpy_version) - +if(NOT ${found}) ocv_check_environment_variables(${executable}) if(${executable}) set(PYTHON_EXECUTABLE "${${executable}}") @@ -197,23 +197,24 @@ function(find_python preferred_version min_version library_env include_dir_env endif() # Export return values - set(${found} "${_found}" PARENT_SCOPE) + set(${found} "${_found}" CACHE INTERNAL "") set(${executable} "${_executable}" CACHE FILEPATH "Path to Python interpretor") - set(${version_string} "${_version_string}" PARENT_SCOPE) - set(${version_major} "${_version_major}" PARENT_SCOPE) - set(${version_minor} "${_version_minor}" PARENT_SCOPE) - set(${libs_found} "${_libs_found}" PARENT_SCOPE) - set(${libs_version_string} "${_libs_version_string}" PARENT_SCOPE) - set(${libraries} "${_libraries}" PARENT_SCOPE) + set(${version_string} "${_version_string}" CACHE INTERNAL "") + set(${version_major} "${_version_major}" CACHE INTERNAL "") + set(${version_minor} "${_version_minor}" CACHE INTERNAL "") + set(${libs_found} "${_libs_found}" CACHE INTERNAL "") + set(${libs_version_string} "${_libs_version_string}" CACHE INTERNAL "") + set(${libraries} "${_libraries}" CACHE INTERNAL "Python libraries") set(${library} "${_library}" CACHE FILEPATH "Path to Python library") - set(${debug_libraries} "${_debug_libraries}" PARENT_SCOPE) + set(${debug_libraries} "${_debug_libraries}" CACHE INTERNAL "") set(${debug_library} "${_debug_library}" CACHE FILEPATH "Path to Python debug") - set(${include_path} "${_include_path}" PARENT_SCOPE) + set(${include_path} "${_include_path}" CACHE INTERNAL "") set(${include_dir} "${_include_dir}" CACHE PATH "Python include dir") set(${include_dir2} "${_include_dir2}" CACHE PATH "Python include dir 2") set(${packages_path} "${_packages_path}" CACHE PATH "Where to install the python packages.") set(${numpy_include_dirs} ${_numpy_include_dirs} CACHE PATH "Path to numpy headers") - set(${numpy_version} "${_numpy_version}" PARENT_SCOPE) + set(${numpy_version} "${_numpy_version}" CACHE INTERNAL "") +endif() endfunction(find_python) find_python(2.7 "${MIN_VER_PYTHON2}" PYTHON2_LIBRARY PYTHON2_INCLUDE_DIR From f01f1bc5e67f96a470f573888541e5c03e66cc3c Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Wed, 20 Jan 2016 19:20:36 +0300 Subject: [PATCH 090/468] Fixed "Conditional jump or move depends on uninitialised value(s)" valgrind issue due to wrong pointer recalculation for zero level of pyramid. --- modules/legacy/src/pyrsegmentation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/legacy/src/pyrsegmentation.cpp b/modules/legacy/src/pyrsegmentation.cpp index c64b7bcde0..30fed0e569 100644 --- a/modules/legacy/src/pyrsegmentation.cpp +++ b/modules/legacy/src/pyrsegmentation.cpp @@ -130,8 +130,8 @@ static void icvMaxRoi1( _CvRect16u *max_rect, int x, int y ); (float)fabs((a).green - (b).green), \ (float)fabs((a).blue - (b).blue))*/ -#define _CV_NEXT_BASE_C1(p,n) (_CvPyramid*)((char*)(p) + (n)*sizeof(_CvPyramidBase)) -#define _CV_NEXT_BASE_C3(p,n) (_CvPyramidC3*)((char*)(p) + (n)*sizeof(_CvPyramidBaseC3)) +#define _CV_NEXT_BASE_C1(p,n) ((_CvPyramid*)((char*)(p) + (n)*(ptrdiff_t)sizeof(_CvPyramidBase))) +#define _CV_NEXT_BASE_C3(p,n) ((_CvPyramidC3*)((char*)(p) + (n)*(ptrdiff_t)sizeof(_CvPyramidBaseC3))) CV_INLINE float icvRGBDist_Max( const _CvRGBf& a, const _CvRGBf& b ) @@ -868,7 +868,7 @@ icvPyrSegmentation8uC3R( uchar * src_image, int src_step, if( p_cur[size.width].a == 0 ) { - p_cur[size.width].c = p_prev[(l != 0) - 1].c; + p_cur[size.width].c = (l != 0) ? p_prev->c : _CV_NEXT_BASE_C3( p_prev, -1 )->c; } else { From 5a5378b3bf12cbd19561ee608f343e61a22e62ec Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 20 Jan 2016 11:58:48 +0300 Subject: [PATCH 091/468] Added lintian overrides for package signature entry. --- cmake/OpenCVPackaging.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmake/OpenCVPackaging.cmake b/cmake/OpenCVPackaging.cmake index 775605c4f8..0a53e92429 100644 --- a/cmake/OpenCVPackaging.cmake +++ b/cmake/OpenCVPackaging.cmake @@ -289,6 +289,13 @@ else() set(TESTS_LINTIAN_OVERRIDES "empty-binary-package") # there is no tests endif() +set(ALL_COMPONENTS "libs" "dev" "docs" "python" "java" "samples" "tests") + +foreach (comp ${ALL_COMPONENTS}) + string(TOUPPER ${comp} comp_upcase) + list(APPEND ${comp_upcase}_LINTIAN_OVERRIDES "misplaced-extra-member-in-deb") # for signed packages +endforeach() + if(CPACK_GENERATOR STREQUAL "DEB") find_program(GZIP_TOOL NAMES "gzip" PATHS "/bin" "/usr/bin" "/usr/local/bin") if(NOT GZIP_TOOL) @@ -300,7 +307,6 @@ if(CPACK_GENERATOR STREQUAL "DEB") OUTPUT_STRIP_TRAILING_WHITESPACE) set(CHANGELOG_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}") - set(ALL_COMPONENTS "libs" "dev" "docs" "python" "java" "samples" "tests") foreach (comp ${ALL_COMPONENTS}) string(TOUPPER "${comp}" comp_upcase) From 912592de4ce0b6b1c74a56cded3f1a38b64bc6d4 Mon Sep 17 00:00:00 2001 From: Matt Leotta Date: Thu, 21 Jan 2016 16:07:56 -0500 Subject: [PATCH 092/468] Remove "INSTALL_NAME_DIR lib" target property The INSTALL_NAME_DIR property of a target specifies how a dynamic library should be found on OS X. If INSTALL_NAME_DIR is not specified the loader will search relative to the standard search paths. If specified it should either be an absolute path or relative path prefixed with either @executable_path, @load_path, or @rpath. Specifying "lib" does not make sense here and causes linking error as documented here: http://answers.opencv.org/question/4134/cmake-install_name_tool-absolute-path-for-library-on-mac-osx/ and here http://stackoverflow.com/questions/26978806/dyld-library-not-loaded-lib-libopencv-core-3-0-dylib-reason-image-not-found This patch removes INSTALL_NAME_DIR everywhere it is set to "lib". An alternate solution would be to set an absolute path like "${CMAKE_INSTALL_PREFIX}/lib" or relative path like "@executable_path/../lib". However, if there is not specific need for specifying a path, it is probably best left unset. --- apps/annotation/CMakeLists.txt | 1 - apps/haartraining/CMakeLists.txt | 1 - apps/traincascade/CMakeLists.txt | 1 - cmake/OpenCVModule.cmake | 1 - platforms/android/libinfo/CMakeLists.txt | 1 - 5 files changed, 5 deletions(-) diff --git a/apps/annotation/CMakeLists.txt b/apps/annotation/CMakeLists.txt index b34ef3904b..54d89d953f 100644 --- a/apps/annotation/CMakeLists.txt +++ b/apps/annotation/CMakeLists.txt @@ -20,7 +20,6 @@ set_target_properties(${the_target} PROPERTIES DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - INSTALL_NAME_DIR lib OUTPUT_NAME "opencv_annotation") if(ENABLE_SOLUTION_FOLDERS) diff --git a/apps/haartraining/CMakeLists.txt b/apps/haartraining/CMakeLists.txt index 35a26fe36b..122d01ebfe 100644 --- a/apps/haartraining/CMakeLists.txt +++ b/apps/haartraining/CMakeLists.txt @@ -38,7 +38,6 @@ set_target_properties(opencv_haartraining_engine PROPERTIES DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - INSTALL_NAME_DIR lib ) # ----------------------------------------------------------- diff --git a/apps/traincascade/CMakeLists.txt b/apps/traincascade/CMakeLists.txt index 941c0ec711..857604af14 100644 --- a/apps/traincascade/CMakeLists.txt +++ b/apps/traincascade/CMakeLists.txt @@ -26,7 +26,6 @@ set_target_properties(${the_target} PROPERTIES DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - INSTALL_NAME_DIR lib OUTPUT_NAME "opencv_traincascade") if(ENABLE_SOLUTION_FOLDERS) diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake index 88ebe54f79..418bf46fdb 100644 --- a/cmake/OpenCVModule.cmake +++ b/cmake/OpenCVModule.cmake @@ -594,7 +594,6 @@ macro(ocv_create_module) ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - INSTALL_NAME_DIR lib ) # For dynamic link numbering convenions diff --git a/platforms/android/libinfo/CMakeLists.txt b/platforms/android/libinfo/CMakeLists.txt index 592be2d044..010ac14da0 100644 --- a/platforms/android/libinfo/CMakeLists.txt +++ b/platforms/android/libinfo/CMakeLists.txt @@ -34,7 +34,6 @@ add_library(opencv_info SHARED info.c) set_target_properties(${the_module} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} - INSTALL_NAME_DIR lib ) get_filename_component(lib_name "libopencv_info.so" NAME) From c35b00a97e12c8439ef3921ed7deb2a0c940b6ea Mon Sep 17 00:00:00 2001 From: Amro Date: Sat, 23 Jan 2016 17:28:49 +0200 Subject: [PATCH 093/468] fix code snippet showing how to use SparseMat generate indices within the size limit (modulo) --- modules/core/include/opencv2/core/mat.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index ffec538657..77fce1db93 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -2359,15 +2359,16 @@ Elements can be accessed using the following methods: SparseMat::find), for example: @code const int dims = 5; - int size[] = {10, 10, 10, 10, 10}; + int size[5] = {10, 10, 10, 10, 10}; SparseMat sparse_mat(dims, size, CV_32F); for(int i = 0; i < 1000; i++) { int idx[dims]; for(int k = 0; k < dims; k++) - idx[k] = rand() + idx[k] = rand() % size[k]; sparse_mat.ref(idx) += 1.f; } + cout << "nnz = " << sparse_mat.nzcount() << endl; @endcode - Sparse matrix iterators. They are similar to MatIterator but different from NAryMatIterator. That is, the iteration loop is familiar to STL users: From 2f5ea3437e00dab81339e398ae86e655b481f230 Mon Sep 17 00:00:00 2001 From: Patrick Snape Date: Sat, 23 Jan 2016 15:57:46 +0000 Subject: [PATCH 094/468] Update indentation to match rest of file Very cosmetic, but was analyzing code and just wanted to make it consistent. --- modules/features2d/src/matchers.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/features2d/src/matchers.cpp b/modules/features2d/src/matchers.cpp index fad73a2715..e804737199 100644 --- a/modules/features2d/src/matchers.cpp +++ b/modules/features2d/src/matchers.cpp @@ -517,30 +517,32 @@ DescriptorMatcher::~DescriptorMatcher() void DescriptorMatcher::add( InputArrayOfArrays _descriptors ) { - if(_descriptors.isUMatVector()) + if( _descriptors.isUMatVector() ) { std::vector descriptors; - _descriptors.getUMatVector(descriptors); + _descriptors.getUMatVector( descriptors ); utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() ); } - else if(_descriptors.isUMat()) + else if( _descriptors.isUMat() ) { std::vector descriptors = std::vector(1, _descriptors.getUMat()); utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() ); } - else if(_descriptors.isMatVector()) + else if( _descriptors.isMatVector() ) { std::vector descriptors; _descriptors.getMatVector(descriptors); trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() ); } - else if(_descriptors.isMat()) + else if( _descriptors.isMat() ) { std::vector descriptors = std::vector(1, _descriptors.getMat()); trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() ); } else + { CV_Assert( _descriptors.isUMat() || _descriptors.isUMatVector() || _descriptors.isMat() || _descriptors.isMatVector() ); + } } const std::vector& DescriptorMatcher::getTrainDescriptors() const From 05cfe28612fd8dc8fb0ccb876df945c7b435dd26 Mon Sep 17 00:00:00 2001 From: Patrick Snape Date: Sat, 23 Jan 2016 15:58:16 +0000 Subject: [PATCH 095/468] Fix parsing of training vecs for FlannBasedMatcher FlannBasedMatcher::add is overloaded, but the style of parsing the InputArrayOfArrays does not match the style from DescriptorMatcher::add. The issue is that InputArrayOfArrays must be properly marshalled so that the data can be read correctly. In this case, the method expects the training descriptors to be either a vector of matrices or a single matrix (as is shown in DescriptorMatcher::add). These code replicates that for the case of the FlannBasedMatcher::add. In fact, a similar commit to this was added by 26d9a7c but was ultimately not accepted in #4111. This is likely due to the fact that the input arrays were not parsed properly and the case of a single matrix was being improperly handled. I believe this commit to be correct given the logic from DescriptorMatcher::add. --- modules/features2d/src/matchers.cpp | 33 +++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/modules/features2d/src/matchers.cpp b/modules/features2d/src/matchers.cpp index e804737199..a1b557fa9e 100644 --- a/modules/features2d/src/matchers.cpp +++ b/modules/features2d/src/matchers.cpp @@ -1034,12 +1034,37 @@ FlannBasedMatcher::FlannBasedMatcher( const Ptr& _indexParam void FlannBasedMatcher::add( InputArrayOfArrays _descriptors ) { DescriptorMatcher::add( _descriptors ); - std::vector descriptors; - _descriptors.getUMatVector(descriptors); - for( size_t i = 0; i < descriptors.size(); i++ ) + if( _descriptors.isUMatVector() ) { - addedDescCount += descriptors[i].rows; + std::vector descriptors; + _descriptors.getUMatVector( descriptors ); + + for( size_t i = 0; i < descriptors.size(); i++ ) + { + addedDescCount += descriptors[i].rows; + } + } + else if( _descriptors.isUMat() ) + { + addedDescCount += _descriptors.getUMat().rows; + } + else if( _descriptors.isMatVector() ) + { + std::vector descriptors; + _descriptors.getMatVector(descriptors); + for( size_t i = 0; i < descriptors.size(); i++ ) + { + addedDescCount += descriptors[i].rows; + } + } + else if( _descriptors.isMat() ) + { + addedDescCount += _descriptors.getMat().rows; + } + else + { + CV_Assert( _descriptors.isUMat() || _descriptors.isUMatVector() || _descriptors.isMat() || _descriptors.isMatVector() ); } } From 34c006fcc416905dc502424f23f92919c503b159 Mon Sep 17 00:00:00 2001 From: Marian Zajko Date: Mon, 25 Jan 2016 11:05:55 +0100 Subject: [PATCH 096/468] Fixed ximea cmake settings Fixed ximea cmake settings for 32bit win build and linux. --- modules/videoio/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index b5da8d090d..1a3449e3b5 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -131,10 +131,12 @@ if(HAVE_XIMEA) endif() if(WIN32 AND X86_64) list(APPEND VIDEOIO_LIBRARIES xiapi64) + elseif(WIN32) + list(APPEND VIDEOIO_LIBRARIES xiapi32) elseif(APPLE) list(APPEND VIDEOIO_LIBRARIES "-framework m3api") else() - list(APPEND VIDEOIO_LIBRARIES xiapi32) + list(APPEND VIDEOIO_LIBRARIES m3api) endif() endif(HAVE_XIMEA) From a387d6fa267c286b3178d604782594c3dbf8372e Mon Sep 17 00:00:00 2001 From: Marian Zajko Date: Mon, 25 Jan 2016 13:13:13 +0100 Subject: [PATCH 097/468] - removed whitespaces --- modules/videoio/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt index 1a3449e3b5..41b0691b75 100644 --- a/modules/videoio/CMakeLists.txt +++ b/modules/videoio/CMakeLists.txt @@ -132,7 +132,7 @@ if(HAVE_XIMEA) if(WIN32 AND X86_64) list(APPEND VIDEOIO_LIBRARIES xiapi64) elseif(WIN32) - list(APPEND VIDEOIO_LIBRARIES xiapi32) + list(APPEND VIDEOIO_LIBRARIES xiapi32) elseif(APPLE) list(APPEND VIDEOIO_LIBRARIES "-framework m3api") else() From 96f5a930f4a793cbd27d1f3a1304fcace5078c54 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 26 Jan 2016 13:49:11 +0300 Subject: [PATCH 098/468] test: regression 5991 --- modules/core/test/test_mat.cpp | 11 +++++++++++ modules/core/test/test_umat.cpp | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp index 2344df28a5..e2de3249b6 100644 --- a/modules/core/test/test_mat.cpp +++ b/modules/core/test/test_mat.cpp @@ -1472,3 +1472,14 @@ TEST(Core_Mat_vector, copyTo_roi_row) EXPECT_EQ(4, (int)dst2[3]); EXPECT_EQ(5, (int)dst2[4]); } + +TEST(Mat, regression_5991) +{ + int sz[] = {2,3,2}; + Mat mat(3, sz, CV_32F, Scalar(1)); + ASSERT_NO_THROW(mat.convertTo(mat, CV_8U)); + EXPECT_EQ(sz[0], mat.size[0]); + EXPECT_EQ(sz[1], mat.size[1]); + EXPECT_EQ(sz[2], mat.size[2]); + EXPECT_EQ(0, cvtest::norm(mat, Mat(3, sz, CV_8U, Scalar(1)), NORM_INF)); +} diff --git a/modules/core/test/test_umat.cpp b/modules/core/test/test_umat.cpp index a8641d0980..09c59b60d2 100644 --- a/modules/core/test/test_umat.cpp +++ b/modules/core/test/test_umat.cpp @@ -1343,4 +1343,15 @@ TEST(UMat, testWrongLifetime_Mat) } } +TEST(UMat, DISABLED_regression_5991) +{ + int sz[] = {2,3,2}; + UMat mat(3, sz, CV_32F, Scalar(1)); + ASSERT_NO_THROW(mat.convertTo(mat, CV_8U)); + EXPECT_EQ(sz[0], mat.size[0]); + EXPECT_EQ(sz[1], mat.size[1]); + EXPECT_EQ(sz[2], mat.size[2]); + EXPECT_EQ(0, cvtest::norm(mat.getMat(ACCESS_READ), Mat(3, sz, CV_8U, Scalar(1)), NORM_INF)); +} + } } // namespace cvtest::ocl From 2978a16c859dafab2bb75e95fc66229ffc8c4571 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 26 Jan 2016 13:59:10 +0300 Subject: [PATCH 099/468] core: preserve sizes values (fixes #5991) _sizes can point to internal structure which is destroyed by release() call --- modules/core/src/matrix.cpp | 15 +++++++++++++++ modules/core/src/umatrix.cpp | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp index 4a260eb646..08c5501e4e 100644 --- a/modules/core/src/matrix.cpp +++ b/modules/core/src/matrix.cpp @@ -397,6 +397,14 @@ void Mat::create(int d, const int* _sizes, int _type) return; } + int _sizes_backup[CV_MAX_DIM]; // #5991 + if (_sizes == (this->size.p)) + { + for(i = 0; i < d; i++ ) + _sizes_backup[i] = _sizes[i]; + _sizes = _sizes_backup; + } + release(); if( d == 0 ) return; @@ -4899,6 +4907,13 @@ void SparseMat::create(int d, const int* _sizes, int _type) return; } } + int _sizes_backup[CV_MAX_DIM]; // #5991 + if (_sizes == hdr->size) + { + for(i = 0; i < d; i++ ) + _sizes_backup[i] = _sizes[i]; + _sizes = _sizes_backup; + } release(); flags = MAGIC_VAL | _type; hdr = new Hdr(d, _sizes, _type); diff --git a/modules/core/src/umatrix.cpp b/modules/core/src/umatrix.cpp index 98d6b8c589..958723b7b5 100644 --- a/modules/core/src/umatrix.cpp +++ b/modules/core/src/umatrix.cpp @@ -345,6 +345,14 @@ void UMat::create(int d, const int* _sizes, int _type, UMatUsageFlags _usageFlag return; } + int _sizes_backup[CV_MAX_DIM]; // #5991 + if (_sizes == (this->size.p)) + { + for(i = 0; i < d; i++ ) + _sizes_backup[i] = _sizes[i]; + _sizes = _sizes_backup; + } + release(); if( d == 0 ) return; From 1a0282df21d9e393bfc7089d673361dd15b5ecea Mon Sep 17 00:00:00 2001 From: Oded Green Date: Fri, 29 Jan 2016 20:05:40 -0500 Subject: [PATCH 100/468] CUDA median filtering using histograms --- .../include/opencv2/cudafilters.hpp | 12 + modules/cudafilters/perf/perf_filters.cpp | 40 ++ modules/cudafilters/src/cuda/median_filter.cu | 348 ++++++++++++++++++ modules/cudafilters/src/filtering.cpp | 72 ++++ modules/cudafilters/test/test_filters.cpp | 61 +++ .../include/opencv2/cudaimgproc.hpp | 1 + 6 files changed, 534 insertions(+) create mode 100644 modules/cudafilters/src/cuda/median_filter.cu diff --git a/modules/cudafilters/include/opencv2/cudafilters.hpp b/modules/cudafilters/include/opencv2/cudafilters.hpp index 9e86cc3a71..2d52265613 100644 --- a/modules/cudafilters/include/opencv2/cudafilters.hpp +++ b/modules/cudafilters/include/opencv2/cudafilters.hpp @@ -314,6 +314,18 @@ CV_EXPORTS Ptr createColumnSumFilter(int srcType, int dstType, int ksize //! @} +///////////////////////////// Median Filtering ////////////////////////////// + +/** @brief Performs median filtering for each point of the source image. + +@param srcType type of of source image. Only CV_8UC1 images are supported for now. +@param windowSize Size of the kernerl used for the filtering. Uses a (windowSize x windowSize) filter. +@param partition Specifies the parallel granularity of the workload. This parameter should be used GPU experts when optimizing performance. + +Outputs an image that has been filtered using median-filtering formulation. + */ +CV_EXPORTS Ptr createMedianFilter(int srcType, int windowSize, int partition=128); + }} // namespace cv { namespace cuda { #endif /* __OPENCV_CUDAFILTERS_HPP__ */ diff --git a/modules/cudafilters/perf/perf_filters.cpp b/modules/cudafilters/perf/perf_filters.cpp index e6bb200bba..63abf6df74 100644 --- a/modules/cudafilters/perf/perf_filters.cpp +++ b/modules/cudafilters/perf/perf_filters.cpp @@ -375,3 +375,43 @@ PERF_TEST_P(Sz_Type_Op, MorphologyEx, Combine(CUDA_TYPICAL_MAT_SIZES, Values(CV_ CPU_SANITY_CHECK(dst); } } +////////////////////////////////////////////////////////////////////// +// MedianFilter +////////////////////////////////////////////////////////////////////// +// Median + +DEF_PARAM_TEST(Sz_KernelSz, cv::Size, int); + +//PERF_TEST_P(Sz_Type_KernelSz, Median, Combine(CUDA_TYPICAL_MAT_SIZES, Values(CV_8UC1,CV_8UC1), Values(3, 5, 7, 9, 11, 13, 15))) +PERF_TEST_P(Sz_KernelSz, Median, Combine(CUDA_TYPICAL_MAT_SIZES, Values(3, 5, 7, 9, 11, 13, 15))) +{ + declare.time(20.0); + + const cv::Size size = GET_PARAM(0); + // const int type = GET_PARAM(1); + const int type = CV_8UC1; + const int kernel = GET_PARAM(1); + + cv::Mat src(size, type); + declare.in(src, WARMUP_RNG); + + if (PERF_RUN_CUDA()) + { + const cv::cuda::GpuMat d_src(src); + cv::cuda::GpuMat dst; + + cv::Ptr median = cv::cuda::createMedianFilter(d_src.type(), kernel); + + TEST_CYCLE() median->apply(d_src, dst); + + SANITY_CHECK_NOTHING(); + } + else + { + cv::Mat dst; + + TEST_CYCLE() cv::medianBlur(src,dst,kernel); + + SANITY_CHECK_NOTHING(); + } +} \ No newline at end of file diff --git a/modules/cudafilters/src/cuda/median_filter.cu b/modules/cudafilters/src/cuda/median_filter.cu new file mode 100644 index 0000000000..f66b429a32 --- /dev/null +++ b/modules/cudafilters/src/cuda/median_filter.cu @@ -0,0 +1,348 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000-2008, Intel Corporation, all rights reserved. +// Copyright (C) 2009, Willow Garage Inc., all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#if !defined CUDA_DISABLER + +#include "precomp.hpp" + +using namespace cv; +using namespace cv::cuda; + +#include "opencv2/core/cuda/common.hpp" +#include "opencv2/core/cuda/vec_traits.hpp" +#include "opencv2/core/cuda/vec_math.hpp" +#include "opencv2/core/cuda/saturate_cast.hpp" +#include "opencv2/core/cuda/border_interpolate.hpp" + +namespace cv { namespace cuda { namespace device +{ + // // namespace imgproc + // { + + __device__ void histogramAddAndSub8(int* H, const int * hist_colAdd,const int * hist_colSub){ + int tx = threadIdx.x; + if (tx<8){ + H[tx]+=hist_colAdd[tx]-hist_colSub[tx]; + } + } + + __device__ void histogramMultipleAdd8(int* H, const int * hist_col,int histCount){ + int tx = threadIdx.x; + if (tx<8){ + int temp=H[tx]; + for(int i=0; i=1 ) + Hscan[tx]+=Hscan[tx-1]; + if(tx>=2) + Hscan[tx]+=Hscan[tx-2]; + if(tx>=4) + Hscan[tx]+=Hscan[tx-4]; + } + __syncthreads(); + + if(tx<7){ + if(Hscan[tx+1] > medPos && Hscan[tx] < medPos){ + *retval=tx+1; + *countAtMed=Hscan[tx]; + } + else if(Hscan[tx]==medPos){ + if(Hscan[tx+1]>medPos){ + *retval=tx+1; + *countAtMed=Hscan[tx]; + } + } + } + } + + __device__ void histogramMedianPar32LookupOnly(int* H,int* Hscan, const int medPos,int* retval, int* countAtMed){ + int tx=threadIdx.x; + *retval=*countAtMed=0; + if(tx<32){ + Hscan[tx]=H[tx]; + } + __syncthreads(); + if(tx<32){ + if(tx>=1) + Hscan[tx]+=Hscan[tx-1]; + if(tx>=2) + Hscan[tx]+=Hscan[tx-2]; + if(tx>=4) + Hscan[tx]+=Hscan[tx-4]; + if(tx>=8) + Hscan[tx]+=Hscan[tx-8]; + if(tx>=16) + Hscan[tx]+=Hscan[tx-16]; + } + __syncthreads(); + if(tx<31){ + if(Hscan[tx+1] > medPos && Hscan[tx] < medPos){ + *retval=tx+1; + *countAtMed=Hscan[tx]; + } + else if(Hscan[tx]==medPos){ + if(Hscan[tx+1]>medPos){ + *retval=tx+1; + *countAtMed=Hscan[tx]; + } + } + } + } + + __global__ void cuMedianFilterMultiBlock(PtrStepSzb src, PtrStepSzb dest, PtrStepSzi histPar, PtrStepSzi coarseHistGrid,int r, int medPos_) + { + __shared__ int HCoarse[8]; + __shared__ int HCoarseScan[32]; + __shared__ int HFine[8][32]; + + __shared__ int luc[8]; + + __shared__ int firstBin,countAtMed, retval; + + int rows = src.rows, cols=src.cols; + + int extraRowThread=rows%gridDim.x; + int doExtraRow=blockIdx.x>5)]=initVal; + } + } + __syncthreads(); + + // Fot all remaining rows in the median filter, add the values to the the histogram + for (int j=threadIdx.x; j>5)]++; + } + } + __syncthreads(); + // Going through all the rows that the block is responsible for. + int inc=blockDim.x*256; + int incCoarse=blockDim.x*8; + for(int i=startRow; i< stopRow; i++){ + // For every new row that is started the global histogram for the entire window is restarted. + + histogramClear8(HCoarse); + lucClear8(luc); + // Computing some necessary indices + int possub=::max(0,i-r-1),posadd=::min(rows-1,i+r); + int histPos=threadIdx.x*256; + int histCoarsePos=threadIdx.x*8; + // Going through all the elements of a specific row. Foeach histogram, a value is taken out and + // one value is added. + for (int j=threadIdx.x; j>5) ]--; + histCoarse[histCoarsePos+ (src.ptr(posadd)[j]>>5) ]++; + + histPos+=inc; + histCoarsePos+=incCoarse; + } + __syncthreads(); + + histogramMultipleAdd8(HCoarse,histCoarse, 2*r+1); +// __syncthreads(); + int cols_m_1=cols-1; + + for(int j=r;j=0){ + histogramMedianPar32LookupOnly(HFine[firstBin],HCoarseScan,leftOver,&retval,&countAtMed); + } + else retval=0; + __syncthreads(); + + if (threadIdx.x==0){ + dest.ptr(i)[j]=(firstBin<<5) + retval; + } + histogramAddAndSub8(HCoarse, histCoarse+(int)(posadd<<3),histCoarse+(int)(possub<<3)); + + __syncthreads(); + } + __syncthreads(); + } + } + + void medianFiltering_gpu(const PtrStepSzb src, PtrStepSzb dst, PtrStepSzi devHist, PtrStepSzi devCoarseHist,int kernel, int partitions,cudaStream_t stream){ + int medPos=2*kernel*kernel+2*kernel; + dim3 gridDim; gridDim.x=partitions; + dim3 blockDim; blockDim.x=32; + cuMedianFilterMultiBlock<<>>(src, dst, devHist,devCoarseHist, kernel, medPos); + if (!stream) + cudaSafeCall( cudaDeviceSynchronize() ); + } + +}}} + +#endif diff --git a/modules/cudafilters/src/filtering.cpp b/modules/cudafilters/src/filtering.cpp index ed72a3ab5c..b90a8c1932 100644 --- a/modules/cudafilters/src/filtering.cpp +++ b/modules/cudafilters/src/filtering.cpp @@ -69,6 +69,8 @@ Ptr cv::cuda::createBoxMinFilter(int, Size, Point, int, Scalar) { throw_ Ptr cv::cuda::createRowSumFilter(int, int, int, int, int, Scalar) { throw_no_cuda(); return Ptr(); } Ptr cv::cuda::createColumnSumFilter(int, int, int, int, int, Scalar) { throw_no_cuda(); return Ptr(); } +Ptr cv::cuda::createMedianFilter(int srcType, int _windowSize, int _partitions){ throw_no_cuda(); return Ptr();} + #else namespace @@ -995,4 +997,74 @@ Ptr cv::cuda::createColumnSumFilter(int srcType, int dstType, int ksize, return makePtr(srcType, dstType, ksize, anchor, borderMode, borderVal); } +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Median Filter + + + +namespace cv { namespace cuda { namespace device +{ + void medianFiltering_gpu(const PtrStepSzb src, PtrStepSzb dst, PtrStepSzi devHist, + PtrStepSzi devCoarseHist,int kernel, int partitions, cudaStream_t stream); +}}} + +namespace +{ + class MedianFilter : public Filter + { + public: + MedianFilter(int srcType, int _windowSize, int _partitions=128); + + void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null()); + + private: + int windowSize; + int partitions; + }; + + MedianFilter::MedianFilter(int srcType, int _windowSize, int _partitions) : + windowSize(_windowSize),partitions(_partitions) + { + CV_Assert( srcType == CV_8UC1 ); + CV_Assert(windowSize>=3); + CV_Assert(_partitions>=1); + + } + + void MedianFilter::apply(InputArray _src, OutputArray _dst, Stream& _stream) + { + using namespace cv::cuda::device; + + GpuMat src = _src.getGpuMat(); + _dst.create(src.rows, src.cols, src.type()); + GpuMat dst = _dst.getGpuMat(); + + if (partitions>src.rows) + partitions=src.rows/2; + + // Kernel needs to be half window size + int kernel=windowSize/2; + + CV_Assert(kernel < src.rows); + CV_Assert(kernel < src.cols); + + // Note - these are hardcoded in the actual GPU kernel. Do not change these values. + int histSize=256, histCoarseSize=8; + + BufferPool pool(_stream); + GpuMat devHist = pool.getBuffer(1, src.cols*histSize*partitions,CV_32SC1); + GpuMat devCoarseHist = pool.getBuffer(1,src.cols*histCoarseSize*partitions,CV_32SC1); + + devHist.setTo(0, _stream); + devCoarseHist.setTo(0, _stream); + + medianFiltering_gpu(src,dst,devHist, devCoarseHist,kernel,partitions,StreamAccessor::getStream(_stream)); + } +} + +Ptr cv::cuda::createMedianFilter(int srcType, int _windowSize, int _partitions) +{ + return makePtr(srcType, _windowSize,_partitions); +} + #endif diff --git a/modules/cudafilters/test/test_filters.cpp b/modules/cudafilters/test/test_filters.cpp index 97661b0caf..bac81c30b7 100644 --- a/modules/cudafilters/test/test_filters.cpp +++ b/modules/cudafilters/test/test_filters.cpp @@ -53,6 +53,7 @@ namespace IMPLEMENT_PARAM_CLASS(Deriv_X, int) IMPLEMENT_PARAM_CLASS(Deriv_Y, int) IMPLEMENT_PARAM_CLASS(Iterations, int) + IMPLEMENT_PARAM_CLASS(KernelSize, int) cv::Mat getInnerROI(cv::InputArray m_, cv::Size ksize) { @@ -647,4 +648,64 @@ INSTANTIATE_TEST_CASE_P(CUDA_Filters, MorphEx, testing::Combine( testing::Values(Iterations(1), Iterations(2), Iterations(3)), WHOLE_SUBMAT)); +///////////////////////////////////////////////////////////////////////////////////////////////// +// Median + + +PARAM_TEST_CASE(Median, cv::cuda::DeviceInfo, cv::Size, MatDepth, KernelSize, UseRoi) +{ + cv::cuda::DeviceInfo devInfo; + cv::Size size; + int type; + int kernel; + bool useRoi; + + virtual void SetUp() + { + devInfo = GET_PARAM(0); + size = GET_PARAM(1); + type = GET_PARAM(2); + kernel = GET_PARAM(3); + useRoi = GET_PARAM(4); + + cv::cuda::setDevice(devInfo.deviceID()); + } +}; + + + +CUDA_TEST_P(Median, Accuracy) +{ + cv::Mat src = randomMat(size, type); + + cv::Ptr median = cv::cuda::createMedianFilter(src.type(), kernel); + + cv::cuda::GpuMat dst = createMat(size, type, useRoi); + median->apply(loadMat(src, useRoi), dst); + + cv::Mat dst_gold; + cv::medianBlur(src,dst_gold,kernel); + + cv::Rect rect(kernel+1,0,src.cols-(2*kernel+1),src.rows); + cv::Mat dst_gold_no_border = dst_gold(rect); + cv::cuda::GpuMat dst_no_border = cv::cuda::GpuMat(dst, rect); + + EXPECT_MAT_NEAR(dst_gold_no_border, dst_no_border, 1); + +} + +INSTANTIATE_TEST_CASE_P(CUDA_Filters, Median, testing::Combine( + ALL_DEVICES, + DIFFERENT_SIZES, + testing::Values(MatDepth(CV_8U)), + testing::Values(KernelSize(3), + KernelSize(5), + KernelSize(7), + KernelSize(9), + KernelSize(11), + KernelSize(13), + KernelSize(15)), + WHOLE_SUBMAT) + ); + #endif // HAVE_CUDA diff --git a/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp b/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp index d84ae24534..b4a05eecd8 100644 --- a/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp +++ b/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp @@ -588,6 +588,7 @@ CV_EXPORTS Ptr createGoodFeaturesToTrackDetector(int srcType, i //! @} cudaimgproc_feature + ///////////////////////////// Mean Shift ////////////////////////////// /** @brief Performs mean-shift filtering for each point of the source image. From ed8368fed78944896be71c93fd4817b2eef7b26b Mon Sep 17 00:00:00 2001 From: atinfinity Date: Sun, 31 Jan 2016 01:28:15 +0900 Subject: [PATCH 101/468] fixed to use NVCUVID in 'cudacodec' module. --- cmake/OpenCVDetectCUDA.cmake | 7 ++++++- modules/cudacodec/CMakeLists.txt | 2 ++ modules/cudacodec/src/precomp.hpp | 4 +++- modules/cudacodec/src/video_writer.cpp | 6 +++--- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index c1cb95888d..9b52a5e8e6 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -33,7 +33,12 @@ if(CUDA_FOUND) if(WIN32) find_cuda_helper_libs(nvcuvenc) endif() - set(HAVE_NVCUVID 1) + if(CUDA_nvcuvid_LIBRARY) + set(HAVE_NVCUVID 1) + endif() + if(CUDA_nvcuvenc_LIBRARY) + set(HAVE_NVCUVENC 1) + endif() endif() message(STATUS "CUDA detected: " ${CUDA_VERSION}) diff --git a/modules/cudacodec/CMakeLists.txt b/modules/cudacodec/CMakeLists.txt index f2e955b6cd..6aecd26db0 100644 --- a/modules/cudacodec/CMakeLists.txt +++ b/modules/cudacodec/CMakeLists.txt @@ -15,7 +15,9 @@ set(extra_libs "") if(HAVE_NVCUVID) list(APPEND extra_libs ${CUDA_CUDA_LIBRARY} ${CUDA_nvcuvid_LIBRARY}) +endif() +if(HAVE_NVCUVENC) if(WIN32) list(APPEND extra_libs ${CUDA_nvcuvenc_LIBRARY}) endif() diff --git a/modules/cudacodec/src/precomp.hpp b/modules/cudacodec/src/precomp.hpp index 80257a0cd6..59504c2c49 100644 --- a/modules/cudacodec/src/precomp.hpp +++ b/modules/cudacodec/src/precomp.hpp @@ -61,7 +61,9 @@ #ifdef WIN32 #define NOMINMAX #include - #include + #ifdef HAVE_NVCUVENC + #include + #endif #else #include #include diff --git a/modules/cudacodec/src/video_writer.cpp b/modules/cudacodec/src/video_writer.cpp index 6faa9d3bf9..f6b9fc7380 100644 --- a/modules/cudacodec/src/video_writer.cpp +++ b/modules/cudacodec/src/video_writer.cpp @@ -47,7 +47,7 @@ using namespace cv; using namespace cv::cuda; using namespace cv::cudacodec; -#if !defined(HAVE_NVCUVID) || !defined(WIN32) +#if !defined(HAVE_NVCUVENC) || !defined(WIN32) cv::cudacodec::EncoderParams::EncoderParams() { throw_no_cuda(); } cv::cudacodec::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); } @@ -60,7 +60,7 @@ Ptr cv::cudacodec::createVideoWriter(const String&, Size, double, c Ptr cv::cudacodec::createVideoWriter(const Ptr&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr(); } Ptr cv::cudacodec::createVideoWriter(const Ptr&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr(); } -#else // !defined HAVE_CUDA || !defined WIN32 +#else // !defined HAVE_NVCUVENC || !defined WIN32 void RGB_to_YV12(const GpuMat& src, GpuMat& dst); @@ -913,4 +913,4 @@ Ptr cv::cudacodec::createVideoWriter(const Ptr& en return makePtr(encoderCallback, frameSize, fps, params, format); } -#endif // !defined HAVE_CUDA || !defined WIN32 +#endif // !defined HAVE_NVCUVENC || !defined WIN32 From 69eaa89e22185dba0c16bbce6e200426c7c566e9 Mon Sep 17 00:00:00 2001 From: atinfinity Date: Sun, 31 Jan 2016 01:56:45 +0900 Subject: [PATCH 102/468] fixed to use NVCUVID in 'cudacodec' module. --- cmake/OpenCVDetectCUDA.cmake | 13 ++++++++++++- modules/gpu/CMakeLists.txt | 9 ++++++--- modules/gpu/src/precomp.hpp | 4 +++- modules/gpu/src/video_writer.cpp | 2 +- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake index cca125034a..d2548f9af5 100644 --- a/cmake/OpenCVDetectCUDA.cmake +++ b/cmake/OpenCVDetectCUDA.cmake @@ -35,7 +35,18 @@ if(CUDA_FOUND) if(WITH_NVCUVID) find_cuda_helper_libs(nvcuvid) - set(HAVE_NVCUVID 1) + + if(WIN32) + find_cuda_helper_libs(nvcuvenc) + endif() + + if(CUDA_nvcuvid_LIBRARY) + set(HAVE_NVCUVID 1) + endif() + + if(CUDA_nvcuvenc_LIBRARY) + set(HAVE_NVCUVENC 1) + endif() endif() message(STATUS "CUDA detected: " ${CUDA_VERSION}) diff --git a/modules/gpu/CMakeLists.txt b/modules/gpu/CMakeLists.txt index 6de3e0efab..caec0efa5a 100644 --- a/modules/gpu/CMakeLists.txt +++ b/modules/gpu/CMakeLists.txt @@ -54,11 +54,14 @@ if(HAVE_CUDA) endif() if(WITH_NVCUVID) - set(cuda_link_libs ${cuda_link_libs} ${CUDA_CUDA_LIBRARY} ${CUDA_nvcuvid_LIBRARY}) + if(HAVE_NVCUVID) + set(cuda_link_libs ${cuda_link_libs} ${CUDA_CUDA_LIBRARY} ${CUDA_nvcuvid_LIBRARY}) + endif() if(WIN32) - find_cuda_helper_libs(nvcuvenc) - set(cuda_link_libs ${cuda_link_libs} ${CUDA_nvcuvenc_LIBRARY}) + if(HAVE_NVCUVENC) + set(cuda_link_libs ${cuda_link_libs} ${CUDA_nvcuvenc_LIBRARY}) + endif() endif() if(WITH_FFMPEG) diff --git a/modules/gpu/src/precomp.hpp b/modules/gpu/src/precomp.hpp index 785783b5e2..a4f75db19a 100644 --- a/modules/gpu/src/precomp.hpp +++ b/modules/gpu/src/precomp.hpp @@ -98,7 +98,9 @@ #include #ifdef WIN32 - #include + #ifdef HAVE_NVCUVENC + #include + #endif #endif #endif diff --git a/modules/gpu/src/video_writer.cpp b/modules/gpu/src/video_writer.cpp index 0937ad1f27..bf51c25408 100644 --- a/modules/gpu/src/video_writer.cpp +++ b/modules/gpu/src/video_writer.cpp @@ -42,7 +42,7 @@ #include "precomp.hpp" -#if !defined(HAVE_CUDA) || defined(CUDA_DISABLER) || !defined(HAVE_NVCUVID) || !defined(WIN32) +#if !defined(HAVE_CUDA) || defined(CUDA_DISABLER) || !defined(HAVE_NVCUVENC) || !defined(WIN32) class cv::gpu::VideoWriter_GPU::Impl { From bf604f178087173a9de29d9bd2098d06000fb73a Mon Sep 17 00:00:00 2001 From: Dmitry-Me Date: Mon, 1 Feb 2016 11:10:13 +0300 Subject: [PATCH 103/468] Reduce variables scope --- modules/calib3d/src/ptsetreg.cpp | 8 ++++---- modules/videostab/src/motion_stabilizing.cpp | 3 +-- modules/videostab/src/outlier_rejection.cpp | 21 ++++++++------------ 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/modules/calib3d/src/ptsetreg.cpp b/modules/calib3d/src/ptsetreg.cpp index e83e19a203..f417696547 100644 --- a/modules/calib3d/src/ptsetreg.cpp +++ b/modules/calib3d/src/ptsetreg.cpp @@ -206,7 +206,7 @@ public: for( iter = 0; iter < niters; iter++ ) { - int i, goodCount, nmodels; + int i, nmodels; if( count > modelPoints ) { bool found = getSubset( m1, m2, ms1, ms2, rng, 10000 ); @@ -227,7 +227,7 @@ public: for( i = 0; i < nmodels; i++ ) { Mat model_i = model.rowRange( i*modelSize.height, (i+1)*modelSize.height ); - goodCount = findInliers( m1, m2, model_i, err, mask, threshold ); + int goodCount = findInliers( m1, m2, model_i, err, mask, threshold ); if( goodCount > MAX(maxGoodCount, modelPoints-1) ) { @@ -284,7 +284,7 @@ public: int d1 = m1.channels() > 1 ? m1.channels() : m1.cols; int d2 = m2.channels() > 1 ? m2.channels() : m2.cols; int count = m1.checkVector(d1), count2 = m2.checkVector(d2); - double minMedian = DBL_MAX, sigma; + double minMedian = DBL_MAX; RNG rng((uint64)-1); @@ -359,7 +359,7 @@ public: if( minMedian < DBL_MAX ) { - sigma = 2.5*1.4826*(1 + 5./(count - modelPoints))*std::sqrt(minMedian); + double sigma = 2.5*1.4826*(1 + 5./(count - modelPoints))*std::sqrt(minMedian); sigma = MAX( sigma, 0.001 ); count = findInliers( m1, m2, bestModel, err, mask, sigma ); diff --git a/modules/videostab/src/motion_stabilizing.cpp b/modules/videostab/src/motion_stabilizing.cpp index 65bbd73bd1..d31c420f64 100644 --- a/modules/videostab/src/motion_stabilizing.cpp +++ b/modules/videostab/src/motion_stabilizing.cpp @@ -602,13 +602,12 @@ static inline bool isGoodMotion(const float M[], float w, float h, float dx, flo { Point2f pt[4] = {Point2f(0,0), Point2f(w,0), Point2f(w,h), Point2f(0,h)}; Point2f Mpt[4]; - float z; for (int i = 0; i < 4; ++i) { Mpt[i].x = M[0]*pt[i].x + M[1]*pt[i].y + M[2]; Mpt[i].y = M[3]*pt[i].x + M[4]*pt[i].y + M[5]; - z = M[6]*pt[i].x + M[7]*pt[i].y + M[8]; + float z = M[6]*pt[i].x + M[7]*pt[i].y + M[8]; Mpt[i].x /= z; Mpt[i].y /= z; } diff --git a/modules/videostab/src/outlier_rejection.cpp b/modules/videostab/src/outlier_rejection.cpp index ee37a93036..3ae6e6b271 100644 --- a/modules/videostab/src/outlier_rejection.cpp +++ b/modules/videostab/src/outlier_rejection.cpp @@ -84,16 +84,14 @@ void TranslationBasedLocalOutlierRejector::process( Size ncells((frameSize.width + cellSize_.width - 1) / cellSize_.width, (frameSize.height + cellSize_.height - 1) / cellSize_.height); - int cx, cy; - // fill grid cells grid_.assign(ncells.area(), Cell()); for (int i = 0; i < npoints; ++i) { - cx = std::min(cvRound(points0_[i].x / cellSize_.width), ncells.width - 1); - cy = std::min(cvRound(points0_[i].y / cellSize_.height), ncells.height - 1); + int cx = std::min(cvRound(points0_[i].x / cellSize_.width), ncells.width - 1); + int cy = std::min(cvRound(points0_[i].y / cellSize_.height), ncells.height - 1); grid_[cy * ncells.width + cx].push_back(i); } @@ -101,19 +99,16 @@ void TranslationBasedLocalOutlierRejector::process( RNG rng(0); int niters = ransacParams_.niters(); - int ninliers, ninliersMax; std::vector inliers; - float dx, dy, dxBest, dyBest; - float x1, y1; - int idx; for (size_t ci = 0; ci < grid_.size(); ++ci) { // estimate translation model at the current cell using RANSAC + float x1, y1; const Cell &cell = grid_[ci]; - ninliersMax = 0; - dxBest = dyBest = 0.f; + int ninliers, ninliersMax = 0; + float dxBest = 0.f, dyBest = 0.f; // find the best hypothesis @@ -121,9 +116,9 @@ void TranslationBasedLocalOutlierRejector::process( { for (int iter = 0; iter < niters; ++iter) { - idx = cell[static_cast(rng) % cell.size()]; - dx = points1_[idx].x - points0_[idx].x; - dy = points1_[idx].y - points0_[idx].y; + int idx = cell[static_cast(rng) % cell.size()]; + float dx = points1_[idx].x - points0_[idx].x; + float dy = points1_[idx].y - points0_[idx].y; ninliers = 0; for (size_t i = 0; i < cell.size(); ++i) From db6e095fcc0d6a582cf94bafd5d5b50dc5664376 Mon Sep 17 00:00:00 2001 From: atinfinity Date: Mon, 1 Feb 2016 20:59:11 +0900 Subject: [PATCH 104/468] added cmakedefine to cmake/templates/cvconfig.h.in --- cmake/templates/cvconfig.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in index 608372967a..c80720dcde 100644 --- a/cmake/templates/cvconfig.h.in +++ b/cmake/templates/cvconfig.h.in @@ -120,6 +120,9 @@ /* NVidia Video Decoding API*/ #cmakedefine HAVE_NVCUVID +/* NVidia Video Encoding API*/ +#cmakedefine HAVE_NVCUVENC + /* OpenCL Support */ #cmakedefine HAVE_OPENCL #cmakedefine HAVE_OPENCL_STATIC From cf43790a27f1815e2ae3ed63f16e5d8a77e100b5 Mon Sep 17 00:00:00 2001 From: atinfinity Date: Mon, 1 Feb 2016 21:15:28 +0900 Subject: [PATCH 105/468] added cmakedefine to cmake/templates/cvconfig.h.in --- cmake/templates/cvconfig.h.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in index d1c9e65d3d..caea7da3e7 100644 --- a/cmake/templates/cvconfig.h.in +++ b/cmake/templates/cvconfig.h.in @@ -109,6 +109,9 @@ /* NVidia Video Decoding API*/ #cmakedefine HAVE_NVCUVID +/* NVidia Video Encoding API*/ +#cmakedefine HAVE_NVCUVENC + /* OpenCL Support */ #cmakedefine HAVE_OPENCL #cmakedefine HAVE_OPENCL_STATIC From 43a1874e33ca0d20998aefa41d694912cf24a58d Mon Sep 17 00:00:00 2001 From: Philippe FOUBERT Date: Mon, 1 Feb 2016 19:18:51 +0100 Subject: [PATCH 106/468] Bug correction: The "CvCaptureCAM_XIMEA::getProperty" method had not the same signature as "CvCapture::getProperty" so it was not called when we use the "VideoCapture::get" method (the "const" specifier was missing). --- modules/videoio/src/cap_ximea.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/videoio/src/cap_ximea.cpp b/modules/videoio/src/cap_ximea.cpp index bf3fdf5988..e111e69b7a 100644 --- a/modules/videoio/src/cap_ximea.cpp +++ b/modules/videoio/src/cap_ximea.cpp @@ -2,7 +2,7 @@ #include "precomp.hpp" #ifdef WIN32 -#include "xiApi.h" +#include #else #include #endif @@ -19,7 +19,7 @@ public: virtual bool open( int index ); virtual void close(); - virtual double getProperty(int); + virtual double getProperty(int) const; virtual bool setProperty(int, double); virtual bool grabFrame(); virtual IplImage* retrieveFrame(int); @@ -27,9 +27,9 @@ public: private: void init(); - void errMsg(const char* msg, int errNum); + void errMsg(const char* msg, int errNum) const; void resetCvImage(); - int ocvParamtoXimeaParam(int value); + int ocvParamtoXimeaParam(int value) const; IplImage* frame; HANDLE hmv; @@ -284,7 +284,7 @@ void CvCaptureCAM_XIMEA::resetCvImage() /**********************************************************************************/ -int CvCaptureCAM_XIMEA::ocvParamtoXimeaParam(int property_id) +int CvCaptureCAM_XIMEA::ocvParamtoXimeaParam(int property_id) const { XI_RETURN stat = XI_OK; switch (property_id) @@ -963,7 +963,7 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) /**********************************************************************************/ -double CvCaptureCAM_XIMEA::getProperty( int property_id ) +double CvCaptureCAM_XIMEA::getProperty( int property_id ) const { XI_RETURN stat = XI_OK; double getPropVal = 0; @@ -1572,7 +1572,7 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id ) /**********************************************************************************/ -void CvCaptureCAM_XIMEA::errMsg(const char* msg, int errNum) +void CvCaptureCAM_XIMEA::errMsg(const char* msg, int errNum) const { // with XI_OK there is nothing to report if(errNum == XI_OK) return; From a2bda999211e8be9fbc5d40038fdfc9399de31fc Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Tue, 2 Feb 2016 12:45:41 +0300 Subject: [PATCH 107/468] MacOSX / QTKit capture: trying to fix invalid timer call --- modules/videoio/src/cap_qtkit.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/videoio/src/cap_qtkit.mm b/modules/videoio/src/cap_qtkit.mm index bdbbd2d1e4..ad6037b766 100644 --- a/modules/videoio/src/cap_qtkit.mm +++ b/modules/videoio/src/cap_qtkit.mm @@ -93,6 +93,8 @@ didDropVideoFrameWithSampleBuffer:(QTSampleBuffer *)sampleBuffer - (int)updateImage; - (IplImage*)getOutput; +- (void)doFireTimer:(NSTimer *)timer; + @end /***************************************************************************** @@ -622,6 +624,11 @@ didDropVideoFrameWithSampleBuffer:(QTSampleBuffer *)sampleBuffer return 1; } +- (void)doFireTimer:(NSTimer *)timer { + (void)timer; + // dummy +} + @end From 7e472fbf68d1da7cf4eb636b8add999a826d0b4d Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 3 Feb 2016 14:06:20 +0300 Subject: [PATCH 108/468] ocl: thread-safe OpenCL loading (6056) --- .../core/src/opencl/runtime/opencl_core.cpp | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/modules/core/src/opencl/runtime/opencl_core.cpp b/modules/core/src/opencl/runtime/opencl_core.cpp index 971c0770e5..0ab3381124 100644 --- a/modules/core/src/opencl/runtime/opencl_core.cpp +++ b/modules/core/src/opencl/runtime/opencl_core.cpp @@ -58,11 +58,11 @@ static void* AppleCLGetProcAddress(const char* name) { static bool initialized = false; static void* handle = NULL; - if (!handle) + if (!handle && !initialized) { - if(!initialized) + cv::AutoLock lock(cv::getInitializationMutex()); + if (!initialized) { - initialized = true; const char* path = "/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL"; const char* envPath = getenv("OPENCV_OPENCL_RUNTIME"); if (envPath) @@ -78,10 +78,11 @@ static void* AppleCLGetProcAddress(const char* name) fprintf(stderr, ERROR_MSG_INVALID_VERSION); handle = NULL; } + initialized = true; } - if (!handle) - return NULL; } + if (!handle) + return NULL; return dlsym(handle, name); } #define CV_CL_GET_PROC_ADDRESS(name) AppleCLGetProcAddress(name) @@ -94,11 +95,11 @@ static void* WinGetProcAddress(const char* name) { static bool initialized = false; static HMODULE handle = NULL; - if (!handle) + if (!handle && !initialized) { - if(!initialized) + cv::AutoLock lock(cv::getInitializationMutex()); + if (!initialized) { - initialized = true; handle = GetModuleHandleA("OpenCL.dll"); if (!handle) { @@ -118,10 +119,11 @@ static void* WinGetProcAddress(const char* name) handle = NULL; } } + initialized = true; } - if (!handle) - return NULL; } + if (!handle) + return NULL; return (void*)GetProcAddress(handle, name); } #define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name) @@ -135,11 +137,11 @@ static void* GetProcAddress(const char* name) { static bool initialized = false; static void* handle = NULL; - if (!handle) + if (!handle && !initialized) { - if(!initialized) + cv::AutoLock lock(cv::getInitializationMutex()); + if (!initialized) { - initialized = true; const char* path = "libOpenCL.so"; const char* envPath = getenv("OPENCV_OPENCL_RUNTIME"); if (envPath) @@ -155,10 +157,11 @@ static void* GetProcAddress(const char* name) fprintf(stderr, ERROR_MSG_INVALID_VERSION); handle = NULL; } + initialized = true; } - if (!handle) - return NULL; } + if (!handle) + return NULL; return dlsym(handle, name); } #define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name) From 194b865dafb4b92ece223444bd364854123be86e Mon Sep 17 00:00:00 2001 From: Suleyman TURKMEN Date: Wed, 3 Feb 2016 23:36:30 +0200 Subject: [PATCH 109/468] update documentation of cv::repeat --- modules/core/include/opencv2/core.hpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp index 559226079b..2e47658f73 100644 --- a/modules/core/include/opencv2/core.hpp +++ b/modules/core/include/opencv2/core.hpp @@ -1007,24 +1007,24 @@ CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode); /** @brief Fills the output array with repeated copies of the input array. -The functions repeat duplicate the input array one or more times along each of the two axes: +The function cv::repeat duplicates the input array one or more times along each of the two axes: \f[\texttt{dst} _{ij}= \texttt{src} _{i\mod src.rows, \; j\mod src.cols }\f] The second variant of the function is more convenient to use with @ref MatrixExpressions. @param src input array to replicate. -@param dst output array of the same type as src. -@param ny Flag to specify how many times the src is repeated along the +@param ny Flag to specify how many times the `src` is repeated along the vertical axis. -@param nx Flag to specify how many times the src is repeated along the +@param nx Flag to specify how many times the `src` is repeated along the horizontal axis. -@sa reduce +@param dst output array of the same type as `src`. +@sa cv::reduce */ CV_EXPORTS_W void repeat(InputArray src, int ny, int nx, OutputArray dst); /** @overload @param src input array to replicate. -@param ny Flag to specify how many times the src is repeated along the +@param ny Flag to specify how many times the `src` is repeated along the vertical axis. -@param nx Flag to specify how many times the src is repeated along the +@param nx Flag to specify how many times the `src` is repeated along the horizontal axis. */ CV_EXPORTS Mat repeat(const Mat& src, int ny, int nx); From 89df7923a7a4e1fad5b95d2405add6f0b670352f Mon Sep 17 00:00:00 2001 From: StevenPuttemans Date: Thu, 4 Feb 2016 13:20:21 +0100 Subject: [PATCH 110/468] revert PR 5362 --- modules/objdetect/src/cascadedetect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp index 567770739f..e206992574 100644 --- a/modules/objdetect/src/cascadedetect.cpp +++ b/modules/objdetect/src/cascadedetect.cpp @@ -998,7 +998,7 @@ public: { if( result == 1 ) result = -(int)classifier->data.stages.size(); - if( -result >= 0 ) // TODO: Add variable to define a specific last accepted Stage - ABI_COMPATIBILITY problem with new/changed virtual functions - PR #5362 + if( classifier->data.stages.size() + result == 0 ) { mtx->lock(); rectangles->push_back(Rect(cvRound(x*scalingFactor), From da48061910db0ee78396237bc78d6f2e321ea5eb Mon Sep 17 00:00:00 2001 From: Peter Rekdal Sunde Date: Wed, 3 Feb 2016 01:00:43 +0100 Subject: [PATCH 111/468] Add interrupt callback with default timeout of 30s. Fixes #5730. Fix docs build failure by re-indenting with spaces instead of tabs. Trailing whitespace fixes. http://pullrequest.opencv.org/buildbot/builders/precommit_docs/builds/5152/steps/whitespace/logs/stdio mingw build fix. --- modules/videoio/src/cap_ffmpeg_impl.hpp | 180 ++++++++++++++++++++++++ 1 file changed, 180 insertions(+) diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp index 9da8de5cd3..d8388e9967 100644 --- a/modules/videoio/src/cap_ffmpeg_impl.hpp +++ b/modules/videoio/src/cap_ffmpeg_impl.hpp @@ -129,12 +129,22 @@ extern "C" { #if defined WIN32 || defined _WIN32 #include + #if defined _MSC_VER && _MSC_VER < 1900 + struct timespec + { + time_t tv_sec; + long tv_nsec; + }; + #endif #elif defined __linux__ || defined __APPLE__ #include #include #include + #include #if defined __APPLE__ #include + #include + #include #endif #endif @@ -184,6 +194,116 @@ extern "C" { #endif #endif + +#define LIBAVFORMAT_INTERRUPT_TIMEOUT_MS 30000 + +#ifdef WIN32 +// http://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows + +inline LARGE_INTEGER get_filetime_offset() +{ + SYSTEMTIME s; + FILETIME f; + LARGE_INTEGER t; + + s.wYear = 1970; + s.wMonth = 1; + s.wDay = 1; + s.wHour = 0; + s.wMinute = 0; + s.wSecond = 0; + s.wMilliseconds = 0; + SystemTimeToFileTime(&s, &f); + t.QuadPart = f.dwHighDateTime; + t.QuadPart <<= 32; + t.QuadPart |= f.dwLowDateTime; + return t; +} + +inline void get_monotonic_time(timespec *tv) +{ + LARGE_INTEGER t; + FILETIME f; + double microseconds; + static LARGE_INTEGER offset; + static double frequencyToMicroseconds; + static int initialized = 0; + static BOOL usePerformanceCounter = 0; + + if (!initialized) + { + LARGE_INTEGER performanceFrequency; + initialized = 1; + usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency); + if (usePerformanceCounter) + { + QueryPerformanceCounter(&offset); + frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.; + } + else + { + offset = get_filetime_offset(); + frequencyToMicroseconds = 10.; + } + } + + if (usePerformanceCounter) + { + QueryPerformanceCounter(&t); + } else { + GetSystemTimeAsFileTime(&f); + t.QuadPart = f.dwHighDateTime; + t.QuadPart <<= 32; + t.QuadPart |= f.dwLowDateTime; + } + + t.QuadPart -= offset.QuadPart; + microseconds = (double)t.QuadPart / frequencyToMicroseconds; + t.QuadPart = microseconds; + tv->tv_sec = t.QuadPart / 1000000; + tv->tv_nsec = (t.QuadPart % 1000000) * 1000; +} +#else +inline void get_monotonic_time(timespec *time) +{ +#if defined(__APPLE__) && defined(__MACH__) + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + time->tv_sec = mts.tv_sec; + time->tv_nsec = mts.tv_nsec; +#else + clock_gettime(CLOCK_MONOTONIC, time); +#endif +} +#endif + +inline timespec get_monotonic_time_diff(timespec start, timespec end) +{ + timespec temp; + if (end.tv_nsec - start.tv_nsec < 0) + { + temp.tv_sec = end.tv_sec - start.tv_sec - 1; + temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec; + } + else + { + temp.tv_sec = end.tv_sec - start.tv_sec; + temp.tv_nsec = end.tv_nsec - start.tv_nsec; + } + return temp; +} + +inline double get_monotonic_time_diff_ms(timespec time1, timespec time2) +{ + timespec delta = get_monotonic_time_diff(time1, time2); + double milliseconds = delta.tv_sec * 1000 + (double)delta.tv_nsec / 1000000.0; + + return milliseconds; +} + static int get_number_of_cpus(void) { #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(52, 111, 0) @@ -233,6 +353,14 @@ struct Image_FFMPEG }; +struct AVInterruptCallbackMetadata +{ + timespec value; + unsigned int timeout_after_ms; + int timeout; +}; + + inline void _opencv_ffmpeg_free(void** ptr) { if(*ptr) free(*ptr); @@ -240,6 +368,20 @@ inline void _opencv_ffmpeg_free(void** ptr) } +inline int _opencv_ffmpeg_interrupt_callback(void *ptr) +{ + AVInterruptCallbackMetadata* metadata = (AVInterruptCallbackMetadata*)ptr; + assert(metadata); + + timespec now; + get_monotonic_time(&now); + + metadata->timeout = get_monotonic_time_diff_ms(metadata->value, now) > metadata->timeout_after_ms; + + return metadata->timeout ? -1 : 0; +} + + struct CvCapture_FFMPEG { bool open( const char* filename ); @@ -293,6 +435,8 @@ struct CvCapture_FFMPEG #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) AVDictionary *dict; #endif + + AVInterruptCallbackMetadata interrupt_metadata; }; void CvCapture_FFMPEG::init() @@ -591,6 +735,14 @@ bool CvCapture_FFMPEG::open( const char* _filename ) close(); + /* interrupt callback */ + interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_TIMEOUT_MS; + get_monotonic_time(&interrupt_metadata.value); + + ic = avformat_alloc_context(); + ic->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback; + ic->interrupt_callback.opaque = &interrupt_metadata; + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) av_dict_set(&dict, "rtsp_transport", "tcp", 0); int err = avformat_open_input(&ic, _filename, NULL, &dict); @@ -703,6 +855,13 @@ bool CvCapture_FFMPEG::grabFrame() { av_free_packet (&packet); + + if (interrupt_metadata.timeout) + { + valid = false; + break; + } + int ret = av_read_frame(ic, &packet); if (ret == AVERROR(EAGAIN)) continue; @@ -738,6 +897,9 @@ bool CvCapture_FFMPEG::grabFrame() picture_pts = packet.pts != AV_NOPTS_VALUE_ && packet.pts != 0 ? packet.pts : packet.dts; frame_number++; valid = true; + + // update interrupt value + get_monotonic_time(&interrupt_metadata.value); } else { @@ -2323,6 +2485,8 @@ private: AVFormatContext* ctx_; int video_stream_id_; AVPacket pkt_; + + AVInterruptCallbackMetadata interrupt_metadata; }; bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma_format, int* width, int* height) @@ -2333,6 +2497,14 @@ bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma video_stream_id_ = -1; memset(&pkt_, 0, sizeof(AVPacket)); + /* interrupt callback */ + interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_TIMEOUT_MS; + get_monotonic_time(&interrupt_metadata.value); + + ctx_ = avformat_alloc_context(); + ctx_->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback; + ctx_->interrupt_callback.opaque = &interrupt_metadata; + #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0) avformat_network_init(); #endif @@ -2449,11 +2621,19 @@ bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFi // get the next frame for (;;) { + if(interrupt_metadata.timeout) + { + break; + } + int ret = av_read_frame(ctx_, &pkt_); if (ret == AVERROR(EAGAIN)) continue; + // update interrupt value + get_monotonic_time(&interrupt_metadata.value); + if (ret < 0) { if (ret == (int)AVERROR_EOF) From 6cdf3116c4b4be57ee104caacd58b32245b408c3 Mon Sep 17 00:00:00 2001 From: StevenPuttemans Date: Fri, 5 Feb 2016 11:01:21 +0100 Subject: [PATCH 112/468] deactivate build options by default that are not supposed the be ON by default --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b99e35220b..7be7259dde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,8 +187,8 @@ OCV_OPTION(WITH_OPENGL "Include OpenGL support" OFF OCV_OPTION(WITH_OPENNI "Include OpenNI support" OFF IF (NOT ANDROID AND NOT IOS AND NOT WINRT) ) OCV_OPTION(WITH_OPENNI2 "Include OpenNI2 support" OFF IF (NOT ANDROID AND NOT IOS AND NOT WINRT) ) OCV_OPTION(WITH_PNG "Include PNG support" ON) -OCV_OPTION(WITH_PVAPI "Include Prosilica GigE support" ON IF (NOT ANDROID AND NOT IOS AND NOT WINRT) ) -OCV_OPTION(WITH_GIGEAPI "Include Smartek GigE support" ON IF (NOT ANDROID AND NOT IOS AND NOT WINRT) ) +OCV_OPTION(WITH_PVAPI "Include Prosilica GigE support" OFF IF (NOT ANDROID AND NOT IOS AND NOT WINRT) ) +OCV_OPTION(WITH_GIGEAPI "Include Smartek GigE support" OFF IF (NOT ANDROID AND NOT IOS AND NOT WINRT) ) OCV_OPTION(WITH_QT "Build with Qt Backend support" OFF IF (NOT ANDROID AND NOT IOS AND NOT WINRT) ) OCV_OPTION(WITH_WIN32UI "Build with Win32 UI Backend support" ON IF WIN32 AND NOT WINRT) OCV_OPTION(WITH_QUICKTIME "Use QuickTime for Video I/O insted of QTKit" OFF IF APPLE ) From 873399705d58979a905357bea030bf88cd77cddd Mon Sep 17 00:00:00 2001 From: StevenPuttemans Date: Fri, 5 Feb 2016 13:21:40 +0100 Subject: [PATCH 113/468] add clarification on the acces paramter of the at operator --- modules/core/include/opencv2/core/mat.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index ffec538657..1fa0a76854 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -1702,6 +1702,14 @@ public: for(int j = 0; j < H.cols; j++) H.at(i,j)=1./(i+j+1); @endcode + + Keep in mind that the size identifier used in the at operator cannot be chosen at random. It depends + on the image from which you are trying to retrieve the data. The table below gives a better insight in this: + - If matrix is of type `CV_8U` or `CV_8S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_16U` or `CV_16S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_32S` or `CV_32F` then use `Mat.at(y,x)`. + - If matrix is of type `CV_64FU` then use `Mat.at(y,x)`. + @param i0 Index along the dimension 0 */ template _Tp& at(int i0=0); From c10c8db97dcc8a9cac085c458b40ae74a7cbb2cd Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sat, 6 Feb 2016 15:19:28 +0300 Subject: [PATCH 114/468] cmake: skip checks for host paths on cross-compilation (5897) --- cmake/OpenCVFindLibsVideo.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake index 2e09cf24b3..64642daa2a 100644 --- a/cmake/OpenCVFindLibsVideo.cmake +++ b/cmake/OpenCVFindLibsVideo.cmake @@ -214,7 +214,7 @@ if(WITH_FFMPEG) CHECK_INCLUDE_FILE(libavformat/avformat.h HAVE_GENTOO_FFMPEG) CHECK_INCLUDE_FILE(ffmpeg/avformat.h HAVE_FFMPEG_FFMPEG) if(NOT HAVE_GENTOO_FFMPEG AND NOT HAVE_FFMPEG_FFMPEG) - if(EXISTS /usr/include/ffmpeg/libavformat/avformat.h OR HAVE_FFMPEG_SWSCALE) + if((NOT CMAKE_CROSSCOMPILING AND EXISTS /usr/include/ffmpeg/libavformat/avformat.h) OR HAVE_FFMPEG_SWSCALE) set(HAVE_GENTOO_FFMPEG TRUE) endif() endif() From c09b6000c6bbff8a162893fac7dddfab1fc93af1 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sat, 6 Feb 2016 15:20:36 +0300 Subject: [PATCH 115/468] ffmpeg: compatibility guard for interrupt callback feature --- modules/videoio/src/cap_ffmpeg_impl.hpp | 38 +++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp index d8388e9967..504561d1ee 100644 --- a/modules/videoio/src/cap_ffmpeg_impl.hpp +++ b/modules/videoio/src/cap_ffmpeg_impl.hpp @@ -195,11 +195,21 @@ extern "C" { #endif +#ifndef USE_AV_INTERRUPT_CALLBACK +#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 21, 0) +#define USE_AV_INTERRUPT_CALLBACK 1 +#else +#define USE_AV_INTERRUPT_CALLBACK 0 +#endif +#endif + +#if USE_AV_INTERRUPT_CALLBACK #define LIBAVFORMAT_INTERRUPT_TIMEOUT_MS 30000 #ifdef WIN32 // http://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows +static inline LARGE_INTEGER get_filetime_offset() { SYSTEMTIME s; @@ -220,6 +230,7 @@ inline LARGE_INTEGER get_filetime_offset() return t; } +static inline void get_monotonic_time(timespec *tv) { LARGE_INTEGER t; @@ -264,6 +275,7 @@ inline void get_monotonic_time(timespec *tv) tv->tv_nsec = (t.QuadPart % 1000000) * 1000; } #else +static inline void get_monotonic_time(timespec *time) { #if defined(__APPLE__) && defined(__MACH__) @@ -280,6 +292,7 @@ inline void get_monotonic_time(timespec *time) } #endif +static inline timespec get_monotonic_time_diff(timespec start, timespec end) { timespec temp; @@ -296,6 +309,7 @@ inline timespec get_monotonic_time_diff(timespec start, timespec end) return temp; } +static inline double get_monotonic_time_diff_ms(timespec time1, timespec time2) { timespec delta = get_monotonic_time_diff(time1, time2); @@ -303,6 +317,7 @@ inline double get_monotonic_time_diff_ms(timespec time1, timespec time2) return milliseconds; } +#endif // USE_AV_INTERRUPT_CALLBACK static int get_number_of_cpus(void) { @@ -353,6 +368,7 @@ struct Image_FFMPEG }; +#if USE_AV_INTERRUPT_CALLBACK struct AVInterruptCallbackMetadata { timespec value; @@ -360,14 +376,14 @@ struct AVInterruptCallbackMetadata int timeout; }; - +static inline void _opencv_ffmpeg_free(void** ptr) { if(*ptr) free(*ptr); *ptr = 0; } - +static inline int _opencv_ffmpeg_interrupt_callback(void *ptr) { AVInterruptCallbackMetadata* metadata = (AVInterruptCallbackMetadata*)ptr; @@ -380,6 +396,7 @@ inline int _opencv_ffmpeg_interrupt_callback(void *ptr) return metadata->timeout ? -1 : 0; } +#endif struct CvCapture_FFMPEG @@ -435,8 +452,9 @@ struct CvCapture_FFMPEG #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) AVDictionary *dict; #endif - +#if USE_AV_INTERRUPT_CALLBACK AVInterruptCallbackMetadata interrupt_metadata; +#endif }; void CvCapture_FFMPEG::init() @@ -735,6 +753,7 @@ bool CvCapture_FFMPEG::open( const char* _filename ) close(); +#if USE_AV_INTERRUPT_CALLBACK /* interrupt callback */ interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_TIMEOUT_MS; get_monotonic_time(&interrupt_metadata.value); @@ -742,6 +761,7 @@ bool CvCapture_FFMPEG::open( const char* _filename ) ic = avformat_alloc_context(); ic->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback; ic->interrupt_callback.opaque = &interrupt_metadata; +#endif #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0) av_dict_set(&dict, "rtsp_transport", "tcp", 0); @@ -856,11 +876,13 @@ bool CvCapture_FFMPEG::grabFrame() av_free_packet (&packet); +#if USE_AV_INTERRUPT_CALLBACK if (interrupt_metadata.timeout) { valid = false; break; } +#endif int ret = av_read_frame(ic, &packet); if (ret == AVERROR(EAGAIN)) continue; @@ -898,8 +920,10 @@ bool CvCapture_FFMPEG::grabFrame() frame_number++; valid = true; +#if USE_AV_INTERRUPT_CALLBACK // update interrupt value get_monotonic_time(&interrupt_metadata.value); +#endif } else { @@ -2486,7 +2510,9 @@ private: int video_stream_id_; AVPacket pkt_; +#if USE_AV_INTERRUPT_CALLBACK AVInterruptCallbackMetadata interrupt_metadata; +#endif }; bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma_format, int* width, int* height) @@ -2497,6 +2523,7 @@ bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma video_stream_id_ = -1; memset(&pkt_, 0, sizeof(AVPacket)); +#if USE_AV_INTERRUPT_CALLBACK /* interrupt callback */ interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_TIMEOUT_MS; get_monotonic_time(&interrupt_metadata.value); @@ -2504,6 +2531,7 @@ bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma ctx_ = avformat_alloc_context(); ctx_->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback; ctx_->interrupt_callback.opaque = &interrupt_metadata; +#endif #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0) avformat_network_init(); @@ -2621,18 +2649,22 @@ bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFi // get the next frame for (;;) { +#if USE_AV_INTERRUPT_CALLBACK if(interrupt_metadata.timeout) { break; } +#endif int ret = av_read_frame(ctx_, &pkt_); if (ret == AVERROR(EAGAIN)) continue; +#if USE_AV_INTERRUPT_CALLBACK // update interrupt value get_monotonic_time(&interrupt_metadata.value); +#endif if (ret < 0) { From 4a5ed701755ef8c5184b9dbe4e6fa6080bd093f2 Mon Sep 17 00:00:00 2001 From: Pranav Ganorkar Date: Sun, 7 Feb 2016 03:09:21 +0530 Subject: [PATCH 116/468] removed dirname variable --- apps/traincascade/imagestorage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/traincascade/imagestorage.cpp b/apps/traincascade/imagestorage.cpp index fdaa33b6dd..4055350c2e 100644 --- a/apps/traincascade/imagestorage.cpp +++ b/apps/traincascade/imagestorage.cpp @@ -28,7 +28,7 @@ CvCascadeImageReader::NegReader::NegReader() bool CvCascadeImageReader::NegReader::create( const string _filename, Size _winSize ) { - string dirname, str; + string str; std::ifstream file(_filename.c_str()); if ( !file.is_open() ) return false; From 4f5497837a78572fad9dffe0b56f4a8e560d4593 Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Mon, 8 Feb 2016 11:04:19 +0300 Subject: [PATCH 117/468] Removed gittip link This project is dead from 1st September last year --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index da3c9613c7..7dbc823200 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ ### OpenCV: Open Source Computer Vision Library -[![Gittip](http://img.shields.io/gittip/OpenCV.png)](https://www.gittip.com/OpenCV/) - #### Resources * Homepage: From 544824ffc1c13d53742f0ddaf3f5158de0c7f748 Mon Sep 17 00:00:00 2001 From: Alexander Shishkov Date: Mon, 8 Feb 2016 11:07:58 +0300 Subject: [PATCH 118/468] Removed gittip link This project is dead from the 1st September last year --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 3a26ad8555..e74a329668 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ ### OpenCV: Open Source Computer Vision Library -[![Gittip](http://img.shields.io/gittip/OpenCV.png)](https://www.gittip.com/OpenCV/) - #### Resources * Homepage: From a70c54f2c592e7d64dfbf5af1ba8ba5cb4137624 Mon Sep 17 00:00:00 2001 From: Steven Puttemans Date: Mon, 8 Feb 2016 10:20:08 +0100 Subject: [PATCH 119/468] Added suggestions from PR6068 As discussed here: https://github.com/Itseez/opencv/pull/6068#issuecomment-180797723 --- modules/core/include/opencv2/core/mat.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 1fa0a76854..06aa48d3be 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -1706,9 +1706,12 @@ public: Keep in mind that the size identifier used in the at operator cannot be chosen at random. It depends on the image from which you are trying to retrieve the data. The table below gives a better insight in this: - If matrix is of type `CV_8U` or `CV_8S` then use `Mat.at(y,x)`. - - If matrix is of type `CV_16U` or `CV_16S` then use `Mat.at(y,x)`. - - If matrix is of type `CV_32S` or `CV_32F` then use `Mat.at(y,x)`. - - If matrix is of type `CV_64FU` then use `Mat.at(y,x)`. + - If matrix is of type `CV_8S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_16U` then use `Mat.at(y,x)`. + - If matrix is of type `CV_16S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_32S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_32F` then use `Mat.at(y,x)`. + - If matrix is of type `CV_64F` then use `Mat.at(y,x)`. @param i0 Index along the dimension 0 */ From b030ac0433768b2e9eef1e53849a7a719023db6f Mon Sep 17 00:00:00 2001 From: Mathieu Barnachon Date: Mon, 8 Feb 2016 13:17:08 +0100 Subject: [PATCH 120/468] Ensure the Cuda context is initialized correctly as long as the setDevice is not called in a multi-thread environment. --- modules/core/src/cuda_info.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/core/src/cuda_info.cpp b/modules/core/src/cuda_info.cpp index 5ad33ce8a1..08013ca988 100644 --- a/modules/core/src/cuda_info.cpp +++ b/modules/core/src/cuda_info.cpp @@ -70,6 +70,7 @@ void cv::cuda::setDevice(int device) (void) device; throw_no_cuda(); #else + cudaFree(0); cudaSafeCall( cudaSetDevice(device) ); #endif } From cd96df1407a5c5bfb15ca2d0d8d962fa5e310ea8 Mon Sep 17 00:00:00 2001 From: Steven Puttemans Date: Mon, 8 Feb 2016 13:26:06 +0100 Subject: [PATCH 121/468] Update mat.hpp --- modules/core/include/opencv2/core/mat.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp index 06aa48d3be..d554663783 100644 --- a/modules/core/include/opencv2/core/mat.hpp +++ b/modules/core/include/opencv2/core/mat.hpp @@ -1705,7 +1705,7 @@ public: Keep in mind that the size identifier used in the at operator cannot be chosen at random. It depends on the image from which you are trying to retrieve the data. The table below gives a better insight in this: - - If matrix is of type `CV_8U` or `CV_8S` then use `Mat.at(y,x)`. + - If matrix is of type `CV_8U` then use `Mat.at(y,x)`. - If matrix is of type `CV_8S` then use `Mat.at(y,x)`. - If matrix is of type `CV_16U` then use `Mat.at(y,x)`. - If matrix is of type `CV_16S` then use `Mat.at(y,x)`. From 112aa491045d2001741ac157dc359f65a92ae260 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Mon, 8 Feb 2016 17:11:35 +0300 Subject: [PATCH 122/468] ExifReader::getFormat : check buffer length before accessing, fixes 6059 --- modules/imgcodecs/src/jpeg_exif.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/imgcodecs/src/jpeg_exif.cpp b/modules/imgcodecs/src/jpeg_exif.cpp index 103e72ddec..ebc4f05352 100644 --- a/modules/imgcodecs/src/jpeg_exif.cpp +++ b/modules/imgcodecs/src/jpeg_exif.cpp @@ -245,7 +245,10 @@ void ExifReader::parseExif() */ Endianess_t ExifReader::getFormat() const { - if( m_data[0] != m_data[1] ) + if (m_data.size() < 1) + return NONE; + + if( m_data.size() > 1 && m_data[0] != m_data[1] ) { return NONE; } From c21657336b585b0edfe01b69fa2046e6aeaada9d Mon Sep 17 00:00:00 2001 From: Marian Zajko Date: Fri, 29 Jan 2016 14:55:22 +0100 Subject: [PATCH 123/468] ximea interface update - fixed getProperty call definition - added new parameter defitions removed whitespaces Reworked enumerators to keep values from previous commit ximea enums fixes - fixed whitespaces issue - fixed duplicate enum values error ximea enum definitions update - fixed videioio.hpp code style - fixed ABI violation in enums - added new parameter handlers to cpp XIMEA setProperty update Added acquisition resetting to buffer size adjustment parameters. --- modules/videoio/include/opencv2/videoio.hpp | 173 +++++++++++++++--- .../include/opencv2/videoio/videoio_c.h | 8 + modules/videoio/src/cap_ximea.cpp | 74 ++++++++ 3 files changed, 233 insertions(+), 22 deletions(-) diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index ccd6c06378..cff796d997 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -254,30 +254,159 @@ enum { CAP_PVAPI_PIXELFORMAT_MONO8 = 1, // Mono8 CAP_PVAPI_PIXELFORMAT_BGRA32 = 8, // Bgra32 }; -// Properties of cameras available through XIMEA SDK interface -enum { CAP_PROP_XI_DOWNSAMPLING = 400, // Change image resolution by binning or skipping. - CAP_PROP_XI_DATA_FORMAT = 401, // Output data format. - CAP_PROP_XI_OFFSET_X = 402, // Horizontal offset from the origin to the area of interest (in pixels). - CAP_PROP_XI_OFFSET_Y = 403, // Vertical offset from the origin to the area of interest (in pixels). - CAP_PROP_XI_TRG_SOURCE = 404, // Defines source of trigger. - CAP_PROP_XI_TRG_SOFTWARE = 405, // Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE. - CAP_PROP_XI_GPI_SELECTOR = 406, // Selects general purpose input - CAP_PROP_XI_GPI_MODE = 407, // Set general purpose input mode - CAP_PROP_XI_GPI_LEVEL = 408, // Get general purpose level - CAP_PROP_XI_GPO_SELECTOR = 409, // Selects general purpose output - CAP_PROP_XI_GPO_MODE = 410, // Set general purpose output mode - CAP_PROP_XI_LED_SELECTOR = 411, // Selects camera signalling LED - CAP_PROP_XI_LED_MODE = 412, // Define camera signalling LED functionality - CAP_PROP_XI_MANUAL_WB = 413, // Calculates White Balance(must be called during acquisition) - CAP_PROP_XI_AUTO_WB = 414, // Automatic white balance - CAP_PROP_XI_AEAG = 415, // Automatic exposure/gain - CAP_PROP_XI_EXP_PRIORITY = 416, // Exposure priority (0.5 - exposure 50%, gain 50%). - CAP_PROP_XI_AE_MAX_LIMIT = 417, // Maximum limit of exposure in AEAG procedure - CAP_PROP_XI_AG_MAX_LIMIT = 418, // Maximum limit of gain in AEAG procedure - CAP_PROP_XI_AEAG_LEVEL = 419, // Average intensity of output signal AEAG should achieve(in %) - CAP_PROP_XI_TIMEOUT = 420 // Image capture timeout in milliseconds + // Properties of cameras available through XIMEA SDK interface +enum { CAP_PROP_XI_DOWNSAMPLING = 400, // Change image resolution by binning or skipping. + CAP_PROP_XI_DATA_FORMAT = 401, // Output data format. + CAP_PROP_XI_OFFSET_X = 402, // Horizontal offset from the origin to the area of interest (in pixels). + CAP_PROP_XI_OFFSET_Y = 403, // Vertical offset from the origin to the area of interest (in pixels). + CAP_PROP_XI_TRG_SOURCE = 404, // Defines source of trigger. + CAP_PROP_XI_TRG_SOFTWARE = 405, // Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE. + CAP_PROP_XI_GPI_SELECTOR = 406, // Selects general purpose input + CAP_PROP_XI_GPI_MODE = 407, // Set general purpose input mode + CAP_PROP_XI_GPI_LEVEL = 408, // Get general purpose level + CAP_PROP_XI_GPO_SELECTOR = 409, // Selects general purpose output + CAP_PROP_XI_GPO_MODE = 410, // Set general purpose output mode + CAP_PROP_XI_LED_SELECTOR = 411, // Selects camera signalling LED + CAP_PROP_XI_LED_MODE = 412, // Define camera signalling LED functionality + CAP_PROP_XI_MANUAL_WB = 413, // Calculates White Balance(must be called during acquisition) + CAP_PROP_XI_AUTO_WB = 414, // Automatic white balance + CAP_PROP_XI_AEAG = 415, // Automatic exposure/gain + CAP_PROP_XI_EXP_PRIORITY = 416, // Exposure priority (0.5 - exposure 50%, gain 50%). + CAP_PROP_XI_AE_MAX_LIMIT = 417, // Maximum limit of exposure in AEAG procedure + CAP_PROP_XI_AG_MAX_LIMIT = 418, // Maximum limit of gain in AEAG procedure + CAP_PROP_XI_AEAG_LEVEL = 419, // Average intensity of output signal AEAG should achieve(in %) + CAP_PROP_XI_TIMEOUT = 420, // Image capture timeout in milliseconds + CAP_PROP_XI_EXPOSURE = 421, // Exposure time in microseconds + CAP_PROP_XI_EXPOSURE_BURST_COUNT = 422, // Sets the number of times of exposure in one frame. + CAP_PROP_XI_GAIN_SELECTOR = 423, // Gain selector for parameter Gain allows to select different type of gains. + CAP_PROP_XI_GAIN = 424, // Gain in dB + CAP_PROP_XI_DOWNSAMPLING_TYPE = 426, // Change image downsampling type. + CAP_PROP_XI_BINNING_SELECTOR = 427, // Binning engine selector. + CAP_PROP_XI_BINNING_VERTICAL = 428, // Vertical Binning - number of vertical photo-sensitive cells to combine together. + CAP_PROP_XI_BINNING_HORIZONTAL = 429, // Horizontal Binning - number of horizontal photo-sensitive cells to combine together. + CAP_PROP_XI_BINNING_PATTERN = 430, // Binning pattern type. + CAP_PROP_XI_DECIMATION_SELECTOR = 431, // Decimation engine selector. + CAP_PROP_XI_DECIMATION_VERTICAL = 432, // Vertical Decimation - vertical sub-sampling of the image - reduces the vertical resolution of the image by the specified vertical decimation factor. + CAP_PROP_XI_DECIMATION_HORIZONTAL = 433, // Horizontal Decimation - horizontal sub-sampling of the image - reduces the horizontal resolution of the image by the specified vertical decimation factor. + CAP_PROP_XI_DECIMATION_PATTERN = 434, // Decimation pattern type. + CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR = 587, // Selects which test pattern generator is controlled by the TestPattern feature. + CAP_PROP_XI_TEST_PATTERN = 588, // Selects which test pattern type is generated by the selected generator. + CAP_PROP_XI_IMAGE_DATA_FORMAT = 435, // Output data format. + CAP_PROP_XI_SHUTTER_TYPE = 436, // Change sensor shutter type(CMOS sensor). + CAP_PROP_XI_SENSOR_TAPS = 437, // Number of taps + CAP_PROP_XI_AEAG_ROI_OFFSET_X = 439, // Automatic exposure/gain ROI offset X + CAP_PROP_XI_AEAG_ROI_OFFSET_Y = 440, // Automatic exposure/gain ROI offset Y + CAP_PROP_XI_AEAG_ROI_WIDTH = 441, // Automatic exposure/gain ROI Width + CAP_PROP_XI_AEAG_ROI_HEIGHT = 442, // Automatic exposure/gain ROI Height + CAP_PROP_XI_BPC = 445, // Correction of bad pixels + CAP_PROP_XI_WB_KR = 448, // White balance red coefficient + CAP_PROP_XI_WB_KG = 449, // White balance green coefficient + CAP_PROP_XI_WB_KB = 450, // White balance blue coefficient + CAP_PROP_XI_WIDTH = 451, // Width of the Image provided by the device (in pixels). + CAP_PROP_XI_HEIGHT = 452, // Height of the Image provided by the device (in pixels). + CAP_PROP_XI_REGION_SELECTOR = 589, // Selects Region in Multiple ROI which parameters are set by width, height, ... ,region mode + CAP_PROP_XI_REGION_MODE = 595, // Activates/deactivates Region selected by Region Selector + CAP_PROP_XI_LIMIT_BANDWIDTH = 459, // Set/get bandwidth(datarate)(in Megabits) + CAP_PROP_XI_SENSOR_DATA_BIT_DEPTH = 460, // Sensor output data bit depth. + CAP_PROP_XI_OUTPUT_DATA_BIT_DEPTH = 461, // Device output data bit depth. + CAP_PROP_XI_IMAGE_DATA_BIT_DEPTH = 462, // bitdepth of data returned by function xiGetImage + CAP_PROP_XI_OUTPUT_DATA_PACKING = 463, // Device output data packing (or grouping) enabled. Packing could be enabled if output_data_bit_depth > 8 and packing capability is available. + CAP_PROP_XI_OUTPUT_DATA_PACKING_TYPE = 464, // Data packing type. Some cameras supports only specific packing type. + CAP_PROP_XI_IS_COOLED = 465, // Returns 1 for cameras that support cooling. + CAP_PROP_XI_COOLING = 466, // Start camera cooling. + CAP_PROP_XI_TARGET_TEMP = 467, // Set sensor target temperature for cooling. + CAP_PROP_XI_CHIP_TEMP = 468, // Camera sensor temperature + CAP_PROP_XI_HOUS_TEMP = 469, // Camera housing tepmerature + CAP_PROP_XI_HOUS_BACK_SIDE_TEMP = 590, // Camera housing back side tepmerature + CAP_PROP_XI_CMS = 470, // Mode of color management system. + CAP_PROP_XI_APPLY_CMS = 471, // Enable applying of CMS profiles to xiGetImage (see XI_PRM_INPUT_CMS_PROFILE, XI_PRM_OUTPUT_CMS_PROFILE). + CAP_PROP_XI_IMAGE_IS_COLOR = 474, // Returns 1 for color cameras. + CAP_PROP_XI_COLOR_FILTER_ARRAY = 475, // Returns color filter array type of RAW data. + CAP_PROP_XI_GAMMAY = 476, // Luminosity gamma + CAP_PROP_XI_GAMMAC = 477, // Chromaticity gamma + CAP_PROP_XI_SHARPNESS = 478, // Sharpness Strenght + CAP_PROP_XI_CC_MATRIX_00 = 479, // Color Correction Matrix element [0][0] + CAP_PROP_XI_CC_MATRIX_01 = 480, // Color Correction Matrix element [0][1] + CAP_PROP_XI_CC_MATRIX_02 = 481, // Color Correction Matrix element [0][2] + CAP_PROP_XI_CC_MATRIX_03 = 482, // Color Correction Matrix element [0][3] + CAP_PROP_XI_CC_MATRIX_10 = 483, // Color Correction Matrix element [1][0] + CAP_PROP_XI_CC_MATRIX_11 = 484, // Color Correction Matrix element [1][1] + CAP_PROP_XI_CC_MATRIX_12 = 485, // Color Correction Matrix element [1][2] + CAP_PROP_XI_CC_MATRIX_13 = 486, // Color Correction Matrix element [1][3] + CAP_PROP_XI_CC_MATRIX_20 = 487, // Color Correction Matrix element [2][0] + CAP_PROP_XI_CC_MATRIX_21 = 488, // Color Correction Matrix element [2][1] + CAP_PROP_XI_CC_MATRIX_22 = 489, // Color Correction Matrix element [2][2] + CAP_PROP_XI_CC_MATRIX_23 = 490, // Color Correction Matrix element [2][3] + CAP_PROP_XI_CC_MATRIX_30 = 491, // Color Correction Matrix element [3][0] + CAP_PROP_XI_CC_MATRIX_31 = 492, // Color Correction Matrix element [3][1] + CAP_PROP_XI_CC_MATRIX_32 = 493, // Color Correction Matrix element [3][2] + CAP_PROP_XI_CC_MATRIX_33 = 494, // Color Correction Matrix element [3][3] + CAP_PROP_XI_DEFAULT_CC_MATRIX = 495, // Set default Color Correction Matrix + CAP_PROP_XI_TRG_SELECTOR = 498, // Selects the type of trigger. + CAP_PROP_XI_ACQ_FRAME_BURST_COUNT = 499, // Sets number of frames acquired by burst. This burst is used only if trigger is set to FrameBurstStart + CAP_PROP_XI_DEBOUNCE_EN = 507, // Enable/Disable debounce to selected GPI + CAP_PROP_XI_DEBOUNCE_T0 = 508, // Debounce time (x * 10us) + CAP_PROP_XI_DEBOUNCE_T1 = 509, // Debounce time (x * 10us) + CAP_PROP_XI_DEBOUNCE_POL = 510, // Debounce polarity (pol = 1 t0 - falling edge, t1 - rising edge) + CAP_PROP_XI_LENS_MODE = 511, // Status of lens control interface. This shall be set to XI_ON before any Lens operations. + CAP_PROP_XI_LENS_APERTURE_VALUE = 512, // Current lens aperture value in stops. Examples: 2.8, 4, 5.6, 8, 11 + CAP_PROP_XI_LENS_FOCUS_MOVEMENT_VALUE = 513, // Lens current focus movement value to be used by XI_PRM_LENS_FOCUS_MOVE in motor steps. + CAP_PROP_XI_LENS_FOCUS_MOVE = 514, // Moves lens focus motor by steps set in XI_PRM_LENS_FOCUS_MOVEMENT_VALUE. + CAP_PROP_XI_LENS_FOCUS_DISTANCE = 515, // Lens focus distance in cm. + CAP_PROP_XI_LENS_FOCAL_LENGTH = 516, // Lens focal distance in mm. + CAP_PROP_XI_LENS_FEATURE_SELECTOR = 517, // Selects the current feature which is accessible by XI_PRM_LENS_FEATURE. + CAP_PROP_XI_LENS_FEATURE = 518, // Allows access to lens feature value currently selected by XI_PRM_LENS_FEATURE_SELECTOR. + CAP_PROP_XI_DEVICE_MODEL_ID = 521, // Return device model id + CAP_PROP_XI_DEVICE_SN = 522, // Return device serial number + CAP_PROP_XI_IMAGE_DATA_FORMAT_RGB32_ALPHA = 529, // The alpha channel of RGB32 output image format. + CAP_PROP_XI_IMAGE_PAYLOAD_SIZE = 530, // Buffer size in bytes sufficient for output image returned by xiGetImage + CAP_PROP_XI_TRANSPORT_PIXEL_FORMAT = 531, // Current format of pixels on transport layer. + CAP_PROP_XI_SENSOR_CLOCK_FREQ_HZ = 532, // Sensor clock frequency in Hz. + CAP_PROP_XI_SENSOR_CLOCK_FREQ_INDEX = 533, // Sensor clock frequency index. Sensor with selected frequencies have possibility to set the frequency only by this index. + CAP_PROP_XI_SENSOR_OUTPUT_CHANNEL_COUNT = 534, // Number of output channels from sensor used for data transfer. + CAP_PROP_XI_FRAMERATE = 535, // Define framerate in Hz + CAP_PROP_XI_COUNTER_SELECTOR = 536, // Select counter + CAP_PROP_XI_COUNTER_VALUE = 537, // Counter status + CAP_PROP_XI_ACQ_TIMING_MODE = 538, // Type of sensor frames timing. + CAP_PROP_XI_AVAILABLE_BANDWIDTH = 539, // Calculate and return available interface bandwidth(int Megabits) + CAP_PROP_XI_BUFFER_POLICY = 540, // Data move policy + CAP_PROP_XI_LUT_EN = 541, // Activates LUT. + CAP_PROP_XI_LUT_INDEX = 542, // Control the index (offset) of the coefficient to access in the LUT. + CAP_PROP_XI_LUT_VALUE = 543, // Value at entry LUTIndex of the LUT + CAP_PROP_XI_TRG_DELAY = 544, // Specifies the delay in microseconds (us) to apply after the trigger reception before activating it. + CAP_PROP_XI_TS_RST_MODE = 545, // Defines how time stamp reset engine will be armed + CAP_PROP_XI_TS_RST_SOURCE = 546, // Defines which source will be used for timestamp reset. Writing this parameter will trigger settings of engine (arming) + CAP_PROP_XI_IS_DEVICE_EXIST = 547, // Returns 1 if camera connected and works properly. + CAP_PROP_XI_ACQ_BUFFER_SIZE = 548, // Acquisition buffer size in buffer_size_unit. Default bytes. + CAP_PROP_XI_ACQ_BUFFER_SIZE_UNIT = 549, // Acquisition buffer size unit in bytes. Default 1. E.g. Value 1024 means that buffer_size is in KiBytes + CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_SIZE = 550, // Acquisition transport buffer size in bytes + CAP_PROP_XI_BUFFERS_QUEUE_SIZE = 551, // Queue of field/frame buffers + CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_COMMIT = 552, // Number of buffers to commit to low level + CAP_PROP_XI_RECENT_FRAME = 553, // GetImage returns most recent frame + CAP_PROP_XI_DEVICE_RESET = 554, // Resets the camera to default state. + CAP_PROP_XI_COLUMN_FPN_CORRECTION = 555, // Correction of column FPN + CAP_PROP_XI_ROW_FPN_CORRECTION = 591, // Correction of row FPN + CAP_PROP_XI_SENSOR_MODE = 558, // Current sensor mode. Allows to select sensor mode by one integer. Setting of this parameter affects: image dimensions and downsampling. + CAP_PROP_XI_HDR = 559, // Enable High Dynamic Range feature. + CAP_PROP_XI_HDR_KNEEPOINT_COUNT = 560, // The number of kneepoints in the PWLR. + CAP_PROP_XI_HDR_T1 = 561, // position of first kneepoint(in % of XI_PRM_EXPOSURE) + CAP_PROP_XI_HDR_T2 = 562, // position of second kneepoint (in % of XI_PRM_EXPOSURE) + CAP_PROP_XI_KNEEPOINT1 = 563, // value of first kneepoint (% of sensor saturation) + CAP_PROP_XI_KNEEPOINT2 = 564, // value of second kneepoint (% of sensor saturation) + CAP_PROP_XI_IMAGE_BLACK_LEVEL = 565, // Last image black level counts. Can be used for Offline processing to recall it. + CAP_PROP_XI_HW_REVISION = 571, // Returns hardware revision number. + CAP_PROP_XI_DEBUG_LEVEL = 572, // Set debug level + CAP_PROP_XI_AUTO_BANDWIDTH_CALCULATION = 573, // Automatic bandwidth calculation, + CAP_PROP_XI_FFS_FILE_ID = 594, // File number. + CAP_PROP_XI_FFS_FILE_SIZE = 580, // Size of file. + CAP_PROP_XI_FREE_FFS_SIZE = 581, // Size of free camera FFS. + CAP_PROP_XI_USED_FFS_SIZE = 582, // Size of used camera FFS. + CAP_PROP_XI_FFS_ACCESS_KEY = 583, // Setting of key enables file operations on some cameras. + CAP_PROP_XI_SENSOR_FEATURE_SELECTOR = 585, // Selects the current feature which is accessible by XI_PRM_SENSOR_FEATURE_VALUE. + CAP_PROP_XI_SENSOR_FEATURE_VALUE = 586, // Allows access to sensor feature value currently selected by XI_PRM_SENSOR_FEATURE_SELECTOR. }; + // Properties of cameras available through AVFOUNDATION interface enum { CAP_PROP_IOS_DEVICE_FOCUS = 9001, CAP_PROP_IOS_DEVICE_EXPOSURE = 9002, diff --git a/modules/videoio/include/opencv2/videoio/videoio_c.h b/modules/videoio/include/opencv2/videoio/videoio_c.h index 47f46fa76a..8d2af30210 100644 --- a/modules/videoio/include/opencv2/videoio/videoio_c.h +++ b/modules/videoio/include/opencv2/videoio/videoio_c.h @@ -274,6 +274,8 @@ enum CV_CAP_PROP_XI_DECIMATION_VERTICAL = 432, // Vertical Decimation - vertical sub-sampling of the image - reduces the vertical resolution of the image by the specified vertical decimation factor. CV_CAP_PROP_XI_DECIMATION_HORIZONTAL = 433, // Horizontal Decimation - horizontal sub-sampling of the image - reduces the horizontal resolution of the image by the specified vertical decimation factor. CV_CAP_PROP_XI_DECIMATION_PATTERN = 434, // Decimation pattern type. + CV_CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR = 587, // Selects which test pattern generator is controlled by the TestPattern feature. + CV_CAP_PROP_XI_TEST_PATTERN = 588, // Selects which test pattern type is generated by the selected generator. CV_CAP_PROP_XI_IMAGE_DATA_FORMAT = 435, // Output data format. CV_CAP_PROP_XI_SHUTTER_TYPE = 436, // Change sensor shutter type(CMOS sensor). CV_CAP_PROP_XI_SENSOR_TAPS = 437, // Number of taps @@ -287,6 +289,8 @@ enum CV_CAP_PROP_XI_WB_KB = 450, // White balance blue coefficient CV_CAP_PROP_XI_WIDTH = 451, // Width of the Image provided by the device (in pixels). CV_CAP_PROP_XI_HEIGHT = 452, // Height of the Image provided by the device (in pixels). + CV_CAP_PROP_XI_REGION_SELECTOR = 589, // Selects Region in Multiple ROI which parameters are set by width, height, ... ,region mode + CV_CAP_PROP_XI_REGION_MODE = 595, // Activates/deactivates Region selected by Region Selector CV_CAP_PROP_XI_LIMIT_BANDWIDTH = 459, // Set/get bandwidth(datarate)(in Megabits) CV_CAP_PROP_XI_SENSOR_DATA_BIT_DEPTH = 460, // Sensor output data bit depth. CV_CAP_PROP_XI_OUTPUT_DATA_BIT_DEPTH = 461, // Device output data bit depth. @@ -298,6 +302,7 @@ enum CV_CAP_PROP_XI_TARGET_TEMP = 467, // Set sensor target temperature for cooling. CV_CAP_PROP_XI_CHIP_TEMP = 468, // Camera sensor temperature CV_CAP_PROP_XI_HOUS_TEMP = 469, // Camera housing tepmerature + CV_CAP_PROP_XI_HOUS_BACK_SIDE_TEMP = 590, // Camera housing back side tepmerature CV_CAP_PROP_XI_CMS = 470, // Mode of color management system. CV_CAP_PROP_XI_APPLY_CMS = 471, // Enable applying of CMS profiles to xiGetImage (see XI_PRM_INPUT_CMS_PROFILE, XI_PRM_OUTPUT_CMS_PROFILE). CV_CAP_PROP_XI_IMAGE_IS_COLOR = 474, // Returns 1 for color cameras. @@ -365,6 +370,7 @@ enum CV_CAP_PROP_XI_RECENT_FRAME = 553, // GetImage returns most recent frame CV_CAP_PROP_XI_DEVICE_RESET = 554, // Resets the camera to default state. CV_CAP_PROP_XI_COLUMN_FPN_CORRECTION = 555, // Correction of column FPN + CV_CAP_PROP_XI_ROW_FPN_CORRECTION = 591, // Correction of row FPN CV_CAP_PROP_XI_SENSOR_MODE = 558, // Current sensor mode. Allows to select sensor mode by one integer. Setting of this parameter affects: image dimensions and downsampling. CV_CAP_PROP_XI_HDR = 559, // Enable High Dynamic Range feature. CV_CAP_PROP_XI_HDR_KNEEPOINT_COUNT = 560, // The number of kneepoints in the PWLR. @@ -376,6 +382,8 @@ enum CV_CAP_PROP_XI_HW_REVISION = 571, // Returns hardware revision number. CV_CAP_PROP_XI_DEBUG_LEVEL = 572, // Set debug level CV_CAP_PROP_XI_AUTO_BANDWIDTH_CALCULATION = 573, // Automatic bandwidth calculation, + CV_CAP_PROP_XI_FFS_FILE_ID = 594, // File number. + CV_CAP_PROP_XI_FFS_FILE_SIZE = 580, // Size of file. CV_CAP_PROP_XI_FREE_FFS_SIZE = 581, // Size of free camera FFS. CV_CAP_PROP_XI_USED_FFS_SIZE = 582, // Size of used camera FFS. CV_CAP_PROP_XI_FFS_ACCESS_KEY = 583, // Setting of key enables file operations on some cameras. diff --git a/modules/videoio/src/cap_ximea.cpp b/modules/videoio/src/cap_ximea.cpp index e111e69b7a..cf0a016fb7 100644 --- a/modules/videoio/src/cap_ximea.cpp +++ b/modules/videoio/src/cap_ximea.cpp @@ -399,6 +399,16 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) value_type = xiTypeEnum; doAcqReset = true; break; + case CV_CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR: + ximea_param = "test_pattern_generator_selector"; + value_type = xiTypeEnum; + doAcqReset = true; + break; + case CV_CAP_PROP_XI_TEST_PATTERN: + ximea_param = "test_pattern"; + value_type = xiTypeEnum; + doAcqReset = true; + break; case CV_CAP_PROP_XI_IMAGE_DATA_FORMAT: ximea_param = "imgdataformat"; value_type = xiTypeEnum; @@ -478,6 +488,16 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) value_type = xiTypeInteger; doAcqReset = true; break; + case CV_CAP_PROP_XI_REGION_SELECTOR : + ximea_param = "region_selector"; + value_type = xiTypeInteger; + doAcqReset = true; + break; + case CV_CAP_PROP_XI_REGION_MODE : + ximea_param = "region_mode"; + value_type = xiTypeInteger; + doAcqReset = true; + break; case CV_CAP_PROP_XI_EXP_PRIORITY: ximea_param = "exp_priority"; value_type = xiTypeFloat; @@ -544,6 +564,10 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) ximea_param = "hous_temp"; value_type = xiTypeFloat; break; + case CV_CAP_PROP_XI_HOUS_BACK_SIDE_TEMP: + ximea_param = "hous_back_side_temp"; + value_type = xiTypeFloat; + break; case CV_CAP_PROP_XI_CMS: ximea_param = "cms"; value_type = xiTypeEnum; @@ -820,22 +844,27 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) case CV_CAP_PROP_XI_ACQ_BUFFER_SIZE: ximea_param = "acq_buffer_size"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_ACQ_BUFFER_SIZE_UNIT: ximea_param = "acq_buffer_size_unit"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_SIZE: ximea_param = "acq_transport_buffer_size"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_BUFFERS_QUEUE_SIZE: ximea_param = "buffers_queue_size"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_COMMIT: ximea_param = "acq_transport_buffer_commit"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_RECENT_FRAME: ximea_param = "recent_frame"; @@ -850,6 +879,10 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) ximea_param = "column_fpn_correction"; value_type = xiTypeEnum; break; + case CV_CAP_PROP_XI_ROW_FPN_CORRECTION: + ximea_param = "row_fpn_correction"; + value_type = xiTypeEnum; + break; case CV_CAP_PROP_XI_SENSOR_MODE: ximea_param = "sensor_mode"; value_type = xiTypeEnum; @@ -894,6 +927,14 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) ximea_param = "auto_bandwidth_calculation"; value_type = xiTypeBoolean; break; + case CV_CAP_PROP_XI_FFS_FILE_ID: + ximea_param = "ffs_file_id"; + value_type = xiTypeInteger; + break; + case CV_CAP_PROP_XI_FFS_FILE_SIZE: + ximea_param = "ffs_file_size"; + value_type = xiTypeInteger; + break; case CV_CAP_PROP_XI_FREE_FFS_SIZE: ximea_param = "free_ffs_size"; value_type = xiTypeInteger; @@ -1042,6 +1083,14 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id ) const ximea_param = "decimation_pattern"; value_type = xiTypeEnum; break; + case CV_CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR: + ximea_param = "test_pattern_generator_selector"; + value_type = xiTypeEnum; + break; + case CV_CAP_PROP_XI_TEST_PATTERN: + ximea_param = "test_pattern"; + value_type = xiTypeEnum; + break; case CV_CAP_PROP_XI_IMAGE_DATA_FORMAT: ximea_param = "imgdataformat"; value_type = xiTypeEnum; @@ -1114,6 +1163,14 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id ) const ximea_param = "offsetY"; value_type = xiTypeInteger; break; + case CV_CAP_PROP_XI_REGION_SELECTOR : + ximea_param = "region_selector"; + value_type = xiTypeInteger; + break; + case CV_CAP_PROP_XI_REGION_MODE : + ximea_param = "region_mode"; + value_type = xiTypeInteger; + break; case CV_CAP_PROP_XI_EXP_PRIORITY: ximea_param = "exp_priority"; value_type = xiTypeFloat; @@ -1174,6 +1231,10 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id ) const ximea_param = "hous_temp"; value_type = xiTypeFloat; break; + case CV_CAP_PROP_XI_HOUS_BACK_SIDE_TEMP: + ximea_param = "hous_back_side_temp"; + value_type = xiTypeFloat; + break; case CV_CAP_PROP_XI_CMS: ximea_param = "cms"; value_type = xiTypeEnum; @@ -1478,6 +1539,10 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id ) const ximea_param = "column_fpn_correction"; value_type = xiTypeEnum; break; + case CV_CAP_PROP_XI_ROW_FPN_CORRECTION: + ximea_param = "row_fpn_correction"; + value_type = xiTypeEnum; + break; case CV_CAP_PROP_XI_SENSOR_MODE: ximea_param = "sensor_mode"; value_type = xiTypeEnum; @@ -1522,6 +1587,14 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id ) const ximea_param = "auto_bandwidth_calculation"; value_type = xiTypeBoolean; break; + case CV_CAP_PROP_XI_FFS_FILE_ID: + ximea_param = "ffs_file_id"; + value_type = xiTypeInteger; + break; + case CV_CAP_PROP_XI_FFS_FILE_SIZE: + ximea_param = "ffs_file_size"; + value_type = xiTypeInteger; + break; case CV_CAP_PROP_XI_FREE_FFS_SIZE: ximea_param = "free_ffs_size"; value_type = xiTypeInteger; @@ -1640,6 +1713,7 @@ void CvCaptureCAM_XIMEA::errMsg(const char* msg, int errNum) const case XI_BUFFER_SIZE_TOO_SMALL : error_message = "Buffer provided by user is too small"; break; case XI_COULDNT_INIT_PROCESSOR : error_message = "Couldnt initialize processor."; break; case XI_NOT_INITIALIZED : error_message = "The object/module/procedure/process being referred to has not been started."; break; + case XI_RESOURCE_NOT_FOUND : error_message = "Resource not found(could be processor, file, item..)."; break; case XI_UNKNOWN_PARAM : error_message = "Unknown parameter"; break; case XI_WRONG_PARAM_VALUE : error_message = "Wrong parameter value"; break; case XI_WRONG_PARAM_TYPE : error_message = "Wrong parameter type"; break; From de8b3ee231f8e730c01acb5d2c57a8b4b554ddcb Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 9 Feb 2016 14:24:56 +0300 Subject: [PATCH 124/468] cmake: add timestamp into build info log (6089) --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7be7259dde..6ec4f518fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -759,6 +759,12 @@ endif() # ========================== build platform ========================== status("") status(" Platform:") +if(NOT CMAKE_VERSION VERSION_LESS 2.8.11 AND NOT BUILD_INFO_SKIP_TIMESTAMP) + string(TIMESTAMP TIMESTAMP "" UTC) + if(TIMESTAMP) + status(" Timestamp:" ${TIMESTAMP}) + endif() +endif() status(" Host:" ${CMAKE_HOST_SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_VERSION} ${CMAKE_HOST_SYSTEM_PROCESSOR}) if(CMAKE_CROSSCOMPILING) status(" Target:" ${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_VERSION} ${CMAKE_SYSTEM_PROCESSOR}) From 1dac67f0137ec387022d285b1ba95e5d8f03a69e Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 9 Feb 2016 14:36:42 +0300 Subject: [PATCH 125/468] cmake: add version control revision info for extra modules --- CMakeLists.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ec4f518fc..89756b14d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -755,6 +755,36 @@ status("General configuration for OpenCV ${OPENCV_VERSION} ===================== if(OPENCV_VCSVERSION) status(" Version control:" ${OPENCV_VCSVERSION}) endif() +if(OPENCV_EXTRA_MODULES_PATH AND NOT BUILD_INFO_SKIP_EXTRA_MODULES) + set(__dump_extra_header OFF) + foreach(p ${OPENCV_EXTRA_MODULES_PATH}) + if(EXISTS ${p}) + if(NOT __dump_extra_header) + set(__dump_extra_header ON) + status("") + status(" Extra modules:") + else() + status("") + endif() + set(EXTRA_MODULES_VCSVERSION "unknown") + if(GIT_FOUND) + execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "[0-9].[0-9].[0-9]*" + WORKING_DIRECTORY "${p}" + OUTPUT_VARIABLE EXTRA_MODULES_VCSVERSION + RESULT_VARIABLE GIT_RESULT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(NOT GIT_RESULT EQUAL 0) + set(EXTRA_MODULES_VCSVERSION "unknown") + endif() + endif() + status(" Location (extra):" ${p}) + status(" Version control (extra):" ${EXTRA_MODULES_VCSVERSION}) + endif() + endforeach() + unset(__dump_extra_header) +endif() # ========================== build platform ========================== status("") From 9ac35173e32471a8485e303c0e14be99060bb074 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 9 Feb 2016 14:44:05 +0300 Subject: [PATCH 126/468] cmake: remove non-ascii symbols --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89756b14d7..0065507b33 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -693,7 +693,7 @@ include(cmake/OpenCVGenPkgconfig.cmake) # Generate OpenCV.mk for ndk-build (Android build tool) include(cmake/OpenCVGenAndroidMK.cmake) -# Generate OpenCVСonfig.cmake and OpenCVConfig-version.cmake for cmake projects +# Generate OpenCVConfig.cmake and OpenCVConfig-version.cmake for cmake projects include(cmake/OpenCVGenConfig.cmake) # Generate Info.plist for the IOS framework From 6a0d3b3e42a1afd8f63b7e4b290c8227b93d7735 Mon Sep 17 00:00:00 2001 From: Mathieu Barnachon Date: Tue, 9 Feb 2016 14:40:09 +0100 Subject: [PATCH 127/468] Called after setDevice. Wrap in a cudaSafeCall. --- modules/core/src/cuda_info.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/cuda_info.cpp b/modules/core/src/cuda_info.cpp index 08013ca988..b412438581 100644 --- a/modules/core/src/cuda_info.cpp +++ b/modules/core/src/cuda_info.cpp @@ -70,8 +70,8 @@ void cv::cuda::setDevice(int device) (void) device; throw_no_cuda(); #else - cudaFree(0); cudaSafeCall( cudaSetDevice(device) ); + cudaSafeCall( cudaFree(0) ); #endif } From a2f0963d66a7a7cfdb1771e4936cf63b69aa0d05 Mon Sep 17 00:00:00 2001 From: "joao.faro" Date: Wed, 2 Sep 2015 17:14:40 +0100 Subject: [PATCH 128/468] SVMSGD class added --- doc/opencv.bib | 18 ++- modules/ml/include/opencv2/ml.hpp | 121 ++++++++++++++++++ modules/ml/src/svmsgd.cpp | 201 ++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+), 10 deletions(-) create mode 100644 modules/ml/src/svmsgd.cpp diff --git a/doc/opencv.bib b/doc/opencv.bib index 021c5b4b3f..17eedf7172 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -415,16 +415,6 @@ pages = {2548--2555}, organization = {IEEE} } -@ARTICLE{Louhichi07, - author = {Louhichi, H. and Fournel, T. and Lavest, J. M. and Ben Aissia, H.}, - title = {Self-calibration of Scheimpflug cameras: an easy protocol}, - year = {2007}, - pages = {2616–2622}, - journal = {Meas. Sci. Technol.}, - volume = {18}, - number = {8}, - publisher = {IOP Publishing Ltd} -} @ARTICLE{LibSVM, author = {Chang, Chih-Chung and Lin, Chih-Jen}, title = {LIBSVM: a library for support vector machines}, @@ -874,3 +864,11 @@ year={2007}, organization={IEEE} } +@incollection{bottou2010large, + title={Large-scale machine learning with stochastic gradient descent}, + author={Bottou, L{\'e}on}, + booktitle={Proceedings of COMPSTAT'2010}, + pages={177--186}, + year={2010}, + publisher={Springer} +} \ No newline at end of file diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 7acce7f33c..d5debdbf18 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1513,6 +1513,127 @@ CV_EXPORTS void randMVNormal( InputArray mean, InputArray cov, int nsamples, Out CV_EXPORTS void createConcentricSpheresTestSet( int nsamples, int nfeatures, int nclasses, OutputArray samples, OutputArray responses); +/****************************************************************************************\ +* Stochastic Gradient Descent SVM Classifier * +\****************************************************************************************/ + +/*! +@brief Stochastic Gradient Descent SVM classifier + +SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, as presented in @cite bottou2010large. +The gradient descent show amazing performance for large-scale problems, reducing the computing time. This allows a fast and reliable online update of the classifier for each new feature which +is fundamental when dealing with variations of data over time (like weather and illumination changes in videosurveillance, for example). + +First, create the SVMSGD object. To enable the online update, a value for updateFrequency should be defined. + +Then the SVM model can be trained using the train features and the correspondent labels. + +After that, the label of a new feature vector can be predicted using the predict function. If the updateFrequency was defined in the constructor, the predict function will update the weights automatically. + +@code +// Initialize object +SVMSGD SvmSgd; + +// Train the Stochastic Gradient Descent SVM +SvmSgd.train(trainFeatures, labels); + +// Predict label for the new feature vector (1xM) +predictedLabel = SvmSgd.predict(newFeatureVector); +@endcode + +*/ +class CV_EXPORTS_W SVMSGD { + + public: + /** @brief SGDSVM constructor. + + @param lambda regularization + @param learnRate learning rate + @param nIterations number of training iterations + + */ + SVMSGD(float lambda = 0.000001, float learnRate = 2, uint nIterations = 100000); + + /** @brief SGDSVM constructor. + + @param updateFrequency online update frequency + @param learnRateDecay learn rate decay over time: learnRate = learnRate * learnDecay + @param lambda regularization + @param learnRate learning rate + @param nIterations number of training iterations + + */ + SVMSGD(uint updateFrequency, float learnRateDecay = 1, float lambda = 0.000001, float learnRate = 2, uint nIterations = 100000); + virtual ~SVMSGD(); + virtual SVMSGD* clone() const; + + /** @brief Train the SGDSVM classifier. + + The function trains the SGDSVM classifier using the train features and the correspondent labels (-1 or 1). + + @param trainFeatures features used for training. Each row is a new sample. + @param labels mat (size Nx1 with N = number of features) with the label of each training feature. + + */ + virtual void train(cv::Mat trainFeatures, cv::Mat labels); + + /** @brief Predict the label of a new feature vector. + + The function predicts and returns the label of a new feature vector, using the previously trained SVM model. + + @param newFeature new feature vector used for prediction + + */ + virtual float predict(cv::Mat newFeature); + + /** @brief Returns the weights of the trained model. + + */ + virtual std::vector getWeights(){ return _weights; }; + + /** @brief Sets the weights of the trained model. + + @param weights weights used to predict the label of a new feature vector. + + */ + virtual void setWeights(std::vector weights){ _weights = weights; }; + + private: + void updateWeights(); + void generateRandomIndex(); + float calcInnerProduct(float *rowDataPointer); + void updateWeights(float innerProduct, float *rowDataPointer, int label); + + // Vector with SVM weights + std::vector _weights; + + // Random index generation + long long int _randomNumber; + unsigned int _randomIndex; + + // Number of features and samples + unsigned int _nFeatures; + unsigned int _nTrainSamples; + + // Parameters for learning + float _lambda; //regularization + float _learnRate; //learning rate + unsigned int _nIterations; //number of training iterations + + // Vars to control the features slider matrix + bool _onlineUpdate; + bool _initPredict; + uint _slidingWindowSize; + uint _predictSlidingWindowSize; + float* _labelSlider; + float _learnRateDecay; + + // Mat with features slider and correspondent counter + unsigned int _sliderCounter; + cv::Mat _featuresSlider; + +}; + //! @} ml } diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp new file mode 100644 index 0000000000..3114e43d9f --- /dev/null +++ b/modules/ml/src/svmsgd.cpp @@ -0,0 +1,201 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Copyright (C) 2014, Itseez Inc, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "precomp.hpp" + +/****************************************************************************************\ +* Stochastic Gradient Descent SVM Classifier * +\****************************************************************************************/ + +namespace cv { +namespace ml { + +SVMSGD::SVMSGD(float lambda, float learnRate, uint nIterations){ + + // Initialize with random seed + _randomNumber = 1; + + // Initialize constants + _slidingWindowSize = 0; + _nFeatures = 0; + _predictSlidingWindowSize = 1; + + // Initialize sliderCounter at index 0 + _sliderCounter = 0; + + // Parameters for learning + _lambda = lambda; // regularization + _learnRate = learnRate; // learning rate (ideally should be large at beginning and decay each iteration) + _nIterations = nIterations; // number of training iterations + + // True only in the first predict iteration + _initPredict = true; + + // Online update flag + _onlineUpdate = false; +} + +SVMSGD::SVMSGD(uint updateFrequency, float learnRateDecay, float lambda, float learnRate, uint nIterations){ + + // Initialize with random seed + _randomNumber = 1; + + // Initialize constants + _slidingWindowSize = 0; + _nFeatures = 0; + _predictSlidingWindowSize = updateFrequency; + + // Initialize sliderCounter at index 0 + _sliderCounter = 0; + + // Parameters for learning + _lambda = lambda; // regularization + _learnRate = learnRate; // learning rate (ideally should be large at beginning and decay each iteration) + _nIterations = nIterations; // number of training iterations + + // True only in the first predict iteration + _initPredict = true; + + // Online update flag + _onlineUpdate = true; + + // Learn rate decay: _learnRate = _learnRate * _learnDecay + _learnRateDecay = learnRateDecay; +} + +SVMSGD::~SVMSGD(){ + +} + +SVMSGD* SVMSGD::clone() const{ + return new SVMSGD(*this); +} + +void SVMSGD::train(cv::Mat trainFeatures, cv::Mat labels){ + + // Initialize _nFeatures + _slidingWindowSize = trainFeatures.rows; + _nFeatures = trainFeatures.cols; + + float innerProduct; + // Initialize weights vector with zeros + if (_weights.size()==0){ + _weights.reserve(_nFeatures); + for (uint feat = 0; feat < _nFeatures; ++feat){ + _weights.push_back(0.0); + } + } + + // Stochastic gradient descent SVM + for (uint iter = 0; iter < _nIterations; ++iter){ + generateRandomIndex(); + innerProduct = calcInnerProduct(trainFeatures.ptr(_randomIndex)); + int label = (labels.at(_randomIndex,0) > 0) ? 1 : -1; // ensure that labels are -1 or 1 + updateWeights(innerProduct, trainFeatures.ptr(_randomIndex), label ); + } +} + +float SVMSGD::predict(cv::Mat newFeature){ + float innerProduct; + + if (_initPredict){ + _nFeatures = newFeature.cols; + _slidingWindowSize = _predictSlidingWindowSize; + _featuresSlider = cv::Mat::zeros(_slidingWindowSize, _nFeatures, CV_32F); + _initPredict = false; + _labelSlider = new float[_predictSlidingWindowSize](); + _learnRate = _learnRate * _learnRateDecay; + } + + innerProduct = calcInnerProduct(newFeature.ptr(0)); + + // Resultant label (-1 or 1) + int label = (innerProduct>=0) ? 1 : -1; + + if (_onlineUpdate){ + // Update the featuresSlider with newFeature and _labelSlider with label + newFeature.row(0).copyTo(_featuresSlider.row(_sliderCounter)); + _labelSlider[_sliderCounter] = float(label); + + // Update weights with a random index + if (_sliderCounter == _slidingWindowSize-1){ + generateRandomIndex(); + updateWeights(innerProduct, _featuresSlider.ptr(_randomIndex), int(_labelSlider[_randomIndex]) ); + } + + // _sliderCounter++ if < _slidingWindowSize + _sliderCounter = (_sliderCounter == _slidingWindowSize-1) ? 0 : (_sliderCounter+1); + } + + return float(label); +} + +void SVMSGD::generateRandomIndex(){ + // Choose random sample, using Mikolov's fast almost-uniform random number + _randomNumber = _randomNumber * (unsigned long long) 25214903917 + 11; + _randomIndex = uint(_randomNumber % (unsigned long long) _slidingWindowSize); +} + +float SVMSGD::calcInnerProduct(float *rowDataPointer){ + float innerProduct = 0; + for (uint feat = 0; feat < _nFeatures; ++feat){ + innerProduct += _weights[feat] * rowDataPointer[feat]; + } + return innerProduct; +} + +void SVMSGD::updateWeights(float innerProduct, float *rowDataPointer, int label){ + if (label * innerProduct > 1) { + // Not a support vector, only apply weight decay + for (uint feat = 0; feat < _nFeatures; feat++) { + _weights[feat] -= _learnRate * _lambda * _weights[feat]; + } + } else { + // It's a support vector, add it to the weights + for (uint feat = 0; feat < _nFeatures; feat++) { + _weights[feat] -= _learnRate * (_lambda * _weights[feat] - label * rowDataPointer[feat]); + } + } +} + +} +} From 40bf97c6d11a8144f212a07e4ff1eff0eaa9d1a7 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 20 Jan 2016 12:59:44 +0300 Subject: [PATCH 129/468] Refactored SVMSGD class --- include/opencv2/opencv.hpp | 1 + modules/ml/include/opencv2/ml.hpp | 120 ------ modules/ml/include/opencv2/ml/svmsgd.hpp | 134 ++++++ modules/ml/src/precomp.hpp | 2 +- modules/ml/src/svmsgd.cpp | 503 +++++++++++++++++------ modules/ml/test/test_mltests2.cpp | 31 +- modules/ml/test/test_precomp.hpp | 3 + modules/ml/test/test_save_load.cpp | 17 +- modules/ml/test/test_svmsgd.cpp | 182 ++++++++ modules/ts/src/ts_gtest.cpp | 2 +- samples/cpp/train_svmsgd.cpp | 226 ++++++++++ 11 files changed, 980 insertions(+), 241 deletions(-) create mode 100644 modules/ml/include/opencv2/ml/svmsgd.hpp create mode 100644 modules/ml/test/test_svmsgd.cpp create mode 100644 samples/cpp/train_svmsgd.cpp diff --git a/include/opencv2/opencv.hpp b/include/opencv2/opencv.hpp index 49b6a6691f..e411621d0c 100644 --- a/include/opencv2/opencv.hpp +++ b/include/opencv2/opencv.hpp @@ -75,6 +75,7 @@ #endif #ifdef HAVE_OPENCV_ML #include "opencv2/ml.hpp" +#include "opencv2/ml/svmsgd.hpp" #endif #endif diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index d5debdbf18..791f580093 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1513,126 +1513,6 @@ CV_EXPORTS void randMVNormal( InputArray mean, InputArray cov, int nsamples, Out CV_EXPORTS void createConcentricSpheresTestSet( int nsamples, int nfeatures, int nclasses, OutputArray samples, OutputArray responses); -/****************************************************************************************\ -* Stochastic Gradient Descent SVM Classifier * -\****************************************************************************************/ - -/*! -@brief Stochastic Gradient Descent SVM classifier - -SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, as presented in @cite bottou2010large. -The gradient descent show amazing performance for large-scale problems, reducing the computing time. This allows a fast and reliable online update of the classifier for each new feature which -is fundamental when dealing with variations of data over time (like weather and illumination changes in videosurveillance, for example). - -First, create the SVMSGD object. To enable the online update, a value for updateFrequency should be defined. - -Then the SVM model can be trained using the train features and the correspondent labels. - -After that, the label of a new feature vector can be predicted using the predict function. If the updateFrequency was defined in the constructor, the predict function will update the weights automatically. - -@code -// Initialize object -SVMSGD SvmSgd; - -// Train the Stochastic Gradient Descent SVM -SvmSgd.train(trainFeatures, labels); - -// Predict label for the new feature vector (1xM) -predictedLabel = SvmSgd.predict(newFeatureVector); -@endcode - -*/ -class CV_EXPORTS_W SVMSGD { - - public: - /** @brief SGDSVM constructor. - - @param lambda regularization - @param learnRate learning rate - @param nIterations number of training iterations - - */ - SVMSGD(float lambda = 0.000001, float learnRate = 2, uint nIterations = 100000); - - /** @brief SGDSVM constructor. - - @param updateFrequency online update frequency - @param learnRateDecay learn rate decay over time: learnRate = learnRate * learnDecay - @param lambda regularization - @param learnRate learning rate - @param nIterations number of training iterations - - */ - SVMSGD(uint updateFrequency, float learnRateDecay = 1, float lambda = 0.000001, float learnRate = 2, uint nIterations = 100000); - virtual ~SVMSGD(); - virtual SVMSGD* clone() const; - - /** @brief Train the SGDSVM classifier. - - The function trains the SGDSVM classifier using the train features and the correspondent labels (-1 or 1). - - @param trainFeatures features used for training. Each row is a new sample. - @param labels mat (size Nx1 with N = number of features) with the label of each training feature. - - */ - virtual void train(cv::Mat trainFeatures, cv::Mat labels); - - /** @brief Predict the label of a new feature vector. - - The function predicts and returns the label of a new feature vector, using the previously trained SVM model. - - @param newFeature new feature vector used for prediction - - */ - virtual float predict(cv::Mat newFeature); - - /** @brief Returns the weights of the trained model. - - */ - virtual std::vector getWeights(){ return _weights; }; - - /** @brief Sets the weights of the trained model. - - @param weights weights used to predict the label of a new feature vector. - - */ - virtual void setWeights(std::vector weights){ _weights = weights; }; - - private: - void updateWeights(); - void generateRandomIndex(); - float calcInnerProduct(float *rowDataPointer); - void updateWeights(float innerProduct, float *rowDataPointer, int label); - - // Vector with SVM weights - std::vector _weights; - - // Random index generation - long long int _randomNumber; - unsigned int _randomIndex; - - // Number of features and samples - unsigned int _nFeatures; - unsigned int _nTrainSamples; - - // Parameters for learning - float _lambda; //regularization - float _learnRate; //learning rate - unsigned int _nIterations; //number of training iterations - - // Vars to control the features slider matrix - bool _onlineUpdate; - bool _initPredict; - uint _slidingWindowSize; - uint _predictSlidingWindowSize; - float* _labelSlider; - float _learnRateDecay; - - // Mat with features slider and correspondent counter - unsigned int _sliderCounter; - cv::Mat _featuresSlider; - -}; //! @} ml diff --git a/modules/ml/include/opencv2/ml/svmsgd.hpp b/modules/ml/include/opencv2/ml/svmsgd.hpp new file mode 100644 index 0000000000..f61a905963 --- /dev/null +++ b/modules/ml/include/opencv2/ml/svmsgd.hpp @@ -0,0 +1,134 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Copyright (C) 2014, Itseez Inc, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_ML_SVMSGD_HPP__ +#define __OPENCV_ML_SVMSGD_HPP__ + +#ifdef __cplusplus + +#include "opencv2/ml.hpp" + +namespace cv +{ +namespace ml +{ + + +/****************************************************************************************\ +* Stochastic Gradient Descent SVM Classifier * +\****************************************************************************************/ + +/*! +@brief Stochastic Gradient Descent SVM classifier + +SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, as presented in @cite bottou2010large. +The gradient descent show amazing performance for large-scale problems, reducing the computing time. This allows a fast and reliable online update of the classifier for each new feature which +is fundamental when dealing with variations of data over time (like weather and illumination changes in videosurveillance, for example). + +First, create the SVMSGD object. To enable the online update, a value for updateFrequency should be defined. + +Then the SVM model can be trained using the train features and the correspondent labels. + +After that, the label of a new feature vector can be predicted using the predict function. If the updateFrequency was defined in the constructor, the predict function will update the weights automatically. + +@code +// Initialize object +SVMSGD SvmSgd; + +// Train the Stochastic Gradient Descent SVM +SvmSgd.train(trainFeatures, labels); + +// Predict label for the new feature vector (1xM) +predictedLabel = SvmSgd.predict(newFeatureVector); +@endcode + +*/ + +class CV_EXPORTS_W SVMSGD : public cv::ml::StatModel +{ +public: + + enum SvmsgdType + { + ILLEGAL_VALUE, + SGD, //Stochastic Gradient Descent + ASGD //Average Stochastic Gradient Descent + }; + + /** + * @return the weights of the trained model. + */ + CV_WRAP virtual Mat getWeights() = 0; + + CV_WRAP virtual float getShift() = 0; + + CV_WRAP static Ptr create(); + + CV_WRAP virtual void setOptimalParameters(int type = ASGD) = 0; + + CV_WRAP virtual int getType() const = 0; + + CV_WRAP virtual void setType(int type) = 0; + + CV_WRAP virtual float getLambda() const = 0; + + CV_WRAP virtual void setLambda(float lambda) = 0; + + CV_WRAP virtual float getGamma0() const = 0; + + CV_WRAP virtual void setGamma0(float gamma0) = 0; + + CV_WRAP virtual float getC() const = 0; + + CV_WRAP virtual void setC(float c) = 0; + + CV_WRAP virtual cv::TermCriteria getTermCriteria() const = 0; + + CV_WRAP virtual void setTermCriteria(const cv::TermCriteria &val) = 0; +}; + +} //ml +} //cv + +#endif // __clpusplus +#endif // __OPENCV_ML_SVMSGD_HPP diff --git a/modules/ml/src/precomp.hpp b/modules/ml/src/precomp.hpp index 84821988b6..9318e4a78c 100644 --- a/modules/ml/src/precomp.hpp +++ b/modules/ml/src/precomp.hpp @@ -45,7 +45,7 @@ #include "opencv2/ml.hpp" #include "opencv2/core/core_c.h" #include "opencv2/core/utility.hpp" - +#include "opencv2/ml/svmsgd.hpp" #include "opencv2/core/private.hpp" #include diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 3114e43d9f..91377cfc4f 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -41,161 +41,430 @@ //M*/ #include "precomp.hpp" +#include "limits" /****************************************************************************************\ * Stochastic Gradient Descent SVM Classifier * \****************************************************************************************/ -namespace cv { -namespace ml { +namespace cv +{ +namespace ml +{ -SVMSGD::SVMSGD(float lambda, float learnRate, uint nIterations){ +class SVMSGDImpl : public SVMSGD +{ - // Initialize with random seed - _randomNumber = 1; +public: + SVMSGDImpl(); - // Initialize constants - _slidingWindowSize = 0; - _nFeatures = 0; - _predictSlidingWindowSize = 1; + virtual ~SVMSGDImpl() {} - // Initialize sliderCounter at index 0 - _sliderCounter = 0; + virtual bool train(const Ptr& data, int); + + virtual float predict( InputArray samples, OutputArray results=noArray(), int flags = 0 ) const; + + virtual bool isClassifier() const { return params.svmsgdType == SGD || params.svmsgdType == ASGD; } + + virtual bool isTrained() const; + + virtual void clear(); + + virtual void write(FileStorage& fs) const; + + virtual void read(const FileNode& fn); + + virtual Mat getWeights(){ return weights_; } + + virtual float getShift(){ return shift_; } + + virtual int getVarCount() const { return weights_.cols; } + + virtual String getDefaultName() const {return "opencv_ml_svmsgd";} + + virtual void setOptimalParameters(int type = ASGD); + + virtual int getType() const; + + virtual void setType(int type); + + CV_IMPL_PROPERTY(float, Lambda, params.lambda) + CV_IMPL_PROPERTY(float, Gamma0, params.gamma0) + CV_IMPL_PROPERTY(float, C, params.c) + CV_IMPL_PROPERTY_S(cv::TermCriteria, TermCriteria, params.termCrit) + + private: + void updateWeights(InputArray sample, bool is_first_class, float gamma); + float calcShift(InputArray trainSamples, InputArray trainResponses) const; + std::pair areClassesEmpty(Mat responses); + void writeParams( FileStorage& fs ) const; + void readParams( const FileNode& fn ); + static inline bool isFirstClass(float val) { return val > 0; } + + + // Vector with SVM weights + Mat weights_; + float shift_; + + // Random index generation + RNG rng_; // Parameters for learning - _lambda = lambda; // regularization - _learnRate = learnRate; // learning rate (ideally should be large at beginning and decay each iteration) - _nIterations = nIterations; // number of training iterations + struct SVMSGDParams + { + float lambda; //regularization + float gamma0; //learning rate + float c; + TermCriteria termCrit; + SvmsgdType svmsgdType; + }; - // True only in the first predict iteration - _initPredict = true; + SVMSGDParams params; +}; - // Online update flag - _onlineUpdate = false; +Ptr SVMSGD::create() +{ + return makePtr(); } -SVMSGD::SVMSGD(uint updateFrequency, float learnRateDecay, float lambda, float learnRate, uint nIterations){ - // Initialize with random seed - _randomNumber = 1; +bool SVMSGDImpl::train(const Ptr& data, int) +{ + clear(); - // Initialize constants - _slidingWindowSize = 0; - _nFeatures = 0; - _predictSlidingWindowSize = updateFrequency; + Mat trainSamples = data->getTrainSamples(); - // Initialize sliderCounter at index 0 - _sliderCounter = 0; + // Initialize varCount + int trainSamplesCount_ = trainSamples.rows; + int varCount = trainSamples.cols; - // Parameters for learning - _lambda = lambda; // regularization - _learnRate = learnRate; // learning rate (ideally should be large at beginning and decay each iteration) - _nIterations = nIterations; // number of training iterations - - // True only in the first predict iteration - _initPredict = true; - - // Online update flag - _onlineUpdate = true; - - // Learn rate decay: _learnRate = _learnRate * _learnDecay - _learnRateDecay = learnRateDecay; -} - -SVMSGD::~SVMSGD(){ - -} - -SVMSGD* SVMSGD::clone() const{ - return new SVMSGD(*this); -} - -void SVMSGD::train(cv::Mat trainFeatures, cv::Mat labels){ - - // Initialize _nFeatures - _slidingWindowSize = trainFeatures.rows; - _nFeatures = trainFeatures.cols; - - float innerProduct; // Initialize weights vector with zeros - if (_weights.size()==0){ - _weights.reserve(_nFeatures); - for (uint feat = 0; feat < _nFeatures; ++feat){ - _weights.push_back(0.0); - } + weights_ = Mat::zeros(1, varCount, CV_32F); + + Mat trainResponses = data->getTrainResponses(); // (trainSamplesCount x 1) matrix + + std::pair are_empty = areClassesEmpty(trainResponses); + + if ( are_empty.first && are_empty.second ) + { + weights_.release(); + return false; + } + if ( are_empty.first || are_empty.second ) + { + shift_ = are_empty.first ? -1 : 1; + return true; + } + + + Mat currentSample; + float gamma = 0; + Mat lastWeights = Mat::zeros(1, varCount, CV_32F); //weights vector for calculating terminal criterion + Mat averageWeights; //average weights vector for ASGD model + double err = DBL_MAX; + if (params.svmsgdType == ASGD) + { + averageWeights = Mat::zeros(1, varCount, CV_32F); } // Stochastic gradient descent SVM - for (uint iter = 0; iter < _nIterations; ++iter){ - generateRandomIndex(); - innerProduct = calcInnerProduct(trainFeatures.ptr(_randomIndex)); - int label = (labels.at(_randomIndex,0) > 0) ? 1 : -1; // ensure that labels are -1 or 1 - updateWeights(innerProduct, trainFeatures.ptr(_randomIndex), label ); - } -} + for (int iter = 0; (iter < params.termCrit.maxCount)&&(err > params.termCrit.epsilon); iter++) + { + //generate sample number + int randomNumber = rng_.uniform(0, trainSamplesCount_); -float SVMSGD::predict(cv::Mat newFeature){ - float innerProduct; + currentSample = trainSamples.row(randomNumber); - if (_initPredict){ - _nFeatures = newFeature.cols; - _slidingWindowSize = _predictSlidingWindowSize; - _featuresSlider = cv::Mat::zeros(_slidingWindowSize, _nFeatures, CV_32F); - _initPredict = false; - _labelSlider = new float[_predictSlidingWindowSize](); - _learnRate = _learnRate * _learnRateDecay; - } + //update gamma + gamma = params.gamma0 * std::pow((1 + params.lambda * params.gamma0 * (float)iter), (-params.c)); - innerProduct = calcInnerProduct(newFeature.ptr(0)); + bool is_first_class = isFirstClass(trainResponses.at(randomNumber)); + updateWeights( currentSample, is_first_class, gamma ); - // Resultant label (-1 or 1) - int label = (innerProduct>=0) ? 1 : -1; - - if (_onlineUpdate){ - // Update the featuresSlider with newFeature and _labelSlider with label - newFeature.row(0).copyTo(_featuresSlider.row(_sliderCounter)); - _labelSlider[_sliderCounter] = float(label); - - // Update weights with a random index - if (_sliderCounter == _slidingWindowSize-1){ - generateRandomIndex(); - updateWeights(innerProduct, _featuresSlider.ptr(_randomIndex), int(_labelSlider[_randomIndex]) ); + //average weights (only for ASGD model) + if (params.svmsgdType == ASGD) + { + averageWeights = ((float)iter/ (1 + (float)iter)) * averageWeights + weights_ / (1 + (float) iter); } - // _sliderCounter++ if < _slidingWindowSize - _sliderCounter = (_sliderCounter == _slidingWindowSize-1) ? 0 : (_sliderCounter+1); + err = norm(weights_ - lastWeights); + weights_.copyTo(lastWeights); } - return float(label); -} - -void SVMSGD::generateRandomIndex(){ - // Choose random sample, using Mikolov's fast almost-uniform random number - _randomNumber = _randomNumber * (unsigned long long) 25214903917 + 11; - _randomIndex = uint(_randomNumber % (unsigned long long) _slidingWindowSize); -} - -float SVMSGD::calcInnerProduct(float *rowDataPointer){ - float innerProduct = 0; - for (uint feat = 0; feat < _nFeatures; ++feat){ - innerProduct += _weights[feat] * rowDataPointer[feat]; + if (params.svmsgdType == ASGD) + { + weights_ = averageWeights; } - return innerProduct; + + shift_ = calcShift(trainSamples, trainResponses); + + return true; } -void SVMSGD::updateWeights(float innerProduct, float *rowDataPointer, int label){ - if (label * innerProduct > 1) { +std::pair SVMSGDImpl::areClassesEmpty(Mat responses) +{ + std::pair are_classes_empty(true, true); + int limit_index = responses.rows; + + for(int index = 0; index < limit_index; index++) + { + if (isFirstClass(responses.at(index,0))) + are_classes_empty.first = false; + else + are_classes_empty.second = false; + + if (!are_classes_empty.first && ! are_classes_empty.second) + break; + } + + return are_classes_empty; +} + +float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const +{ + float distance_to_classes[2] = { std::numeric_limits::max(), std::numeric_limits::max() }; + + Mat trainSamples = _samples.getMat(); + int trainSamplesCount = trainSamples.rows; + + Mat trainResponses = _responses.getMat(); + + for (int samplesIndex = 0; samplesIndex < trainSamplesCount; samplesIndex++) + { + Mat currentSample = trainSamples.row(samplesIndex); + float scalar_product = currentSample.dot(weights_); + + bool is_first_class = isFirstClass(trainResponses.at(samplesIndex)); + int index = is_first_class ? 0:1; + float sign_to_mul = is_first_class ? 1 : -1; + float cur_distance = scalar_product * sign_to_mul ; + + if (cur_distance < distance_to_classes[index]) + { + distance_to_classes[index] = cur_distance; + } + } + + //todo: areClassesEmpty(); make const; + return -(distance_to_classes[0] - distance_to_classes[1]) / 2.f; +} + +float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) const +{ + float result = 0; + cv::Mat samples = _samples.getMat(); + int nSamples = samples.rows; + cv::Mat results; + + CV_Assert( samples.cols == weights_.cols && samples.type() == CV_32F ); + + if( _results.needed() ) + { + _results.create( nSamples, 1, samples.type() ); + results = _results.getMat(); + } + else + { + CV_Assert( nSamples == 1 ); + results = Mat(1, 1, CV_32F, &result); + } + + Mat currentSample; + float criterion = 0; + + for (int sampleIndex = 0; sampleIndex < nSamples; sampleIndex++) + { + currentSample = samples.row(sampleIndex); + criterion = currentSample.dot(weights_) + shift_; + results.at(sampleIndex) = (criterion >= 0) ? 1 : -1; + } + + return result; +} + +void SVMSGDImpl::updateWeights(InputArray _sample, bool is_first_class, float gamma) +{ + Mat sample = _sample.getMat(); + + int responce = is_first_class ? 1 : -1; // ensure that trainResponses are -1 or 1 + + if ( sample.dot(weights_) * responce > 1) + { // Not a support vector, only apply weight decay - for (uint feat = 0; feat < _nFeatures; feat++) { - _weights[feat] -= _learnRate * _lambda * _weights[feat]; - } - } else { + weights_ *= (1.f - gamma * params.lambda); + } + else + { // It's a support vector, add it to the weights - for (uint feat = 0; feat < _nFeatures; feat++) { - _weights[feat] -= _learnRate * (_lambda * _weights[feat] - label * rowDataPointer[feat]); - } + weights_ -= (gamma * params.lambda) * weights_ - gamma * responce * sample; + //std::cout << "sample " << sample << std::endl; + //std::cout << "weights_ " << weights_ << std::endl; } } +bool SVMSGDImpl::isTrained() const +{ + return !weights_.empty(); } + +void SVMSGDImpl::write(FileStorage& fs) const +{ + if( !isTrained() ) + CV_Error( CV_StsParseError, "SVMSGD model data is invalid, it hasn't been trained" ); + + writeParams( fs ); + + fs << "shift" << shift_; + fs << "weights" << weights_; } + +void SVMSGDImpl::writeParams( FileStorage& fs ) const +{ + String SvmsgdTypeStr; + + switch (params.svmsgdType) + { + case SGD: + SvmsgdTypeStr = "SGD"; + break; + case ASGD: + SvmsgdTypeStr = "ASGD"; + break; + case ILLEGAL_VALUE: + SvmsgdTypeStr = format("Uknown_%d", params.svmsgdType); + default: + std::cout << "params.svmsgdType isn't initialized" << std::endl; + } + + + fs << "svmsgdType" << SvmsgdTypeStr; + + fs << "lambda" << params.lambda; + fs << "gamma0" << params.gamma0; + fs << "c" << params.c; + + fs << "term_criteria" << "{:"; + if( params.termCrit.type & TermCriteria::EPS ) + fs << "epsilon" << params.termCrit.epsilon; + if( params.termCrit.type & TermCriteria::COUNT ) + fs << "iterations" << params.termCrit.maxCount; + fs << "}"; +} + + + +void SVMSGDImpl::read(const FileNode& fn) +{ + clear(); + + readParams(fn); + + shift_ = (float) fn["shift"]; + fn["weights"] >> weights_; +} + +void SVMSGDImpl::readParams( const FileNode& fn ) +{ + String svmsgdTypeStr = (String)fn["svmsgdType"]; + SvmsgdType svmsgdType = + svmsgdTypeStr == "SGD" ? SGD : + svmsgdTypeStr == "ASGD" ? ASGD : ILLEGAL_VALUE; + + if( svmsgdType == ILLEGAL_VALUE ) + CV_Error( CV_StsParseError, "Missing or invalid SVMSGD type" ); + + params.svmsgdType = svmsgdType; + + CV_Assert ( fn["lambda"].isReal() ); + params.lambda = (float)fn["lambda"]; + + CV_Assert ( fn["gamma0"].isReal() ); + params.gamma0 = (float)fn["gamma0"]; + + CV_Assert ( fn["c"].isReal() ); + params.c = (float)fn["c"]; + + FileNode tcnode = fn["term_criteria"]; + if( !tcnode.empty() ) + { + params.termCrit.epsilon = (double)tcnode["epsilon"]; + params.termCrit.maxCount = (int)tcnode["iterations"]; + params.termCrit.type = (params.termCrit.epsilon > 0 ? TermCriteria::EPS : 0) + + (params.termCrit.maxCount > 0 ? TermCriteria::COUNT : 0); + } + else + params.termCrit = TermCriteria( TermCriteria::EPS + TermCriteria::COUNT, 1000, FLT_EPSILON ); + +} + +void SVMSGDImpl::clear() +{ + weights_.release(); + shift_ = 0; +} + + +SVMSGDImpl::SVMSGDImpl() +{ + clear(); + rng_(0); + + params.svmsgdType = ILLEGAL_VALUE; + + // Parameters for learning + params.lambda = 0; // regularization + params.gamma0 = 0; // learning rate (ideally should be large at beginning and decay each iteration) + params.c = 0; + + TermCriteria _termCrit(TermCriteria::COUNT + TermCriteria::EPS, 0, 0); + params.termCrit = _termCrit; +} + +void SVMSGDImpl::setOptimalParameters(int type) +{ + switch (type) + { + case SGD: + params.svmsgdType = SGD; + params.lambda = 0.00001; + params.gamma0 = 0.05; + params.c = 1; + params.termCrit.maxCount = 50000; + params.termCrit.epsilon = 0.00000001; + break; + + case ASGD: + params.svmsgdType = ASGD; + params.lambda = 0.00001; + params.gamma0 = 0.5; + params.c = 0.75; + params.termCrit.maxCount = 100000; + params.termCrit.epsilon = 0.000001; + break; + + default: + CV_Error( CV_StsParseError, "SVMSGD model data is invalid" ); + } +} + +void SVMSGDImpl::setType(int type) +{ + switch (type) + { + case SGD: + params.svmsgdType = SGD; + break; + case ASGD: + params.svmsgdType = ASGD; + break; + default: + params.svmsgdType = ILLEGAL_VALUE; + } +} + +int SVMSGDImpl::getType() const +{ + return params.svmsgdType; +} +} //ml +} //cv diff --git a/modules/ml/test/test_mltests2.cpp b/modules/ml/test/test_mltests2.cpp index 919fae6ce4..6603a35c5b 100644 --- a/modules/ml/test/test_mltests2.cpp +++ b/modules/ml/test/test_mltests2.cpp @@ -193,6 +193,16 @@ int str_to_boost_type( String& str ) // 8. rtrees // 9. ertrees +int str_to_svmsgd_type( String& str ) +{ + if ( !str.compare("SGD") ) + return SVMSGD::SGD; + if ( !str.compare("ASGD") ) + return SVMSGD::ASGD; + CV_Error( CV_StsBadArg, "incorrect boost type string" ); + return -1; +} + // ---------------------------------- MLBaseTest --------------------------------------------------- CV_MLBaseTest::CV_MLBaseTest(const char* _modelName) @@ -248,7 +258,9 @@ void CV_MLBaseTest::run( int ) { string filename = ts->get_data_path(); filename += get_validation_filename(); + validationFS.open( filename, FileStorage::READ ); + read_params( *validationFS ); int code = cvtest::TS::OK; @@ -436,6 +448,21 @@ int CV_MLBaseTest::train( int testCaseIdx ) model = m; } + else if( modelName == CV_SVMSGD ) + { + String svmsgdTypeStr; + modelParamsNode["svmsgdType"] >> svmsgdTypeStr; + Ptr m = SVMSGD::create(); + int type = str_to_svmsgd_type( svmsgdTypeStr ); + m->setType(type); + //m->setType(str_to_svmsgd_type( svmsgdTypeStr )); + m->setLambda(modelParamsNode["lambda"]); + m->setGamma0(modelParamsNode["gamma0"]); + m->setC(modelParamsNode["c"]); + m->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10000, 0.00001)); + model = m; + } + if( !model.empty() ) is_trained = model->train(data, 0); @@ -457,7 +484,7 @@ float CV_MLBaseTest::get_test_error( int /*testCaseIdx*/, vector *resp ) else if( modelName == CV_ANN ) err = ann_calc_error( model, data, cls_map, type, resp ); else if( modelName == CV_DTREE || modelName == CV_BOOST || modelName == CV_RTREES || - modelName == CV_SVM || modelName == CV_NBAYES || modelName == CV_KNEAREST ) + modelName == CV_SVM || modelName == CV_NBAYES || modelName == CV_KNEAREST || modelName == CV_SVMSGD ) err = model->calcError( data, true, _resp ); if( !_resp.empty() && resp ) _resp.convertTo(*resp, CV_32F); @@ -485,6 +512,8 @@ void CV_MLBaseTest::load( const char* filename ) model = Algorithm::load( filename ); else if( modelName == CV_RTREES ) model = Algorithm::load( filename ); + else if( modelName == CV_SVMSGD ) + model = Algorithm::load( filename ); else CV_Error( CV_StsNotImplemented, "invalid stat model name"); } diff --git a/modules/ml/test/test_precomp.hpp b/modules/ml/test/test_precomp.hpp index 329b9bd6c0..18cee968fb 100644 --- a/modules/ml/test/test_precomp.hpp +++ b/modules/ml/test/test_precomp.hpp @@ -13,6 +13,7 @@ #include #include "opencv2/ts.hpp" #include "opencv2/ml.hpp" +#include "opencv2/ml/svmsgd.hpp" #include "opencv2/core/core_c.h" #define CV_NBAYES "nbayes" @@ -24,6 +25,7 @@ #define CV_BOOST "boost" #define CV_RTREES "rtrees" #define CV_ERTREES "ertrees" +#define CV_SVMSGD "svmsgd" enum { CV_TRAIN_ERROR=0, CV_TEST_ERROR=1 }; @@ -38,6 +40,7 @@ using cv::ml::ANN_MLP; using cv::ml::DTrees; using cv::ml::Boost; using cv::ml::RTrees; +using cv::ml::SVMSGD; class CV_MLBaseTest : public cvtest::BaseTest { diff --git a/modules/ml/test/test_save_load.cpp b/modules/ml/test/test_save_load.cpp index 2d6f144bb9..354c6e0307 100644 --- a/modules/ml/test/test_save_load.cpp +++ b/modules/ml/test/test_save_load.cpp @@ -150,12 +150,20 @@ int CV_SLMLTest::validate_test_results( int testCaseIdx ) TEST(ML_NaiveBayes, save_load) { CV_SLMLTest test( CV_NBAYES ); test.safe_run(); } TEST(ML_KNearest, save_load) { CV_SLMLTest test( CV_KNEAREST ); test.safe_run(); } -TEST(ML_SVM, save_load) { CV_SLMLTest test( CV_SVM ); test.safe_run(); } +TEST(ML_SVM, save_load) +{ + CV_SLMLTest test( CV_SVM ); + test.safe_run(); +} TEST(ML_ANN, save_load) { CV_SLMLTest test( CV_ANN ); test.safe_run(); } TEST(ML_DTree, save_load) { CV_SLMLTest test( CV_DTREE ); test.safe_run(); } TEST(ML_Boost, save_load) { CV_SLMLTest test( CV_BOOST ); test.safe_run(); } TEST(ML_RTrees, save_load) { CV_SLMLTest test( CV_RTREES ); test.safe_run(); } TEST(DISABLED_ML_ERTrees, save_load) { CV_SLMLTest test( CV_ERTREES ); test.safe_run(); } +TEST(MV_SVMSGD, save_load){ + CV_SLMLTest test( CV_SVMSGD ); + test.safe_run(); +} class CV_LegacyTest : public cvtest::BaseTest { @@ -201,6 +209,8 @@ protected: model = Algorithm::load(filename); else if (modelName == CV_RTREES) model = Algorithm::load(filename); + else if (modelName == CV_SVMSGD) + model = Algorithm::load(filename); if (!model) { code = cvtest::TS::FAIL_INVALID_TEST_DATA; @@ -260,6 +270,11 @@ TEST(ML_DTree, legacy_load) { CV_LegacyTest test(CV_DTREE, "_abalone.xml;_mushro TEST(ML_NBayes, legacy_load) { CV_LegacyTest test(CV_NBAYES, "_waveform.xml"); test.safe_run(); } TEST(ML_SVM, legacy_load) { CV_LegacyTest test(CV_SVM, "_poletelecomm.xml;_waveform.xml"); test.safe_run(); } TEST(ML_RTrees, legacy_load) { CV_LegacyTest test(CV_RTREES, "_waveform.xml"); test.safe_run(); } +TEST(ML_SVMSGD, legacy_load) +{ + CV_LegacyTest test(CV_SVMSGD, "_waveform.xml"); + test.safe_run(); +} /*TEST(ML_SVM, throw_exception_when_save_untrained_model) { diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp new file mode 100644 index 0000000000..9f4aafc08b --- /dev/null +++ b/modules/ml/test/test_svmsgd.cpp @@ -0,0 +1,182 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// Intel License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2000, Intel Corporation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of Intel Corporation may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#include "test_precomp.hpp" +#include "opencv2/highgui.hpp" + +using namespace cv; +using namespace cv::ml; +using cv::ml::SVMSGD; +using cv::ml::TrainData; + + + +class CV_SVMSGDTrainTest : public cvtest::BaseTest +{ +public: + CV_SVMSGDTrainTest(Mat _weights, float _shift); +private: + virtual void run( int start_from ); + float decisionFunction(Mat sample, Mat weights, float shift); + + cv::Ptr data; + cv::Mat testSamples; + cv::Mat testResponses; + static const int TEST_VALUE_LIMIT = 50; +}; + +CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(Mat weights, float shift) +{ + int datasize = 100000; + int varCount = weights.cols; + cv::Mat samples = cv::Mat::zeros( datasize, varCount, CV_32FC1 ); + cv::Mat responses = cv::Mat::zeros( datasize, 1, CV_32FC1 ); + cv::RNG rng(0); + + float lowerLimit = -TEST_VALUE_LIMIT; + float upperLimit = TEST_VALUE_LIMIT; + + + rng.fill(samples, RNG::UNIFORM, lowerLimit, upperLimit); + for (int sampleIndex = 0; sampleIndex < datasize; sampleIndex++) + { + responses.at( sampleIndex ) = decisionFunction(samples.row(sampleIndex), weights, shift) > 0 ? 1 : -1; + } + + data = TrainData::create( samples, cv::ml::ROW_SAMPLE, responses ); + + int testSamplesCount = 100000; + + testSamples.create(testSamplesCount, varCount, CV_32FC1); + rng.fill(testSamples, RNG::UNIFORM, lowerLimit, upperLimit); + testResponses.create(testSamplesCount, 1, CV_32FC1); + + for (int i = 0 ; i < testSamplesCount; i++) + { + testResponses.at(i) = decisionFunction(testSamples.row(i), weights, shift) > 0 ? 1 : -1; + } +} + +void CV_SVMSGDTrainTest::run( int /*start_from*/ ) +{ + cv::Ptr svmsgd = SVMSGD::create(); + + svmsgd->setOptimalParameters(SVMSGD::ASGD); + + svmsgd->train( data ); + + Mat responses; + + svmsgd->predict(testSamples, responses); + + int errCount = 0; + int testSamplesCount = testSamples.rows; + + for (int i = 0; i < testSamplesCount; i++) + { + if (responses.at(i) * testResponses.at(i) < 0 ) + errCount++; + } + + float err = (float)errCount / testSamplesCount; + std::cout << "err " << err << std::endl; + + if ( err > 0.01 ) + { + ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + } +} + +float CV_SVMSGDTrainTest::decisionFunction(Mat sample, Mat weights, float shift) +{ + return sample.dot(weights) + shift; +} + +TEST(ML_SVMSGD, train0) +{ + int varCount = 2; + + Mat weights; + weights.create(1, varCount, CV_32FC1); + weights.at(0) = 1; + weights.at(1) = 0; + + float shift = 5; + + CV_SVMSGDTrainTest test(weights, shift); + test.safe_run(); +} + +TEST(ML_SVMSGD, train1) +{ + int varCount = 5; + + Mat weights; + weights.create(1, varCount, CV_32FC1); + + float lowerLimit = -1; + float upperLimit = 1; + cv::RNG rng(0); + rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit); + + float shift = rng.uniform(-5.f, 5.f); + + CV_SVMSGDTrainTest test(weights, shift); + test.safe_run(); +} + +TEST(ML_SVMSGD, train2) +{ + int varCount = 100; + + Mat weights; + weights.create(1, varCount, CV_32FC1); + + float lowerLimit = -1; + float upperLimit = 1; + cv::RNG rng(0); + rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit); + + float shift = rng.uniform(-1000.f, 1000.f); + + CV_SVMSGDTrainTest test(weights, shift); + test.safe_run(); +} diff --git a/modules/ts/src/ts_gtest.cpp b/modules/ts/src/ts_gtest.cpp index 29a3996be8..5604eb7e62 100644 --- a/modules/ts/src/ts_gtest.cpp +++ b/modules/ts/src/ts_gtest.cpp @@ -5659,7 +5659,7 @@ class TestCaseNameIs { // Returns true iff the name of test_case matches name_. bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; } private: diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp new file mode 100644 index 0000000000..cee821739f --- /dev/null +++ b/samples/cpp/train_svmsgd.cpp @@ -0,0 +1,226 @@ +#include +#include "opencv2/video/tracking.hpp" +#include "opencv2/imgproc/imgproc.hpp" +#include "opencv2/highgui/highgui.hpp" + +using namespace cv; +using namespace cv::ml; + +#define WIDTH 841 +#define HEIGHT 594 + +struct Data +{ + Mat img; + Mat samples; + Mat responses; + RNG rng; + //Point points[2]; + + Data() + { + img = Mat::zeros(HEIGHT, WIDTH, CV_8UC3); + imshow("Train svmsgd", img); + } +}; + +bool doTrain(const Mat samples,const Mat responses, Mat &weights, float &shift); +bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2]); +bool findCrossPoint(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint); +void fillSegments(std::vector > &segments); +void redraw(Data data, const Point points[2]); +void addPointsRetrainAndRedraw(Data &data, int x, int y); + + +bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift) +{ + cv::Ptr svmsgd = SVMSGD::create(); + svmsgd->setOptimalParameters(SVMSGD::ASGD); + svmsgd->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 50000, 0.0000001)); + svmsgd->setLambda(0.01); + svmsgd->setGamma0(1); + // svmsgd->setC(5); + + cv::Ptr train_data = TrainData::create( samples, cv::ml::ROW_SAMPLE, responses ); + svmsgd->train( train_data ); + + if (svmsgd->isTrained()) + { + weights = svmsgd->getWeights(); + shift = svmsgd->getShift(); + + std::cout << weights << std::endl; + std::cout << shift << std::endl; + + return true; + } + return false; +} + + +bool findCrossPoint(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint) +{ + int x = 0; + int y = 0; + //с (0,0) всё плохо + if (segment.first.x == segment.second.x && weights.at(1) != 0) + { + x = segment.first.x; + y = -(weights.at(0) * x + shift) / weights.at(1); + if (y >= 0 && y <= HEIGHT) + { + crossPoint.x = x; + crossPoint.y = y; + return true; + } + } + else if (segment.first.y == segment.second.y && weights.at(0) != 0) + { + y = segment.first.y; + x = - (weights.at(1) * y + shift) / weights.at(0); + if (x >= 0 && x <= WIDTH) + { + crossPoint.x = x; + crossPoint.y = y; + return true; + } + } + return false; +} + +bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2]) +{ + if (weights.empty()) + { + return false; + } + + int foundPointsCount = 0; + std::vector > segments; + fillSegments(segments); + + for (int i = 0; i < 4; i++) + { + if (findCrossPoint(weights, shift, segments[i], points[foundPointsCount])) + foundPointsCount++; + if (foundPointsCount > 2) + break; + } + return true; +} + +void fillSegments(std::vector > &segments) +{ + std::pair curSegment; + + curSegment.first = Point(0,0); + curSegment.second = Point(0,HEIGHT); + segments.push_back(curSegment); + + curSegment.first = Point(0,0); + curSegment.second = Point(WIDTH,0); + segments.push_back(curSegment); + + curSegment.first = Point(WIDTH,0); + curSegment.second = Point(WIDTH,HEIGHT); + segments.push_back(curSegment); + + curSegment.first = Point(0,HEIGHT); + curSegment.second = Point(WIDTH,HEIGHT); + segments.push_back(curSegment); +} + +void redraw(Data data, const Point points[2]) +{ + data.img = Mat::zeros(HEIGHT, WIDTH, CV_8UC3); + Point center; + int radius = 3; + Scalar color; + for (int i = 0; i < data.samples.rows; i++) + { + center.x = data.samples.at(i,0); + center.y = data.samples.at(i,1); + color = (data.responses.at(i) > 0) ? Scalar(128,128,0) : Scalar(0,128,128); + circle(data.img, center, radius, color, 5); + } + line(data.img, points[0],points[1],cv::Scalar(1,255,1)); + + imshow("Train svmsgd", data.img); +} + +void addPointsRetrainAndRedraw(Data &data, int x, int y) +{ + + Mat currentSample(1, 2, CV_32F); + //start +/* + Mat _weights; + _weights.create(1, 2, CV_32FC1); + _weights.at(0) = 1; + _weights.at(1) = -1; + + int _x, _y; + + for (int i=0;i<199;i++) + { + _x = data.rng.uniform(0,800); + _y = data.rng.uniform(0,500);*/ + currentSample.at(0,0) = x; + currentSample.at(0,1) = y; + //if (currentSample.dot(_weights) > 0) + //data.responses.push_back(1); + // else data.responses.push_back(-1); + + //finish + data.samples.push_back(currentSample); + + + + Mat weights(1, 2, CV_32F); + float shift = 0; + + if (doTrain(data.samples, data.responses, weights, shift)) + { + Point points[2]; + shift = 0; + + findPointsForLine(weights, shift, points); + + redraw(data, points); + } +} + + +static void onMouse( int event, int x, int y, int, void* pData) +{ + Data &data = *(Data*)pData; + + switch( event ) + { + case CV_EVENT_LBUTTONUP: + data.responses.push_back(1); + addPointsRetrainAndRedraw(data, x, y); + + break; + + case CV_EVENT_RBUTTONDOWN: + data.responses.push_back(-1); + addPointsRetrainAndRedraw(data, x, y); + break; + } + +} + +int main() +{ + + Data data; + + setMouseCallback( "Train svmsgd", onMouse, &data ); + waitKey(); + + + + + return 0; +} From acd74037b32ddec5e1bf28dea5ec161570daa227 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 3 Feb 2016 15:31:05 +0300 Subject: [PATCH 130/468] Increasing the dimension of features space in the SVMSGD::train function. --- include/opencv2/opencv.hpp | 1 - modules/ml/include/opencv2/ml.hpp | 115 ++++++++ modules/ml/include/opencv2/ml/svmsgd.hpp | 134 --------- modules/ml/src/precomp.hpp | 1 - modules/ml/src/svmsgd.cpp | 335 ++++++++++++++--------- modules/ml/test/test_precomp.hpp | 1 - modules/ml/test/test_svmsgd.cpp | 28 +- samples/cpp/train_svmsgd.cpp | 146 +++++----- 8 files changed, 412 insertions(+), 349 deletions(-) delete mode 100644 modules/ml/include/opencv2/ml/svmsgd.hpp diff --git a/include/opencv2/opencv.hpp b/include/opencv2/opencv.hpp index e411621d0c..49b6a6691f 100644 --- a/include/opencv2/opencv.hpp +++ b/include/opencv2/opencv.hpp @@ -75,7 +75,6 @@ #endif #ifdef HAVE_OPENCV_ML #include "opencv2/ml.hpp" -#include "opencv2/ml/svmsgd.hpp" #endif #endif diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 791f580093..3a04368e1e 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1496,6 +1496,121 @@ public: CV_WRAP static Ptr create(); }; + +/****************************************************************************************\ +* Stochastic Gradient Descent SVM Classifier * +\****************************************************************************************/ + +/*! +@brief Stochastic Gradient Descent SVM classifier + +SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, as presented in @cite bottou2010large. +The gradient descent show amazing performance for large-scale problems, reducing the computing time. + + + +First, create the SVMSGD object. Set parametrs of model (type, lambda, gamma0, c) using the functions setType, setLambda, setGamma0 and setC or the function setOptimalParametrs. +Recommended model type is ASGD. + +Then the SVM model can be trained using the train features and the correspondent labels. + +After that, the label of a new feature vector can be predicted using the predict function. + +@code +// Initialize object +SVMSGD SvmSgd; + +// Train the Stochastic Gradient Descent SVM +SvmSgd.train(trainFeatures, labels); + +// Predict label for the new feature vector (1xM) +predictedLabel = SvmSgd.predict(newFeatureVector); +@endcode + +*/ + +class CV_EXPORTS_W SVMSGD : public cv::ml::StatModel +{ +public: + + /** SVMSGD type. + ASGD is often the preferable choice. */ + enum SvmsgdType + { + ILLEGAL_VALUE, + SGD, //!Stochastic Gradient Descent + ASGD //!Average Stochastic Gradient Descent + }; + + /** + * @return the weights of the trained model (decision function f(x) = weights * x + shift). + */ + CV_WRAP virtual Mat getWeights() = 0; + + /** + * @return the shift of the trained model (decision function f(x) = weights * x + shift). + */ + CV_WRAP virtual float getShift() = 0; + + + /** Creates empty model. + Use StatModel::train to train the model. Since %SVMSGD has several parameters, you may want to + find the best parameters for your problem or use setOptimalParameters() to set some default parameters. + */ + CV_WRAP static Ptr create(); + + /** Function sets optimal parameters values for chosen SVM SGD model. + * If chosen type is ASGD, function sets the following values for parameters of model: + * lambda = 0.00001; + * gamma0 = 0.05; + * c = 0.75; + * termCrit.maxCount = 100000; + * termCrit.epsilon = 0.00001; + * + * If SGD: + * lambda = 0.0001; + * gamma0 = 0.05; + * c = 1; + * termCrit.maxCount = 100000; + * termCrit.epsilon = 0.00001; + * @param type is the type of SVMSGD classifier. Legal values are SvmsgdType::SGD and SvmsgdType::ASGD. + * Recommended value is SvmsgdType::ASGD (by default). + */ + CV_WRAP virtual void setOptimalParameters(int type = ASGD) = 0; + + /** %Algorithm type, one of SVMSGD::SvmsgdType. */ + /** @see setAlgorithmType */ + CV_WRAP virtual int getType() const = 0; + /** @copybrief getAlgorithmType @see getAlgorithmType */ + CV_WRAP virtual void setType(int type) = 0; + + /** Parameter _Lambda_ of a %SVMSGD optimization problem. Default value is 0. */ + /** @see setLambda */ + CV_WRAP virtual float getLambda() const = 0; + /** @copybrief getLambda @see getLambda */ + CV_WRAP virtual void setLambda(float lambda) = 0; + + /** Parameter _Gamma0_ of a %SVMSGD optimization problem. Default value is 0. */ + /** @see setGamma0 */ + CV_WRAP virtual float getGamma0() const = 0; + CV_WRAP virtual void setGamma0(float gamma0) = 0; + + /** Parameter _C_ of a %SVMSGD optimization problem. Default value is 0. */ + /** @see setC */ + CV_WRAP virtual float getC() const = 0; + /** @copybrief getC @see getC */ + CV_WRAP virtual void setC(float c) = 0; + + /** @brief Termination criteria of the training algorithm. + You can specify the maximum number of iterations (maxCount) and/or how much the error could + change between the iterations to make the algorithm continue (epsilon).*/ + /** @see setTermCriteria */ + CV_WRAP virtual TermCriteria getTermCriteria() const = 0; + /** @copybrief getTermCriteria @see getTermCriteria */ + CV_WRAP virtual void setTermCriteria(const cv::TermCriteria &val) = 0; +}; + + /****************************************************************************************\ * Auxilary functions declarations * \****************************************************************************************/ diff --git a/modules/ml/include/opencv2/ml/svmsgd.hpp b/modules/ml/include/opencv2/ml/svmsgd.hpp deleted file mode 100644 index f61a905963..0000000000 --- a/modules/ml/include/opencv2/ml/svmsgd.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2000, Intel Corporation, all rights reserved. -// Copyright (C) 2013, OpenCV Foundation, all rights reserved. -// Copyright (C) 2014, Itseez Inc, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -//M*/ - -#ifndef __OPENCV_ML_SVMSGD_HPP__ -#define __OPENCV_ML_SVMSGD_HPP__ - -#ifdef __cplusplus - -#include "opencv2/ml.hpp" - -namespace cv -{ -namespace ml -{ - - -/****************************************************************************************\ -* Stochastic Gradient Descent SVM Classifier * -\****************************************************************************************/ - -/*! -@brief Stochastic Gradient Descent SVM classifier - -SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, as presented in @cite bottou2010large. -The gradient descent show amazing performance for large-scale problems, reducing the computing time. This allows a fast and reliable online update of the classifier for each new feature which -is fundamental when dealing with variations of data over time (like weather and illumination changes in videosurveillance, for example). - -First, create the SVMSGD object. To enable the online update, a value for updateFrequency should be defined. - -Then the SVM model can be trained using the train features and the correspondent labels. - -After that, the label of a new feature vector can be predicted using the predict function. If the updateFrequency was defined in the constructor, the predict function will update the weights automatically. - -@code -// Initialize object -SVMSGD SvmSgd; - -// Train the Stochastic Gradient Descent SVM -SvmSgd.train(trainFeatures, labels); - -// Predict label for the new feature vector (1xM) -predictedLabel = SvmSgd.predict(newFeatureVector); -@endcode - -*/ - -class CV_EXPORTS_W SVMSGD : public cv::ml::StatModel -{ -public: - - enum SvmsgdType - { - ILLEGAL_VALUE, - SGD, //Stochastic Gradient Descent - ASGD //Average Stochastic Gradient Descent - }; - - /** - * @return the weights of the trained model. - */ - CV_WRAP virtual Mat getWeights() = 0; - - CV_WRAP virtual float getShift() = 0; - - CV_WRAP static Ptr create(); - - CV_WRAP virtual void setOptimalParameters(int type = ASGD) = 0; - - CV_WRAP virtual int getType() const = 0; - - CV_WRAP virtual void setType(int type) = 0; - - CV_WRAP virtual float getLambda() const = 0; - - CV_WRAP virtual void setLambda(float lambda) = 0; - - CV_WRAP virtual float getGamma0() const = 0; - - CV_WRAP virtual void setGamma0(float gamma0) = 0; - - CV_WRAP virtual float getC() const = 0; - - CV_WRAP virtual void setC(float c) = 0; - - CV_WRAP virtual cv::TermCriteria getTermCriteria() const = 0; - - CV_WRAP virtual void setTermCriteria(const cv::TermCriteria &val) = 0; -}; - -} //ml -} //cv - -#endif // __clpusplus -#endif // __OPENCV_ML_SVMSGD_HPP diff --git a/modules/ml/src/precomp.hpp b/modules/ml/src/precomp.hpp index 9318e4a78c..0a5fa06035 100644 --- a/modules/ml/src/precomp.hpp +++ b/modules/ml/src/precomp.hpp @@ -45,7 +45,6 @@ #include "opencv2/ml.hpp" #include "opencv2/core/core_c.h" #include "opencv2/core/utility.hpp" -#include "opencv2/ml/svmsgd.hpp" #include "opencv2/core/private.hpp" #include diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 91377cfc4f..5c75023b7d 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -42,6 +42,12 @@ #include "precomp.hpp" #include "limits" +//#include "math.h" + +#include + +using std::cout; +using std::endl; /****************************************************************************************\ * Stochastic Gradient Descent SVM Classifier * @@ -64,7 +70,7 @@ public: virtual float predict( InputArray samples, OutputArray results=noArray(), int flags = 0 ) const; - virtual bool isClassifier() const { return params.svmsgdType == SGD || params.svmsgdType == ASGD; } + virtual bool isClassifier() const; virtual bool isTrained() const; @@ -93,22 +99,29 @@ public: CV_IMPL_PROPERTY(float, C, params.c) CV_IMPL_PROPERTY_S(cv::TermCriteria, TermCriteria, params.termCrit) - private: - void updateWeights(InputArray sample, bool is_first_class, float gamma); - float calcShift(InputArray trainSamples, InputArray trainResponses) const; +private: + void updateWeights(InputArray sample, bool isFirstClass, float gamma, Mat weights); + std::pair areClassesEmpty(Mat responses); + void writeParams( FileStorage& fs ) const; + void readParams( const FileNode& fn ); + static inline bool isFirstClass(float val) { return val > 0; } + static void normalizeSamples(Mat &matrix, Mat &multiplier, Mat &average); + + float calcShift(InputArray _samples, InputArray _responses) const; + + static void makeExtendedTrainSamples(const Mat trainSamples, Mat &extendedTrainSamples, Mat &multiplier); + + // Vector with SVM weights Mat weights_; float shift_; - // Random index generation - RNG rng_; - // Parameters for learning struct SVMSGDParams { @@ -127,97 +140,88 @@ Ptr SVMSGD::create() return makePtr(); } - -bool SVMSGDImpl::train(const Ptr& data, int) -{ - clear(); - - Mat trainSamples = data->getTrainSamples(); - - // Initialize varCount - int trainSamplesCount_ = trainSamples.rows; - int varCount = trainSamples.cols; - - // Initialize weights vector with zeros - weights_ = Mat::zeros(1, varCount, CV_32F); - - Mat trainResponses = data->getTrainResponses(); // (trainSamplesCount x 1) matrix - - std::pair are_empty = areClassesEmpty(trainResponses); - - if ( are_empty.first && are_empty.second ) - { - weights_.release(); - return false; - } - if ( are_empty.first || are_empty.second ) - { - shift_ = are_empty.first ? -1 : 1; - return true; - } - - - Mat currentSample; - float gamma = 0; - Mat lastWeights = Mat::zeros(1, varCount, CV_32F); //weights vector for calculating terminal criterion - Mat averageWeights; //average weights vector for ASGD model - double err = DBL_MAX; - if (params.svmsgdType == ASGD) - { - averageWeights = Mat::zeros(1, varCount, CV_32F); - } - - // Stochastic gradient descent SVM - for (int iter = 0; (iter < params.termCrit.maxCount)&&(err > params.termCrit.epsilon); iter++) - { - //generate sample number - int randomNumber = rng_.uniform(0, trainSamplesCount_); - - currentSample = trainSamples.row(randomNumber); - - //update gamma - gamma = params.gamma0 * std::pow((1 + params.lambda * params.gamma0 * (float)iter), (-params.c)); - - bool is_first_class = isFirstClass(trainResponses.at(randomNumber)); - updateWeights( currentSample, is_first_class, gamma ); - - //average weights (only for ASGD model) - if (params.svmsgdType == ASGD) - { - averageWeights = ((float)iter/ (1 + (float)iter)) * averageWeights + weights_ / (1 + (float) iter); - } - - err = norm(weights_ - lastWeights); - weights_.copyTo(lastWeights); - } - - if (params.svmsgdType == ASGD) - { - weights_ = averageWeights; - } - - shift_ = calcShift(trainSamples, trainResponses); - - return true; -} - std::pair SVMSGDImpl::areClassesEmpty(Mat responses) { - std::pair are_classes_empty(true, true); + CV_Assert(responses.cols == 1); + std::pair emptyInClasses(true, true); int limit_index = responses.rows; for(int index = 0; index < limit_index; index++) { - if (isFirstClass(responses.at(index,0))) - are_classes_empty.first = false; + if (isFirstClass(responses.at(index))) + emptyInClasses.first = false; else - are_classes_empty.second = false; + emptyInClasses.second = false; - if (!are_classes_empty.first && ! are_classes_empty.second) + if (!emptyInClasses.first && ! emptyInClasses.second) break; } - return are_classes_empty; + return emptyInClasses; +} + +void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &multiplier, Mat &average) +{ + int featuresCount = samples.cols; + int samplesCount = samples.rows; + + average = Mat(1, featuresCount, samples.type()); + for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++) + { + average.at(featureIndex) = mean(samples.col(featureIndex))[0]; + } + + for (int sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) + { + samples.row(sampleIndex) -= average; + } + + Mat featureNorm(1, featuresCount, samples.type()); + for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++) + { + featureNorm.at(featureIndex) = norm(samples.col(featureIndex)); + } + + multiplier = sqrt(samplesCount) / featureNorm; + for (int sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) + { + samples.row(sampleIndex) = samples.row(sampleIndex).mul(multiplier); + } +} + +void SVMSGDImpl::makeExtendedTrainSamples(const Mat trainSamples, Mat &extendedTrainSamples, Mat &multiplier) +{ + Mat normalisedTrainSamples = trainSamples.clone(); + int samplesCount = normalisedTrainSamples.rows; + + Mat average; + + normalizeSamples(normalisedTrainSamples, multiplier, average); + + Mat onesCol = Mat::ones(samplesCount, 1, CV_32F); + cv::hconcat(normalisedTrainSamples, onesCol, extendedTrainSamples); + + //cout << "SVMSGDImpl::makeExtendedTrainSamples average: \n" << average << endl; + //cout << "SVMSGDImpl::makeExtendedTrainSamples multiplier: \n" << multiplier << endl; +} + + +void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, Mat weights) +{ + Mat sample = _sample.getMat(); + + int response = firstClass ? 1 : -1; // ensure that trainResponses are -1 or 1 + + if ( sample.dot(weights) * response > 1) + { + // Not a support vector, only apply weight decay + weights *= (1.f - gamma * params.lambda); + } + else + { + // It's a support vector, add it to the weights + weights -= (gamma * params.lambda) * weights - (gamma * response) * sample; + } } float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const @@ -232,12 +236,12 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const for (int samplesIndex = 0; samplesIndex < trainSamplesCount; samplesIndex++) { Mat currentSample = trainSamples.row(samplesIndex); - float scalar_product = currentSample.dot(weights_); + float dotProduct = currentSample.dot(weights_); - bool is_first_class = isFirstClass(trainResponses.at(samplesIndex)); - int index = is_first_class ? 0:1; - float sign_to_mul = is_first_class ? 1 : -1; - float cur_distance = scalar_product * sign_to_mul ; + bool firstClass = isFirstClass(trainResponses.at(samplesIndex)); + int index = firstClass ? 0:1; + float signToMul = firstClass ? 1 : -1; + float cur_distance = dotProduct * signToMul; if (cur_distance < distance_to_classes[index]) { @@ -245,10 +249,109 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const } } - //todo: areClassesEmpty(); make const; return -(distance_to_classes[0] - distance_to_classes[1]) / 2.f; } +bool SVMSGDImpl::train(const Ptr& data, int) +{ + //cout << "SVMSGDImpl::train begin" << endl; + clear(); + CV_Assert( isClassifier() ); //toDo: consider + + Mat trainSamples = data->getTrainSamples(); + + //cout << "SVMSGDImpl::train trainSamples: \n" << trainSamples << endl; + + int featureCount = trainSamples.cols; + Mat trainResponses = data->getTrainResponses(); // (trainSamplesCount x 1) matrix + + //cout << "SVMSGDImpl::train trainresponses: \n" << trainResponses << endl; + + std::pair areEmpty = areClassesEmpty(trainResponses); + + //cout << "SVMSGDImpl::train areEmpty" << areEmpty.first << "," << areEmpty.second << endl; + + if ( areEmpty.first && areEmpty.second ) + { + return false; + } + if ( areEmpty.first || areEmpty.second ) + { + weights_ = Mat::zeros(1, featureCount, CV_32F); + shift_ = areEmpty.first ? -1 : 1; + return true; + } + + Mat extendedTrainSamples; + Mat multiplier; + makeExtendedTrainSamples(trainSamples, extendedTrainSamples, multiplier); + + //cout << "SVMSGDImpl::train extendedTrainSamples: \n" << extendedTrainSamples << endl; + + int extendedTrainSamplesCount = extendedTrainSamples.rows; + int extendedFeatureCount = extendedTrainSamples.cols; + + Mat extendedWeights = Mat::zeros(1, extendedFeatureCount, CV_32F); // Initialize extendedWeights vector with zeros + Mat previousWeights = Mat::zeros(1, extendedFeatureCount, CV_32F); //extendedWeights vector for calculating terminal criterion + Mat averageExtendedWeights; //average extendedWeights vector for ASGD model + if (params.svmsgdType == ASGD) + { + averageExtendedWeights = Mat::zeros(1, extendedFeatureCount, CV_32F); + } + + RNG rng(0); + + int maxCount = (params.termCrit.type & TermCriteria::COUNT) ? params.termCrit.maxCount : INT_MAX; + double epsilon = (params.termCrit.type & TermCriteria::EPS) ? params.termCrit.epsilon : 0; + + double err = DBL_MAX; + // Stochastic gradient descent SVM + for (int iter = 0; (iter < maxCount) && (err > epsilon); iter++) + { + int randomNumber = rng.uniform(0, extendedTrainSamplesCount); //generate sample number + + Mat currentSample = extendedTrainSamples.row(randomNumber); + bool firstClass = isFirstClass(trainResponses.at(randomNumber)); + + float gamma = params.gamma0 * std::pow((1 + params.lambda * params.gamma0 * (float)iter), (-params.c)); //update gamma + + updateWeights( currentSample, firstClass, gamma, extendedWeights ); + + //average weights (only for ASGD model) + if (params.svmsgdType == ASGD) + { + averageExtendedWeights = ((float)iter/ (1 + (float)iter)) * averageExtendedWeights + extendedWeights / (1 + (float) iter); + err = norm(averageExtendedWeights - previousWeights); + averageExtendedWeights.copyTo(previousWeights); + } + else + { + err = norm(extendedWeights - previousWeights); + extendedWeights.copyTo(previousWeights); + } + } + + if (params.svmsgdType == ASGD) + { + extendedWeights = averageExtendedWeights; + } + + //cout << "SVMSGDImpl::train extendedWeights: \n" << extendedWeights << endl; + + Rect roi(0, 0, featureCount, 1); + weights_ = extendedWeights(roi); + weights_ = weights_.mul(1/multiplier); + + //cout << "SVMSGDImpl::train weights: \n" << weights_ << endl; + + shift_ = calcShift(trainSamples, trainResponses); + + //cout << "SVMSGDImpl::train shift = " << shift_ << endl; + + return true; +} + + float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) const { float result = 0; @@ -269,37 +372,21 @@ float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) cons results = Mat(1, 1, CV_32F, &result); } - Mat currentSample; - float criterion = 0; - for (int sampleIndex = 0; sampleIndex < nSamples; sampleIndex++) { - currentSample = samples.row(sampleIndex); - criterion = currentSample.dot(weights_) + shift_; + Mat currentSample = samples.row(sampleIndex); + float criterion = currentSample.dot(weights_) + shift_; results.at(sampleIndex) = (criterion >= 0) ? 1 : -1; } return result; } -void SVMSGDImpl::updateWeights(InputArray _sample, bool is_first_class, float gamma) +bool SVMSGDImpl::isClassifier() const { - Mat sample = _sample.getMat(); - - int responce = is_first_class ? 1 : -1; // ensure that trainResponses are -1 or 1 - - if ( sample.dot(weights_) * responce > 1) - { - // Not a support vector, only apply weight decay - weights_ *= (1.f - gamma * params.lambda); - } - else - { - // It's a support vector, add it to the weights - weights_ -= (gamma * params.lambda) * weights_ - gamma * responce * sample; - //std::cout << "sample " << sample << std::endl; - //std::cout << "weights_ " << weights_ << std::endl; - } + return (params.svmsgdType == SGD || params.svmsgdType == ASGD) + && + (params.lambda > 0) && (params.gamma0 > 0) && (params.c >= 0); } bool SVMSGDImpl::isTrained() const @@ -314,8 +401,8 @@ void SVMSGDImpl::write(FileStorage& fs) const writeParams( fs ); - fs << "shift" << shift_; fs << "weights" << weights_; + fs << "shift" << shift_; } void SVMSGDImpl::writeParams( FileStorage& fs ) const @@ -359,8 +446,8 @@ void SVMSGDImpl::read(const FileNode& fn) readParams(fn); - shift_ = (float) fn["shift"]; fn["weights"] >> weights_; + fn["shift"] >> shift_; } void SVMSGDImpl::readParams( const FileNode& fn ) @@ -393,21 +480,19 @@ void SVMSGDImpl::readParams( const FileNode& fn ) (params.termCrit.maxCount > 0 ? TermCriteria::COUNT : 0); } else - params.termCrit = TermCriteria( TermCriteria::EPS + TermCriteria::COUNT, 1000, FLT_EPSILON ); + params.termCrit = TermCriteria( TermCriteria::EPS + TermCriteria::COUNT, 100000, FLT_EPSILON ); } void SVMSGDImpl::clear() { weights_.release(); - shift_ = 0; } SVMSGDImpl::SVMSGDImpl() { clear(); - rng_(0); params.svmsgdType = ILLEGAL_VALUE; @@ -426,20 +511,20 @@ void SVMSGDImpl::setOptimalParameters(int type) { case SGD: params.svmsgdType = SGD; - params.lambda = 0.00001; + params.lambda = 0.0001; params.gamma0 = 0.05; params.c = 1; - params.termCrit.maxCount = 50000; - params.termCrit.epsilon = 0.00000001; + params.termCrit.maxCount = 100000; + params.termCrit.epsilon = 0.00001; break; case ASGD: params.svmsgdType = ASGD; params.lambda = 0.00001; - params.gamma0 = 0.5; + params.gamma0 = 0.05; params.c = 0.75; params.termCrit.maxCount = 100000; - params.termCrit.epsilon = 0.000001; + params.termCrit.epsilon = 0.00001; break; default: diff --git a/modules/ml/test/test_precomp.hpp b/modules/ml/test/test_precomp.hpp index 18cee968fb..3147a9d96c 100644 --- a/modules/ml/test/test_precomp.hpp +++ b/modules/ml/test/test_precomp.hpp @@ -13,7 +13,6 @@ #include #include "opencv2/ts.hpp" #include "opencv2/ml.hpp" -#include "opencv2/ml/svmsgd.hpp" #include "opencv2/core/core_c.h" #define CV_NBAYES "nbayes" diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 9f4aafc08b..5445271eec 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -52,7 +52,7 @@ using cv::ml::TrainData; class CV_SVMSGDTrainTest : public cvtest::BaseTest { public: - CV_SVMSGDTrainTest(Mat _weights, float _shift); + CV_SVMSGDTrainTest(Mat _weights, float shift); private: virtual void run( int start_from ); float decisionFunction(Mat sample, Mat weights, float shift); @@ -60,7 +60,7 @@ private: cv::Ptr data; cv::Mat testSamples; cv::Mat testResponses; - static const int TEST_VALUE_LIMIT = 50; + static const int TEST_VALUE_LIMIT = 500; }; CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(Mat weights, float shift) @@ -81,6 +81,11 @@ CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(Mat weights, float shift) responses.at( sampleIndex ) = decisionFunction(samples.row(sampleIndex), weights, shift) > 0 ? 1 : -1; } + + + std::cout << "real weights\n" << weights/norm(weights) << "\n" << std::endl; + std::cout << "real shift \n" << shift/norm(weights) << "\n" << std::endl; + data = TrainData::create( samples, cv::ml::ROW_SAMPLE, responses ); int testSamplesCount = 100000; @@ -100,8 +105,9 @@ void CV_SVMSGDTrainTest::run( int /*start_from*/ ) cv::Ptr svmsgd = SVMSGD::create(); svmsgd->setOptimalParameters(SVMSGD::ASGD); + svmsgd->setTermCriteria(TermCriteria(TermCriteria::EPS, 0, 0.00005)); - svmsgd->train( data ); + svmsgd->train(data); Mat responses; @@ -116,6 +122,12 @@ void CV_SVMSGDTrainTest::run( int /*start_from*/ ) errCount++; } + + float normW = norm(svmsgd->getWeights()); + + std::cout << "found weights\n" << svmsgd->getWeights()/normW << "\n" << std::endl; + std::cout << "found shift \n" << svmsgd->getShift()/normW << "\n" << std::endl; + float err = (float)errCount / testSamplesCount; std::cout << "err " << err << std::endl; @@ -138,8 +150,8 @@ TEST(ML_SVMSGD, train0) weights.create(1, varCount, CV_32FC1); weights.at(0) = 1; weights.at(1) = 0; - - float shift = 5; + cv::RNG rng(1); + float shift = rng.uniform(-varCount, varCount); CV_SVMSGDTrainTest test(weights, shift); test.safe_run(); @@ -157,7 +169,7 @@ TEST(ML_SVMSGD, train1) cv::RNG rng(0); rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit); - float shift = rng.uniform(-5.f, 5.f); + float shift = rng.uniform(-varCount, varCount); CV_SVMSGDTrainTest test(weights, shift); test.safe_run(); @@ -175,8 +187,8 @@ TEST(ML_SVMSGD, train2) cv::RNG rng(0); rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit); - float shift = rng.uniform(-1000.f, 1000.f); + float shift = rng.uniform(-varCount, varCount); - CV_SVMSGDTrainTest test(weights, shift); + CV_SVMSGDTrainTest test(weights,shift); test.safe_run(); } diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index cee821739f..19c30ffca9 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -12,10 +12,8 @@ using namespace cv::ml; struct Data { Mat img; - Mat samples; - Mat responses; - RNG rng; - //Point points[2]; + Mat samples; //Set of train samples. Contains points on image + Mat responses; //Set of responses for train samples Data() { @@ -24,24 +22,36 @@ struct Data } }; -bool doTrain(const Mat samples,const Mat responses, Mat &weights, float &shift); -bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2]); -bool findCrossPoint(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint); -void fillSegments(std::vector > &segments); +//Train with SVMSGD algorithm +//(samples, responses) is a train set +//weights is a required vector for decision function of SVMSGD algorithm +bool doTrain(const Mat samples, const Mat responses, Mat &weights, float &shift); + +//function finds two points for drawing line (wx = 0) +bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2], int width, int height); + +// function finds cross point of line (wx = 0) and segment ( (y = HEIGHT, 0 <= x <= WIDTH) or (x = WIDTH, 0 <= y <= HEIGHT) ) +bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint); + +//segments' initialization ( (y = HEIGHT, 0 <= x <= WIDTH) and (x = WIDTH, 0 <= y <= HEIGHT) ) +void fillSegments(std::vector > &segments, int width, int height); + +//redraw points' set and line (wx = 0) void redraw(Data data, const Point points[2]); -void addPointsRetrainAndRedraw(Data &data, int x, int y); + +//add point in train set, train SVMSGD algorithm and draw results on image +void addPointRetrainAndRedraw(Data &data, int x, int y); bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift) { cv::Ptr svmsgd = SVMSGD::create(); svmsgd->setOptimalParameters(SVMSGD::ASGD); - svmsgd->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 50000, 0.0000001)); - svmsgd->setLambda(0.01); - svmsgd->setGamma0(1); - // svmsgd->setC(5); + svmsgd->setTermCriteria(TermCriteria(TermCriteria::EPS, 0, 0.00000001)); + svmsgd->setLambda(0.00000001); - cv::Ptr train_data = TrainData::create( samples, cv::ml::ROW_SAMPLE, responses ); + + cv::Ptr train_data = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); svmsgd->train( train_data ); if (svmsgd->isTrained()) @@ -49,36 +59,39 @@ bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift weights = svmsgd->getWeights(); shift = svmsgd->getShift(); - std::cout << weights << std::endl; - std::cout << shift << std::endl; - return true; } return false; } -bool findCrossPoint(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint) +bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint) { int x = 0; int y = 0; - //с (0,0) всё плохо - if (segment.first.x == segment.second.x && weights.at(1) != 0) + int xMin = std::min(segment.first.x, segment.second.x); + int xMax = std::max(segment.first.x, segment.second.x); + int yMin = std::min(segment.first.y, segment.second.y); + int yMax = std::max(segment.first.y, segment.second.y); + + CV_Assert(xMin == xMax || yMin == yMax); + + if (xMin == xMax && weights.at(1) != 0) { - x = segment.first.x; - y = -(weights.at(0) * x + shift) / weights.at(1); - if (y >= 0 && y <= HEIGHT) + x = xMin; + y = std::floor( - (weights.at(0) * x + shift) / weights.at(1)); + if (y >= yMin && y <= yMax) { crossPoint.x = x; crossPoint.y = y; return true; } } - else if (segment.first.y == segment.second.y && weights.at(0) != 0) + else if (yMin == yMax && weights.at(0) != 0) { - y = segment.first.y; - x = - (weights.at(1) * y + shift) / weights.at(0); - if (x >= 0 && x <= WIDTH) + y = yMin; + x = std::floor( - (weights.at(1) * y + shift) / weights.at(0)); + if (x >= xMin && x <= xMax) { crossPoint.x = x; crossPoint.y = y; @@ -88,7 +101,7 @@ bool findCrossPoint(const Mat &weights, float shift, const std::pair > segments; - fillSegments(segments); + fillSegments(segments, width, height); - for (int i = 0; i < 4; i++) + for (uint i = 0; i < segments.size(); i++) { - if (findCrossPoint(weights, shift, segments[i], points[foundPointsCount])) + if (findCrossPointWithBorders(weights, shift, segments[i], points[foundPointsCount])) foundPointsCount++; - if (foundPointsCount > 2) + if (foundPointsCount >= 2) break; } + return true; } -void fillSegments(std::vector > &segments) +void fillSegments(std::vector > &segments, int width, int height) { - std::pair curSegment; + std::pair currentSegment; - curSegment.first = Point(0,0); - curSegment.second = Point(0,HEIGHT); - segments.push_back(curSegment); + currentSegment.first = Point(width, 0); + currentSegment.second = Point(width, height); + segments.push_back(currentSegment); - curSegment.first = Point(0,0); - curSegment.second = Point(WIDTH,0); - segments.push_back(curSegment); + currentSegment.first = Point(0, height); + currentSegment.second = Point(width, height); + segments.push_back(currentSegment); - curSegment.first = Point(WIDTH,0); - curSegment.second = Point(WIDTH,HEIGHT); - segments.push_back(curSegment); + currentSegment.first = Point(0, 0); + currentSegment.second = Point(width, 0); + segments.push_back(currentSegment); - curSegment.first = Point(0,HEIGHT); - curSegment.second = Point(WIDTH,HEIGHT); - segments.push_back(curSegment); + currentSegment.first = Point(0, 0); + currentSegment.second = Point(0, height); + segments.push_back(currentSegment); } void redraw(Data data, const Point points[2]) { - data.img = Mat::zeros(HEIGHT, WIDTH, CV_8UC3); + data.img.setTo(0); Point center; int radius = 3; Scalar color; @@ -143,48 +157,26 @@ void redraw(Data data, const Point points[2]) color = (data.responses.at(i) > 0) ? Scalar(128,128,0) : Scalar(0,128,128); circle(data.img, center, radius, color, 5); } - line(data.img, points[0],points[1],cv::Scalar(1,255,1)); + line(data.img, points[0], points[1],cv::Scalar(1,255,1)); imshow("Train svmsgd", data.img); } -void addPointsRetrainAndRedraw(Data &data, int x, int y) +void addPointRetrainAndRedraw(Data &data, int x, int y) { - Mat currentSample(1, 2, CV_32F); - //start -/* - Mat _weights; - _weights.create(1, 2, CV_32FC1); - _weights.at(0) = 1; - _weights.at(1) = -1; - int _x, _y; - - for (int i=0;i<199;i++) - { - _x = data.rng.uniform(0,800); - _y = data.rng.uniform(0,500);*/ currentSample.at(0,0) = x; currentSample.at(0,1) = y; - //if (currentSample.dot(_weights) > 0) - //data.responses.push_back(1); - // else data.responses.push_back(-1); - - //finish data.samples.push_back(currentSample); - - Mat weights(1, 2, CV_32F); float shift = 0; if (doTrain(data.samples, data.responses, weights, shift)) - { + { Point points[2]; - shift = 0; - - findPointsForLine(weights, shift, points); + findPointsForLine(weights, shift, points, data.img.cols, data.img.rows); redraw(data, points); } @@ -199,13 +191,13 @@ static void onMouse( int event, int x, int y, int, void* pData) { case CV_EVENT_LBUTTONUP: data.responses.push_back(1); - addPointsRetrainAndRedraw(data, x, y); + addPointRetrainAndRedraw(data, x, y); break; case CV_EVENT_RBUTTONDOWN: data.responses.push_back(-1); - addPointsRetrainAndRedraw(data, x, y); + addPointRetrainAndRedraw(data, x, y); break; } @@ -213,14 +205,10 @@ static void onMouse( int event, int x, int y, int, void* pData) int main() { - Data data; setMouseCallback( "Train svmsgd", onMouse, &data ); waitKey(); - - - return 0; } From bfdca05f251398e0638dc168436ded0705df258b Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Tue, 9 Feb 2016 18:42:23 +0300 Subject: [PATCH 131/468] Added margin type, added tests with different scales of features. Also fixed documentation, refactored sample. --- modules/ml/include/opencv2/ml.hpp | 127 +++++++++++---- modules/ml/src/svmsgd.cpp | 180 +++++++++++++-------- modules/ml/test/test_mltests2.cpp | 25 ++- modules/ml/test/test_save_load.cpp | 6 +- modules/ml/test/test_svmsgd.cpp | 249 ++++++++++++++++++++--------- samples/cpp/train_svmsgd.cpp | 63 ++++---- 6 files changed, 429 insertions(+), 221 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 3a04368e1e..ec7c0730ec 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1504,27 +1504,78 @@ public: /*! @brief Stochastic Gradient Descent SVM classifier -SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, as presented in @cite bottou2010large. +SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, +as presented in @cite bottou2010large. The gradient descent show amazing performance for large-scale problems, reducing the computing time. +The classifier has 5 parameters. These are +- model type, +- margin type, +- \f$\lambda\f$ (strength of restrictions on outliers), +- \f$\gamma_0\f$ (initial step size), +- \f$c\f$ (power coefficient for decreasing of step size), +- and termination criteria. +The model type may have one of the following values: \ref SGD and \ref ASGD. -First, create the SVMSGD object. Set parametrs of model (type, lambda, gamma0, c) using the functions setType, setLambda, setGamma0 and setC or the function setOptimalParametrs. -Recommended model type is ASGD. +- \ref SGD is the classic version of SVMSGD classifier: every next step is calculated by the formula + \f[w_{t+1} = w_t - \gamma(t) \frac{dQ_i}{dw} |_{w = w_t}\f] + where + - \f$w_t\f$ is the weights vector for decision function at step \f$t\f$, + - \f$\gamma(t)\f$ is the step size of model parameters at the iteration \f$t\f$, it is decreased on each step by the formula + \f$\gamma(t) = \gamma_0 (1 + \lambda \gamma_0 t) ^ {-c}\f$ + - \f$Q_i\f$ is the target functional from SVM task for sample with number \f$i\f$, this sample is chosen stochastically on each step of the algorithm. -Then the SVM model can be trained using the train features and the correspondent labels. +- \ref ASGD is Average Stochastic Gradient Descent SVM Classifier. ASGD classifier averages weights vector on each step of algorithm by the formula +\f$\widehat{w}_{t+1} = \frac{t}{1+t}\widehat{w}_{t} + \frac{1}{1+t}w_{t+1}\f$ -After that, the label of a new feature vector can be predicted using the predict function. +The recommended model type is ASGD (following @cite bottou2010large). + +The margin type may have one of the following values: \ref SOFT_MARGIN or \ref HARD_MARGIN. + +- You should use \ref HARD_MARGIN type, if you have linearly separable sets. +- You should use \ref SOFT_MARGIN type, if you have non-linearly separable sets or sets with outliers. +- In the general case (if you know nothing about linearly separability of your sets), use SOFT_MARGIN. + +The other parameters may be described as follows: +- \f$\lambda\f$ parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers + (the less the parameter, the less probability that an outlier will be ignored). + Recommended value for SGD model is 0.0001, for ASGD model is 0.00001. + +- \f$\gamma_0\f$ parameter is the initial value for the step size \f$\gamma(t)\f$. + You will have to find the best \f$\gamma_0\f$ for your problem. + +- \f$c\f$ is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. + Recommended value for SGD model is 1, for ASGD model is 0.75. + +- Termination criteria can be TermCriteria::COUNT, TermCriteria::EPS or TermCriteria::COUNT + TermCriteria::EPS. + You will have to find the best termination criteria for your problem. + +Note that the parameters \f$\lambda\f$, \f$\gamma_0\f$, and \f$c\f$ should be positive. + +To use SVMSGD algorithm do as follows: + +- first, create the SVMSGD object. + +- then set parameters (model type, margin type, \f$\lambda\f$, \f$\gamma_0\f$, \f$c\f$) using the functions + setSvmsgdType(), setMarginType(), setLambda(), setGamma0(), and setC(), or the function setOptimalParameters(). + +- then the SVM model can be trained using the train features and the correspondent labels by the method train(). + +- after that, the label of a new feature vector can be predicted using the method predict(). @code -// Initialize object -SVMSGD SvmSgd; +// Create empty object +cv::Ptr svmsgd = SVMSGD::create(); + +// Set parameters +svmsgd->setOptimalParameters(); // Train the Stochastic Gradient Descent SVM -SvmSgd.train(trainFeatures, labels); +SvmSgd->train(trainData); -// Predict label for the new feature vector (1xM) -predictedLabel = SvmSgd.predict(newFeatureVector); +// Predict labels for the new samples +svmsgd->predict(samples, responses); @endcode */ @@ -1537,9 +1588,17 @@ public: ASGD is often the preferable choice. */ enum SvmsgdType { - ILLEGAL_VALUE, - SGD, //!Stochastic Gradient Descent - ASGD //!Average Stochastic Gradient Descent + ILLEGAL_SVMSGD_TYPE, + SGD, //!< Stochastic Gradient Descent + ASGD //!< Average Stochastic Gradient Descent + }; + + /** Margin type.*/ + enum MarginType + { + ILLEGAL_MARGIN_TYPE, + SOFT_MARGIN, //!< General case, suits to the case of non-linearly separable sets, allows outliers. + HARD_MARGIN //!< More accurate for the case of linearly separable sets. }; /** @@ -1553,49 +1612,59 @@ public: CV_WRAP virtual float getShift() = 0; - /** Creates empty model. + /** @brief Creates empty model. Use StatModel::train to train the model. Since %SVMSGD has several parameters, you may want to find the best parameters for your problem or use setOptimalParameters() to set some default parameters. */ CV_WRAP static Ptr create(); - /** Function sets optimal parameters values for chosen SVM SGD model. + /** @brief Function sets optimal parameters values for chosen SVM SGD model. * If chosen type is ASGD, function sets the following values for parameters of model: - * lambda = 0.00001; - * gamma0 = 0.05; - * c = 0.75; + * \f$\lambda = 0.00001\f$; + * \f$\gamma_0 = 0.05\f$; + * \f$c = 0.75\f$; * termCrit.maxCount = 100000; * termCrit.epsilon = 0.00001; * * If SGD: - * lambda = 0.0001; - * gamma0 = 0.05; - * c = 1; + * \f$\lambda = 0.0001\f$; + * \f$\gamma_0 = 0.05\f$; + * \f$c = 1\f$; * termCrit.maxCount = 100000; * termCrit.epsilon = 0.00001; - * @param type is the type of SVMSGD classifier. Legal values are SvmsgdType::SGD and SvmsgdType::ASGD. + * @param svmsgdType is the type of SVMSGD classifier. Legal values are SvmsgdType::SGD and SvmsgdType::ASGD. * Recommended value is SvmsgdType::ASGD (by default). + * @param marginType is the type of margin constraint. Legal values are MarginType::SOFT_MARGIN and MarginType::HARD_MARGIN. + * Default value is MarginType::SOFT_MARGIN. */ - CV_WRAP virtual void setOptimalParameters(int type = ASGD) = 0; + CV_WRAP virtual void setOptimalParameters(int svmsgdType = ASGD, int marginType = SOFT_MARGIN) = 0; - /** %Algorithm type, one of SVMSGD::SvmsgdType. */ + /** @brief %Algorithm type, one of SVMSGD::SvmsgdType. */ /** @see setAlgorithmType */ - CV_WRAP virtual int getType() const = 0; + CV_WRAP virtual int getSvmsgdType() const = 0; /** @copybrief getAlgorithmType @see getAlgorithmType */ - CV_WRAP virtual void setType(int type) = 0; + CV_WRAP virtual void setSvmsgdType(int svmsgdType) = 0; - /** Parameter _Lambda_ of a %SVMSGD optimization problem. Default value is 0. */ + /** @brief %Margin type, one of SVMSGD::MarginType. */ + /** @see setMarginType */ + CV_WRAP virtual int getMarginType() const = 0; + /** @copybrief getMarginType @see getMarginType */ + CV_WRAP virtual void setMarginType(int marginType) = 0; + + + /** @brief Parameter \f$\lambda\f$ of a %SVMSGD optimization problem. Default value is 0. */ /** @see setLambda */ CV_WRAP virtual float getLambda() const = 0; /** @copybrief getLambda @see getLambda */ CV_WRAP virtual void setLambda(float lambda) = 0; - /** Parameter _Gamma0_ of a %SVMSGD optimization problem. Default value is 0. */ + /** @brief Parameter \f$\gamma_0\f$ of a %SVMSGD optimization problem. Default value is 0. */ /** @see setGamma0 */ CV_WRAP virtual float getGamma0() const = 0; + /** @copybrief getGamma0 @see getGamma0 */ CV_WRAP virtual void setGamma0(float gamma0) = 0; - /** Parameter _C_ of a %SVMSGD optimization problem. Default value is 0. */ + /** @brief Parameter \f$c\f$ of a %SVMSGD optimization problem. Default value is 0. */ /** @see setC */ CV_WRAP virtual float getC() const = 0; /** @copybrief getC @see getC */ diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 5c75023b7d..cfb2c760e0 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -42,7 +42,6 @@ #include "precomp.hpp" #include "limits" -//#include "math.h" #include @@ -76,9 +75,9 @@ public: virtual void clear(); - virtual void write(FileStorage& fs) const; + virtual void write(FileStorage &fs) const; - virtual void read(const FileNode& fn); + virtual void read(const FileNode &fn); virtual Mat getWeights(){ return weights_; } @@ -88,11 +87,15 @@ public: virtual String getDefaultName() const {return "opencv_ml_svmsgd";} - virtual void setOptimalParameters(int type = ASGD); + virtual void setOptimalParameters(int svmsgdType = ASGD, int marginType = SOFT_MARGIN); - virtual int getType() const; + virtual int getSvmsgdType() const; - virtual void setType(int type); + virtual void setSvmsgdType(int svmsgdType); + + virtual int getMarginType() const; + + virtual void setMarginType(int marginType); CV_IMPL_PROPERTY(float, Lambda, params.lambda) CV_IMPL_PROPERTY(float, Gamma0, params.gamma0) @@ -100,21 +103,21 @@ public: CV_IMPL_PROPERTY_S(cv::TermCriteria, TermCriteria, params.termCrit) private: - void updateWeights(InputArray sample, bool isFirstClass, float gamma, Mat weights); + void updateWeights(InputArray sample, bool isFirstClass, float gamma, Mat &weights); std::pair areClassesEmpty(Mat responses); - void writeParams( FileStorage& fs ) const; + void writeParams( FileStorage &fs ) const; - void readParams( const FileNode& fn ); + void readParams( const FileNode &fn ); static inline bool isFirstClass(float val) { return val > 0; } - static void normalizeSamples(Mat &matrix, Mat &multiplier, Mat &average); + static void normalizeSamples(Mat &matrix, Mat &average, float &multiplier); float calcShift(InputArray _samples, InputArray _responses) const; - static void makeExtendedTrainSamples(const Mat trainSamples, Mat &extendedTrainSamples, Mat &multiplier); + static void makeExtendedTrainSamples(const Mat &trainSamples, Mat &extendedTrainSamples, Mat &average, float &multiplier); @@ -130,6 +133,7 @@ private: float c; TermCriteria termCrit; SvmsgdType svmsgdType; + MarginType marginType; }; SVMSGDParams params; @@ -160,7 +164,7 @@ std::pair SVMSGDImpl::areClassesEmpty(Mat responses) return emptyInClasses; } -void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &multiplier, Mat &average) +void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) { int featuresCount = samples.cols; int samplesCount = samples.rows; @@ -176,37 +180,25 @@ void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &multiplier, Mat &average) samples.row(sampleIndex) -= average; } - Mat featureNorm(1, featuresCount, samples.type()); - for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++) - { - featureNorm.at(featureIndex) = norm(samples.col(featureIndex)); - } + double normValue = norm(samples); - multiplier = sqrt(samplesCount) / featureNorm; - for (int sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) - { - samples.row(sampleIndex) = samples.row(sampleIndex).mul(multiplier); - } + multiplier = sqrt(samples.total()) / normValue; + + samples *= multiplier; } -void SVMSGDImpl::makeExtendedTrainSamples(const Mat trainSamples, Mat &extendedTrainSamples, Mat &multiplier) +void SVMSGDImpl::makeExtendedTrainSamples(const Mat &trainSamples, Mat &extendedTrainSamples, Mat &average, float &multiplier) { Mat normalisedTrainSamples = trainSamples.clone(); int samplesCount = normalisedTrainSamples.rows; - Mat average; - - normalizeSamples(normalisedTrainSamples, multiplier, average); + normalizeSamples(normalisedTrainSamples, average, multiplier); Mat onesCol = Mat::ones(samplesCount, 1, CV_32F); cv::hconcat(normalisedTrainSamples, onesCol, extendedTrainSamples); - - //cout << "SVMSGDImpl::makeExtendedTrainSamples average: \n" << average << endl; - //cout << "SVMSGDImpl::makeExtendedTrainSamples multiplier: \n" << multiplier << endl; } - -void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, Mat weights) +void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, Mat& weights) { Mat sample = _sample.getMat(); @@ -226,7 +218,7 @@ void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const { - float distance_to_classes[2] = { std::numeric_limits::max(), std::numeric_limits::max() }; + float distanceToClasses[2] = { std::numeric_limits::max(), std::numeric_limits::max() }; Mat trainSamples = _samples.getMat(); int trainSamplesCount = trainSamples.rows; @@ -241,36 +233,29 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const bool firstClass = isFirstClass(trainResponses.at(samplesIndex)); int index = firstClass ? 0:1; float signToMul = firstClass ? 1 : -1; - float cur_distance = dotProduct * signToMul; + float curDistance = dotProduct * signToMul; - if (cur_distance < distance_to_classes[index]) + if (curDistance < distanceToClasses[index]) { - distance_to_classes[index] = cur_distance; + distanceToClasses[index] = curDistance; } } - return -(distance_to_classes[0] - distance_to_classes[1]) / 2.f; + return -(distanceToClasses[0] - distanceToClasses[1]) / 2.f; } bool SVMSGDImpl::train(const Ptr& data, int) { - //cout << "SVMSGDImpl::train begin" << endl; clear(); CV_Assert( isClassifier() ); //toDo: consider Mat trainSamples = data->getTrainSamples(); - //cout << "SVMSGDImpl::train trainSamples: \n" << trainSamples << endl; - int featureCount = trainSamples.cols; Mat trainResponses = data->getTrainResponses(); // (trainSamplesCount x 1) matrix - //cout << "SVMSGDImpl::train trainresponses: \n" << trainResponses << endl; - std::pair areEmpty = areClassesEmpty(trainResponses); - //cout << "SVMSGDImpl::train areEmpty" << areEmpty.first << "," << areEmpty.second << endl; - if ( areEmpty.first && areEmpty.second ) { return false; @@ -283,10 +268,9 @@ bool SVMSGDImpl::train(const Ptr& data, int) } Mat extendedTrainSamples; - Mat multiplier; - makeExtendedTrainSamples(trainSamples, extendedTrainSamples, multiplier); - - //cout << "SVMSGDImpl::train extendedTrainSamples: \n" << extendedTrainSamples << endl; + Mat average; + float multiplier = 0; + makeExtendedTrainSamples(trainSamples, extendedTrainSamples, average, multiplier); int extendedTrainSamplesCount = extendedTrainSamples.rows; int extendedFeatureCount = extendedTrainSamples.cols; @@ -301,6 +285,7 @@ bool SVMSGDImpl::train(const Ptr& data, int) RNG rng(0); + CV_Assert (params.termCrit.type & TermCriteria::COUNT || params.termCrit.type & TermCriteria::EPS); int maxCount = (params.termCrit.type & TermCriteria::COUNT) ? params.termCrit.maxCount : INT_MAX; double epsilon = (params.termCrit.type & TermCriteria::EPS) ? params.termCrit.epsilon : 0; @@ -336,17 +321,20 @@ bool SVMSGDImpl::train(const Ptr& data, int) extendedWeights = averageExtendedWeights; } - //cout << "SVMSGDImpl::train extendedWeights: \n" << extendedWeights << endl; - Rect roi(0, 0, featureCount, 1); weights_ = extendedWeights(roi); - weights_ = weights_.mul(1/multiplier); + weights_ *= multiplier; - //cout << "SVMSGDImpl::train weights: \n" << weights_ << endl; + CV_Assert(params.marginType == SOFT_MARGIN || params.marginType == HARD_MARGIN); - shift_ = calcShift(trainSamples, trainResponses); - - //cout << "SVMSGDImpl::train shift = " << shift_ << endl; + if (params.marginType == SOFT_MARGIN) + { + shift_ = extendedWeights.at(featureCount) - weights_.dot(average); + } + else + { + shift_ = calcShift(trainSamples, trainResponses); + } return true; } @@ -385,6 +373,8 @@ float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) cons bool SVMSGDImpl::isClassifier() const { return (params.svmsgdType == SGD || params.svmsgdType == ASGD) + && + (params.marginType == SOFT_MARGIN || params.marginType == HARD_MARGIN) && (params.lambda > 0) && (params.gamma0 > 0) && (params.c >= 0); } @@ -417,15 +407,32 @@ void SVMSGDImpl::writeParams( FileStorage& fs ) const case ASGD: SvmsgdTypeStr = "ASGD"; break; - case ILLEGAL_VALUE: - SvmsgdTypeStr = format("Uknown_%d", params.svmsgdType); + case ILLEGAL_SVMSGD_TYPE: + SvmsgdTypeStr = format("Unknown_%d", params.svmsgdType); default: std::cout << "params.svmsgdType isn't initialized" << std::endl; } - fs << "svmsgdType" << SvmsgdTypeStr; + String marginTypeStr; + + switch (params.marginType) + { + case SOFT_MARGIN: + marginTypeStr = "SOFT_MARGIN"; + break; + case HARD_MARGIN: + marginTypeStr = "HARD_MARGIN"; + break; + case ILLEGAL_MARGIN_TYPE: + marginTypeStr = format("Unknown_%d", params.marginType); + default: + std::cout << "params.marginType isn't initialized" << std::endl; + } + + fs << "marginType" << marginTypeStr; + fs << "lambda" << params.lambda; fs << "gamma0" << params.gamma0; fs << "c" << params.c; @@ -438,8 +445,6 @@ void SVMSGDImpl::writeParams( FileStorage& fs ) const fs << "}"; } - - void SVMSGDImpl::read(const FileNode& fn) { clear(); @@ -455,13 +460,23 @@ void SVMSGDImpl::readParams( const FileNode& fn ) String svmsgdTypeStr = (String)fn["svmsgdType"]; SvmsgdType svmsgdType = svmsgdTypeStr == "SGD" ? SGD : - svmsgdTypeStr == "ASGD" ? ASGD : ILLEGAL_VALUE; + svmsgdTypeStr == "ASGD" ? ASGD : ILLEGAL_SVMSGD_TYPE; - if( svmsgdType == ILLEGAL_VALUE ) + if( svmsgdType == ILLEGAL_SVMSGD_TYPE ) CV_Error( CV_StsParseError, "Missing or invalid SVMSGD type" ); params.svmsgdType = svmsgdType; + String marginTypeStr = (String)fn["marginType"]; + MarginType marginType = + marginTypeStr == "SOFT_MARGIN" ? SOFT_MARGIN : + marginTypeStr == "HARD_MARGIN" ? HARD_MARGIN : ILLEGAL_MARGIN_TYPE; + + if( marginType == ILLEGAL_MARGIN_TYPE ) + CV_Error( CV_StsParseError, "Missing or invalid margin type" ); + + params.marginType = marginType; + CV_Assert ( fn["lambda"].isReal() ); params.lambda = (float)fn["lambda"]; @@ -494,7 +509,8 @@ SVMSGDImpl::SVMSGDImpl() { clear(); - params.svmsgdType = ILLEGAL_VALUE; + params.svmsgdType = ILLEGAL_SVMSGD_TYPE; + params.marginType = ILLEGAL_MARGIN_TYPE; // Parameters for learning params.lambda = 0; // regularization @@ -505,26 +521,28 @@ SVMSGDImpl::SVMSGDImpl() params.termCrit = _termCrit; } -void SVMSGDImpl::setOptimalParameters(int type) +void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) { - switch (type) + switch (svmsgdType) { case SGD: params.svmsgdType = SGD; + params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : + (marginType == HARD_MARGIN) ? HARD_MARGIN : ILLEGAL_MARGIN_TYPE; params.lambda = 0.0001; params.gamma0 = 0.05; params.c = 1; - params.termCrit.maxCount = 100000; - params.termCrit.epsilon = 0.00001; + params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001); break; case ASGD: params.svmsgdType = ASGD; + params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : + (marginType == HARD_MARGIN) ? HARD_MARGIN : ILLEGAL_MARGIN_TYPE; params.lambda = 0.00001; params.gamma0 = 0.05; params.c = 0.75; - params.termCrit.maxCount = 100000; - params.termCrit.epsilon = 0.00001; + params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001); break; default: @@ -532,7 +550,7 @@ void SVMSGDImpl::setOptimalParameters(int type) } } -void SVMSGDImpl::setType(int type) +void SVMSGDImpl::setSvmsgdType(int type) { switch (type) { @@ -543,13 +561,33 @@ void SVMSGDImpl::setType(int type) params.svmsgdType = ASGD; break; default: - params.svmsgdType = ILLEGAL_VALUE; + params.svmsgdType = ILLEGAL_SVMSGD_TYPE; } } -int SVMSGDImpl::getType() const +int SVMSGDImpl::getSvmsgdType() const { return params.svmsgdType; } + +void SVMSGDImpl::setMarginType(int type) +{ + switch (type) + { + case HARD_MARGIN: + params.marginType = HARD_MARGIN; + break; + case SOFT_MARGIN: + params.marginType = SOFT_MARGIN; + break; + default: + params.marginType = ILLEGAL_MARGIN_TYPE; + } +} + +int SVMSGDImpl::getMarginType() const +{ + return params.marginType; +} } //ml } //cv diff --git a/modules/ml/test/test_mltests2.cpp b/modules/ml/test/test_mltests2.cpp index 6603a35c5b..9cdd368c4c 100644 --- a/modules/ml/test/test_mltests2.cpp +++ b/modules/ml/test/test_mltests2.cpp @@ -199,10 +199,19 @@ int str_to_svmsgd_type( String& str ) return SVMSGD::SGD; if ( !str.compare("ASGD") ) return SVMSGD::ASGD; - CV_Error( CV_StsBadArg, "incorrect boost type string" ); + CV_Error( CV_StsBadArg, "incorrect svmsgd type string" ); return -1; } +int str_to_margin_type( String& str ) +{ + if ( !str.compare("SOFT_MARGIN") ) + return SVMSGD::SOFT_MARGIN; + if ( !str.compare("HARD_MARGIN") ) + return SVMSGD::HARD_MARGIN; + CV_Error( CV_StsBadArg, "incorrect svmsgd margin type string" ); + return -1; +} // ---------------------------------- MLBaseTest --------------------------------------------------- CV_MLBaseTest::CV_MLBaseTest(const char* _modelName) @@ -452,10 +461,16 @@ int CV_MLBaseTest::train( int testCaseIdx ) { String svmsgdTypeStr; modelParamsNode["svmsgdType"] >> svmsgdTypeStr; - Ptr m = SVMSGD::create(); - int type = str_to_svmsgd_type( svmsgdTypeStr ); - m->setType(type); - //m->setType(str_to_svmsgd_type( svmsgdTypeStr )); + + Ptr m = SVMSGD::create(); + int svmsgdType = str_to_svmsgd_type( svmsgdTypeStr ); + m->setSvmsgdType(svmsgdType); + + String marginTypeStr; + modelParamsNode["marginType"] >> marginTypeStr; + int marginType = str_to_margin_type( marginTypeStr ); + m->setMarginType(marginType); + m->setLambda(modelParamsNode["lambda"]); m->setGamma0(modelParamsNode["gamma0"]); m->setC(modelParamsNode["c"]); diff --git a/modules/ml/test/test_save_load.cpp b/modules/ml/test/test_save_load.cpp index 354c6e0307..1bec3cc274 100644 --- a/modules/ml/test/test_save_load.cpp +++ b/modules/ml/test/test_save_load.cpp @@ -270,11 +270,7 @@ TEST(ML_DTree, legacy_load) { CV_LegacyTest test(CV_DTREE, "_abalone.xml;_mushro TEST(ML_NBayes, legacy_load) { CV_LegacyTest test(CV_NBAYES, "_waveform.xml"); test.safe_run(); } TEST(ML_SVM, legacy_load) { CV_LegacyTest test(CV_SVM, "_poletelecomm.xml;_waveform.xml"); test.safe_run(); } TEST(ML_RTrees, legacy_load) { CV_LegacyTest test(CV_RTREES, "_waveform.xml"); test.safe_run(); } -TEST(ML_SVMSGD, legacy_load) -{ - CV_LegacyTest test(CV_SVMSGD, "_waveform.xml"); - test.safe_run(); -} +TEST(ML_SVMSGD, legacy_load) { CV_LegacyTest test(CV_SVMSGD, "_waveform.xml"); test.safe_run(); } /*TEST(ML_SVM, throw_exception_when_save_untrained_model) { diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 5445271eec..7fe298172c 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -52,45 +52,99 @@ using cv::ml::TrainData; class CV_SVMSGDTrainTest : public cvtest::BaseTest { public: - CV_SVMSGDTrainTest(Mat _weights, float shift); + enum TrainDataType + { + UNIFORM_SAME_SCALE, + UNIFORM_DIFFERENT_SCALES + }; + + CV_SVMSGDTrainTest(Mat _weights, float shift, TrainDataType type, double precision = 0.01); private: virtual void run( int start_from ); - float decisionFunction(Mat sample, Mat weights, float shift); + static float decisionFunction(const Mat &sample, const Mat &weights, float shift); + void makeTrainData(Mat weights, float shift); + void makeTestData(Mat weights, float shift); + void generateSameScaleData(Mat &samples); + void generateDifferentScalesData(Mat &samples, float shift); + TrainDataType type; + double precision; cv::Ptr data; cv::Mat testSamples; cv::Mat testResponses; static const int TEST_VALUE_LIMIT = 500; }; -CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(Mat weights, float shift) +void CV_SVMSGDTrainTest::generateSameScaleData(Mat &samples) +{ + float lowerLimit = -TEST_VALUE_LIMIT; + float upperLimit = TEST_VALUE_LIMIT; + cv::RNG rng(0); + rng.fill(samples, RNG::UNIFORM, lowerLimit, upperLimit); +} + +void CV_SVMSGDTrainTest::generateDifferentScalesData(Mat &samples, float shift) +{ + int featureCount = samples.cols; + + float lowerLimit = -TEST_VALUE_LIMIT; + float upperLimit = TEST_VALUE_LIMIT; + cv::RNG rng(10); + + + for (int featureIndex = 0; featureIndex < featureCount; featureIndex++) + { + int crit = rng.uniform(0, 2); + + if (crit > 0) + { + rng.fill(samples.col(featureIndex), RNG::UNIFORM, lowerLimit - shift, upperLimit - shift); + } + else + { + rng.fill(samples.col(featureIndex), RNG::UNIFORM, lowerLimit/10, upperLimit/10); + } + } +} + +void CV_SVMSGDTrainTest::makeTrainData(Mat weights, float shift) { int datasize = 100000; - int varCount = weights.cols; - cv::Mat samples = cv::Mat::zeros( datasize, varCount, CV_32FC1 ); - cv::Mat responses = cv::Mat::zeros( datasize, 1, CV_32FC1 ); - cv::RNG rng(0); + int featureCount = weights.cols; + cv::Mat samples = cv::Mat::zeros(datasize, featureCount, CV_32FC1); + cv::Mat responses = cv::Mat::zeros(datasize, 1, CV_32FC1); + + switch(type) + { + case UNIFORM_SAME_SCALE: + generateSameScaleData(samples); + break; + case UNIFORM_DIFFERENT_SCALES: + generateDifferentScalesData(samples, shift); + break; + default: + CV_Error(CV_StsBadArg, "Unknown train data type"); + } + + for (int sampleIndex = 0; sampleIndex < datasize; sampleIndex++) + { + responses.at(sampleIndex) = decisionFunction(samples.row(sampleIndex), weights, shift) > 0 ? 1 : -1; + } + + data = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); +} + +void CV_SVMSGDTrainTest::makeTestData(Mat weights, float shift) +{ + int testSamplesCount = 100000; + int featureCount = weights.cols; float lowerLimit = -TEST_VALUE_LIMIT; float upperLimit = TEST_VALUE_LIMIT; + cv::RNG rng(0); - rng.fill(samples, RNG::UNIFORM, lowerLimit, upperLimit); - for (int sampleIndex = 0; sampleIndex < datasize; sampleIndex++) - { - responses.at( sampleIndex ) = decisionFunction(samples.row(sampleIndex), weights, shift) > 0 ? 1 : -1; - } - - - - std::cout << "real weights\n" << weights/norm(weights) << "\n" << std::endl; - std::cout << "real shift \n" << shift/norm(weights) << "\n" << std::endl; - - data = TrainData::create( samples, cv::ml::ROW_SAMPLE, responses ); - - int testSamplesCount = 100000; - - testSamples.create(testSamplesCount, varCount, CV_32FC1); + testSamples.create(testSamplesCount, featureCount, CV_32FC1); rng.fill(testSamples, RNG::UNIFORM, lowerLimit, upperLimit); testResponses.create(testSamplesCount, 1, CV_32FC1); @@ -100,12 +154,24 @@ CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(Mat weights, float shift) } } +CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(Mat weights, float shift, TrainDataType _type, double _precision) +{ + type = _type; + precision = _precision; + makeTrainData(weights, shift); + makeTestData(weights, shift); +} + +float CV_SVMSGDTrainTest::decisionFunction(const Mat &sample, const Mat &weights, float shift) +{ + return sample.dot(weights) + shift; +} + void CV_SVMSGDTrainTest::run( int /*start_from*/ ) { cv::Ptr svmsgd = SVMSGD::create(); - svmsgd->setOptimalParameters(SVMSGD::ASGD); - svmsgd->setTermCriteria(TermCriteria(TermCriteria::EPS, 0, 0.00005)); + svmsgd->setOptimalParameters(); svmsgd->train(data); @@ -118,77 +184,106 @@ void CV_SVMSGDTrainTest::run( int /*start_from*/ ) for (int i = 0; i < testSamplesCount; i++) { - if (responses.at(i) * testResponses.at(i) < 0 ) + if (responses.at(i) * testResponses.at(i) < 0) errCount++; } - - float normW = norm(svmsgd->getWeights()); - - std::cout << "found weights\n" << svmsgd->getWeights()/normW << "\n" << std::endl; - std::cout << "found shift \n" << svmsgd->getShift()/normW << "\n" << std::endl; - float err = (float)errCount / testSamplesCount; std::cout << "err " << err << std::endl; - if ( err > 0.01 ) + if ( err > precision ) { - ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY ); + ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); } } -float CV_SVMSGDTrainTest::decisionFunction(Mat sample, Mat weights, float shift) + +void makeWeightsAndShift(int featureCount, Mat &weights, float &shift) { - return sample.dot(weights) + shift; -} - -TEST(ML_SVMSGD, train0) -{ - int varCount = 2; - - Mat weights; - weights.create(1, varCount, CV_32FC1); - weights.at(0) = 1; - weights.at(1) = 0; - cv::RNG rng(1); - float shift = rng.uniform(-varCount, varCount); - - CV_SVMSGDTrainTest test(weights, shift); - test.safe_run(); -} - -TEST(ML_SVMSGD, train1) -{ - int varCount = 5; - - Mat weights; - weights.create(1, varCount, CV_32FC1); - - float lowerLimit = -1; - float upperLimit = 1; + weights.create(1, featureCount, CV_32FC1); cv::RNG rng(0); + double lowerLimit = -1; + double upperLimit = 1; + rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit); - - float shift = rng.uniform(-varCount, varCount); - - CV_SVMSGDTrainTest test(weights, shift); - test.safe_run(); + shift = rng.uniform(-featureCount, featureCount); } -TEST(ML_SVMSGD, train2) + +TEST(ML_SVMSGD, trainSameScale2) { - int varCount = 100; + int featureCount = 2; Mat weights; - weights.create(1, varCount, CV_32FC1); - float lowerLimit = -1; - float upperLimit = 1; - cv::RNG rng(0); - rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit); + float shift = 0; + makeWeightsAndShift(featureCount, weights, shift); - float shift = rng.uniform(-varCount, varCount); - - CV_SVMSGDTrainTest test(weights,shift); + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE); + test.safe_run(); +} + +TEST(ML_SVMSGD, trainSameScale5) +{ + int featureCount = 5; + + Mat weights; + + float shift = 0; + makeWeightsAndShift(featureCount, weights, shift); + + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE); + test.safe_run(); +} + +TEST(ML_SVMSGD, trainSameScale100) +{ + int featureCount = 100; + + Mat weights; + + float shift = 0; + makeWeightsAndShift(featureCount, weights, shift); + + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE); + test.safe_run(); +} + +TEST(ML_SVMSGD, trainDifferentScales2) +{ + int featureCount = 2; + + Mat weights; + + float shift = 0; + makeWeightsAndShift(featureCount, weights, shift); + + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01); + test.safe_run(); +} + +TEST(ML_SVMSGD, trainDifferentScales5) +{ + int featureCount = 5; + + Mat weights; + + float shift = 0; + makeWeightsAndShift(featureCount, weights, shift); + + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.05); + test.safe_run(); +} + +TEST(ML_SVMSGD, trainDifferentScales100) +{ + int featureCount = 100; + + Mat weights; + + float shift = 0; + makeWeightsAndShift(featureCount, weights, shift); + + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.10); test.safe_run(); } diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index 19c30ffca9..7d537341f8 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -40,16 +40,13 @@ void fillSegments(std::vector > &segments, int width, int void redraw(Data data, const Point points[2]); //add point in train set, train SVMSGD algorithm and draw results on image -void addPointRetrainAndRedraw(Data &data, int x, int y); +void addPointRetrainAndRedraw(Data &data, int x, int y, int response); bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift) { cv::Ptr svmsgd = SVMSGD::create(); - svmsgd->setOptimalParameters(SVMSGD::ASGD); - svmsgd->setTermCriteria(TermCriteria(TermCriteria::EPS, 0, 0.00000001)); - svmsgd->setLambda(0.00000001); - + svmsgd->setOptimalParameters(); cv::Ptr train_data = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); svmsgd->train( train_data ); @@ -64,6 +61,27 @@ bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift return false; } +void fillSegments(std::vector > &segments, int width, int height) +{ + std::pair currentSegment; + + currentSegment.first = Point(width, 0); + currentSegment.second = Point(width, height); + segments.push_back(currentSegment); + + currentSegment.first = Point(0, height); + currentSegment.second = Point(width, height); + segments.push_back(currentSegment); + + currentSegment.first = Point(0, 0); + currentSegment.second = Point(width, 0); + segments.push_back(currentSegment); + + currentSegment.first = Point(0, 0); + currentSegment.second = Point(0, height); + segments.push_back(currentSegment); +} + bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint) { @@ -123,27 +141,6 @@ bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2], int return true; } -void fillSegments(std::vector > &segments, int width, int height) -{ - std::pair currentSegment; - - currentSegment.first = Point(width, 0); - currentSegment.second = Point(width, height); - segments.push_back(currentSegment); - - currentSegment.first = Point(0, height); - currentSegment.second = Point(width, height); - segments.push_back(currentSegment); - - currentSegment.first = Point(0, 0); - currentSegment.second = Point(width, 0); - segments.push_back(currentSegment); - - currentSegment.first = Point(0, 0); - currentSegment.second = Point(0, height); - segments.push_back(currentSegment); -} - void redraw(Data data, const Point points[2]) { data.img.setTo(0); @@ -162,19 +159,20 @@ void redraw(Data data, const Point points[2]) imshow("Train svmsgd", data.img); } -void addPointRetrainAndRedraw(Data &data, int x, int y) +void addPointRetrainAndRedraw(Data &data, int x, int y, int response) { Mat currentSample(1, 2, CV_32F); currentSample.at(0,0) = x; currentSample.at(0,1) = y; data.samples.push_back(currentSample); + data.responses.push_back(response); Mat weights(1, 2, CV_32F); float shift = 0; if (doTrain(data.samples, data.responses, weights, shift)) - { + { Point points[2]; findPointsForLine(weights, shift, points, data.img.cols, data.img.rows); @@ -189,15 +187,12 @@ static void onMouse( int event, int x, int y, int, void* pData) switch( event ) { - case CV_EVENT_LBUTTONUP: - data.responses.push_back(1); - addPointRetrainAndRedraw(data, x, y); - + case CV_EVENT_LBUTTONUP: + addPointRetrainAndRedraw(data, x, y, 1); break; case CV_EVENT_RBUTTONDOWN: - data.responses.push_back(-1); - addPointRetrainAndRedraw(data, x, y); + addPointRetrainAndRedraw(data, x, y, -1); break; } From 41c0a38344361ad455f9df3a7c9c68ac3633b24c Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 10 Feb 2016 14:52:50 +0300 Subject: [PATCH 132/468] Fixed test samples for tests with different borders Added new test (separating two points) --- modules/ml/src/svmsgd.cpp | 2 +- modules/ml/test/test_save_load.cpp | 5 +- modules/ml/test/test_svmsgd.cpp | 121 ++++++++++++++++++++--------- samples/cpp/train_svmsgd.cpp | 4 +- 4 files changed, 89 insertions(+), 43 deletions(-) diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index cfb2c760e0..4ad103e383 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -146,7 +146,7 @@ Ptr SVMSGD::create() std::pair SVMSGDImpl::areClassesEmpty(Mat responses) { - CV_Assert(responses.cols == 1); + CV_Assert(responses.cols == 1 || responses.rows == 1); std::pair emptyInClasses(true, true); int limit_index = responses.rows; diff --git a/modules/ml/test/test_save_load.cpp b/modules/ml/test/test_save_load.cpp index 1bec3cc274..f55f9b8a11 100644 --- a/modules/ml/test/test_save_load.cpp +++ b/modules/ml/test/test_save_load.cpp @@ -160,10 +160,7 @@ TEST(ML_DTree, save_load) { CV_SLMLTest test( CV_DTREE ); test.safe_run(); } TEST(ML_Boost, save_load) { CV_SLMLTest test( CV_BOOST ); test.safe_run(); } TEST(ML_RTrees, save_load) { CV_SLMLTest test( CV_RTREES ); test.safe_run(); } TEST(DISABLED_ML_ERTrees, save_load) { CV_SLMLTest test( CV_ERTREES ); test.safe_run(); } -TEST(MV_SVMSGD, save_load){ - CV_SLMLTest test( CV_SVMSGD ); - test.safe_run(); -} +TEST(MV_SVMSGD, save_load){ CV_SLMLTest test( CV_SVMSGD ); test.safe_run(); } class CV_LegacyTest : public cvtest::BaseTest { diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 7fe298172c..666ef18be6 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -58,39 +58,40 @@ public: UNIFORM_DIFFERENT_SCALES }; - CV_SVMSGDTrainTest(Mat _weights, float shift, TrainDataType type, double precision = 0.01); + CV_SVMSGDTrainTest(const Mat &_weights, float shift, TrainDataType type, double precision = 0.01); private: virtual void run( int start_from ); static float decisionFunction(const Mat &sample, const Mat &weights, float shift); void makeTrainData(Mat weights, float shift); void makeTestData(Mat weights, float shift); - void generateSameScaleData(Mat &samples); - void generateDifferentScalesData(Mat &samples, float shift); + void generateSameBorders(int featureCount); + void generateDifferentBorders(int featureCount); TrainDataType type; double precision; + std::vector > borders; cv::Ptr data; cv::Mat testSamples; cv::Mat testResponses; static const int TEST_VALUE_LIMIT = 500; }; -void CV_SVMSGDTrainTest::generateSameScaleData(Mat &samples) +void CV_SVMSGDTrainTest::generateSameBorders(int featureCount) +{ + float lowerLimit = -TEST_VALUE_LIMIT; + float upperLimit = TEST_VALUE_LIMIT; + + for (int featureIndex = 0; featureIndex < featureCount; featureIndex++) + { + borders.push_back(std::pair(lowerLimit, upperLimit)); + } +} + +void CV_SVMSGDTrainTest::generateDifferentBorders(int featureCount) { float lowerLimit = -TEST_VALUE_LIMIT; float upperLimit = TEST_VALUE_LIMIT; cv::RNG rng(0); - rng.fill(samples, RNG::UNIFORM, lowerLimit, upperLimit); -} - -void CV_SVMSGDTrainTest::generateDifferentScalesData(Mat &samples, float shift) -{ - int featureCount = samples.cols; - - float lowerLimit = -TEST_VALUE_LIMIT; - float upperLimit = TEST_VALUE_LIMIT; - cv::RNG rng(10); - for (int featureIndex = 0; featureIndex < featureCount; featureIndex++) { @@ -98,11 +99,11 @@ void CV_SVMSGDTrainTest::generateDifferentScalesData(Mat &samples, float shift) if (crit > 0) { - rng.fill(samples.col(featureIndex), RNG::UNIFORM, lowerLimit - shift, upperLimit - shift); + borders.push_back(std::pair(lowerLimit, upperLimit)); } else { - rng.fill(samples.col(featureIndex), RNG::UNIFORM, lowerLimit/10, upperLimit/10); + borders.push_back(std::pair(lowerLimit/1000, upperLimit/1000)); } } } @@ -111,21 +112,16 @@ void CV_SVMSGDTrainTest::makeTrainData(Mat weights, float shift) { int datasize = 100000; int featureCount = weights.cols; - cv::Mat samples = cv::Mat::zeros(datasize, featureCount, CV_32FC1); - cv::Mat responses = cv::Mat::zeros(datasize, 1, CV_32FC1); + RNG rng(0); - switch(type) + cv::Mat samples = cv::Mat::zeros(datasize, featureCount, CV_32FC1); + + for (int featureIndex = 0; featureIndex < featureCount; featureIndex++) { - case UNIFORM_SAME_SCALE: - generateSameScaleData(samples); - break; - case UNIFORM_DIFFERENT_SCALES: - generateDifferentScalesData(samples, shift); - break; - default: - CV_Error(CV_StsBadArg, "Unknown train data type"); + rng.fill(samples.col(featureIndex), RNG::UNIFORM, borders[featureIndex].first, borders[featureIndex].second); } + cv::Mat responses = cv::Mat::zeros(datasize, 1, CV_32FC1); for (int sampleIndex = 0; sampleIndex < datasize; sampleIndex++) { responses.at(sampleIndex) = decisionFunction(samples.row(sampleIndex), weights, shift) > 0 ? 1 : -1; @@ -138,14 +134,14 @@ void CV_SVMSGDTrainTest::makeTestData(Mat weights, float shift) { int testSamplesCount = 100000; int featureCount = weights.cols; - - float lowerLimit = -TEST_VALUE_LIMIT; - float upperLimit = TEST_VALUE_LIMIT; - cv::RNG rng(0); testSamples.create(testSamplesCount, featureCount, CV_32FC1); - rng.fill(testSamples, RNG::UNIFORM, lowerLimit, upperLimit); + for (int featureIndex = 0; featureIndex < featureCount; featureIndex++) + { + rng.fill(testSamples.col(featureIndex), RNG::UNIFORM, borders[featureIndex].first, borders[featureIndex].second); + } + testResponses.create(testSamplesCount, 1, CV_32FC1); for (int i = 0 ; i < testSamplesCount; i++) @@ -154,10 +150,25 @@ void CV_SVMSGDTrainTest::makeTestData(Mat weights, float shift) } } -CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(Mat weights, float shift, TrainDataType _type, double _precision) +CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(const Mat &weights, float shift, TrainDataType _type, double _precision) { type = _type; precision = _precision; + + int featureCount = weights.cols; + + switch(type) + { + case UNIFORM_SAME_SCALE: + generateSameBorders(featureCount); + break; + case UNIFORM_DIFFERENT_SCALES: + generateDifferentBorders(featureCount); + break; + default: + CV_Error(CV_StsBadArg, "Unknown train data type"); + } + makeTrainData(weights, shift); makeTestData(weights, shift); } @@ -271,7 +282,7 @@ TEST(ML_SVMSGD, trainDifferentScales5) float shift = 0; makeWeightsAndShift(featureCount, weights, shift); - CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.05); + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01); test.safe_run(); } @@ -284,6 +295,44 @@ TEST(ML_SVMSGD, trainDifferentScales100) float shift = 0; makeWeightsAndShift(featureCount, weights, shift); - CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.10); + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01); test.safe_run(); } + +TEST(ML_SVMSGD, twoPoints) +{ + Mat samples(2, 2, CV_32FC1); + samples.at(0,0) = 0; + samples.at(0,1) = 0; + samples.at(1,0) = 1000; + samples.at(1,1) = 1; + + Mat responses(2, 1, CV_32FC1); + responses.at(0) = -1; + responses.at(1) = 1; + + cv::Ptr trainData = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); + + Mat realWeights(1, 2, CV_32FC1); + realWeights.at(0) = 1000; + realWeights.at(1) = 1; + + float realShift = -500000.5; + + float normRealWeights = norm(realWeights); + realWeights /= normRealWeights; + realShift /= normRealWeights; + + cv::Ptr svmsgd = SVMSGD::create(); + svmsgd->setOptimalParameters(); + svmsgd->train( trainData ); + + Mat foundWeights = svmsgd->getWeights(); + float foundShift = svmsgd->getShift(); + + float normFoundWeights = norm(foundWeights); + foundWeights /= normFoundWeights; + foundShift /= normFoundWeights; + CV_Assert((norm(foundWeights - realWeights) < 0.001) && (abs((foundShift - realShift) / realShift) < 0.05)); +} + diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index 7d537341f8..cca845ef58 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -48,8 +48,8 @@ bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift cv::Ptr svmsgd = SVMSGD::create(); svmsgd->setOptimalParameters(); - cv::Ptr train_data = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); - svmsgd->train( train_data ); + cv::Ptr trainData = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); + svmsgd->train( trainData ); if (svmsgd->isTrained()) { From 05353a149256ea1a2548cebe3a2b03c43d17bc96 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 10 Feb 2016 15:40:09 +0300 Subject: [PATCH 133/468] Removed trailing whitespaces --- modules/ml/src/svmsgd.cpp | 4 ++-- modules/ml/test/test_svmsgd.cpp | 1 - samples/cpp/train_svmsgd.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 4ad103e383..8de076fa23 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -140,7 +140,7 @@ private: }; Ptr SVMSGD::create() -{ +{ return makePtr(); } @@ -265,7 +265,7 @@ bool SVMSGDImpl::train(const Ptr& data, int) weights_ = Mat::zeros(1, featureCount, CV_32F); shift_ = areEmpty.first ? -1 : 1; return true; - } + } Mat extendedTrainSamples; Mat average; diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 666ef18be6..993a0de6b8 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -335,4 +335,3 @@ TEST(ML_SVMSGD, twoPoints) foundShift /= normFoundWeights; CV_Assert((norm(foundWeights - realWeights) < 0.001) && (abs((foundShift - realShift) / realShift) < 0.05)); } - diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index cca845ef58..616665e87d 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -187,7 +187,7 @@ static void onMouse( int event, int x, int y, int, void* pData) switch( event ) { - case CV_EVENT_LBUTTONUP: + case CV_EVENT_LBUTTONUP: addPointRetrainAndRedraw(data, x, y, 1); break; From c52217236732542b7ce9e70036bdb9a7574bfcd8 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 10 Feb 2016 16:44:16 +0300 Subject: [PATCH 134/468] Fixed small bug in SVMSGD::clear(). --- modules/ml/src/svmsgd.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 8de076fa23..64b44814c5 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -502,6 +502,7 @@ void SVMSGDImpl::readParams( const FileNode& fn ) void SVMSGDImpl::clear() { weights_.release(); + shift_ = 0; } From 617dd5db5b4cea0dbf4ae89d83bc5dfb2e324721 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 10 Feb 2016 17:37:05 +0300 Subject: [PATCH 135/468] Fixed doc/opencv.bib --- doc/opencv.bib | 12 +++++++++++- modules/ml/include/opencv2/ml.hpp | 1 - modules/ml/src/precomp.hpp | 1 + modules/ml/test/test_mltests2.cpp | 2 -- modules/ml/test/test_save_load.cpp | 6 +----- modules/ts/src/ts_gtest.cpp | 2 +- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/doc/opencv.bib b/doc/opencv.bib index 17eedf7172..58ede18322 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -415,6 +415,16 @@ pages = {2548--2555}, organization = {IEEE} } +@ARTICLE{Louhichi07, + author = {Louhichi, H. and Fournel, T. and Lavest, J. M. and Ben Aissia, H.}, + title = {Self-calibration of Scheimpflug cameras: an easy protocol}, + year = {2007}, + pages = {2616–2622}, + journal = {Meas. Sci. Technol.}, + volume = {18}, + number = {8}, + publisher = {IOP Publishing Ltd} +} @ARTICLE{LibSVM, author = {Chang, Chih-Chung and Lin, Chih-Jen}, title = {LIBSVM: a library for support vector machines}, @@ -871,4 +881,4 @@ pages={177--186}, year={2010}, publisher={Springer} -} \ No newline at end of file +} diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index ec7c0730ec..3a8c2ba25b 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1697,7 +1697,6 @@ CV_EXPORTS void randMVNormal( InputArray mean, InputArray cov, int nsamples, Out CV_EXPORTS void createConcentricSpheresTestSet( int nsamples, int nfeatures, int nclasses, OutputArray samples, OutputArray responses); - //! @} ml } diff --git a/modules/ml/src/precomp.hpp b/modules/ml/src/precomp.hpp index 0a5fa06035..84821988b6 100644 --- a/modules/ml/src/precomp.hpp +++ b/modules/ml/src/precomp.hpp @@ -45,6 +45,7 @@ #include "opencv2/ml.hpp" #include "opencv2/core/core_c.h" #include "opencv2/core/utility.hpp" + #include "opencv2/core/private.hpp" #include diff --git a/modules/ml/test/test_mltests2.cpp b/modules/ml/test/test_mltests2.cpp index 9cdd368c4c..01f5568daf 100644 --- a/modules/ml/test/test_mltests2.cpp +++ b/modules/ml/test/test_mltests2.cpp @@ -267,9 +267,7 @@ void CV_MLBaseTest::run( int ) { string filename = ts->get_data_path(); filename += get_validation_filename(); - validationFS.open( filename, FileStorage::READ ); - read_params( *validationFS ); int code = cvtest::TS::OK; diff --git a/modules/ml/test/test_save_load.cpp b/modules/ml/test/test_save_load.cpp index f55f9b8a11..d127471cc9 100644 --- a/modules/ml/test/test_save_load.cpp +++ b/modules/ml/test/test_save_load.cpp @@ -150,11 +150,7 @@ int CV_SLMLTest::validate_test_results( int testCaseIdx ) TEST(ML_NaiveBayes, save_load) { CV_SLMLTest test( CV_NBAYES ); test.safe_run(); } TEST(ML_KNearest, save_load) { CV_SLMLTest test( CV_KNEAREST ); test.safe_run(); } -TEST(ML_SVM, save_load) -{ - CV_SLMLTest test( CV_SVM ); - test.safe_run(); -} +TEST(ML_SVM, save_load) { CV_SLMLTest test( CV_SVM ); test.safe_run(); } TEST(ML_ANN, save_load) { CV_SLMLTest test( CV_ANN ); test.safe_run(); } TEST(ML_DTree, save_load) { CV_SLMLTest test( CV_DTREE ); test.safe_run(); } TEST(ML_Boost, save_load) { CV_SLMLTest test( CV_BOOST ); test.safe_run(); } diff --git a/modules/ts/src/ts_gtest.cpp b/modules/ts/src/ts_gtest.cpp index 5604eb7e62..29a3996be8 100644 --- a/modules/ts/src/ts_gtest.cpp +++ b/modules/ts/src/ts_gtest.cpp @@ -5659,7 +5659,7 @@ class TestCaseNameIs { // Returns true iff the name of test_case matches name_. bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; } private: From 0307dd19fdd7f4b0b5fa25c532dd0f34ad9574cd Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 10 Feb 2016 18:21:45 +0300 Subject: [PATCH 136/468] Minor fix in declaration of SVMSGD::setOptimalParameters --- modules/ml/include/opencv2/ml.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 3a8c2ba25b..e23c242d5c 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1637,7 +1637,7 @@ public: * @param marginType is the type of margin constraint. Legal values are MarginType::SOFT_MARGIN and MarginType::HARD_MARGIN. * Default value is MarginType::SOFT_MARGIN. */ - CV_WRAP virtual void setOptimalParameters(int svmsgdType = ASGD, int marginType = SOFT_MARGIN) = 0; + CV_WRAP virtual void setOptimalParameters(int svmsgdType = SVMSGD::ASGD, int marginType = SVMSGD::SOFT_MARGIN) = 0; /** @brief %Algorithm type, one of SVMSGD::SvmsgdType. */ /** @see setAlgorithmType */ From 5496dedd6a38db7561f2a3a2d3c13407dd4972ea Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 10 Feb 2016 19:46:24 +0300 Subject: [PATCH 137/468] Fixed warnings. --- modules/ml/include/opencv2/ml.hpp | 4 ++-- modules/ml/src/svmsgd.cpp | 31 ++++++++++++++++--------------- modules/ml/test/test_svmsgd.cpp | 12 ++++++------ samples/cpp/train_svmsgd.cpp | 12 ++++++------ 4 files changed, 30 insertions(+), 29 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index e23c242d5c..8b56f0d798 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1640,9 +1640,9 @@ public: CV_WRAP virtual void setOptimalParameters(int svmsgdType = SVMSGD::ASGD, int marginType = SVMSGD::SOFT_MARGIN) = 0; /** @brief %Algorithm type, one of SVMSGD::SvmsgdType. */ - /** @see setAlgorithmType */ + /** @see setSvmsgdType */ CV_WRAP virtual int getSvmsgdType() const = 0; - /** @copybrief getAlgorithmType @see getAlgorithmType */ + /** @copybrief getSvmsgdType @see getSvmsgdType */ CV_WRAP virtual void setSvmsgdType(int svmsgdType) = 0; /** @brief %Margin type, one of SVMSGD::MarginType. */ diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 64b44814c5..3ae051a9dc 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -172,7 +172,8 @@ void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) average = Mat(1, featuresCount, samples.type()); for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++) { - average.at(featureIndex) = mean(samples.col(featureIndex))[0]; + Scalar scalAverage = mean(samples.col(featureIndex))[0]; + average.at(featureIndex) = static_cast(scalAverage[0]); } for (int sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) @@ -182,7 +183,7 @@ void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) double normValue = norm(samples); - multiplier = sqrt(samples.total()) / normValue; + multiplier = static_cast(sqrt(samples.total()) / normValue); samples *= multiplier; } @@ -228,11 +229,11 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const for (int samplesIndex = 0; samplesIndex < trainSamplesCount; samplesIndex++) { Mat currentSample = trainSamples.row(samplesIndex); - float dotProduct = currentSample.dot(weights_); + float dotProduct = static_cast(currentSample.dot(weights_)); bool firstClass = isFirstClass(trainResponses.at(samplesIndex)); - int index = firstClass ? 0:1; - float signToMul = firstClass ? 1 : -1; + int index = firstClass ? 0 : 1; + float signToMul = firstClass ? 1.f : -1.f; float curDistance = dotProduct * signToMul; if (curDistance < distanceToClasses[index]) @@ -263,7 +264,7 @@ bool SVMSGDImpl::train(const Ptr& data, int) if ( areEmpty.first || areEmpty.second ) { weights_ = Mat::zeros(1, featureCount, CV_32F); - shift_ = areEmpty.first ? -1 : 1; + shift_ = areEmpty.first ? -1.f : 1.f; return true; } @@ -329,7 +330,7 @@ bool SVMSGDImpl::train(const Ptr& data, int) if (params.marginType == SOFT_MARGIN) { - shift_ = extendedWeights.at(featureCount) - weights_.dot(average); + shift_ = extendedWeights.at(featureCount) - static_cast(weights_.dot(average)); } else { @@ -363,8 +364,8 @@ float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) cons for (int sampleIndex = 0; sampleIndex < nSamples; sampleIndex++) { Mat currentSample = samples.row(sampleIndex); - float criterion = currentSample.dot(weights_) + shift_; - results.at(sampleIndex) = (criterion >= 0) ? 1 : -1; + float criterion = static_cast(currentSample.dot(weights_)) + shift_; + results.at(sampleIndex) = (criterion >= 0) ? 1.f : -1.f; } return result; @@ -530,9 +531,9 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) params.svmsgdType = SGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : (marginType == HARD_MARGIN) ? HARD_MARGIN : ILLEGAL_MARGIN_TYPE; - params.lambda = 0.0001; - params.gamma0 = 0.05; - params.c = 1; + params.lambda = 0.0001f; + params.gamma0 = 0.05f; + params.c = 1.f; params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001); break; @@ -540,9 +541,9 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) params.svmsgdType = ASGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : (marginType == HARD_MARGIN) ? HARD_MARGIN : ILLEGAL_MARGIN_TYPE; - params.lambda = 0.00001; - params.gamma0 = 0.05; - params.c = 0.75; + params.lambda = 0.00001f; + params.gamma0 = 0.05f; + params.c = 0.75f; params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001); break; diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 993a0de6b8..592e66b3b0 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -124,7 +124,7 @@ void CV_SVMSGDTrainTest::makeTrainData(Mat weights, float shift) cv::Mat responses = cv::Mat::zeros(datasize, 1, CV_32FC1); for (int sampleIndex = 0; sampleIndex < datasize; sampleIndex++) { - responses.at(sampleIndex) = decisionFunction(samples.row(sampleIndex), weights, shift) > 0 ? 1 : -1; + responses.at(sampleIndex) = decisionFunction(samples.row(sampleIndex), weights, shift) > 0 ? 1.f : -1.f; } data = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); @@ -146,7 +146,7 @@ void CV_SVMSGDTrainTest::makeTestData(Mat weights, float shift) for (int i = 0 ; i < testSamplesCount; i++) { - testResponses.at(i) = decisionFunction(testSamples.row(i), weights, shift) > 0 ? 1 : -1; + testResponses.at(i) = decisionFunction(testSamples.row(i), weights, shift) > 0 ? 1.f : -1.f; } } @@ -175,7 +175,7 @@ CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(const Mat &weights, float shift, TrainDat float CV_SVMSGDTrainTest::decisionFunction(const Mat &sample, const Mat &weights, float shift) { - return sample.dot(weights) + shift; + return static_cast(sample.dot(weights)) + shift; } void CV_SVMSGDTrainTest::run( int /*start_from*/ ) @@ -217,7 +217,7 @@ void makeWeightsAndShift(int featureCount, Mat &weights, float &shift) double upperLimit = 1; rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit); - shift = rng.uniform(-featureCount, featureCount); + shift = static_cast(rng.uniform(-featureCount, featureCount)); } @@ -319,7 +319,7 @@ TEST(ML_SVMSGD, twoPoints) float realShift = -500000.5; - float normRealWeights = norm(realWeights); + float normRealWeights = static_cast(norm(realWeights)); realWeights /= normRealWeights; realShift /= normRealWeights; @@ -330,7 +330,7 @@ TEST(ML_SVMSGD, twoPoints) Mat foundWeights = svmsgd->getWeights(); float foundShift = svmsgd->getShift(); - float normFoundWeights = norm(foundWeights); + float normFoundWeights = static_cast(norm(foundWeights)); foundWeights /= normFoundWeights; foundShift /= normFoundWeights; CV_Assert((norm(foundWeights - realWeights) < 0.001) && (abs((foundShift - realShift) / realShift) < 0.05)); diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index 616665e87d..aed8228c4b 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -97,7 +97,7 @@ bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair< if (xMin == xMax && weights.at(1) != 0) { x = xMin; - y = std::floor( - (weights.at(0) * x + shift) / weights.at(1)); + y = static_cast(std::floor( - (weights.at(0) * x + shift) / weights.at(1))); if (y >= yMin && y <= yMax) { crossPoint.x = x; @@ -108,7 +108,7 @@ bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair< else if (yMin == yMax && weights.at(0) != 0) { y = yMin; - x = std::floor( - (weights.at(1) * y + shift) / weights.at(0)); + x = static_cast(std::floor( - (weights.at(1) * y + shift) / weights.at(0))); if (x >= xMin && x <= xMax) { crossPoint.x = x; @@ -149,8 +149,8 @@ void redraw(Data data, const Point points[2]) Scalar color; for (int i = 0; i < data.samples.rows; i++) { - center.x = data.samples.at(i,0); - center.y = data.samples.at(i,1); + center.x = static_cast(data.samples.at(i,0)); + center.y = static_cast(data.samples.at(i,1)); color = (data.responses.at(i) > 0) ? Scalar(128,128,0) : Scalar(0,128,128); circle(data.img, center, radius, color, 5); } @@ -163,8 +163,8 @@ void addPointRetrainAndRedraw(Data &data, int x, int y, int response) { Mat currentSample(1, 2, CV_32F); - currentSample.at(0,0) = x; - currentSample.at(0,1) = y; + currentSample.at(0,0) = (float)x; + currentSample.at(0,1) = (float)y; data.samples.push_back(currentSample); data.responses.push_back(response); From 87bbaa2c27fefef4829b869302d3ac190d6fbfde Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 4 Feb 2016 11:55:00 +0300 Subject: [PATCH 138/468] ocl: OpenCL headers are located in "CL" subfolder (3rdparty/include) --- cmake/checks/opencl.cpp | 5 +---- .../core/opencl/runtime/autogenerated/opencl_core.hpp | 4 ---- .../opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp | 4 ---- .../src/opencl/runtime/generator/template/opencl_core.hpp.in | 4 ---- .../src/opencl/runtime/generator/template/opencl_gl.hpp.in | 4 ---- 5 files changed, 1 insertion(+), 20 deletions(-) diff --git a/cmake/checks/opencl.cpp b/cmake/checks/opencl.cpp index 95a36f3ac7..b71b92f670 100644 --- a/cmake/checks/opencl.cpp +++ b/cmake/checks/opencl.cpp @@ -1,8 +1,5 @@ -#if defined __APPLE__ -#include -#else +// custom OpenCL headers are located in "CL" subfolder (3rdparty/include/...) #include -#endif #ifndef _MSC_VER #ifdef CL_VERSION_1_2 diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp index f824ce9334..801709e2c0 100644 --- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp +++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp @@ -95,11 +95,7 @@ #define clUnloadPlatformCompiler clUnloadPlatformCompiler_ #define clWaitForEvents clWaitForEvents_ -#if defined __APPLE__ -#include -#else #include -#endif // generated by parser_cl.py #undef clBuildProgram diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp index f37ad158e1..64a7fedbac 100644 --- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp +++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp @@ -17,11 +17,7 @@ #define clGetGLObjectInfo clGetGLObjectInfo_ #define clGetGLTextureInfo clGetGLTextureInfo_ -#if defined __APPLE__ -#include -#else #include -#endif // generated by parser_cl.py #undef clCreateFromGLBuffer diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_core.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_core.hpp.in index 4196622c0b..b6c8f05d51 100644 --- a/modules/core/src/opencl/runtime/generator/template/opencl_core.hpp.in +++ b/modules/core/src/opencl/runtime/generator/template/opencl_core.hpp.in @@ -4,11 +4,7 @@ @CL_REMAP_ORIGIN@ -#if defined __APPLE__ -#include -#else #include -#endif @CL_REMAP_DYNAMIC@ diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in index 24434d2de7..4bed423318 100644 --- a/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in +++ b/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in @@ -4,11 +4,7 @@ @CL_REMAP_ORIGIN@ -#if defined __APPLE__ -#include -#else #include -#endif @CL_REMAP_DYNAMIC@ From c7bdbef5042dadfe032dfb5d80f9b90bec830371 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 4 Feb 2016 12:04:04 +0300 Subject: [PATCH 139/468] ocl: fix OpenGL sharing detection (6052) Apple OpenCL framework hasn't OpenGL sharing extension --- .../opencl/runtime/autogenerated/opencl_gl.hpp | 4 ++++ .../runtime/autogenerated/opencl_gl_wrappers.hpp | 4 ++++ .../runtime/autogenerated/opencl_gl_impl.hpp | 4 ++++ .../core/src/opencl/runtime/generator/common.py | 4 ++-- .../core/src/opencl/runtime/generator/generate.sh | 0 .../runtime/generator/template/opencl_gl.hpp.in | 4 ++++ .../generator/template/opencl_gl_impl.hpp.in | 4 ++++ .../generator/template/opencl_gl_wrappers.hpp.in | 4 ++++ modules/core/src/opencl/runtime/opencl_core.cpp | 4 ++++ modules/core/src/opengl.cpp | 15 +++++++++++++++ 10 files changed, 45 insertions(+), 2 deletions(-) mode change 100644 => 100755 modules/core/src/opencl/runtime/generator/generate.sh diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp index 64a7fedbac..1ad4a6acc2 100644 --- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp +++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp @@ -41,6 +41,8 @@ #undef clGetGLTextureInfo #define clGetGLTextureInfo clGetGLTextureInfo_pfn +#ifdef cl_khr_gl_sharing + // generated by parser_cl.py extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLBuffer)(cl_context, cl_mem_flags, cl_GLuint, int*); extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLRenderbuffer)(cl_context, cl_mem_flags, cl_GLuint, cl_int*); @@ -52,3 +54,5 @@ extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReleaseGLObjects)(cl_comma extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLContextInfoKHR)(const cl_context_properties*, cl_gl_context_info, size_t, void*, size_t*); extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLObjectInfo)(cl_mem, cl_gl_object_type*, cl_GLuint*); extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLTextureInfo)(cl_mem, cl_gl_texture_info, size_t, void*, size_t*); + +#endif // cl_khr_gl_sharing diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp index 105867f47a..8338ac6817 100644 --- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp +++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp @@ -5,6 +5,8 @@ #error "Invalid usage" #endif +#ifdef cl_khr_gl_sharing + // generated by parser_cl.py #undef clCreateFromGLBuffer #define clCreateFromGLBuffer clCreateFromGLBuffer_fn @@ -36,3 +38,5 @@ inline cl_int clGetGLObjectInfo(cl_mem p0, cl_gl_object_type* p1, cl_GLuint* p2) #undef clGetGLTextureInfo #define clGetGLTextureInfo clGetGLTextureInfo_fn inline cl_int clGetGLTextureInfo(cl_mem p0, cl_gl_texture_info p1, size_t p2, void* p3, size_t* p4) { return clGetGLTextureInfo_pfn(p0, p1, p2, p3, p4); } + +#endif // cl_khr_gl_sharing diff --git a/modules/core/src/opencl/runtime/autogenerated/opencl_gl_impl.hpp b/modules/core/src/opencl/runtime/autogenerated/opencl_gl_impl.hpp index 6d97180508..5b371330c4 100644 --- a/modules/core/src/opencl/runtime/autogenerated/opencl_gl_impl.hpp +++ b/modules/core/src/opencl/runtime/autogenerated/opencl_gl_impl.hpp @@ -139,6 +139,8 @@ struct opencl_gl_fn14 } // anonymous namespace +#ifdef cl_khr_gl_sharing + // generated by parser_cl.py cl_mem (CL_API_CALL*clCreateFromGLBuffer)(cl_context, cl_mem_flags, cl_GLuint, int*) = opencl_gl_fn4::switch_fn; @@ -196,3 +198,5 @@ static const struct DynamicFnEntry* opencl_gl_fn_list[] = { }; // number of enabled functions: 10 + +#endif // cl_khr_gl_sharing diff --git a/modules/core/src/opencl/runtime/generator/common.py b/modules/core/src/opencl/runtime/generator/common.py index 80c545295f..5f81e8ee57 100644 --- a/modules/core/src/opencl/runtime/generator/common.py +++ b/modules/core/src/opencl/runtime/generator/common.py @@ -254,6 +254,6 @@ def ProcessTemplate(inputFile, ctx, noteLine='//\n// AUTOGENERATED, DO NOT EDIT\ assert line[-1] == '@' name = line[1:-1] assert ctx.has_key(name), name - line = ctx[name] - print line, + line = ctx[name] + ('\n' if len(ctx[name]) > 0 and ctx[name][-1] != '\n' else '') + sys.stdout.write(line) f.close() diff --git a/modules/core/src/opencl/runtime/generator/generate.sh b/modules/core/src/opencl/runtime/generator/generate.sh old mode 100644 new mode 100755 diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in index 4bed423318..13a33c7153 100644 --- a/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in +++ b/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in @@ -8,4 +8,8 @@ @CL_REMAP_DYNAMIC@ +#ifdef cl_khr_gl_sharing + @CL_FN_DECLARATIONS@ + +#endif // cl_khr_gl_sharing diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_gl_impl.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_gl_impl.hpp.in index 14586017a4..cba1278a32 100644 --- a/modules/core/src/opencl/runtime/generator/template/opencl_gl_impl.hpp.in +++ b/modules/core/src/opencl/runtime/generator/template/opencl_gl_impl.hpp.in @@ -4,8 +4,12 @@ namespace { @CL_FN_SWITCH@ } // anonymous namespace +#ifdef cl_khr_gl_sharing + @CL_FN_ENTRY_DEFINITIONS@ @CL_FN_ENTRY_LIST@ @CL_NUMBER_OF_ENABLED_FUNCTIONS@ + +#endif // cl_khr_gl_sharing diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_gl_wrappers.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_gl_wrappers.hpp.in index 0aeefb4f44..fc03179140 100644 --- a/modules/core/src/opencl/runtime/generator/template/opencl_gl_wrappers.hpp.in +++ b/modules/core/src/opencl/runtime/generator/template/opencl_gl_wrappers.hpp.in @@ -2,4 +2,8 @@ #error "Invalid usage" #endif +#ifdef cl_khr_gl_sharing + @CL_FN_INLINE_WRAPPERS@ + +#endif // cl_khr_gl_sharing diff --git a/modules/core/src/opencl/runtime/opencl_core.cpp b/modules/core/src/opencl/runtime/opencl_core.cpp index 0ab3381124..405a5936a2 100644 --- a/modules/core/src/opencl/runtime/opencl_core.cpp +++ b/modules/core/src/opencl/runtime/opencl_core.cpp @@ -286,6 +286,8 @@ static void* opencl_check_fn(int ID) #include "opencv2/core/opencl/runtime/opencl_gl.hpp" +#ifdef cl_khr_gl_sharing + static void* opencl_gl_check_fn(int ID); #include "autogenerated/opencl_gl_impl.hpp" @@ -306,6 +308,8 @@ static void* opencl_gl_check_fn(int ID) return func; } +#endif // cl_khr_gl_sharing + #endif // HAVE_OPENGL #endif diff --git a/modules/core/src/opengl.cpp b/modules/core/src/opengl.cpp index 3bbc0f8e9f..f3d106fd24 100644 --- a/modules/core/src/opengl.cpp +++ b/modules/core/src/opengl.cpp @@ -1580,6 +1580,11 @@ void cv::ogl::render(const ogl::Arrays& arr, InputArray indices, int mode, Scala #ifdef HAVE_OPENCL # include "opencv2/core/opencl/runtime/opencl_gl.hpp" +# ifdef cl_khr_gl_sharing +# define HAVE_OPENCL_OPENGL_SHARING +# else +# define NO_OPENCL_SHARING_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without OpenCL/OpenGL sharing support") +# endif #else // HAVE_OPENCL # define NO_OPENCL_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without OpenCL support") #endif // HAVE_OPENCL @@ -1602,6 +1607,8 @@ Context& initializeContextFromGL() NO_OPENGL_SUPPORT_ERROR; #elif !defined(HAVE_OPENCL) NO_OPENCL_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL_OPENGL_SHARING) + NO_OPENCL_SHARING_ERROR; #else cl_uint numPlatforms; cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms); @@ -1701,6 +1708,8 @@ void convertToGLTexture2D(InputArray src, Texture2D& texture) NO_OPENGL_SUPPORT_ERROR; #elif !defined(HAVE_OPENCL) NO_OPENCL_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL_OPENGL_SHARING) + NO_OPENCL_SHARING_ERROR; #else Size srcSize = src.size(); CV_Assert(srcSize.width == (int)texture.cols() && srcSize.height == (int)texture.rows()); @@ -1753,6 +1762,8 @@ void convertFromGLTexture2D(const Texture2D& texture, OutputArray dst) NO_OPENGL_SUPPORT_ERROR; #elif !defined(HAVE_OPENCL) NO_OPENCL_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL_OPENGL_SHARING) + NO_OPENCL_SHARING_ERROR; #else // check texture format const int dtype = CV_8UC4; @@ -1812,6 +1823,8 @@ UMat mapGLBuffer(const Buffer& buffer, int accessFlags) NO_OPENGL_SUPPORT_ERROR; #elif !defined(HAVE_OPENCL) NO_OPENCL_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL_OPENGL_SHARING) + NO_OPENCL_SHARING_ERROR; #else using namespace cv::ocl; Context& ctx = Context::getDefault(); @@ -1862,6 +1875,8 @@ void unmapGLBuffer(UMat& u) NO_OPENGL_SUPPORT_ERROR; #elif !defined(HAVE_OPENCL) NO_OPENCL_SUPPORT_ERROR; +#elif !defined(HAVE_OPENCL_OPENGL_SHARING) + NO_OPENCL_SHARING_ERROR; #else using namespace cv::ocl; cl_command_queue clQueue = (cl_command_queue)Queue::getDefault().ptr(); From b2ca10a81f8fbd6d9bddfb0d73b388a9459861ff Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 11 Feb 2016 12:57:10 +0300 Subject: [PATCH 140/468] cmake: fix find_library() for bzip2 --- cmake/OpenCVFindLibsVideo.cmake | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake index 64642daa2a..20e31518a4 100644 --- a/cmake/OpenCVFindLibsVideo.cmake +++ b/cmake/OpenCVFindLibsVideo.cmake @@ -224,11 +224,7 @@ if(WITH_FFMPEG) if(HAVE_FFMPEG) # Find the bzip2 library because it is required on some systems - FIND_LIBRARY(BZIP2_LIBRARIES NAMES bz2 bzip2) - if(NOT BZIP2_LIBRARIES) - # Do an other trial - FIND_FILE(BZIP2_LIBRARIES NAMES libbz2.so.1 PATHS /lib) - endif() + FIND_LIBRARY(BZIP2_LIBRARIES NAMES bz2 bzip2 libbz2.so.1) else() find_path(FFMPEG_INCLUDE_DIR "libavformat/avformat.h" PATHS /usr/local /usr /opt From 15793b1301c54685ff94e5eae7f03195014ac3a1 Mon Sep 17 00:00:00 2001 From: ahb Date: Sat, 5 Dec 2015 12:48:02 +0100 Subject: [PATCH 141/468] add TestData::getTestSamples() --- modules/ml/include/opencv2/ml.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 7acce7f33c..da0cea8b9d 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -224,6 +224,12 @@ public: CV_WRAP virtual void setTrainTestSplitRatio(double ratio, bool shuffle=true) = 0; CV_WRAP virtual void shuffleTrainTest() = 0; + CV_WRAP Mat getTestSamples() const { + Mat idx = getTestSampleIdx(); + Mat samples = getSamples(); + return idx.empty() ? Mat() : getSubVector(samples, idx); + } + CV_WRAP static Mat getSubVector(const Mat& vec, const Mat& idx); /** @brief Reads the dataset from a .csv file and returns the ready-to-use training data. From 54abb83c82e5f524615128b86b3eb4dc364eb0ff Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Fri, 12 Feb 2016 12:32:26 +0300 Subject: [PATCH 142/468] ml: moved getTestSamples implementation to src --- modules/ml/include/opencv2/ml.hpp | 7 ++----- modules/ml/src/data.cpp | 7 +++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index da0cea8b9d..0b9026950e 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -224,11 +224,8 @@ public: CV_WRAP virtual void setTrainTestSplitRatio(double ratio, bool shuffle=true) = 0; CV_WRAP virtual void shuffleTrainTest() = 0; - CV_WRAP Mat getTestSamples() const { - Mat idx = getTestSampleIdx(); - Mat samples = getSamples(); - return idx.empty() ? Mat() : getSubVector(samples, idx); - } + /** @brief Returns matrix of test samples */ + CV_WRAP Mat getTestSamples() const; CV_WRAP static Mat getSubVector(const Mat& vec, const Mat& idx); diff --git a/modules/ml/src/data.cpp b/modules/ml/src/data.cpp index a1608e3984..ad652568c7 100644 --- a/modules/ml/src/data.cpp +++ b/modules/ml/src/data.cpp @@ -50,6 +50,13 @@ static const int VAR_MISSED = VAR_ORDERED; TrainData::~TrainData() {} +Mat TrainData::getTestSamples() const +{ + Mat idx = getTestSampleIdx(); + Mat samples = getSamples(); + return idx.empty() ? Mat() : getSubVector(samples, idx); +} + Mat TrainData::getSubVector(const Mat& vec, const Mat& idx) { if( idx.empty() ) From f48cda2f95aa0507f0af56714e755d46b7444b62 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 12 Feb 2016 13:15:15 +0300 Subject: [PATCH 143/468] test: initialize test data in test_umat.cpp (6102) --- modules/core/test/test_umat.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/core/test/test_umat.cpp b/modules/core/test/test_umat.cpp index 09c59b60d2..26b1bbd2b8 100644 --- a/modules/core/test/test_umat.cpp +++ b/modules/core/test/test_umat.cpp @@ -1035,7 +1035,7 @@ TEST(UMat, synchronization_map_unmap) }; try { - UMat u(1000, 1000, CV_32FC1); + UMat u(1000, 1000, CV_32FC1, Scalar::all(0)); parallel_for_(cv::Range(0, 2), TestParallelLoopBody(u)); } catch (const cv::Exception& e) @@ -1056,7 +1056,7 @@ TEST(UMat, async_unmap) { try { - Mat m = Mat(1000, 1000, CV_8UC1); + Mat m = Mat(1000, 1000, CV_8UC1, Scalar::all(0)); UMat u = m.getUMat(ACCESS_READ); UMat dst; add(u, Scalar::all(0), dst); // start async operation @@ -1101,7 +1101,7 @@ TEST(UMat, unmap_in_class) }; try { - Mat m = Mat(1000, 1000, CV_8UC1); + Mat m = Mat(1000, 1000, CV_8UC1, Scalar::all(0)); Logic l; l.processData(m); UMat result = l.getResult(); @@ -1127,7 +1127,7 @@ TEST(UMat, map_unmap_counting) return; } std::cout << "Host memory: " << cv::ocl::Device::getDefault().hostUnifiedMemory() << std::endl; - Mat m(Size(10, 10), CV_8UC1); + Mat m(Size(10, 10), CV_8UC1, Scalar::all(0)); UMat um = m.getUMat(ACCESS_RW); { Mat d1 = um.getMat(ACCESS_RW); @@ -1156,7 +1156,7 @@ OCL_TEST(UMat, DISABLED_OCL_ThreadSafe_CleanupCallback_1_VeryLongTest) const int type = CV_8UC1; const int dtype = CV_16UC1; - Mat src(srcSize, type); + Mat src(srcSize, type, Scalar::all(0)); Mat dst_ref(srcSize, dtype); // Generate reference data as additional check @@ -1198,7 +1198,7 @@ OCL_TEST(UMat, DISABLED_OCL_ThreadSafe_CleanupCallback_2_VeryLongTest) // Use multiple iterations to increase chance of data race catching for(int k = 0; k < 10000; k++) { - Mat src(srcSize, type); // Declare src inside loop now to catch its destruction on stack + Mat src(srcSize, type, Scalar::all(0)); // Declare src inside loop now to catch its destruction on stack { UMat tmpUMat = src.getUMat(ACCESS_RW); tmpUMat.convertTo(dst, dtype); @@ -1216,7 +1216,7 @@ TEST(UMat, DISABLED_Test_same_behaviour_read_and_read) bool exceptionDetected = false; try { - UMat u(Size(10, 10), CV_8UC1); + UMat u(Size(10, 10), CV_8UC1, Scalar::all(0)); Mat m = u.getMat(ACCESS_READ); UMat dst; add(u, Scalar::all(1), dst); @@ -1234,7 +1234,7 @@ TEST(UMat, DISABLED_Test_same_behaviour_read_and_write) bool exceptionDetected = false; try { - UMat u(Size(10, 10), CV_8UC1); + UMat u(Size(10, 10), CV_8UC1, Scalar::all(0)); Mat m = u.getMat(ACCESS_READ); add(u, Scalar::all(1), u); } @@ -1250,7 +1250,7 @@ TEST(UMat, DISABLED_Test_same_behaviour_write_and_read) bool exceptionDetected = false; try { - UMat u(Size(10, 10), CV_8UC1); + UMat u(Size(10, 10), CV_8UC1, Scalar::all(0)); Mat m = u.getMat(ACCESS_WRITE); UMat dst; add(u, Scalar::all(1), dst); @@ -1267,7 +1267,7 @@ TEST(UMat, DISABLED_Test_same_behaviour_write_and_write) bool exceptionDetected = false; try { - UMat u(Size(10, 10), CV_8UC1); + UMat u(Size(10, 10), CV_8UC1, Scalar::all(0)); Mat m = u.getMat(ACCESS_WRITE); add(u, Scalar::all(1), u); } From 359acc0d338b2f858064ae098fd7cf4b63d3455c Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Fri, 12 Feb 2016 13:35:46 +0300 Subject: [PATCH 144/468] Tutorials: moved imgcodecs and videoio tutorials to separate pages --- .../highgui/table_of_content_highgui.markdown | 15 +-------------- .../{highgui => imgcodecs}/images/gdal-io.jpg | Bin .../raster-gdal/images/gdal_flood-zone.jpg | Bin .../raster-gdal/images/gdal_heat-map.jpg | Bin .../raster-gdal/images/gdal_output.jpg | Bin .../raster-gdal/raster_io_gdal.markdown | 2 +- .../imgcodecs/table_of_content_highgui.markdown | 12 ++++++++++++ doc/tutorials/tutorials.markdown | 15 +++++++++------ .../{highgui => videoio}/intelperc.markdown | 0 .../{highgui => videoio}/kinect_openni.markdown | 0 .../videoio/table_of_content_videoio.markdown | 6 +++++- .../GDAL_IO/gdal-image.cpp | 0 12 files changed, 28 insertions(+), 22 deletions(-) rename doc/tutorials/{highgui => imgcodecs}/images/gdal-io.jpg (100%) rename doc/tutorials/{highgui => imgcodecs}/raster-gdal/images/gdal_flood-zone.jpg (100%) rename doc/tutorials/{highgui => imgcodecs}/raster-gdal/images/gdal_heat-map.jpg (100%) rename doc/tutorials/{highgui => imgcodecs}/raster-gdal/images/gdal_output.jpg (100%) rename doc/tutorials/{highgui => imgcodecs}/raster-gdal/raster_io_gdal.markdown (98%) create mode 100644 doc/tutorials/imgcodecs/table_of_content_highgui.markdown rename doc/tutorials/{highgui => videoio}/intelperc.markdown (100%) rename doc/tutorials/{highgui => videoio}/kinect_openni.markdown (100%) rename samples/cpp/tutorial_code/{HighGUI => imgcodecs}/GDAL_IO/gdal-image.cpp (100%) diff --git a/doc/tutorials/highgui/table_of_content_highgui.markdown b/doc/tutorials/highgui/table_of_content_highgui.markdown index 8f8b28f428..a8f1d4e344 100644 --- a/doc/tutorials/highgui/table_of_content_highgui.markdown +++ b/doc/tutorials/highgui/table_of_content_highgui.markdown @@ -1,8 +1,7 @@ High Level GUI and Media (highgui module) {#tutorial_table_of_content_highgui} ========================================= -This section contains valuable tutorials about how to read/save your image/video files and how to -use the built-in graphical user interface of the library. +This section contains tutorials about how to use the built-in graphical user interface of the library. - @subpage tutorial_trackbar @@ -11,15 +10,3 @@ use the built-in graphical user interface of the library. *Author:* Ana Huamán We will learn how to add a Trackbar to our applications - -- @subpage tutorial_raster_io_gdal - - *Compatibility:* \> OpenCV 2.0 - - *Author:* Marvin Smith - - Read common GIS Raster and DEM files to display and manipulate geographic data. - -- @subpage tutorial_kinect_openni - -- @subpage tutorial_intelperc diff --git a/doc/tutorials/highgui/images/gdal-io.jpg b/doc/tutorials/imgcodecs/images/gdal-io.jpg similarity index 100% rename from doc/tutorials/highgui/images/gdal-io.jpg rename to doc/tutorials/imgcodecs/images/gdal-io.jpg diff --git a/doc/tutorials/highgui/raster-gdal/images/gdal_flood-zone.jpg b/doc/tutorials/imgcodecs/raster-gdal/images/gdal_flood-zone.jpg similarity index 100% rename from doc/tutorials/highgui/raster-gdal/images/gdal_flood-zone.jpg rename to doc/tutorials/imgcodecs/raster-gdal/images/gdal_flood-zone.jpg diff --git a/doc/tutorials/highgui/raster-gdal/images/gdal_heat-map.jpg b/doc/tutorials/imgcodecs/raster-gdal/images/gdal_heat-map.jpg similarity index 100% rename from doc/tutorials/highgui/raster-gdal/images/gdal_heat-map.jpg rename to doc/tutorials/imgcodecs/raster-gdal/images/gdal_heat-map.jpg diff --git a/doc/tutorials/highgui/raster-gdal/images/gdal_output.jpg b/doc/tutorials/imgcodecs/raster-gdal/images/gdal_output.jpg similarity index 100% rename from doc/tutorials/highgui/raster-gdal/images/gdal_output.jpg rename to doc/tutorials/imgcodecs/raster-gdal/images/gdal_output.jpg diff --git a/doc/tutorials/highgui/raster-gdal/raster_io_gdal.markdown b/doc/tutorials/imgcodecs/raster-gdal/raster_io_gdal.markdown similarity index 98% rename from doc/tutorials/highgui/raster-gdal/raster_io_gdal.markdown rename to doc/tutorials/imgcodecs/raster-gdal/raster_io_gdal.markdown index 95137be2d1..a511d80887 100644 --- a/doc/tutorials/highgui/raster-gdal/raster_io_gdal.markdown +++ b/doc/tutorials/imgcodecs/raster-gdal/raster_io_gdal.markdown @@ -28,7 +28,7 @@ of the bay rise 10, 50, and 100 meters. Code ---- -@include cpp/tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp +@include cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp How to Read Raster Data using GDAL ---------------------------------- diff --git a/doc/tutorials/imgcodecs/table_of_content_highgui.markdown b/doc/tutorials/imgcodecs/table_of_content_highgui.markdown new file mode 100644 index 0000000000..e78e8276f4 --- /dev/null +++ b/doc/tutorials/imgcodecs/table_of_content_highgui.markdown @@ -0,0 +1,12 @@ +Image Input and Output (imgcodecs module) {#tutorial_table_of_content_imgcodecs} +========================================= + +This section contains tutorials about how to read/save your image files. + +- @subpage tutorial_raster_io_gdal + + *Compatibility:* \> OpenCV 2.0 + + *Author:* Marvin Smith + + Read common GIS Raster and DEM files to display and manipulate geographic data. diff --git a/doc/tutorials/tutorials.markdown b/doc/tutorials/tutorials.markdown index 035c69a290..9319217772 100644 --- a/doc/tutorials/tutorials.markdown +++ b/doc/tutorials/tutorials.markdown @@ -25,10 +25,17 @@ As always, we would be happy to hear your comments and receive your contribution - @subpage tutorial_table_of_content_highgui - This section - contains valuable tutorials about how to read/save your image/video files and how to use the + This section contains valuable tutorials about how to use the built-in graphical user interface of the library. +- @subpage tutorial_table_of_content_imgcodecs + + These tutorials show how to read and write images using imgcodecs module. + +- @subpage tutorial_table_of_content_videoio + + These tutorials show how to read and write videos using videio module. + - @subpage tutorial_table_of_content_calib3d Although we got @@ -71,10 +78,6 @@ As always, we would be happy to hear your comments and receive your contribution Run OpenCV and your vision apps on an iDevice -- @subpage tutorial_table_of_content_videoio - - These tutorials show how to read and write videos using videio module. - - @subpage tutorial_table_of_content_viz These tutorials show how to use Viz module effectively. diff --git a/doc/tutorials/highgui/intelperc.markdown b/doc/tutorials/videoio/intelperc.markdown similarity index 100% rename from doc/tutorials/highgui/intelperc.markdown rename to doc/tutorials/videoio/intelperc.markdown diff --git a/doc/tutorials/highgui/kinect_openni.markdown b/doc/tutorials/videoio/kinect_openni.markdown similarity index 100% rename from doc/tutorials/highgui/kinect_openni.markdown rename to doc/tutorials/videoio/kinect_openni.markdown diff --git a/doc/tutorials/videoio/table_of_content_videoio.markdown b/doc/tutorials/videoio/table_of_content_videoio.markdown index b1b669ded7..4f62765115 100644 --- a/doc/tutorials/videoio/table_of_content_videoio.markdown +++ b/doc/tutorials/videoio/table_of_content_videoio.markdown @@ -16,4 +16,8 @@ This section contains tutorials about how to read/save your video files. *Compatibility:* \> OpenCV 2.0 - *Author:* Bernát Gábor \ No newline at end of file + *Author:* Bernát Gábor + +- @subpage tutorial_kinect_openni + +- @subpage tutorial_intelperc diff --git a/samples/cpp/tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp b/samples/cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp similarity index 100% rename from samples/cpp/tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp rename to samples/cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp From 6c0c0466c6677091d2ba2bba9dcd1618e2132e8d Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Fri, 12 Feb 2016 13:42:44 +0300 Subject: [PATCH 145/468] Tutorials: moved Megamind.avi files to samples/data folder --- .../video_input_psnr_ssim.markdown | 6 +++--- .../video => data}/Megamind.avi | Bin .../video => data}/Megamind_bugy.avi | Bin 3 files changed, 3 insertions(+), 3 deletions(-) rename samples/{cpp/tutorial_code/videoio/video-input-psnr-ssim/video => data}/Megamind.avi (100%) rename samples/{cpp/tutorial_code/videoio/video-input-psnr-ssim/video => data}/Megamind_bugy.avi (100%) diff --git a/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown b/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown index ef82b67236..9dbff286ca 100644 --- a/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown +++ b/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown @@ -20,10 +20,10 @@ As a test case where to show off these using OpenCV I've created a small program video files and performs a similarity check between them. This is something you could use to check just how well a new video compressing algorithms works. Let there be a reference (original) video like [this small Megamind clip -](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind.avi) and [a compressed -version of it ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind_bugy.avi). +](https://github.com/Itseez/opencv/tree/master/samples/data/Megamind.avi) and [a compressed +version of it ](https://github.com/Itseez/opencv/tree/master/samples/data/Megamind_bugy.avi). You may also find the source code and these video file in the -`samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/` folder of the OpenCV source library. +`samples/data` folder of the OpenCV source library. @include cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp diff --git a/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind.avi b/samples/data/Megamind.avi similarity index 100% rename from samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind.avi rename to samples/data/Megamind.avi diff --git a/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind_bugy.avi b/samples/data/Megamind_bugy.avi similarity index 100% rename from samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video/Megamind_bugy.avi rename to samples/data/Megamind_bugy.avi From 068769263e166fc1de885a9f2116511cb790da98 Mon Sep 17 00:00:00 2001 From: Ilya Lavrenov Date: Fri, 12 Feb 2016 00:33:18 +0300 Subject: [PATCH 146/468] fixed compilation warning --- modules/core/include/opencv2/core/types_c.h | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/core/include/opencv2/core/types_c.h b/modules/core/include/opencv2/core/types_c.h index 9e9231db08..c21cd2c758 100644 --- a/modules/core/include/opencv2/core/types_c.h +++ b/modules/core/include/opencv2/core/types_c.h @@ -317,6 +317,7 @@ enum { #define ARM_ROUND(_value, _asm_string) \ int res; \ float temp; \ + (void)temp; \ asm(_asm_string : [res] "=r" (res), [temp] "=w" (temp) : [value] "w" (_value)); \ return res; // 2. version for double From 232f564011cad27fbde05fd713a04a6b38945bfd Mon Sep 17 00:00:00 2001 From: Rahul Chhabra Date: Sun, 14 Feb 2016 10:18:14 +0530 Subject: [PATCH 147/468] Update imgproc.hpp In reference to Issue #6110, the order of markerType and color is changed. --- modules/imgproc/include/opencv2/imgproc.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index 717dcf578a..08c6036a7e 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -3947,8 +3947,8 @@ marker types are supported, see cv::MarkerTypes for more information. @param img Image. @param position The point where the crosshair is positioned. -@param markerType The specific type of marker you want to use, see cv::MarkerTypes @param color Line color. +@param markerType The specific type of marker you want to use, see cv::MarkerTypes @param thickness Line thickness. @param line_type Type of the line, see cv::LineTypes @param markerSize The length of the marker axis [default = 20 pixels] From 45461398447abc64051bf20e77c42cc17b72e350 Mon Sep 17 00:00:00 2001 From: Eric Zavesky Date: Mon, 15 Feb 2016 04:26:03 -0600 Subject: [PATCH 148/468] - remove zero threshold that prevents ORB from finding any local features --- .../tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp index ba845dc6df..a146f1e823 100755 --- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp +++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp @@ -140,7 +140,6 @@ int main(int argc, char **argv) Ptr akaze = AKAZE::create(); akaze->setThreshold(akaze_thresh); Ptr orb = ORB::create(); - orb->setMaxFeatures(stats.keypoints); Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming"); Tracker akaze_tracker(akaze, matcher); Tracker orb_tracker(orb, matcher); From 4c5af4f3618c68f3c2bc2a940f8bf2256f50acb9 Mon Sep 17 00:00:00 2001 From: Eric Zavesky Date: Mon, 15 Feb 2016 04:27:28 -0600 Subject: [PATCH 149/468] - add ROI selection, allow device input, use BB for area exclusion - previously BB was ignored for first frame, now masks analysis area - also allow real-time feedback of processing --- .../AKAZE_tracking/planar_tracking.cpp | 85 ++++++++++++++----- 1 file changed, 65 insertions(+), 20 deletions(-) diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp index a146f1e823..85ca00385d 100755 --- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp +++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp @@ -1,6 +1,8 @@ #include #include #include +#include //for ROI +#include //for imshow #include #include #include @@ -17,6 +19,7 @@ const double nn_match_ratio = 0.8f; // Nearest-neighbour matching ratio const int bb_min_inliers = 100; // Minimal number of inliers to draw bounding box const int stats_update_period = 10; // On-screen statistics are updated every 10 frames +namespace example { class Tracker { public: @@ -40,12 +43,22 @@ protected: void Tracker::setFirstFrame(const Mat frame, vector bb, string title, Stats& stats) { + cv::Point *ptMask = new cv::Point[bb.size()]; + const Point* ptContain = { &ptMask[0] }; + int iSize = static_cast(bb.size()); + for (size_t i=0; idetectAndCompute(first_frame, noArray(), first_kp, first_desc); + cv::Mat matMask = cv::Mat::zeros(frame.size(), CV_8UC1); + cv::fillPoly(matMask, &ptContain, &iSize, 1, cv::Scalar::all(255)); + detector->detectAndCompute(first_frame, matMask, first_kp, first_desc); stats.keypoints = (int)first_kp.size(); drawBoundingBox(first_frame, bb); putText(first_frame, title, Point(0, 60), FONT_HERSHEY_PLAIN, 5, Scalar::all(0), 4); object_bb = bb; + delete ptMask; } Mat Tracker::process(const Mat frame, Stats& stats) @@ -104,17 +117,35 @@ Mat Tracker::process(const Mat frame, Stats& stats) Scalar(255, 0, 0), Scalar(255, 0, 0)); return res; } +} int main(int argc, char **argv) { - if(argc < 4) { + if(argc < 3) { cerr << "Usage: " << endl << - "akaze_track input_path output_path bounding_box" << endl; + "akaze_track input_path output_path [bounding_box_path]" << endl + " (for camera input_path=N for camera N)" << endl; return 1; } - VideoCapture video_in(argv[1]); - VideoWriter video_out(argv[2], - (int)video_in.get(CAP_PROP_FOURCC), + + std::string video_name = argv[1]; + std::stringstream ssFormat; + ssFormat << atoi(argv[1]); + VideoCapture video_in; + int iFourCC = 0, frame_count = 0; + if (video_name.compare(ssFormat.str())==0) { //test str==str(num) + video_in.open(atoi(argv[1])); + cerr << "Capturing for 10 seconds from camera..." << endl; + iFourCC = CV_FOURCC('D', 'I', 'V', 'X'); //default to mp4 (sample) + frame_count = 10*static_cast(video_in.get(CAP_PROP_FPS)); + } + else { + video_in.open(video_name); + iFourCC = static_cast(video_in.get(CAP_PROP_FOURCC)); + frame_count = static_cast(video_in.get(CAP_PROP_FRAME_COUNT)); + } + + VideoWriter video_out(argv[2], iFourCC, (int)video_in.get(CAP_PROP_FPS), Size(2 * (int)video_in.get(CAP_PROP_FRAME_WIDTH), 2 * (int)video_in.get(CAP_PROP_FRAME_HEIGHT))); @@ -128,33 +159,43 @@ int main(int argc, char **argv) return 1; } - vector bb; - FileStorage fs(argv[3], FileStorage::READ); - if(fs["bounding_box"].empty()) { - cerr << "Couldn't read bounding_box from " << argv[3] << endl; - return 1; - } - fs["bounding_box"] >> bb; - Stats stats, akaze_stats, orb_stats; Ptr akaze = AKAZE::create(); akaze->setThreshold(akaze_thresh); Ptr orb = ORB::create(); Ptr matcher = DescriptorMatcher::create("BruteForce-Hamming"); - Tracker akaze_tracker(akaze, matcher); - Tracker orb_tracker(orb, matcher); + example::Tracker akaze_tracker(akaze, matcher); + example::Tracker orb_tracker(orb, matcher); Mat frame; video_in >> frame; + vector bb; + if (argc < 4) { //attempt to alow GUI selection + cv::Rect2d uBox = selectROI(video_name, frame); + bb.push_back(cv::Point2f(uBox.x, uBox.y)); + bb.push_back(cv::Point2f(uBox.x+uBox.width, uBox.y)); + bb.push_back(cv::Point2f(uBox.x+uBox.width, uBox.y+uBox.height)); + bb.push_back(cv::Point2f(uBox.x, uBox.y+uBox.height)); + } + else { + FileStorage fs(argv[3], FileStorage::READ); + if(fs["bounding_box"].empty()) { + cerr << "Couldn't read bounding_box from " << argv[3] << endl; + return 1; + } + fs["bounding_box"] >> bb; + } akaze_tracker.setFirstFrame(frame, bb, "AKAZE", stats); orb_tracker.setFirstFrame(frame, bb, "ORB", stats); Stats akaze_draw_stats, orb_draw_stats; - int frame_count = (int)video_in.get(CAP_PROP_FRAME_COUNT); Mat akaze_res, orb_res, res_frame; - for(int i = 1; i < frame_count; i++) { + int i = 1; + for(i = 1; i < frame_count; i++) { bool update_stats = (i % stats_update_period == 0); video_in >> frame; + // stop the program if no more images + if(frame.rows==0 || frame.cols==0) break; akaze_res = akaze_tracker.process(frame, stats); akaze_stats += stats; @@ -173,10 +214,14 @@ int main(int argc, char **argv) drawStatistics(orb_res, orb_draw_stats); vconcat(akaze_res, orb_res, res_frame); video_out << res_frame; + cv::imshow(video_name, res_frame); + if (i==1) //resize for easier display + cv::resizeWindow(video_name, frame.cols, frame.rows); + if(cv::waitKey(1)==27)break; //quit on ESC button cout << i << "/" << frame_count - 1 << endl; } - akaze_stats /= frame_count - 1; - orb_stats /= frame_count - 1; + akaze_stats /= i - 1; + orb_stats /= i - 1; printStatistics("AKAZE", akaze_stats); printStatistics("ORB", orb_stats); return 0; From d7e57f2152b5a890bf0363977db0b7cd694d4de8 Mon Sep 17 00:00:00 2001 From: Eric Zavesky Date: Mon, 15 Feb 2016 04:54:59 -0600 Subject: [PATCH 150/468] - fix typo from last minute change --- .../features2D/AKAZE_tracking/planar_tracking.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp index 85ca00385d..51e9a0377b 100755 --- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp +++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp @@ -122,9 +122,9 @@ Mat Tracker::process(const Mat frame, Stats& stats) int main(int argc, char **argv) { if(argc < 3) { - cerr << "Usage: " << endl << - "akaze_track input_path output_path [bounding_box_path]" << endl - " (for camera input_path=N for camera N)" << endl; + cerr << "Usage: " << endl + << "akaze_track input_path output_path [bounding_box_path]" << endl + << " (for camera input_path=N for camera N)" << endl; return 1; } From 335f7e791602b7a89b1764892fd9b19d6cfe2a7e Mon Sep 17 00:00:00 2001 From: Eric Zavesky Date: Mon, 15 Feb 2016 05:33:37 -0600 Subject: [PATCH 151/468] - trim whitespace, as required by build machine --- .../tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp index 51e9a0377b..dfeb63d192 100755 --- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp +++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp @@ -122,7 +122,7 @@ Mat Tracker::process(const Mat frame, Stats& stats) int main(int argc, char **argv) { if(argc < 3) { - cerr << "Usage: " << endl + cerr << "Usage: " << endl << "akaze_track input_path output_path [bounding_box_path]" << endl << " (for camera input_path=N for camera N)" << endl; return 1; From ff549527697af8a66889c5a7d010fe6a768b1076 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Mon, 15 Feb 2016 14:35:36 +0300 Subject: [PATCH 152/468] Corrected spelling mistakes --- modules/ml/include/opencv2/ml.hpp | 2 +- modules/ml/src/svmsgd.cpp | 23 +++++++++++------------ modules/ml/test/test_svmsgd.cpp | 2 +- samples/cpp/train_svmsgd.cpp | 4 ++-- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 8b56f0d798..346df8f15c 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1535,7 +1535,7 @@ The margin type may have one of the following values: \ref SOFT_MARGIN or \ref H - You should use \ref HARD_MARGIN type, if you have linearly separable sets. - You should use \ref SOFT_MARGIN type, if you have non-linearly separable sets or sets with outliers. -- In the general case (if you know nothing about linearly separability of your sets), use SOFT_MARGIN. +- In the general case (if you know nothing about linear separability of your sets), use SOFT_MARGIN. The other parameters may be described as follows: - \f$\lambda\f$ parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 3ae051a9dc..77ac2ad67b 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -11,7 +11,7 @@ // For Open Source Computer Vision Library // // Copyright (C) 2000, Intel Corporation, all rights reserved. -// Copyright (C) 2014, Itseez Inc, all rights reserved. +// Copyright (C) 2016, Itseez Inc, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without modification, @@ -103,7 +103,7 @@ public: CV_IMPL_PROPERTY_S(cv::TermCriteria, TermCriteria, params.termCrit) private: - void updateWeights(InputArray sample, bool isFirstClass, float gamma, Mat &weights); + void updateWeights(InputArray sample, bool isPositive, float gamma, Mat &weights); std::pair areClassesEmpty(Mat responses); @@ -111,7 +111,7 @@ private: void readParams( const FileNode &fn ); - static inline bool isFirstClass(float val) { return val > 0; } + static inline bool isPositive(float val) { return val > 0; } static void normalizeSamples(Mat &matrix, Mat &average, float &multiplier); @@ -152,7 +152,7 @@ std::pair SVMSGDImpl::areClassesEmpty(Mat responses) for(int index = 0; index < limit_index; index++) { - if (isFirstClass(responses.at(index))) + if (isPositive(responses.at(index))) emptyInClasses.first = false; else emptyInClasses.second = false; @@ -172,7 +172,7 @@ void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) average = Mat(1, featuresCount, samples.type()); for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++) { - Scalar scalAverage = mean(samples.col(featureIndex))[0]; + Scalar scalAverage = mean(samples.col(featureIndex)); average.at(featureIndex) = static_cast(scalAverage[0]); } @@ -190,13 +190,13 @@ void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) void SVMSGDImpl::makeExtendedTrainSamples(const Mat &trainSamples, Mat &extendedTrainSamples, Mat &average, float &multiplier) { - Mat normalisedTrainSamples = trainSamples.clone(); - int samplesCount = normalisedTrainSamples.rows; + Mat normalizedTrainSamples = trainSamples.clone(); + int samplesCount = normalizedTrainSamples.rows; - normalizeSamples(normalisedTrainSamples, average, multiplier); + normalizeSamples(normalizedTrainSamples, average, multiplier); Mat onesCol = Mat::ones(samplesCount, 1, CV_32F); - cv::hconcat(normalisedTrainSamples, onesCol, extendedTrainSamples); + cv::hconcat(normalizedTrainSamples, onesCol, extendedTrainSamples); } void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, Mat& weights) @@ -231,7 +231,7 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const Mat currentSample = trainSamples.row(samplesIndex); float dotProduct = static_cast(currentSample.dot(weights_)); - bool firstClass = isFirstClass(trainResponses.at(samplesIndex)); + bool firstClass = isPositive(trainResponses.at(samplesIndex)); int index = firstClass ? 0 : 1; float signToMul = firstClass ? 1.f : -1.f; float curDistance = dotProduct * signToMul; @@ -297,11 +297,10 @@ bool SVMSGDImpl::train(const Ptr& data, int) int randomNumber = rng.uniform(0, extendedTrainSamplesCount); //generate sample number Mat currentSample = extendedTrainSamples.row(randomNumber); - bool firstClass = isFirstClass(trainResponses.at(randomNumber)); float gamma = params.gamma0 * std::pow((1 + params.lambda * params.gamma0 * (float)iter), (-params.c)); //update gamma - updateWeights( currentSample, firstClass, gamma, extendedWeights ); + updateWeights( currentSample, isPositive(trainResponses.at(randomNumber)), gamma, extendedWeights ); //average weights (only for ASGD model) if (params.svmsgdType == ASGD) diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 592e66b3b0..00ebbf3341 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -134,7 +134,7 @@ void CV_SVMSGDTrainTest::makeTestData(Mat weights, float shift) { int testSamplesCount = 100000; int featureCount = weights.cols; - cv::RNG rng(0); + cv::RNG rng(42); testSamples.create(testSamplesCount, featureCount, CV_32FC1); for (int featureIndex = 0; featureIndex < featureCount; featureIndex++) diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index aed8228c4b..a68f613b2f 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -6,8 +6,6 @@ using namespace cv; using namespace cv::ml; -#define WIDTH 841 -#define HEIGHT 594 struct Data { @@ -17,6 +15,8 @@ struct Data Data() { + const int WIDTH = 841; + const int HEIGHT = 594; img = Mat::zeros(HEIGHT, WIDTH, CV_8UC3); imshow("Train svmsgd", img); } From 77fa8d9d5a743f4f7b92a2c82e7d1b2bd053e26a Mon Sep 17 00:00:00 2001 From: Eric Zavesky Date: Mon, 15 Feb 2016 05:37:54 -0600 Subject: [PATCH 153/468] - fix windows-based warnings for type casts --- .../features2D/AKAZE_tracking/planar_tracking.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp index dfeb63d192..c407c8611d 100755 --- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp +++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp @@ -47,8 +47,8 @@ void Tracker::setFirstFrame(const Mat frame, vector bb, string title, S const Point* ptContain = { &ptMask[0] }; int iSize = static_cast(bb.size()); for (size_t i=0; i(bb[i].x); + ptMask[i].y = static_cast(bb[i].y); } first_frame = frame.clone(); cv::Mat matMask = cv::Mat::zeros(frame.size(), CV_8UC1); @@ -172,10 +172,10 @@ int main(int argc, char **argv) vector bb; if (argc < 4) { //attempt to alow GUI selection cv::Rect2d uBox = selectROI(video_name, frame); - bb.push_back(cv::Point2f(uBox.x, uBox.y)); - bb.push_back(cv::Point2f(uBox.x+uBox.width, uBox.y)); - bb.push_back(cv::Point2f(uBox.x+uBox.width, uBox.y+uBox.height)); - bb.push_back(cv::Point2f(uBox.x, uBox.y+uBox.height)); + bb.push_back(cv::Point2f(static_cast(uBox.x), static_cast(uBox.y))); + bb.push_back(cv::Point2f(static_cast(uBox.x+uBox.width), static_cast(uBox.y))); + bb.push_back(cv::Point2f(static_cast(uBox.x+uBox.width), static_cast(uBox.y+uBox.height))); + bb.push_back(cv::Point2f(static_cast(uBox.x), static_cast(uBox.y+uBox.height))); } else { FileStorage fs(argv[3], FileStorage::READ); From 02cd8cf039bf475b24f86709e0d42911844ece35 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Mon, 15 Feb 2016 15:09:59 +0300 Subject: [PATCH 154/468] Deleted illegal type values. --- modules/ml/include/opencv2/ml.hpp | 2 - modules/ml/src/svmsgd.cpp | 92 +++++++------------------------ 2 files changed, 21 insertions(+), 73 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 346df8f15c..75fb6d134b 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1588,7 +1588,6 @@ public: ASGD is often the preferable choice. */ enum SvmsgdType { - ILLEGAL_SVMSGD_TYPE, SGD, //!< Stochastic Gradient Descent ASGD //!< Average Stochastic Gradient Descent }; @@ -1596,7 +1595,6 @@ public: /** Margin type.*/ enum MarginType { - ILLEGAL_MARGIN_TYPE, SOFT_MARGIN, //!< General case, suits to the case of non-linearly separable sets, allows outliers. HARD_MARGIN //!< More accurate for the case of linearly separable sets. }; diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 77ac2ad67b..0f1efcfea6 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -89,14 +89,8 @@ public: virtual void setOptimalParameters(int svmsgdType = ASGD, int marginType = SOFT_MARGIN); - virtual int getSvmsgdType() const; - - virtual void setSvmsgdType(int svmsgdType); - - virtual int getMarginType() const; - - virtual void setMarginType(int marginType); - + CV_IMPL_PROPERTY(int, SvmsgdType, params.svmsgdType) + CV_IMPL_PROPERTY(int, MarginType, params.marginType) CV_IMPL_PROPERTY(float, Lambda, params.lambda) CV_IMPL_PROPERTY(float, Gamma0, params.gamma0) CV_IMPL_PROPERTY(float, C, params.c) @@ -132,8 +126,8 @@ private: float gamma0; //learning rate float c; TermCriteria termCrit; - SvmsgdType svmsgdType; - MarginType marginType; + int svmsgdType; + int marginType; }; SVMSGDParams params; @@ -148,9 +142,9 @@ std::pair SVMSGDImpl::areClassesEmpty(Mat responses) { CV_Assert(responses.cols == 1 || responses.rows == 1); std::pair emptyInClasses(true, true); - int limit_index = responses.rows; + int limitIndex = responses.rows; - for(int index = 0; index < limit_index; index++) + for(int index = 0; index < limitIndex; index++) { if (isPositive(responses.at(index))) emptyInClasses.first = false; @@ -276,9 +270,9 @@ bool SVMSGDImpl::train(const Ptr& data, int) int extendedTrainSamplesCount = extendedTrainSamples.rows; int extendedFeatureCount = extendedTrainSamples.cols; - Mat extendedWeights = Mat::zeros(1, extendedFeatureCount, CV_32F); // Initialize extendedWeights vector with zeros - Mat previousWeights = Mat::zeros(1, extendedFeatureCount, CV_32F); //extendedWeights vector for calculating terminal criterion - Mat averageExtendedWeights; //average extendedWeights vector for ASGD model + Mat extendedWeights = Mat::zeros(1, extendedFeatureCount, CV_32F); + Mat previousWeights = Mat::zeros(1, extendedFeatureCount, CV_32F); + Mat averageExtendedWeights; if (params.svmsgdType == ASGD) { averageExtendedWeights = Mat::zeros(1, extendedFeatureCount, CV_32F); @@ -407,10 +401,8 @@ void SVMSGDImpl::writeParams( FileStorage& fs ) const case ASGD: SvmsgdTypeStr = "ASGD"; break; - case ILLEGAL_SVMSGD_TYPE: - SvmsgdTypeStr = format("Unknown_%d", params.svmsgdType); default: - std::cout << "params.svmsgdType isn't initialized" << std::endl; + SvmsgdTypeStr = format("Unknown_%d", params.svmsgdType); } fs << "svmsgdType" << SvmsgdTypeStr; @@ -425,10 +417,8 @@ void SVMSGDImpl::writeParams( FileStorage& fs ) const case HARD_MARGIN: marginTypeStr = "HARD_MARGIN"; break; - case ILLEGAL_MARGIN_TYPE: - marginTypeStr = format("Unknown_%d", params.marginType); default: - std::cout << "params.marginType isn't initialized" << std::endl; + marginTypeStr = format("Unknown_%d", params.marginType); } fs << "marginType" << marginTypeStr; @@ -458,21 +448,21 @@ void SVMSGDImpl::read(const FileNode& fn) void SVMSGDImpl::readParams( const FileNode& fn ) { String svmsgdTypeStr = (String)fn["svmsgdType"]; - SvmsgdType svmsgdType = + int svmsgdType = svmsgdTypeStr == "SGD" ? SGD : - svmsgdTypeStr == "ASGD" ? ASGD : ILLEGAL_SVMSGD_TYPE; + svmsgdTypeStr == "ASGD" ? ASGD : -1; - if( svmsgdType == ILLEGAL_SVMSGD_TYPE ) + if( svmsgdType < 0 ) CV_Error( CV_StsParseError, "Missing or invalid SVMSGD type" ); params.svmsgdType = svmsgdType; String marginTypeStr = (String)fn["marginType"]; - MarginType marginType = + int marginType = marginTypeStr == "SOFT_MARGIN" ? SOFT_MARGIN : - marginTypeStr == "HARD_MARGIN" ? HARD_MARGIN : ILLEGAL_MARGIN_TYPE; + marginTypeStr == "HARD_MARGIN" ? HARD_MARGIN : -1; - if( marginType == ILLEGAL_MARGIN_TYPE ) + if( marginType < 0 ) CV_Error( CV_StsParseError, "Missing or invalid margin type" ); params.marginType = marginType; @@ -510,8 +500,8 @@ SVMSGDImpl::SVMSGDImpl() { clear(); - params.svmsgdType = ILLEGAL_SVMSGD_TYPE; - params.marginType = ILLEGAL_MARGIN_TYPE; + params.svmsgdType = -1; + params.marginType = -1; // Parameters for learning params.lambda = 0; // regularization @@ -529,7 +519,7 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) case SGD: params.svmsgdType = SGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : - (marginType == HARD_MARGIN) ? HARD_MARGIN : ILLEGAL_MARGIN_TYPE; + (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; params.lambda = 0.0001f; params.gamma0 = 0.05f; params.c = 1.f; @@ -539,7 +529,7 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) case ASGD: params.svmsgdType = ASGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : - (marginType == HARD_MARGIN) ? HARD_MARGIN : ILLEGAL_MARGIN_TYPE; + (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; params.lambda = 0.00001f; params.gamma0 = 0.05f; params.c = 0.75f; @@ -550,45 +540,5 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) CV_Error( CV_StsParseError, "SVMSGD model data is invalid" ); } } - -void SVMSGDImpl::setSvmsgdType(int type) -{ - switch (type) - { - case SGD: - params.svmsgdType = SGD; - break; - case ASGD: - params.svmsgdType = ASGD; - break; - default: - params.svmsgdType = ILLEGAL_SVMSGD_TYPE; - } -} - -int SVMSGDImpl::getSvmsgdType() const -{ - return params.svmsgdType; -} - -void SVMSGDImpl::setMarginType(int type) -{ - switch (type) - { - case HARD_MARGIN: - params.marginType = HARD_MARGIN; - break; - case SOFT_MARGIN: - params.marginType = SOFT_MARGIN; - break; - default: - params.marginType = ILLEGAL_MARGIN_TYPE; - } -} - -int SVMSGDImpl::getMarginType() const -{ - return params.marginType; -} } //ml } //cv From a54870aace5fe287d2b4a65dc16927ef2cd91509 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Tue, 16 Feb 2016 11:37:27 +0300 Subject: [PATCH 155/468] Added filename emptyness check to the Exif reader, fixes 6120 --- modules/imgcodecs/src/grfmt_jpeg.cpp | 13 ++++++++----- modules/imgcodecs/src/jpeg_exif.cpp | 5 +++++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/imgcodecs/src/grfmt_jpeg.cpp b/modules/imgcodecs/src/grfmt_jpeg.cpp index 8a2900a194..093b88c400 100644 --- a/modules/imgcodecs/src/grfmt_jpeg.cpp +++ b/modules/imgcodecs/src/grfmt_jpeg.cpp @@ -267,13 +267,16 @@ int JpegDecoder::getOrientation() { int orientation = JPEG_ORIENTATION_TL; - ExifReader reader( m_filename ); - if( reader.parse() ) + if (m_filename.size() > 0) { - ExifEntry_t entry = reader.getTag( ORIENTATION ); - if (entry.tag != INVALID_TAG) + ExifReader reader( m_filename ); + if( reader.parse() ) { - orientation = entry.field_u16; //orientation is unsigned short, so check field_u16 + ExifEntry_t entry = reader.getTag( ORIENTATION ); + if (entry.tag != INVALID_TAG) + { + orientation = entry.field_u16; //orientation is unsigned short, so check field_u16 + } } } diff --git a/modules/imgcodecs/src/jpeg_exif.cpp b/modules/imgcodecs/src/jpeg_exif.cpp index ebc4f05352..61b27bbf90 100644 --- a/modules/imgcodecs/src/jpeg_exif.cpp +++ b/modules/imgcodecs/src/jpeg_exif.cpp @@ -128,6 +128,11 @@ std::map ExifReader::getExif() size_t count; + if (m_filename.size() == 0) + { + return m_exif; + } + FILE* f = fopen( m_filename.c_str(), "rb" ); if( !f ) From e55a053d71a36403f06e1d99590fdafdd5e216a2 Mon Sep 17 00:00:00 2001 From: Marian Zajko Date: Wed, 17 Feb 2016 11:18:49 +0100 Subject: [PATCH 156/468] ximea new param - added CAP_PROP_XI_SENSOR_BOARD_TEMP parameter - added acquisition resetting for paramters that require it --- modules/videoio/include/opencv2/videoio.hpp | 1 + .../videoio/include/opencv2/videoio/videoio_c.h | 1 + modules/videoio/src/cap_ximea.cpp | 17 +++++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp index cff796d997..6b3b97b6af 100644 --- a/modules/videoio/include/opencv2/videoio.hpp +++ b/modules/videoio/include/opencv2/videoio.hpp @@ -318,6 +318,7 @@ enum { CAP_PROP_XI_DOWNSAMPLING = 400, // Change CAP_PROP_XI_CHIP_TEMP = 468, // Camera sensor temperature CAP_PROP_XI_HOUS_TEMP = 469, // Camera housing tepmerature CAP_PROP_XI_HOUS_BACK_SIDE_TEMP = 590, // Camera housing back side tepmerature + CAP_PROP_XI_SENSOR_BOARD_TEMP = 596, // Camera sensor board temperature CAP_PROP_XI_CMS = 470, // Mode of color management system. CAP_PROP_XI_APPLY_CMS = 471, // Enable applying of CMS profiles to xiGetImage (see XI_PRM_INPUT_CMS_PROFILE, XI_PRM_OUTPUT_CMS_PROFILE). CAP_PROP_XI_IMAGE_IS_COLOR = 474, // Returns 1 for color cameras. diff --git a/modules/videoio/include/opencv2/videoio/videoio_c.h b/modules/videoio/include/opencv2/videoio/videoio_c.h index 8d2af30210..91d26ea5ae 100644 --- a/modules/videoio/include/opencv2/videoio/videoio_c.h +++ b/modules/videoio/include/opencv2/videoio/videoio_c.h @@ -303,6 +303,7 @@ enum CV_CAP_PROP_XI_CHIP_TEMP = 468, // Camera sensor temperature CV_CAP_PROP_XI_HOUS_TEMP = 469, // Camera housing tepmerature CV_CAP_PROP_XI_HOUS_BACK_SIDE_TEMP = 590, // Camera housing back side tepmerature + CV_CAP_PROP_XI_SENSOR_BOARD_TEMP = 596, // Camera sensor board temperature CV_CAP_PROP_XI_CMS = 470, // Mode of color management system. CV_CAP_PROP_XI_APPLY_CMS = 471, // Enable applying of CMS profiles to xiGetImage (see XI_PRM_INPUT_CMS_PROFILE, XI_PRM_OUTPUT_CMS_PROFILE). CV_CAP_PROP_XI_IMAGE_IS_COLOR = 474, // Returns 1 for color cameras. diff --git a/modules/videoio/src/cap_ximea.cpp b/modules/videoio/src/cap_ximea.cpp index cf0a016fb7..e31c01a5c9 100644 --- a/modules/videoio/src/cap_ximea.cpp +++ b/modules/videoio/src/cap_ximea.cpp @@ -568,6 +568,10 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) ximea_param = "hous_back_side_temp"; value_type = xiTypeFloat; break; + case CV_CAP_PROP_XI_SENSOR_BOARD_TEMP: + ximea_param = "sensor_board_temp"; + value_type = xiTypeFloat; + break; case CV_CAP_PROP_XI_CMS: ximea_param = "cms"; value_type = xiTypeEnum; @@ -676,6 +680,7 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) case CV_CAP_PROP_XI_TRG_SELECTOR: ximea_param = "trigger_selector"; value_type = xiTypeEnum; + doAcqReset = true; break; case CV_CAP_PROP_XI_ACQ_FRAME_BURST_COUNT: ximea_param = "acq_frame_burst_count"; @@ -780,14 +785,17 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) case CV_CAP_PROP_XI_SENSOR_CLOCK_FREQ_HZ: ximea_param = "sensor_clock_freq_hz"; value_type = xiTypeFloat; + doAcqReset = true; break; case CV_CAP_PROP_XI_SENSOR_CLOCK_FREQ_INDEX: ximea_param = "sensor_clock_freq_index"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_SENSOR_OUTPUT_CHANNEL_COUNT: ximea_param = "sensor_output_channel_count"; value_type = xiTypeEnum; + doAcqReset = true; break; case CV_CAP_PROP_XI_FRAMERATE: ximea_param = "framerate"; @@ -808,6 +816,7 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) case CV_CAP_PROP_XI_AVAILABLE_BANDWIDTH: ximea_param = "available_bandwidth"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_BUFFER_POLICY: ximea_param = "buffer_policy"; @@ -816,14 +825,17 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) case CV_CAP_PROP_XI_LUT_EN: ximea_param = "LUTEnable"; value_type = xiTypeBoolean; + doAcqReset = true; break; case CV_CAP_PROP_XI_LUT_INDEX: ximea_param = "LUTIndex"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_LUT_VALUE: ximea_param = "LUTValue"; value_type = xiTypeInteger; + doAcqReset = true; break; case CV_CAP_PROP_XI_TRG_DELAY: ximea_param = "trigger_delay"; @@ -886,6 +898,7 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value ) case CV_CAP_PROP_XI_SENSOR_MODE: ximea_param = "sensor_mode"; value_type = xiTypeEnum; + doAcqReset = true; break; case CV_CAP_PROP_XI_HDR: ximea_param = "hdr"; @@ -1235,6 +1248,10 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id ) const ximea_param = "hous_back_side_temp"; value_type = xiTypeFloat; break; + case CV_CAP_PROP_XI_SENSOR_BOARD_TEMP: + ximea_param = "sensor_board_temp"; + value_type = xiTypeFloat; + break; case CV_CAP_PROP_XI_CMS: ximea_param = "cms"; value_type = xiTypeEnum; From da93a5527dff49c36100b750f340193319c22689 Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 18 Feb 2016 00:23:20 -0500 Subject: [PATCH 157/468] Thrust allocator for temporary storage used with thrust algorithms. --- .../include/opencv2/core/cuda/utility.hpp | 9 ++++ modules/core/src/cuda/gpu_mat.cu | 41 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/modules/core/include/opencv2/core/cuda/utility.hpp b/modules/core/include/opencv2/core/cuda/utility.hpp index ed604712a7..96616d67b5 100644 --- a/modules/core/include/opencv2/core/cuda/utility.hpp +++ b/modules/core/include/opencv2/core/cuda/utility.hpp @@ -54,6 +54,15 @@ namespace cv { namespace cuda { namespace device { + struct CV_EXPORTS ThrustAllocator + { + typedef uchar value_type; + + virtual __device__ __host__ uchar* allocate(size_t numBytes) = 0; + virtual __device__ __host__ void free(uchar* ptr) = 0; + static ThrustAllocator& getAllocator(); + static void setAllocator(ThrustAllocator* allocator); + }; #define OPENCV_CUDA_LOG_WARP_SIZE (5) #define OPENCV_CUDA_WARP_SIZE (1 << OPENCV_CUDA_LOG_WARP_SIZE) #define OPENCV_CUDA_LOG_MEM_BANKS ((__CUDA_ARCH__ >= 200) ? 5 : 4) // 32 banks on fermi, 16 on tesla diff --git a/modules/core/src/cuda/gpu_mat.cu b/modules/core/src/cuda/gpu_mat.cu index f21c5f4c19..a4e8ee7302 100644 --- a/modules/core/src/cuda/gpu_mat.cu +++ b/modules/core/src/cuda/gpu_mat.cu @@ -50,11 +50,52 @@ #include "opencv2/core/cuda.hpp" #include "opencv2/cudev.hpp" +#include "opencv2/core/cuda/utility.hpp" using namespace cv; using namespace cv::cuda; using namespace cv::cudev; +namespace +{ + class DefaultThrustAllocator: public cv::cuda::device::ThrustAllocator + { + public: + __device__ __host__ uchar* allocate(size_t numBytes) + { +#ifndef __CUDA_ARCH__ + uchar* ptr; + CV_CUDEV_SAFE_CALL(cudaMalloc(&ptr, numBytes)); + return ptr; +#else + return NULL; +#endif + } + __device__ __host__ void free(uchar* ptr) + { +#ifndef __CUDA_ARCH__ + CV_CUDEV_SAFE_CALL(cudaFree(ptr)); +#endif + } + }; + DefaultThrustAllocator defaultThrustAllocator; + cv::cuda::device::ThrustAllocator* g_thrustAllocator = &defaultThrustAllocator; +} + + +cv::cuda::device::ThrustAllocator& cv::cuda::device::ThrustAllocator::getAllocator() +{ + return *g_thrustAllocator; +} + +void cv::cuda::device::ThrustAllocator::setAllocator(cv::cuda::device::ThrustAllocator* allocator) +{ + if(allocator == NULL) + g_thrustAllocator = &defaultThrustAllocator; + else + g_thrustAllocator = allocator; +} + namespace { class DefaultAllocator : public GpuMat::Allocator From 9a44e921938ef5356084a2a1af6642a78154c80e Mon Sep 17 00:00:00 2001 From: Mathieu Barnachon Date: Thu, 18 Feb 2016 11:28:41 +0100 Subject: [PATCH 158/468] Fix the missing - in file. --- data/haarcascades_cuda/haarcascade_upperbody.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/haarcascades_cuda/haarcascade_upperbody.xml b/data/haarcascades_cuda/haarcascade_upperbody.xml index 98452e2597..f22f8e6709 100644 --- a/data/haarcascades_cuda/haarcascade_upperbody.xml +++ b/data/haarcascades_cuda/haarcascade_upperbody.xml @@ -1,5 +1,5 @@ - Date: Thu, 18 Feb 2016 17:58:28 +0100 Subject: [PATCH 159/468] findHomography sets output mask to all zeros in case of no inlier --- modules/calib3d/src/fundam.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/calib3d/src/fundam.cpp b/modules/calib3d/src/fundam.cpp index 57e3699481..20803a5fe2 100644 --- a/modules/calib3d/src/fundam.cpp +++ b/modules/calib3d/src/fundam.cpp @@ -411,7 +411,13 @@ cv::Mat cv::findHomography( InputArray _points1, InputArray _points2, tempMask.copyTo(_mask); } else + { H.release(); + if(_mask.needed() ) { + tempMask = Mat::zeros(npoints >= 0 ? npoints : 0, 1, CV_8U); + tempMask.copyTo(_mask); + } + } return H; } From 7ad849718c1696ac799258f21726a435fab025b0 Mon Sep 17 00:00:00 2001 From: aravind Date: Wed, 17 Feb 2016 21:57:11 +0530 Subject: [PATCH 160/468] Fixed Fisheye Camera model documentation. --- modules/calib3d/include/opencv2/calib3d.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index 9d3112527f..c52356a75a 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -200,7 +200,7 @@ pattern (every view is described by several 3D-2D point correspondences). The distorted point coordinates are [x'; y'] where - \f[x' = (\theta_d / r) x \\ y' = (\theta_d / r) y \f] + \f[x' = (\theta_d / r) a \\ y' = (\theta_d / r) b \f] Finally, conversion into pixel coordinates: The final pixel coordinates vector [u; v] where: From 95608b1b84faf68a6869a4a6ffb1f1031797441f Mon Sep 17 00:00:00 2001 From: Dan Date: Thu, 18 Feb 2016 15:05:13 -0500 Subject: [PATCH 161/468] free -> deallocate --- modules/core/include/opencv2/core/cuda/utility.hpp | 2 +- modules/core/src/cuda/gpu_mat.cu | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/include/opencv2/core/cuda/utility.hpp b/modules/core/include/opencv2/core/cuda/utility.hpp index 96616d67b5..b93503737e 100644 --- a/modules/core/include/opencv2/core/cuda/utility.hpp +++ b/modules/core/include/opencv2/core/cuda/utility.hpp @@ -59,7 +59,7 @@ namespace cv { namespace cuda { namespace device typedef uchar value_type; virtual __device__ __host__ uchar* allocate(size_t numBytes) = 0; - virtual __device__ __host__ void free(uchar* ptr) = 0; + virtual __device__ __host__ void deallocate(uchar* ptr, size_t numBytes) = 0; static ThrustAllocator& getAllocator(); static void setAllocator(ThrustAllocator* allocator); }; diff --git a/modules/core/src/cuda/gpu_mat.cu b/modules/core/src/cuda/gpu_mat.cu index a4e8ee7302..e5a8facef3 100644 --- a/modules/core/src/cuda/gpu_mat.cu +++ b/modules/core/src/cuda/gpu_mat.cu @@ -71,7 +71,7 @@ namespace return NULL; #endif } - __device__ __host__ void free(uchar* ptr) + __device__ __host__ void deallocate(uchar* ptr, size_t numBytes) { #ifndef __CUDA_ARCH__ CV_CUDEV_SAFE_CALL(cudaFree(ptr)); From 74ee9ac572820dad03008a2dcae249b77856e900 Mon Sep 17 00:00:00 2001 From: Philip Date: Fri, 19 Feb 2016 13:19:51 +0100 Subject: [PATCH 162/468] Add an Issue template for new issues Since we've got a new feature here on github i would like to use it to get all relevant information into the reported issues. https://help.github.com/articles/creating-an-issue-template-for-your-repository/ I started a file but i would like to hear some other options about what to add. add "steps to reproduce" if no code example is applicable change to comments from alalek --- ISSUE_TEMPLATE.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 ISSUE_TEMPLATE.md diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..a4f4c046e3 --- /dev/null +++ b/ISSUE_TEMPLATE.md @@ -0,0 +1,34 @@ +This is a template helping you to create an issue which can be processes as quickly as possible. Feel free to add additional information or remove not relevant points if you do not need them. +### Please state the information for your system +- OpenCV version: 2.4 / 3.x +- Host OS: Linux (Ubuntu 14.04) / Mac OS X 10.11.3 / Windows 10 +- *(if needed, only cross-platform builds)* Target OS: host / Android 6.0 / ARM board / Raspberry Pi 2 +- *(if needed)* Compiler & CMake: GCC 5.3 & CMake 3.5 + +### In which part of the OpenCV library you got the issue? +Examples: +- objdetect, highgui, imgproc, cuda, tests +- face recognition, resizing an image, reading an jpg image + +### Expected behaviour + +### Actual behaviour + +### Additional description + +### Code example to reproduce the issue / Steps to reproduce the issue +Please try to give a full example which will compile as is. +``` +#include "opencv2/core.hpp" +#include +using namespace std; +using namespace cv; + +int main() +{ + double d[] = { 546,2435,7,4534,23423,3 }; + cout << "d = 0x" << reinterpret_cast(d) << endl; + + return 0; +} +``` From 7ff93600b88cf348c6c6d52499da539cb88d2de6 Mon Sep 17 00:00:00 2001 From: Philip Date: Fri, 19 Feb 2016 14:29:59 +0100 Subject: [PATCH 163/468] Create a Pull Request template In addition to the Issue template which is far more important i would like to add this so issues will get closed after merging related PRs rather than being reliant on the reviewer. If someone want to add something here feel free. --- PULL_REQUEST_TEMPLATE.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 PULL_REQUEST_TEMPLATE.md diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..496d748731 --- /dev/null +++ b/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,4 @@ +resolves #XXXX + +### What does this PR change? +Please add your changes here. From f3c4a6aab8c1d60e72e696fa524c01ba644d42fe Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 24 Feb 2016 13:22:07 +0300 Subject: [PATCH 164/468] Rename parameters lambda, gamma0 and c. --- modules/ml/include/opencv2/ml.hpp | 58 +++++++++++----------- modules/ml/src/svmsgd.cpp | 81 +++++++++++++++---------------- modules/ml/test/test_mltests2.cpp | 6 +-- modules/ml/test/test_svmsgd.cpp | 1 - samples/cpp/train_svmsgd.cpp | 4 +- 5 files changed, 74 insertions(+), 76 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 75fb6d134b..7710abdae1 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1511,9 +1511,9 @@ The gradient descent show amazing performance for large-scale problems, reducing The classifier has 5 parameters. These are - model type, - margin type, -- \f$\lambda\f$ (strength of restrictions on outliers), -- \f$\gamma_0\f$ (initial step size), -- \f$c\f$ (power coefficient for decreasing of step size), +- marginRegularization (\f$\lambda\f$), +- initialStepSize (\f$\gamma_0\f$), +- stepDecreasingPower (\f$c\f$), - and termination criteria. The model type may have one of the following values: \ref SGD and \ref ASGD. @@ -1538,27 +1538,27 @@ The margin type may have one of the following values: \ref SOFT_MARGIN or \ref H - In the general case (if you know nothing about linear separability of your sets), use SOFT_MARGIN. The other parameters may be described as follows: -- \f$\lambda\f$ parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers +- marginRegularization parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers (the less the parameter, the less probability that an outlier will be ignored). Recommended value for SGD model is 0.0001, for ASGD model is 0.00001. -- \f$\gamma_0\f$ parameter is the initial value for the step size \f$\gamma(t)\f$. +- initialStepSize parameter is the initial value for the step size \f$\gamma(t)\f$. You will have to find the best \f$\gamma_0\f$ for your problem. -- \f$c\f$ is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. +- stepDecreasingPower is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. Recommended value for SGD model is 1, for ASGD model is 0.75. - Termination criteria can be TermCriteria::COUNT, TermCriteria::EPS or TermCriteria::COUNT + TermCriteria::EPS. You will have to find the best termination criteria for your problem. -Note that the parameters \f$\lambda\f$, \f$\gamma_0\f$, and \f$c\f$ should be positive. +Note that the parameters marginRegularization, initialStepSize, and stepDecreasingPower should be positive. To use SVMSGD algorithm do as follows: - first, create the SVMSGD object. -- then set parameters (model type, margin type, \f$\lambda\f$, \f$\gamma_0\f$, \f$c\f$) using the functions - setSvmsgdType(), setMarginType(), setLambda(), setGamma0(), and setC(), or the function setOptimalParameters(). +- then set parameters (model type, margin type, marginRegularization, initialStepSize, stepDecreasingPower) using the functions + setSvmsgdType(), setMarginType(), setMarginRegularization(), setInitialStepSize(), and setStepDecreasingPower(), or the function setOptimalParameters(). - then the SVM model can be trained using the train features and the correspondent labels by the method train(). @@ -1618,16 +1618,16 @@ public: /** @brief Function sets optimal parameters values for chosen SVM SGD model. * If chosen type is ASGD, function sets the following values for parameters of model: - * \f$\lambda = 0.00001\f$; - * \f$\gamma_0 = 0.05\f$; - * \f$c = 0.75\f$; + * marginRegularization = 0.00001; + * initialStepSize = 0.05; + * stepDecreasingPower = 0.75; * termCrit.maxCount = 100000; * termCrit.epsilon = 0.00001; * * If SGD: - * \f$\lambda = 0.0001\f$; - * \f$\gamma_0 = 0.05\f$; - * \f$c = 1\f$; + * marginRegularization = 0.0001; + * initialStepSize = 0.05; + * stepDecreasingPower = 1; * termCrit.maxCount = 100000; * termCrit.epsilon = 0.00001; * @param svmsgdType is the type of SVMSGD classifier. Legal values are SvmsgdType::SGD and SvmsgdType::ASGD. @@ -1650,23 +1650,23 @@ public: CV_WRAP virtual void setMarginType(int marginType) = 0; - /** @brief Parameter \f$\lambda\f$ of a %SVMSGD optimization problem. Default value is 0. */ - /** @see setLambda */ - CV_WRAP virtual float getLambda() const = 0; - /** @copybrief getLambda @see getLambda */ - CV_WRAP virtual void setLambda(float lambda) = 0; + /** @brief Parameter marginRegularization of a %SVMSGD optimization problem. Default value is 0. */ + /** @see setMarginRegularization */ + CV_WRAP virtual float getMarginRegularization() const = 0; + /** @copybrief getMarginRegularization @see getMarginRegularization */ + CV_WRAP virtual void setMarginRegularization(float marginRegularization) = 0; /** @brief Parameter \f$\gamma_0\f$ of a %SVMSGD optimization problem. Default value is 0. */ - /** @see setGamma0 */ - CV_WRAP virtual float getGamma0() const = 0; - /** @copybrief getGamma0 @see getGamma0 */ - CV_WRAP virtual void setGamma0(float gamma0) = 0; + /** @see setInitialStepSize */ + CV_WRAP virtual float getInitialStepSize() const = 0; + /** @copybrief getInitialStepSize @see getInitialStepSize */ + CV_WRAP virtual void setInitialStepSize(float InitialStepSize) = 0; - /** @brief Parameter \f$c\f$ of a %SVMSGD optimization problem. Default value is 0. */ - /** @see setC */ - CV_WRAP virtual float getC() const = 0; - /** @copybrief getC @see getC */ - CV_WRAP virtual void setC(float c) = 0; + /** @brief Parameter stepDecreasingPower of a %SVMSGD optimization problem. Default value is 0. */ + /** @see setStepDecreasingPower */ + CV_WRAP virtual float getStepDecreasingPower() const = 0; + /** @copybrief getStepDecreasingPower @see getStepDecreasingPower */ + CV_WRAP virtual void setStepDecreasingPower(float stepDecreasingPower) = 0; /** @brief Termination criteria of the training algorithm. You can specify the maximum number of iterations (maxCount) and/or how much the error could diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 0f1efcfea6..17feeff17c 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -91,13 +91,13 @@ public: CV_IMPL_PROPERTY(int, SvmsgdType, params.svmsgdType) CV_IMPL_PROPERTY(int, MarginType, params.marginType) - CV_IMPL_PROPERTY(float, Lambda, params.lambda) - CV_IMPL_PROPERTY(float, Gamma0, params.gamma0) - CV_IMPL_PROPERTY(float, C, params.c) + CV_IMPL_PROPERTY(float, MarginRegularization, params.marginRegularization) + CV_IMPL_PROPERTY(float, InitialStepSize, params.initialStepSize) + CV_IMPL_PROPERTY(float, StepDecreasingPower, params.stepDecreasingPower) CV_IMPL_PROPERTY_S(cv::TermCriteria, TermCriteria, params.termCrit) private: - void updateWeights(InputArray sample, bool isPositive, float gamma, Mat &weights); + void updateWeights(InputArray sample, bool isPositive, float stepSize, Mat &weights); std::pair areClassesEmpty(Mat responses); @@ -122,9 +122,9 @@ private: // Parameters for learning struct SVMSGDParams { - float lambda; //regularization - float gamma0; //learning rate - float c; + float marginRegularization; + float initialStepSize; + float stepDecreasingPower; TermCriteria termCrit; int svmsgdType; int marginType; @@ -166,8 +166,7 @@ void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) average = Mat(1, featuresCount, samples.type()); for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++) { - Scalar scalAverage = mean(samples.col(featureIndex)); - average.at(featureIndex) = static_cast(scalAverage[0]); + average.at(featureIndex) = static_cast(mean(samples.col(featureIndex))[0]); } for (int sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) @@ -193,7 +192,7 @@ void SVMSGDImpl::makeExtendedTrainSamples(const Mat &trainSamples, Mat &extended cv::hconcat(normalizedTrainSamples, onesCol, extendedTrainSamples); } -void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, Mat& weights) +void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float stepSize, Mat& weights) { Mat sample = _sample.getMat(); @@ -202,18 +201,18 @@ void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float gamma, if ( sample.dot(weights) * response > 1) { // Not a support vector, only apply weight decay - weights *= (1.f - gamma * params.lambda); + weights *= (1.f - stepSize * params.marginRegularization); } else { // It's a support vector, add it to the weights - weights -= (gamma * params.lambda) * weights - (gamma * response) * sample; + weights -= (stepSize * params.marginRegularization) * weights - (stepSize * response) * sample; } } float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const { - float distanceToClasses[2] = { std::numeric_limits::max(), std::numeric_limits::max() }; + float margin[2] = { std::numeric_limits::max(), std::numeric_limits::max() }; Mat trainSamples = _samples.getMat(); int trainSamplesCount = trainSamples.rows; @@ -225,18 +224,18 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const Mat currentSample = trainSamples.row(samplesIndex); float dotProduct = static_cast(currentSample.dot(weights_)); - bool firstClass = isPositive(trainResponses.at(samplesIndex)); - int index = firstClass ? 0 : 1; - float signToMul = firstClass ? 1.f : -1.f; - float curDistance = dotProduct * signToMul; + bool positive = isPositive(trainResponses.at(samplesIndex)); + int index = positive ? 0 : 1; + float signToMul = positive ? 1.f : -1.f; + float curMargin = dotProduct * signToMul; - if (curDistance < distanceToClasses[index]) + if (curMargin < margin[index]) { - distanceToClasses[index] = curDistance; + margin[index] = curMargin; } } - return -(distanceToClasses[0] - distanceToClasses[1]) / 2.f; + return -(margin[0] - margin[1]) / 2.f; } bool SVMSGDImpl::train(const Ptr& data, int) @@ -292,9 +291,9 @@ bool SVMSGDImpl::train(const Ptr& data, int) Mat currentSample = extendedTrainSamples.row(randomNumber); - float gamma = params.gamma0 * std::pow((1 + params.lambda * params.gamma0 * (float)iter), (-params.c)); //update gamma + float stepSize = params.initialStepSize * std::pow((1 + params.marginRegularization * params.initialStepSize * (float)iter), (-params.stepDecreasingPower)); //update stepSize - updateWeights( currentSample, isPositive(trainResponses.at(randomNumber)), gamma, extendedWeights ); + updateWeights( currentSample, isPositive(trainResponses.at(randomNumber)), stepSize, extendedWeights ); //average weights (only for ASGD model) if (params.svmsgdType == ASGD) @@ -370,7 +369,7 @@ bool SVMSGDImpl::isClassifier() const && (params.marginType == SOFT_MARGIN || params.marginType == HARD_MARGIN) && - (params.lambda > 0) && (params.gamma0 > 0) && (params.c >= 0); + (params.marginRegularization > 0) && (params.initialStepSize > 0) && (params.stepDecreasingPower >= 0); } bool SVMSGDImpl::isTrained() const @@ -423,9 +422,9 @@ void SVMSGDImpl::writeParams( FileStorage& fs ) const fs << "marginType" << marginTypeStr; - fs << "lambda" << params.lambda; - fs << "gamma0" << params.gamma0; - fs << "c" << params.c; + fs << "marginRegularization" << params.marginRegularization; + fs << "initialStepSize" << params.initialStepSize; + fs << "stepDecreasingPower" << params.stepDecreasingPower; fs << "term_criteria" << "{:"; if( params.termCrit.type & TermCriteria::EPS ) @@ -467,14 +466,14 @@ void SVMSGDImpl::readParams( const FileNode& fn ) params.marginType = marginType; - CV_Assert ( fn["lambda"].isReal() ); - params.lambda = (float)fn["lambda"]; + CV_Assert ( fn["marginRegularization"].isReal() ); + params.marginRegularization = (float)fn["marginRegularization"]; - CV_Assert ( fn["gamma0"].isReal() ); - params.gamma0 = (float)fn["gamma0"]; + CV_Assert ( fn["initialStepSize"].isReal() ); + params.initialStepSize = (float)fn["initialStepSize"]; - CV_Assert ( fn["c"].isReal() ); - params.c = (float)fn["c"]; + CV_Assert ( fn["stepDecreasingPower"].isReal() ); + params.stepDecreasingPower = (float)fn["stepDecreasingPower"]; FileNode tcnode = fn["term_criteria"]; if( !tcnode.empty() ) @@ -504,9 +503,9 @@ SVMSGDImpl::SVMSGDImpl() params.marginType = -1; // Parameters for learning - params.lambda = 0; // regularization - params.gamma0 = 0; // learning rate (ideally should be large at beginning and decay each iteration) - params.c = 0; + params.marginRegularization = 0; // regularization + params.initialStepSize = 0; // learning rate (ideally should be large at beginning and decay each iteration) + params.stepDecreasingPower = 0; TermCriteria _termCrit(TermCriteria::COUNT + TermCriteria::EPS, 0, 0); params.termCrit = _termCrit; @@ -520,9 +519,9 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) params.svmsgdType = SGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; - params.lambda = 0.0001f; - params.gamma0 = 0.05f; - params.c = 1.f; + params.marginRegularization = 0.0001f; + params.initialStepSize = 0.05f; + params.stepDecreasingPower = 1.f; params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001); break; @@ -530,9 +529,9 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) params.svmsgdType = ASGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; - params.lambda = 0.00001f; - params.gamma0 = 0.05f; - params.c = 0.75f; + params.marginRegularization = 0.00001f; + params.initialStepSize = 0.05f; + params.stepDecreasingPower = 0.75f; params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001); break; diff --git a/modules/ml/test/test_mltests2.cpp b/modules/ml/test/test_mltests2.cpp index 01f5568daf..15ae20096c 100644 --- a/modules/ml/test/test_mltests2.cpp +++ b/modules/ml/test/test_mltests2.cpp @@ -469,9 +469,9 @@ int CV_MLBaseTest::train( int testCaseIdx ) int marginType = str_to_margin_type( marginTypeStr ); m->setMarginType(marginType); - m->setLambda(modelParamsNode["lambda"]); - m->setGamma0(modelParamsNode["gamma0"]); - m->setC(modelParamsNode["c"]); + m->setMarginRegularization(modelParamsNode["marginRegularization"]); + m->setInitialStepSize(modelParamsNode["initialStepSize"]); + m->setStepDecreasingPower(modelParamsNode["stepDecreasingPower"]); m->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10000, 0.00001)); model = m; } diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 00ebbf3341..31fd71729a 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -200,7 +200,6 @@ void CV_SVMSGDTrainTest::run( int /*start_from*/ ) } float err = (float)errCount / testSamplesCount; - std::cout << "err " << err << std::endl; if ( err > precision ) { diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index a68f613b2f..efcff01cb8 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -28,7 +28,7 @@ struct Data bool doTrain(const Mat samples, const Mat responses, Mat &weights, float &shift); //function finds two points for drawing line (wx = 0) -bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2], int width, int height); +bool findPointsForLine(const Mat &weights, float shift, Point points[], int width, int height); // function finds cross point of line (wx = 0) and segment ( (y = HEIGHT, 0 <= x <= WIDTH) or (x = WIDTH, 0 <= y <= HEIGHT) ) bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair &segment, Point &crossPoint); @@ -119,7 +119,7 @@ bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair< return false; } -bool findPointsForLine(const Mat &weights, float shift, Point (&points)[2], int width, int height) +bool findPointsForLine(const Mat &weights, float shift, Point points[2], int width, int height) { if (weights.empty()) { From 9d9a5bbbfda3e5109f2550454fc18cb82c35a195 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 24 Feb 2016 13:33:43 +0300 Subject: [PATCH 165/468] Fixed documentation. --- modules/ml/include/opencv2/ml.hpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 7710abdae1..f9d7418d5e 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1511,9 +1511,9 @@ The gradient descent show amazing performance for large-scale problems, reducing The classifier has 5 parameters. These are - model type, - margin type, -- marginRegularization (\f$\lambda\f$), -- initialStepSize (\f$\gamma_0\f$), -- stepDecreasingPower (\f$c\f$), +- margin regularization (\f$\lambda\f$), +- initial step size (\f$\gamma_0\f$), +- step decreasing power (\f$c\f$), - and termination criteria. The model type may have one of the following values: \ref SGD and \ref ASGD. @@ -1538,26 +1538,26 @@ The margin type may have one of the following values: \ref SOFT_MARGIN or \ref H - In the general case (if you know nothing about linear separability of your sets), use SOFT_MARGIN. The other parameters may be described as follows: -- marginRegularization parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers +- Margin regularization parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers (the less the parameter, the less probability that an outlier will be ignored). Recommended value for SGD model is 0.0001, for ASGD model is 0.00001. -- initialStepSize parameter is the initial value for the step size \f$\gamma(t)\f$. +- Initial step size parameter is the initial value for the step size \f$\gamma(t)\f$. You will have to find the best \f$\gamma_0\f$ for your problem. -- stepDecreasingPower is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. +- Step decreasing power is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. Recommended value for SGD model is 1, for ASGD model is 0.75. - Termination criteria can be TermCriteria::COUNT, TermCriteria::EPS or TermCriteria::COUNT + TermCriteria::EPS. You will have to find the best termination criteria for your problem. -Note that the parameters marginRegularization, initialStepSize, and stepDecreasingPower should be positive. +Note that the parameters margin regularization, initial step size, and step decreasing power should be positive. To use SVMSGD algorithm do as follows: - first, create the SVMSGD object. -- then set parameters (model type, margin type, marginRegularization, initialStepSize, stepDecreasingPower) using the functions +- then set parameters (model type, margin type, margin regularization, initial step size, step decreasing power) using the functions setSvmsgdType(), setMarginType(), setMarginRegularization(), setInitialStepSize(), and setStepDecreasingPower(), or the function setOptimalParameters(). - then the SVM model can be trained using the train features and the correspondent labels by the method train(). @@ -1656,7 +1656,7 @@ public: /** @copybrief getMarginRegularization @see getMarginRegularization */ CV_WRAP virtual void setMarginRegularization(float marginRegularization) = 0; - /** @brief Parameter \f$\gamma_0\f$ of a %SVMSGD optimization problem. Default value is 0. */ + /** @brief Parameter initialStepSize of a %SVMSGD optimization problem. Default value is 0. */ /** @see setInitialStepSize */ CV_WRAP virtual float getInitialStepSize() const = 0; /** @copybrief getInitialStepSize @see getInitialStepSize */ From 068677ad50a72b911445ed7a2c7472b70906a882 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Wed, 24 Feb 2016 14:41:51 +0300 Subject: [PATCH 166/468] Fixed documentation. --- modules/ml/include/opencv2/ml.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index f9d7418d5e..6343b344bc 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1506,7 +1506,6 @@ public: SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, as presented in @cite bottou2010large. -The gradient descent show amazing performance for large-scale problems, reducing the computing time. The classifier has 5 parameters. These are - model type, From bb605279b6dfbd882b057e44c011a5fa48437532 Mon Sep 17 00:00:00 2001 From: Pavel Rojtberg Date: Wed, 24 Feb 2016 15:44:32 +0100 Subject: [PATCH 167/468] clarify how to use fisheye::distortPoints --- modules/calib3d/include/opencv2/calib3d.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index c52356a75a..e26e8c13f9 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -1802,6 +1802,10 @@ namespace fisheye @param D Input vector of distortion coefficients \f$(k_1, k_2, k_3, k_4)\f$. @param alpha The skew coefficient. @param distorted Output array of image points, 1xN/Nx1 2-channel, or vector\ . + + Note that the function assumes the camera matrix of the undistorted points to be indentity. + This means if you want to transform back points undistorted with undistortPoints() you have to + multiply them with \f$P^{-1}\f$. */ CV_EXPORTS_W void distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha = 0); From ee2f8d006fb481383685f1f2bfba83b3db43dae9 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Wed, 24 Feb 2016 19:40:50 +0300 Subject: [PATCH 168/468] Cocoa backend: added checks before accessing sliders dictionary --- modules/highgui/src/window_cocoa.mm | 47 +++++++++++++++++------------ 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/modules/highgui/src/window_cocoa.mm b/modules/highgui/src/window_cocoa.mm index 4ab1e360e1..a653cd355c 100644 --- a/modules/highgui/src/window_cocoa.mm +++ b/modules/highgui/src/window_cocoa.mm @@ -230,8 +230,10 @@ CV_IMPL void cvShowImage( const char* name, const CvArr* arr) //Set new view size considering sliders (reserve height and min width) NSRect vrectNew = vrectOld; int slider_height = 0; - for(NSString *key in [window sliders]) { - slider_height += [[[window sliders] valueForKey:key] frame].size.height; + if ([window respondsToSelector:@selector(sliders)]) { + for(NSString *key in [window sliders]) { + slider_height += [[[window sliders] valueForKey:key] frame].size.height; + } } vrectNew.size.height = [[[window contentView] image] size].height + slider_height; vrectNew.size.width = std::max([[[window contentView] image] size].width, MIN_SLIDER_WIDTH); @@ -331,9 +333,12 @@ CV_IMPL int cvCreateTrackbar2(const char* trackbar_name, NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; int res = cvCreateTrackbar(trackbar_name, window_name, val, count, NULL); if(res) { - CVSlider *slider = [[cvGetWindow(window_name) sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; - [slider setCallback2:on_notify2]; - [slider setUserData:userdata]; + CVWindow *window = cvGetWindow(window_name); + if (window && [window respondsToSelector:@selector(sliders)]) { + CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; + [slider setCallback2:on_notify2]; + [slider setUserData:userdata]; + } } [localpool drain]; return res; @@ -383,7 +388,7 @@ cvSetMouseCallback( const char* name, CvMouseCallback function, void* info) localpool4 = [[NSAutoreleasePool alloc] init]; window = cvGetWindow(window_name); - if(window) { + if(window && [window respondsToSelector:@selector(sliders)]) { CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; if(slider) { pos = [[slider slider] intValue]; @@ -414,7 +419,7 @@ CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name localpool5 = [[NSAutoreleasePool alloc] init]; window = cvGetWindow(window_name); - if(window) { + if(window && [window respondsToSelector:@selector(sliders)]) { slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; if(slider) { [[slider slider] setIntValue:pos]; @@ -442,7 +447,7 @@ CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name localpool5 = [[NSAutoreleasePool alloc] init]; window = cvGetWindow(window_name); - if(window) { + if(window && [window respondsToSelector:@selector(sliders)]) { slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; if(slider) { if(maxval >= 0) { @@ -473,7 +478,7 @@ CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name localpool5 = [[NSAutoreleasePool alloc] init]; window = cvGetWindow(window_name); - if(window) { + if(window && [window respondsToSelector:@selector(sliders)]) { slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]]; if(slider) { if(minval >= 0) { @@ -709,9 +714,11 @@ void cv::setWindowTitle(const String& winname, const String& title) double viewHeight = [self contentView].frame.size.height; double viewWidth = [self contentView].frame.size.width; CVWindow *window = (CVWindow *)[[self contentView] window]; - for(NSString *key in [window sliders]) { - NSSlider *slider = [[window sliders] valueForKey:key]; - viewHeight = std::min(viewHeight, (double)([slider frame].origin.y)); + if ([window respondsToSelector:@selector(sliders)]) { + for(NSString *key in [window sliders]) { + NSSlider *slider = [[window sliders] valueForKey:key]; + viewHeight = std::min(viewHeight, (double)([slider frame].origin.y)); + } } viewHeight -= TOP_BORDER; mp.y = viewHeight - mp.y; @@ -929,13 +936,15 @@ void cv::setWindowTitle(const String& winname, const String& title) int height = size.height; CVWindow *cvwindow = (CVWindow *)[self window]; - for(NSString *key in [cvwindow sliders]) { - NSSlider *slider = [[cvwindow sliders] valueForKey:key]; - NSRect r = [slider frame]; - r.origin.y = height - r.size.height; - r.size.width = [[cvwindow contentView] frame].size.width; - [slider setFrame:r]; - height -= r.size.height; + if ([cvwindow respondsToSelector:@selector(sliders)]) { + for(NSString *key in [cvwindow sliders]) { + NSSlider *slider = [[cvwindow sliders] valueForKey:key]; + NSRect r = [slider frame]; + r.origin.y = height - r.size.height; + r.size.width = [[cvwindow contentView] frame].size.width; + [slider setFrame:r]; + height -= r.size.height; + } } [localpool drain]; } From 3cc234588abc3064cf0d5d3113d9bbb75b6a54cf Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Thu, 25 Feb 2016 11:04:23 +0300 Subject: [PATCH 169/468] Added build warnings in case of macro definition conflicts --- modules/core/include/opencv2/core/utility.hpp | 4 ++++ .../stitching/include/opencv2/stitching/detail/blenders.hpp | 4 ++++ .../include/opencv2/stitching/detail/exposure_compensate.hpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp index b66ade5c17..1e6249da8d 100644 --- a/modules/core/include/opencv2/core/utility.hpp +++ b/modules/core/include/opencv2/core/utility.hpp @@ -49,6 +49,10 @@ # error utility.hpp header must be compiled as C++ #endif +#if defined(check) +# warning Detected Apple 'check' macro definition, it can cause build conflicts. Please, include this header before any Apple headers. +#endif + #include "opencv2/core.hpp" namespace cv diff --git a/modules/stitching/include/opencv2/stitching/detail/blenders.hpp b/modules/stitching/include/opencv2/stitching/detail/blenders.hpp index 0e607258a0..3d20036ea1 100644 --- a/modules/stitching/include/opencv2/stitching/detail/blenders.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/blenders.hpp @@ -43,6 +43,10 @@ #ifndef __OPENCV_STITCHING_BLENDERS_HPP__ #define __OPENCV_STITCHING_BLENDERS_HPP__ +#if defined(NO) +# warning Detected Apple 'NO' macro definition, it can cause build conflicts. Please, include this header before any Apple headers. +#endif + #include "opencv2/core.hpp" namespace cv { diff --git a/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp b/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp index ef64e12448..7855956a63 100644 --- a/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp @@ -43,6 +43,10 @@ #ifndef __OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP__ #define __OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP__ +#if defined(NO) +# warning Detected Apple 'NO' macro definition, it can cause build conflicts. Please, include this header before any Apple headers. +#endif + #include "opencv2/core.hpp" namespace cv { From 3a92371b60f2891ad1cf2b8cfe42b626f5062d40 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Thu, 25 Feb 2016 12:19:11 +0300 Subject: [PATCH 170/468] EXIF reader: fixed file descriptor leak in case of broken tags --- modules/imgcodecs/src/jpeg_exif.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/imgcodecs/src/jpeg_exif.cpp b/modules/imgcodecs/src/jpeg_exif.cpp index 61b27bbf90..adb87e5b77 100644 --- a/modules/imgcodecs/src/jpeg_exif.cpp +++ b/modules/imgcodecs/src/jpeg_exif.cpp @@ -170,6 +170,7 @@ std::map ExifReader::getExif() case APP1: //actual Exif Marker exifSize = getFieldSize(f); if (exifSize <= offsetToTiffHeader) { + fclose(f); throw ExifParsingError(); } m_data.resize( exifSize - offsetToTiffHeader ); From 74c87a26a561999ecdaf23102e8ed47519a8b313 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Thu, 25 Feb 2016 15:31:07 +0300 Subject: [PATCH 171/468] Delete function areClassesEmpty(). --- modules/ml/include/opencv2/ml.hpp | 7 ++--- modules/ml/src/svmsgd.cpp | 48 +++++++------------------------ modules/ml/test/test_svmsgd.cpp | 2 -- samples/cpp/train_svmsgd.cpp | 1 - 4 files changed, 12 insertions(+), 46 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index 6343b344bc..e596ead0ed 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1507,7 +1507,7 @@ public: SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach, as presented in @cite bottou2010large. -The classifier has 5 parameters. These are +The classifier has following parameters: - model type, - margin type, - margin regularization (\f$\lambda\f$), @@ -1567,11 +1567,8 @@ To use SVMSGD algorithm do as follows: // Create empty object cv::Ptr svmsgd = SVMSGD::create(); -// Set parameters -svmsgd->setOptimalParameters(); - // Train the Stochastic Gradient Descent SVM -SvmSgd->train(trainData); +svmsgd->train(trainData); // Predict labels for the new samples svmsgd->predict(samples, responses); diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 17feeff17c..0a40481687 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -99,8 +99,6 @@ public: private: void updateWeights(InputArray sample, bool isPositive, float stepSize, Mat &weights); - std::pair areClassesEmpty(Mat responses); - void writeParams( FileStorage &fs ) const; void readParams( const FileNode &fn ); @@ -138,26 +136,6 @@ Ptr SVMSGD::create() return makePtr(); } -std::pair SVMSGDImpl::areClassesEmpty(Mat responses) -{ - CV_Assert(responses.cols == 1 || responses.rows == 1); - std::pair emptyInClasses(true, true); - int limitIndex = responses.rows; - - for(int index = 0; index < limitIndex; index++) - { - if (isPositive(responses.at(index))) - emptyInClasses.first = false; - else - emptyInClasses.second = false; - - if (!emptyInClasses.first && ! emptyInClasses.second) - break; - } - - return emptyInClasses; -} - void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) { int featuresCount = samples.cols; @@ -248,16 +226,20 @@ bool SVMSGDImpl::train(const Ptr& data, int) int featureCount = trainSamples.cols; Mat trainResponses = data->getTrainResponses(); // (trainSamplesCount x 1) matrix - std::pair areEmpty = areClassesEmpty(trainResponses); + CV_Assert(trainResponses.rows == trainSamples.rows); - if ( areEmpty.first && areEmpty.second ) + if (trainResponses.empty()) { return false; } - if ( areEmpty.first || areEmpty.second ) + + int positiveCount = countNonZero(trainResponses >= 0); + int negativeCount = countNonZero(trainResponses < 0); + + if ( positiveCount <= 0 || negativeCount <= 0 ) { weights_ = Mat::zeros(1, featureCount, CV_32F); - shift_ = areEmpty.first ? -1.f : 1.f; + shift_ = (positiveCount > 0) ? 1.f : -1.f; return true; } @@ -340,7 +322,7 @@ float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) cons int nSamples = samples.rows; cv::Mat results; - CV_Assert( samples.cols == weights_.cols && samples.type() == CV_32F ); + CV_Assert( samples.cols == weights_.cols && samples.type() == CV_32FC1); if( _results.needed() ) { @@ -498,17 +480,7 @@ void SVMSGDImpl::clear() SVMSGDImpl::SVMSGDImpl() { clear(); - - params.svmsgdType = -1; - params.marginType = -1; - - // Parameters for learning - params.marginRegularization = 0; // regularization - params.initialStepSize = 0; // learning rate (ideally should be large at beginning and decay each iteration) - params.stepDecreasingPower = 0; - - TermCriteria _termCrit(TermCriteria::COUNT + TermCriteria::EPS, 0, 0); - params.termCrit = _termCrit; + setOptimalParameters(); } void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 31fd71729a..9a206e47ed 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -182,8 +182,6 @@ void CV_SVMSGDTrainTest::run( int /*start_from*/ ) { cv::Ptr svmsgd = SVMSGD::create(); - svmsgd->setOptimalParameters(); - svmsgd->train(data); Mat responses; diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index efcff01cb8..580346a473 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -46,7 +46,6 @@ void addPointRetrainAndRedraw(Data &data, int x, int y, int response); bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift) { cv::Ptr svmsgd = SVMSGD::create(); - svmsgd->setOptimalParameters(); cv::Ptr trainData = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); svmsgd->train( trainData ); From d484893839c568ceebd09fdc9e7ba15fb002dcd5 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Thu, 25 Feb 2016 16:57:03 +0300 Subject: [PATCH 172/468] Deleted functions makeTrainData() and makeTestData() in test_svmsgd.cpp. Added function makeData() in test_svmsgd.cpp. --- modules/ml/include/opencv2/ml.hpp | 8 ++-- modules/ml/src/svmsgd.cpp | 12 +++--- modules/ml/test/test_svmsgd.cpp | 61 +++++++++++-------------------- 3 files changed, 33 insertions(+), 48 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index e596ead0ed..bcd22c46ba 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1626,10 +1626,10 @@ public: * stepDecreasingPower = 1; * termCrit.maxCount = 100000; * termCrit.epsilon = 0.00001; - * @param svmsgdType is the type of SVMSGD classifier. Legal values are SvmsgdType::SGD and SvmsgdType::ASGD. - * Recommended value is SvmsgdType::ASGD (by default). - * @param marginType is the type of margin constraint. Legal values are MarginType::SOFT_MARGIN and MarginType::HARD_MARGIN. - * Default value is MarginType::SOFT_MARGIN. + * @param svmsgdType is the type of SVMSGD classifier. Legal values are SVMSGD::SvmsgdType::SGD and SVMSGD::SvmsgdType::ASGD. + * Recommended value is SVMSGD::SvmsgdType::ASGD (by default). + * @param marginType is the type of margin constraint. Legal values are SVMSGD::MarginType::SOFT_MARGIN and SVMSGD::MarginType::HARD_MARGIN. + * Default value is SVMSGD::MarginType::SOFT_MARGIN. */ CV_WRAP virtual void setOptimalParameters(int svmsgdType = SVMSGD::ASGD, int marginType = SVMSGD::SOFT_MARGIN) = 0; diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 0a40481687..9a03ed9ac6 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -142,6 +142,7 @@ void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier) int samplesCount = samples.rows; average = Mat(1, featuresCount, samples.type()); + CV_Assert(average.type() == CV_32FC1); for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++) { average.at(featureIndex) = static_cast(mean(samples.col(featureIndex))[0]); @@ -170,11 +171,11 @@ void SVMSGDImpl::makeExtendedTrainSamples(const Mat &trainSamples, Mat &extended cv::hconcat(normalizedTrainSamples, onesCol, extendedTrainSamples); } -void SVMSGDImpl::updateWeights(InputArray _sample, bool firstClass, float stepSize, Mat& weights) +void SVMSGDImpl::updateWeights(InputArray _sample, bool positive, float stepSize, Mat& weights) { Mat sample = _sample.getMat(); - int response = firstClass ? 1 : -1; // ensure that trainResponses are -1 or 1 + int response = positive ? 1 : -1; // ensure that trainResponses are -1 or 1 if ( sample.dot(weights) * response > 1) { @@ -197,6 +198,7 @@ float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const Mat trainResponses = _responses.getMat(); + CV_Assert(trainResponses.type() == CV_32FC1); for (int samplesIndex = 0; samplesIndex < trainSamplesCount; samplesIndex++) { Mat currentSample = trainSamples.row(samplesIndex); @@ -261,7 +263,7 @@ bool SVMSGDImpl::train(const Ptr& data, int) RNG rng(0); - CV_Assert (params.termCrit.type & TermCriteria::COUNT || params.termCrit.type & TermCriteria::EPS); + CV_Assert ((params.termCrit.type & TermCriteria::COUNT || params.termCrit.type & TermCriteria::EPS) && (trainResponses.type() == CV_32FC1)); int maxCount = (params.termCrit.type & TermCriteria::COUNT) ? params.termCrit.maxCount : INT_MAX; double epsilon = (params.termCrit.type & TermCriteria::EPS) ? params.termCrit.epsilon : 0; @@ -300,7 +302,7 @@ bool SVMSGDImpl::train(const Ptr& data, int) weights_ = extendedWeights(roi); weights_ *= multiplier; - CV_Assert(params.marginType == SOFT_MARGIN || params.marginType == HARD_MARGIN); + CV_Assert((params.marginType == SOFT_MARGIN || params.marginType == HARD_MARGIN) && (extendedWeights.type() == CV_32FC1)); if (params.marginType == SOFT_MARGIN) { @@ -332,7 +334,7 @@ float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) cons else { CV_Assert( nSamples == 1 ); - results = Mat(1, 1, CV_32F, &result); + results = Mat(1, 1, CV_32FC1, &result); } for (int sampleIndex = 0; sampleIndex < nSamples; sampleIndex++) diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index 9a206e47ed..b6aed3c7e5 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -62,8 +62,7 @@ public: private: virtual void run( int start_from ); static float decisionFunction(const Mat &sample, const Mat &weights, float shift); - void makeTrainData(Mat weights, float shift); - void makeTestData(Mat weights, float shift); + void makeData(int samplesCount, Mat weights, float shift, RNG rng, Mat &samples, Mat & responses); void generateSameBorders(int featureCount); void generateDifferentBorders(int featureCount); @@ -108,46 +107,28 @@ void CV_SVMSGDTrainTest::generateDifferentBorders(int featureCount) } } -void CV_SVMSGDTrainTest::makeTrainData(Mat weights, float shift) +float CV_SVMSGDTrainTest::decisionFunction(const Mat &sample, const Mat &weights, float shift) +{ + return static_cast(sample.dot(weights)) + shift; +} + +void CV_SVMSGDTrainTest::makeData(int samplesCount, Mat weights, float shift, RNG rng, Mat &samples, Mat & responses) { - int datasize = 100000; int featureCount = weights.cols; - RNG rng(0); - - cv::Mat samples = cv::Mat::zeros(datasize, featureCount, CV_32FC1); + samples.create(samplesCount, featureCount, CV_32FC1); for (int featureIndex = 0; featureIndex < featureCount; featureIndex++) { rng.fill(samples.col(featureIndex), RNG::UNIFORM, borders[featureIndex].first, borders[featureIndex].second); } - cv::Mat responses = cv::Mat::zeros(datasize, 1, CV_32FC1); - for (int sampleIndex = 0; sampleIndex < datasize; sampleIndex++) + responses.create(samplesCount, 1, CV_32FC1); + + for (int i = 0 ; i < samplesCount; i++) { - responses.at(sampleIndex) = decisionFunction(samples.row(sampleIndex), weights, shift) > 0 ? 1.f : -1.f; + responses.at(i) = decisionFunction(samples.row(i), weights, shift) > 0 ? 1.f : -1.f; } - data = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses); -} - -void CV_SVMSGDTrainTest::makeTestData(Mat weights, float shift) -{ - int testSamplesCount = 100000; - int featureCount = weights.cols; - cv::RNG rng(42); - - testSamples.create(testSamplesCount, featureCount, CV_32FC1); - for (int featureIndex = 0; featureIndex < featureCount; featureIndex++) - { - rng.fill(testSamples.col(featureIndex), RNG::UNIFORM, borders[featureIndex].first, borders[featureIndex].second); - } - - testResponses.create(testSamplesCount, 1, CV_32FC1); - - for (int i = 0 ; i < testSamplesCount; i++) - { - testResponses.at(i) = decisionFunction(testSamples.row(i), weights, shift) > 0 ? 1.f : -1.f; - } } CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(const Mat &weights, float shift, TrainDataType _type, double _precision) @@ -169,13 +150,16 @@ CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(const Mat &weights, float shift, TrainDat CV_Error(CV_StsBadArg, "Unknown train data type"); } - makeTrainData(weights, shift); - makeTestData(weights, shift); -} + RNG rng(0); -float CV_SVMSGDTrainTest::decisionFunction(const Mat &sample, const Mat &weights, float shift) -{ - return static_cast(sample.dot(weights)) + shift; + Mat trainSamples; + Mat trainResponses; + int trainSamplesCount = 10000; + makeData(trainSamplesCount, weights, shift, rng, trainSamples, trainResponses); + data = TrainData::create(trainSamples, cv::ml::ROW_SAMPLE, trainResponses); + + int testSamplesCount = 100000; + makeData(testSamplesCount, weights, shift, rng, testSamples, testResponses); } void CV_SVMSGDTrainTest::run( int /*start_from*/ ) @@ -205,7 +189,6 @@ void CV_SVMSGDTrainTest::run( int /*start_from*/ ) } } - void makeWeightsAndShift(int featureCount, Mat &weights, float &shift) { weights.create(1, featureCount, CV_32FC1); @@ -253,7 +236,7 @@ TEST(ML_SVMSGD, trainSameScale100) float shift = 0; makeWeightsAndShift(featureCount, weights, shift); - CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE); + CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE, 0.02); test.safe_run(); } From 53711ec29d2715969a0fdbf54ff1f1a6825dda10 Mon Sep 17 00:00:00 2001 From: Marina Noskova Date: Thu, 25 Feb 2016 19:12:54 +0300 Subject: [PATCH 173/468] Deleted default value for parameters in docs. Added some asserts. --- modules/ml/include/opencv2/ml.hpp | 33 +++++-------------- modules/ml/src/svmsgd.cpp | 53 ++++++++++++++----------------- modules/ml/test/test_svmsgd.cpp | 5 +-- samples/cpp/train_svmsgd.cpp | 6 ++-- 4 files changed, 38 insertions(+), 59 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index bcd22c46ba..666710bad1 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1542,7 +1542,7 @@ The other parameters may be described as follows: Recommended value for SGD model is 0.0001, for ASGD model is 0.00001. - Initial step size parameter is the initial value for the step size \f$\gamma(t)\f$. - You will have to find the best \f$\gamma_0\f$ for your problem. + You will have to find the best initial step for your problem. - Step decreasing power is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above. Recommended value for SGD model is 1, for ASGD model is 0.75. @@ -1605,31 +1605,15 @@ public: */ CV_WRAP virtual float getShift() = 0; - /** @brief Creates empty model. - Use StatModel::train to train the model. Since %SVMSGD has several parameters, you may want to - find the best parameters for your problem or use setOptimalParameters() to set some default parameters. + * Use StatModel::train to train the model. Since %SVMSGD has several parameters, you may want to + * find the best parameters for your problem or use setOptimalParameters() to set some default parameters. */ CV_WRAP static Ptr create(); /** @brief Function sets optimal parameters values for chosen SVM SGD model. - * If chosen type is ASGD, function sets the following values for parameters of model: - * marginRegularization = 0.00001; - * initialStepSize = 0.05; - * stepDecreasingPower = 0.75; - * termCrit.maxCount = 100000; - * termCrit.epsilon = 0.00001; - * - * If SGD: - * marginRegularization = 0.0001; - * initialStepSize = 0.05; - * stepDecreasingPower = 1; - * termCrit.maxCount = 100000; - * termCrit.epsilon = 0.00001; - * @param svmsgdType is the type of SVMSGD classifier. Legal values are SVMSGD::SvmsgdType::SGD and SVMSGD::SvmsgdType::ASGD. - * Recommended value is SVMSGD::SvmsgdType::ASGD (by default). - * @param marginType is the type of margin constraint. Legal values are SVMSGD::MarginType::SOFT_MARGIN and SVMSGD::MarginType::HARD_MARGIN. - * Default value is SVMSGD::MarginType::SOFT_MARGIN. + * @param svmsgdType is the type of SVMSGD classifier. + * @param marginType is the type of margin constraint. */ CV_WRAP virtual void setOptimalParameters(int svmsgdType = SVMSGD::ASGD, int marginType = SVMSGD::SOFT_MARGIN) = 0; @@ -1645,20 +1629,19 @@ public: /** @copybrief getMarginType @see getMarginType */ CV_WRAP virtual void setMarginType(int marginType) = 0; - - /** @brief Parameter marginRegularization of a %SVMSGD optimization problem. Default value is 0. */ + /** @brief Parameter marginRegularization of a %SVMSGD optimization problem. */ /** @see setMarginRegularization */ CV_WRAP virtual float getMarginRegularization() const = 0; /** @copybrief getMarginRegularization @see getMarginRegularization */ CV_WRAP virtual void setMarginRegularization(float marginRegularization) = 0; - /** @brief Parameter initialStepSize of a %SVMSGD optimization problem. Default value is 0. */ + /** @brief Parameter initialStepSize of a %SVMSGD optimization problem. */ /** @see setInitialStepSize */ CV_WRAP virtual float getInitialStepSize() const = 0; /** @copybrief getInitialStepSize @see getInitialStepSize */ CV_WRAP virtual void setInitialStepSize(float InitialStepSize) = 0; - /** @brief Parameter stepDecreasingPower of a %SVMSGD optimization problem. Default value is 0. */ + /** @brief Parameter stepDecreasingPower of a %SVMSGD optimization problem. */ /** @see setStepDecreasingPower */ CV_WRAP virtual float getStepDecreasingPower() const = 0; /** @copybrief getStepDecreasingPower @see getStepDecreasingPower */ diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp index 9a03ed9ac6..ed452e35ef 100644 --- a/modules/ml/src/svmsgd.cpp +++ b/modules/ml/src/svmsgd.cpp @@ -97,7 +97,7 @@ public: CV_IMPL_PROPERTY_S(cv::TermCriteria, TermCriteria, params.termCrit) private: - void updateWeights(InputArray sample, bool isPositive, float stepSize, Mat &weights); + void updateWeights(InputArray sample, bool positive, float stepSize, Mat &weights); void writeParams( FileStorage &fs ) const; @@ -111,8 +111,6 @@ private: static void makeExtendedTrainSamples(const Mat &trainSamples, Mat &extendedTrainSamples, Mat &average, float &multiplier); - - // Vector with SVM weights Mat weights_; float shift_; @@ -263,11 +261,12 @@ bool SVMSGDImpl::train(const Ptr& data, int) RNG rng(0); - CV_Assert ((params.termCrit.type & TermCriteria::COUNT || params.termCrit.type & TermCriteria::EPS) && (trainResponses.type() == CV_32FC1)); + CV_Assert (params.termCrit.type & TermCriteria::COUNT || params.termCrit.type & TermCriteria::EPS); int maxCount = (params.termCrit.type & TermCriteria::COUNT) ? params.termCrit.maxCount : INT_MAX; double epsilon = (params.termCrit.type & TermCriteria::EPS) ? params.termCrit.epsilon : 0; double err = DBL_MAX; + CV_Assert (trainResponses.type() == CV_32FC1); // Stochastic gradient descent SVM for (int iter = 0; (iter < maxCount) && (err > epsilon); iter++) { @@ -288,8 +287,8 @@ bool SVMSGDImpl::train(const Ptr& data, int) } else { - err = norm(extendedWeights - previousWeights); - extendedWeights.copyTo(previousWeights); + err = norm(extendedWeights - previousWeights); + extendedWeights.copyTo(previousWeights); } } @@ -316,7 +315,6 @@ bool SVMSGDImpl::train(const Ptr& data, int) return true; } - float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) const { float result = 0; @@ -417,17 +415,6 @@ void SVMSGDImpl::writeParams( FileStorage& fs ) const fs << "iterations" << params.termCrit.maxCount; fs << "}"; } - -void SVMSGDImpl::read(const FileNode& fn) -{ - clear(); - - readParams(fn); - - fn["weights"] >> weights_; - fn["shift"] >> shift_; -} - void SVMSGDImpl::readParams( const FileNode& fn ) { String svmsgdTypeStr = (String)fn["svmsgdType"]; @@ -443,7 +430,7 @@ void SVMSGDImpl::readParams( const FileNode& fn ) String marginTypeStr = (String)fn["marginType"]; int marginType = marginTypeStr == "SOFT_MARGIN" ? SOFT_MARGIN : - marginTypeStr == "HARD_MARGIN" ? HARD_MARGIN : -1; + marginTypeStr == "HARD_MARGIN" ? HARD_MARGIN : -1; if( marginType < 0 ) CV_Error( CV_StsParseError, "Missing or invalid margin type" ); @@ -460,16 +447,22 @@ void SVMSGDImpl::readParams( const FileNode& fn ) params.stepDecreasingPower = (float)fn["stepDecreasingPower"]; FileNode tcnode = fn["term_criteria"]; - if( !tcnode.empty() ) - { - params.termCrit.epsilon = (double)tcnode["epsilon"]; - params.termCrit.maxCount = (int)tcnode["iterations"]; - params.termCrit.type = (params.termCrit.epsilon > 0 ? TermCriteria::EPS : 0) + - (params.termCrit.maxCount > 0 ? TermCriteria::COUNT : 0); - } - else - params.termCrit = TermCriteria( TermCriteria::EPS + TermCriteria::COUNT, 100000, FLT_EPSILON ); + CV_Assert(!tcnode.empty()); + params.termCrit.epsilon = (double)tcnode["epsilon"]; + params.termCrit.maxCount = (int)tcnode["iterations"]; + params.termCrit.type = (params.termCrit.epsilon > 0 ? TermCriteria::EPS : 0) + + (params.termCrit.maxCount > 0 ? TermCriteria::COUNT : 0); + CV_Assert ((params.termCrit.type & TermCriteria::COUNT || params.termCrit.type & TermCriteria::EPS)); +} +void SVMSGDImpl::read(const FileNode& fn) +{ + clear(); + + readParams(fn); + + fn["weights"] >> weights_; + fn["shift"] >> shift_; } void SVMSGDImpl::clear() @@ -492,7 +485,7 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) case SGD: params.svmsgdType = SGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : - (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; + (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; params.marginRegularization = 0.0001f; params.initialStepSize = 0.05f; params.stepDecreasingPower = 1.f; @@ -502,7 +495,7 @@ void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType) case ASGD: params.svmsgdType = ASGD; params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN : - (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; + (marginType == HARD_MARGIN) ? HARD_MARGIN : -1; params.marginRegularization = 0.00001f; params.initialStepSize = 0.05f; params.stepDecreasingPower = 0.75f; diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp index b6aed3c7e5..8d9103e0fb 100644 --- a/modules/ml/test/test_svmsgd.cpp +++ b/modules/ml/test/test_svmsgd.cpp @@ -62,7 +62,7 @@ public: private: virtual void run( int start_from ); static float decisionFunction(const Mat &sample, const Mat &weights, float shift); - void makeData(int samplesCount, Mat weights, float shift, RNG rng, Mat &samples, Mat & responses); + void makeData(int samplesCount, const Mat &weights, float shift, RNG &rng, Mat &samples, Mat & responses); void generateSameBorders(int featureCount); void generateDifferentBorders(int featureCount); @@ -112,7 +112,7 @@ float CV_SVMSGDTrainTest::decisionFunction(const Mat &sample, const Mat &weights return static_cast(sample.dot(weights)) + shift; } -void CV_SVMSGDTrainTest::makeData(int samplesCount, Mat weights, float shift, RNG rng, Mat &samples, Mat & responses) +void CV_SVMSGDTrainTest::makeData(int samplesCount, const Mat &weights, float shift, RNG &rng, Mat &samples, Mat & responses) { int featureCount = weights.cols; @@ -175,6 +175,7 @@ void CV_SVMSGDTrainTest::run( int /*start_from*/ ) int errCount = 0; int testSamplesCount = testSamples.rows; + CV_Assert((responses.type() == CV_32FC1) && (testResponses.type() == CV_32FC1)); for (int i = 0; i < testSamplesCount; i++) { if (responses.at(i) * testResponses.at(i) < 0) diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp index 580346a473..e2942d01ea 100644 --- a/samples/cpp/train_svmsgd.cpp +++ b/samples/cpp/train_svmsgd.cpp @@ -91,6 +91,7 @@ bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair< int yMin = std::min(segment.first.y, segment.second.y); int yMax = std::max(segment.first.y, segment.second.y); + CV_Assert(weights.type() == CV_32FC1); CV_Assert(xMin == xMax || yMin == yMax); if (xMin == xMax && weights.at(1) != 0) @@ -146,6 +147,7 @@ void redraw(Data data, const Point points[2]) Point center; int radius = 3; Scalar color; + CV_Assert((data.samples.type() == CV_32FC1) && (data.responses.type() == CV_32FC1)); for (int i = 0; i < data.samples.rows; i++) { center.x = static_cast(data.samples.at(i,0)); @@ -160,14 +162,14 @@ void redraw(Data data, const Point points[2]) void addPointRetrainAndRedraw(Data &data, int x, int y, int response) { - Mat currentSample(1, 2, CV_32F); + Mat currentSample(1, 2, CV_32FC1); currentSample.at(0,0) = (float)x; currentSample.at(0,1) = (float)y; data.samples.push_back(currentSample); data.responses.push_back(response); - Mat weights(1, 2, CV_32F); + Mat weights(1, 2, CV_32FC1); float shift = 0; if (doTrain(data.samples, data.responses, weights, shift)) From e0f426f78bbf0fd6e161de4a778800b2fb4e7288 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Wed, 24 Feb 2016 14:18:51 +0300 Subject: [PATCH 174/468] Backport of new python tests from master branch(PR https://github.com/Itseez/opencv/pull/6025). At the moment tests requre samples/data copied to source location from master branch. --- modules/python/test/test.py | 48 ++--- modules/python/test/test_calibration.py | 71 +++++++ modules/python/test/test_camshift.py | 92 ++++++++ modules/python/test/test_dft.py | 46 ++++ modules/python/test/test_digits.py | 197 ++++++++++++++++++ modules/python/test/test_facedetect.py | 90 ++++++++ .../python/test/test_feature_homography.py | 160 ++++++++++++++ modules/python/test/test_fitline.py | 66 ++++++ modules/python/test/test_gaussian_mix.py | 58 ++++++ modules/python/test/test_grabcut.py | 67 ++++++ modules/python/test/test_houghcircles.py | 81 +++++++ modules/python/test/test_houghlines.py | 65 ++++++ modules/python/test/test_kmeans.py | 70 +++++++ modules/python/test/test_letter_recog.py | 161 ++++++++++++++ modules/python/test/test_lk_homography.py | 96 +++++++++ modules/python/test/test_lk_track.py | 111 ++++++++++ modules/python/test/test_morphology.py | 51 +++++ modules/python/test/test_mser.py | 65 ++++++ modules/python/test/test_peopledetect.py | 62 ++++++ modules/python/test/test_squares.py | 96 +++++++++ modules/python/test/test_texture_flow.py | 51 +++++ modules/python/test/test_watershed.py | 33 +++ modules/python/test/tests_common.py | 79 +++++++ modules/python/test/tst_scene_render.py | 119 +++++++++++ 24 files changed, 2005 insertions(+), 30 deletions(-) create mode 100644 modules/python/test/test_calibration.py create mode 100644 modules/python/test/test_camshift.py create mode 100644 modules/python/test/test_dft.py create mode 100644 modules/python/test/test_digits.py create mode 100644 modules/python/test/test_facedetect.py create mode 100644 modules/python/test/test_feature_homography.py create mode 100644 modules/python/test/test_fitline.py create mode 100644 modules/python/test/test_gaussian_mix.py create mode 100644 modules/python/test/test_grabcut.py create mode 100644 modules/python/test/test_houghcircles.py create mode 100644 modules/python/test/test_houghlines.py create mode 100644 modules/python/test/test_kmeans.py create mode 100644 modules/python/test/test_letter_recog.py create mode 100644 modules/python/test/test_lk_homography.py create mode 100644 modules/python/test/test_lk_track.py create mode 100644 modules/python/test/test_morphology.py create mode 100644 modules/python/test/test_mser.py create mode 100644 modules/python/test/test_peopledetect.py create mode 100644 modules/python/test/test_squares.py create mode 100644 modules/python/test/test_texture_flow.py create mode 100644 modules/python/test/test_watershed.py create mode 100644 modules/python/test/tests_common.py create mode 100644 modules/python/test/tst_scene_render.py diff --git a/modules/python/test/test.py b/modules/python/test/test.py index a4a3d759a9..e9f1a13506 100755 --- a/modules/python/test/test.py +++ b/modules/python/test/test.py @@ -122,6 +122,15 @@ class OpenCVTests(unittest.TestCase): """ Compute a hash for an image, useful for image comparisons """ return hashlib.md5(im.tostring()).digest() +#import new OpenCV tests(do we really need old ones in this case) +from tests_common import NewOpenCVTests + +basedir = os.path.abspath(os.path.dirname(__file__)) + +def load_tests(loader, tests, pattern): + tests.addTests(loader.discover(basedir, pattern='test_*.py')) + return tests + # Tests to run first; check the handful of basic operations that the later tests rely on class PreliminaryTests(OpenCVTests): @@ -2239,36 +2248,15 @@ if __name__ == '__main__': print "Local repo path:", args.repo print "Local data path:", args.data OpenCVTests.repoPath = args.repo - OpenCVTests.dataPath = args.data + NewOpenCVTests.repoPath = args.repo + try: + OpenCVTests.dataPath = os.environ['OPENCV_TEST_DATA_PATH'] + NewOpenCVTests.extraTestDataPath = OpenCVTests.dataPath + except KeyError: + OpenCVTests.dataPath = args.data + NewOpenCVTests.extraTestDataPath = args.data + if args.data is None: + print('Missing opencv extra repository. Some of tests may fail.') random.seed(0) unit_argv = [sys.argv[0]] + other; unittest.main(argv=unit_argv) -# optlist, args = getopt.getopt(sys.argv[1:], 'l:rd') -# loops = 1 -# shuffle = 0 -# doc_frags = False -# for o,a in optlist: -# if o == '-l': -# loops = int(a) -# if o == '-r': -# shuffle = 1 -# if o == '-d': -# doc_frags = True -# -# cases = [PreliminaryTests, FunctionTests, AreaTests] -# if doc_frags: -# cases += [DocumentFragmentTests] -# everything = [(tc, t) for tc in cases for t in unittest.TestLoader().getTestCaseNames(tc) ] -# if len(args) == 0: -# # cases = [NewTests] -# args = everything -# else: -# args = [(tc, t) for (tc, t) in everything if t in args] -# -# suite = unittest.TestSuite() -# for l in range(loops): -# if shuffle: -# random.shuffle(args) -# for tc,t in args: -# suite.addTest(tc(t)) -# unittest.TextTestRunner(verbosity=2).run(suite) diff --git a/modules/python/test/test_calibration.py b/modules/python/test/test_calibration.py new file mode 100644 index 0000000000..665521862c --- /dev/null +++ b/modules/python/test/test_calibration.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +''' +camera calibration for distorted images with chess board samples +reads distorted images, calculates the calibration and write undistorted images +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 + +from tests_common import NewOpenCVTests + +class calibration_test(NewOpenCVTests): + + def test_calibration(self): + + from glob import glob + img_names = [] + for i in range(1, 15): + if i < 10: + img_names.append('samples/data/left0{}.jpg'.format(str(i))) + elif i != 10: + img_names.append('samples/data/left{}.jpg'.format(str(i))) + + square_size = 1.0 + pattern_size = (9, 6) + pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32) + pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2) + pattern_points *= square_size + + obj_points = [] + img_points = [] + h, w = 0, 0 + img_names_undistort = [] + for fn in img_names: + img = self.get_sample(fn, 0) + if img is None: + continue + + h, w = img.shape[:2] + found, corners = cv2.findChessboardCorners(img, pattern_size) + if found: + term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1) + cv2.cornerSubPix(img, corners, (5, 5), (-1, -1), term) + + if not found: + continue + + img_points.append(corners.reshape(-1, 2)) + obj_points.append(pattern_points) + + # calculate camera distortion + rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (w, h), None, None, flags = 0) + + eps = 0.01 + normCamEps = 10.0 + normDistEps = 0.001 + + cameraMatrixTest = [[ 532.80992189, 0., 342.4952186 ], + [ 0., 532.93346422, 233.8879292 ], + [ 0., 0., 1. ]] + + distCoeffsTest = [ -2.81325576e-01, 2.91130406e-02, + 1.21234330e-03, -1.40825372e-04, 1.54865844e-01] + + self.assertLess(abs(rms - 0.196334638034), eps) + self.assertLess(cv2.norm(camera_matrix - cameraMatrixTest, cv2.NORM_L1), normCamEps) + self.assertLess(cv2.norm(dist_coefs - distCoeffsTest, cv2.NORM_L1), normDistEps) \ No newline at end of file diff --git a/modules/python/test/test_camshift.py b/modules/python/test/test_camshift.py new file mode 100644 index 0000000000..a824320eff --- /dev/null +++ b/modules/python/test/test_camshift.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python + +''' +Camshift tracker +================ + +This is a demo that shows mean-shift based tracking +You select a color objects such as your face and it tracks it. +This reads from video camera (0 by default, or the camera number the user enters) + +http://www.robinhewitt.com/research/track/camshift.html + +''' + +# Python 2/3 compatibility +from __future__ import print_function +import sys +PY3 = sys.version_info[0] == 3 + +if PY3: + xrange = range + +import numpy as np +import cv2 +from tst_scene_render import TestSceneRender + +from tests_common import NewOpenCVTests, intersectionRate + +class camshift_test(NewOpenCVTests): + + framesNum = 300 + frame = None + selection = None + drag_start = None + show_backproj = False + track_window = None + render = None + errors = 0 + + def prepareRender(self): + + self.render = TestSceneRender(self.get_sample('samples/data/pca_test1.jpg'), deformation = True) + + def runTracker(self): + + framesCounter = 0 + self.selection = True + + xmin, ymin, xmax, ymax = self.render.getCurrentRect() + + self.track_window = (xmin, ymin, xmax - xmin, ymax - ymin) + + while True: + framesCounter += 1 + self.frame = self.render.getNextFrame() + hsv = cv2.cvtColor(self.frame, cv2.COLOR_BGR2HSV) + mask = cv2.inRange(hsv, np.array((0., 60., 32.)), np.array((180., 255., 255.))) + + if self.selection: + x0, y0, x1, y1 = self.render.getCurrentRect() + 50 + x0 -= 100 + y0 -= 100 + + hsv_roi = hsv[y0:y1, x0:x1] + mask_roi = mask[y0:y1, x0:x1] + hist = cv2.calcHist( [hsv_roi], [0], mask_roi, [16], [0, 180] ) + cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX) + self.hist = hist.reshape(-1) + self.selection = False + + if self.track_window and self.track_window[2] > 0 and self.track_window[3] > 0: + self.selection = None + prob = cv2.calcBackProject([hsv], [0], self.hist, [0, 180], 1) + prob &= mask + term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 ) + track_box, self.track_window = cv2.CamShift(prob, self.track_window, term_crit) + + trackingRect = np.array(self.track_window) + trackingRect[2] += trackingRect[0] + trackingRect[3] += trackingRect[1] + + if intersectionRate(self.render.getCurrentRect(), trackingRect) < 0.4: + self.errors += 1 + + if framesCounter > self.framesNum: + break + + self.assertLess(float(self.errors) / self.framesNum, 0.4) + + def test_camshift(self): + self.prepareRender() + self.runTracker() \ No newline at end of file diff --git a/modules/python/test/test_dft.py b/modules/python/test/test_dft.py new file mode 100644 index 0000000000..f796939970 --- /dev/null +++ b/modules/python/test/test_dft.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +''' +Test for disctrete fourier transform (dft) +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import cv2 +import numpy as np +import sys + +from tests_common import NewOpenCVTests + +class dft_test(NewOpenCVTests): + def test_dft(self): + + img = self.get_sample('samples/data/rubberwhale1.png', 0) + eps = 0.001 + + #test direct transform + refDft = np.fft.fft2(img) + refDftShift = np.fft.fftshift(refDft) + refMagnitide = np.log(1.0 + np.abs(refDftShift)) + + testDft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT) + testDftShift = np.fft.fftshift(testDft) + testMagnitude = np.log(1.0 + cv2.magnitude(testDftShift[:,:,0], testDftShift[:,:,1])) + + refMagnitide = cv2.normalize(refMagnitide, 0.0, 1.0, cv2.NORM_MINMAX) + testMagnitude = cv2.normalize(testMagnitude, 0.0, 1.0, cv2.NORM_MINMAX) + + self.assertLess(cv2.norm(refMagnitide - testMagnitude), eps) + + #test inverse transform + img_back = np.fft.ifft2(refDft) + img_back = np.abs(img_back) + + img_backTest = cv2.idft(testDft) + img_backTest = cv2.magnitude(img_backTest[:,:,0], img_backTest[:,:,1]) + + img_backTest = cv2.normalize(img_backTest, 0.0, 1.0, cv2.NORM_MINMAX) + img_back = cv2.normalize(img_back, 0.0, 1.0, cv2.NORM_MINMAX) + + self.assertLess(cv2.norm(img_back - img_backTest), eps) \ No newline at end of file diff --git a/modules/python/test/test_digits.py b/modules/python/test/test_digits.py new file mode 100644 index 0000000000..587c355e37 --- /dev/null +++ b/modules/python/test/test_digits.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python + +''' +SVM and KNearest digit recognition. + +Sample loads a dataset of handwritten digits from '../data/digits.png'. +Then it trains a SVM and KNearest classifiers on it and evaluates +their accuracy. + +Following preprocessing is applied to the dataset: + - Moment-based image deskew (see deskew()) + - Digit images are split into 4 10x10 cells and 16-bin + histogram of oriented gradients is computed for each + cell + - Transform histograms to space with Hellinger metric (see [1] (RootSIFT)) + + +[1] R. Arandjelovic, A. Zisserman + "Three things everyone should know to improve object retrieval" + http://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/arandjelovic12.pdf + +''' + + +# Python 2/3 compatibility +from __future__ import print_function + +# built-in modules +from multiprocessing.pool import ThreadPool + +import cv2 + +import numpy as np +from numpy.linalg import norm + + +SZ = 20 # size of each digit is SZ x SZ +CLASS_N = 10 +DIGITS_FN = 'samples/data/digits.png' + +def split2d(img, cell_size, flatten=True): + h, w = img.shape[:2] + sx, sy = cell_size + cells = [np.hsplit(row, w//sx) for row in np.vsplit(img, h//sy)] + cells = np.array(cells) + if flatten: + cells = cells.reshape(-1, sy, sx) + return cells + +def deskew(img): + m = cv2.moments(img) + if abs(m['mu02']) < 1e-2: + return img.copy() + skew = m['mu11']/m['mu02'] + M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]]) + img = cv2.warpAffine(img, M, (SZ, SZ), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR) + return img + +class StatModel(object): + def load(self, fn): + self.model.load(fn) # Known bug: https://github.com/Itseez/opencv/issues/4969 + def save(self, fn): + self.model.save(fn) + +class KNearest(StatModel): + def __init__(self, k = 3): + self.k = k + self.model = cv2.KNearest() + + def train(self, samples, responses): + self.model.train(samples, responses) + + def predict(self, samples): + retval, results, neigh_resp, dists = self.model.find_nearest(samples, self.k) + return results.ravel() + +class SVM(StatModel): + def __init__(self, C = 1, gamma = 0.5): + self.params = dict( kernel_type = cv2.SVM_RBF, + svm_type = cv2.SVM_C_SVC, + C = C, + gamma = gamma ) + self.model = cv2.SVM() + + def train(self, samples, responses): + self.model.train(samples, responses, params = self.params) + + def predict(self, samples): + return self.model.predict_all(samples).ravel() + + +def evaluate_model(model, digits, samples, labels): + resp = model.predict(samples) + err = (labels != resp).mean() + + confusion = np.zeros((10, 10), np.int32) + for i, j in zip(labels, resp): + confusion[int(i), int(j)] += 1 + + return err, confusion + +def preprocess_simple(digits): + return np.float32(digits).reshape(-1, SZ*SZ) / 255.0 + +def preprocess_hog(digits): + samples = [] + for img in digits: + gx = cv2.Sobel(img, cv2.CV_32F, 1, 0) + gy = cv2.Sobel(img, cv2.CV_32F, 0, 1) + mag, ang = cv2.cartToPolar(gx, gy) + bin_n = 16 + bin = np.int32(bin_n*ang/(2*np.pi)) + bin_cells = bin[:10,:10], bin[10:,:10], bin[:10,10:], bin[10:,10:] + mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:] + hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)] + hist = np.hstack(hists) + + # transform to Hellinger kernel + eps = 1e-7 + hist /= hist.sum() + eps + hist = np.sqrt(hist) + hist /= norm(hist) + eps + + samples.append(hist) + return np.float32(samples) + +from tests_common import NewOpenCVTests + +class digits_test(NewOpenCVTests): + + def load_digits(self, fn): + digits_img = self.get_sample(fn, 0) + digits = split2d(digits_img, (SZ, SZ)) + labels = np.repeat(np.arange(CLASS_N), len(digits)/CLASS_N) + return digits, labels + + def test_digits(self): + + digits, labels = self.load_digits(DIGITS_FN) + + # shuffle digits + rand = np.random.RandomState(321) + shuffle = rand.permutation(len(digits)) + digits, labels = digits[shuffle], labels[shuffle] + + digits2 = list(map(deskew, digits)) + samples = preprocess_hog(digits2) + + train_n = int(0.9*len(samples)) + digits_train, digits_test = np.split(digits2, [train_n]) + samples_train, samples_test = np.split(samples, [train_n]) + labels_train, labels_test = np.split(labels, [train_n]) + errors = list() + confusionMatrixes = list() + + model = KNearest(k=4) + model.train(samples_train, labels_train) + error, confusion = evaluate_model(model, digits_test, samples_test, labels_test) + errors.append(error) + confusionMatrixes.append(confusion) + + model = SVM(C=2.67, gamma=5.383) + model.train(samples_train, labels_train) + error, confusion = evaluate_model(model, digits_test, samples_test, labels_test) + errors.append(error) + confusionMatrixes.append(confusion) + + eps = 0.001 + normEps = len(samples_test) * 0.02 + + confusionKNN = [[45, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 57, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 59, 1, 0, 0, 0, 0, 1, 0], + [ 0, 0, 0, 43, 0, 0, 0, 1, 0, 0], + [ 0, 0, 0, 0, 38, 0, 2, 0, 0, 0], + [ 0, 0, 0, 2, 0, 48, 0, 0, 1, 0], + [ 0, 1, 0, 0, 0, 0, 51, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0, 0, 54, 0, 0], + [ 0, 0, 0, 0, 0, 1, 0, 0, 46, 0], + [ 1, 1, 0, 1, 1, 0, 0, 0, 2, 42]] + + confusionSVM = [[45, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 57, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 0, 59, 2, 0, 0, 0, 0, 0, 0], + [ 0, 0, 0, 43, 0, 0, 0, 1, 0, 0], + [ 0, 0, 0, 0, 40, 0, 0, 0, 0, 0], + [ 0, 0, 0, 1, 0, 50, 0, 0, 0, 0], + [ 0, 0, 0, 0, 1, 0, 51, 0, 0, 0], + [ 0, 0, 1, 0, 0, 0, 0, 54, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 47, 0], + [ 0, 1, 0, 1, 0, 0, 0, 0, 1, 45]] + + self.assertLess(cv2.norm(confusionMatrixes[0] - confusionKNN, cv2.NORM_L1), normEps) + self.assertLess(cv2.norm(confusionMatrixes[1] - confusionSVM, cv2.NORM_L1), normEps) + + self.assertLess(errors[0] - 0.034, eps) + self.assertLess(errors[1] - 0.018, eps) \ No newline at end of file diff --git a/modules/python/test/test_facedetect.py b/modules/python/test/test_facedetect.py new file mode 100644 index 0000000000..8d64fde10f --- /dev/null +++ b/modules/python/test/test_facedetect.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python + +''' +face detection using haar cascades +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 + +def detect(img, cascade): + rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30), + flags=cv2.CASCADE_SCALE_IMAGE) + if len(rects) == 0: + return [] + rects[:,2:] += rects[:,:2] + return rects + +from tests_common import NewOpenCVTests, intersectionRate + +class facedetect_test(NewOpenCVTests): + + def test_facedetect(self): + import sys, getopt + + cascade_fn = self.repoPath + '/data/haarcascades/haarcascade_frontalface_alt.xml' + nested_fn = self.repoPath + '/data/haarcascades/haarcascade_eye.xml' + + cascade = cv2.CascadeClassifier(cascade_fn) + nested = cv2.CascadeClassifier(nested_fn) + + samples = ['samples/data/lena.jpg', 'cv/cascadeandhog/images/mona-lisa.png'] + + faces = [] + eyes = [] + + testFaces = [ + #lena + [[218, 200, 389, 371], + [ 244, 240, 294, 290], + [ 309, 246, 352, 289]], + + #lisa + [[167, 119, 307, 259], + [188, 153, 229, 194], + [236, 153, 277, 194]] + ] + + for sample in samples: + + img = self.get_sample( sample) + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + gray = cv2.GaussianBlur(gray, (5, 5), 5.1) + + rects = detect(gray, cascade) + faces.append(rects) + + if not nested.empty(): + for x1, y1, x2, y2 in rects: + roi = gray[y1:y2, x1:x2] + subrects = detect(roi.copy(), nested) + + for rect in subrects: + rect[0] += x1 + rect[2] += x1 + rect[1] += y1 + rect[3] += y1 + + eyes.append(subrects) + + faces_matches = 0 + eyes_matches = 0 + + eps = 0.8 + + for i in range(len(faces)): + for j in range(len(testFaces)): + if intersectionRate(faces[i][0], testFaces[j][0]) > eps: + faces_matches += 1 + #check eyes + if len(eyes[i]) == 2: + if intersectionRate(eyes[i][0], testFaces[j][1]) > eps and intersectionRate(eyes[i][1] , testFaces[j][2]) > eps: + eyes_matches += 1 + elif intersectionRate(eyes[i][1], testFaces[j][1]) > eps and intersectionRate(eyes[i][0], testFaces[j][2]) > eps: + eyes_matches += 1 + + self.assertEqual(faces_matches, 2) + self.assertEqual(eyes_matches, 2) \ No newline at end of file diff --git a/modules/python/test/test_feature_homography.py b/modules/python/test/test_feature_homography.py new file mode 100644 index 0000000000..280945e98b --- /dev/null +++ b/modules/python/test/test_feature_homography.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python + +''' +Feature homography +================== + +Example of using features2d framework for interactive video homography matching. +ORB features and FLANN matcher are used. The actual tracking is implemented by +PlaneTracker class in plane_tracker.py +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 +import sys +PY3 = sys.version_info[0] == 3 + +if PY3: + xrange = range + +# local modules +from tst_scene_render import TestSceneRender + +def intersectionRate(s1, s2): + + x1, y1, x2, y2 = s1 + s1 = np.array([[x1, y1], [x2,y1], [x2, y2], [x1, y2]]) + + area, intersection = cv2.intersectConvexConvex(s1, np.array(s2)) + return 2 * area / (cv2.contourArea(s1) + cv2.contourArea(np.array(s2))) + +from tests_common import NewOpenCVTests + +class feature_homography_test(NewOpenCVTests): + + render = None + tracker = None + framesCounter = 0 + frame = None + + def test_feature_homography(self): + + self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), + self.get_sample('samples/data/box.png'), noise = 0.5, speed = 0.5) + self.frame = self.render.getNextFrame() + self.tracker = PlaneTracker() + self.tracker.clear() + self.tracker.add_target(self.frame, self.render.getCurrentRect()) + + while self.framesCounter < 100: + self.framesCounter += 1 + tracked = self.tracker.track(self.frame) + if len(tracked) > 0: + tracked = tracked[0] + self.assertGreater(intersectionRate(self.render.getCurrentRect(), np.int32(tracked.quad)), 0.6) + else: + self.assertEqual(0, 1, 'Tracking error') + self.frame = self.render.getNextFrame() + + +# built-in modules +from collections import namedtuple + +FLANN_INDEX_KDTREE = 1 +FLANN_INDEX_LSH = 6 +flann_params= dict(algorithm = FLANN_INDEX_LSH, + table_number = 6, # 12 + key_size = 12, # 20 + multi_probe_level = 1) #2 + +MIN_MATCH_COUNT = 10 + +''' + image - image to track + rect - tracked rectangle (x1, y1, x2, y2) + keypoints - keypoints detected inside rect + descrs - their descriptors + data - some user-provided data +''' +PlanarTarget = namedtuple('PlaneTarget', 'image, rect, keypoints, descrs, data') + +''' + target - reference to PlanarTarget + p0 - matched points coords in target image + p1 - matched points coords in input frame + H - homography matrix from p0 to p1 + quad - target bounary quad in input frame +''' +TrackedTarget = namedtuple('TrackedTarget', 'target, p0, p1, H, quad') + +class PlaneTracker: + def __init__(self): + self.detector = cv2.ORB( nfeatures = 1000 ) + self.matcher = cv2.FlannBasedMatcher(flann_params, {}) # bug : need to pass empty dict (#1329) + self.targets = [] + self.frame_points = [] + + def add_target(self, image, rect, data=None): + '''Add a new tracking target.''' + x0, y0, x1, y1 = rect + raw_points, raw_descrs = self.detect_features(image) + points, descs = [], [] + for kp, desc in zip(raw_points, raw_descrs): + x, y = kp.pt + if x0 <= x <= x1 and y0 <= y <= y1: + points.append(kp) + descs.append(desc) + descs = np.uint8(descs) + self.matcher.add([descs]) + target = PlanarTarget(image = image, rect=rect, keypoints = points, descrs=descs, data=data) + self.targets.append(target) + + def clear(self): + '''Remove all targets''' + self.targets = [] + self.matcher.clear() + + def track(self, frame): + '''Returns a list of detected TrackedTarget objects''' + self.frame_points, frame_descrs = self.detect_features(frame) + if len(self.frame_points) < MIN_MATCH_COUNT: + return [] + matches = self.matcher.knnMatch(frame_descrs, k = 2) + matches = [m[0] for m in matches if len(m) == 2 and m[0].distance < m[1].distance * 0.75] + if len(matches) < MIN_MATCH_COUNT: + return [] + matches_by_id = [[] for _ in xrange(len(self.targets))] + for m in matches: + matches_by_id[m.imgIdx].append(m) + tracked = [] + for imgIdx, matches in enumerate(matches_by_id): + if len(matches) < MIN_MATCH_COUNT: + continue + target = self.targets[imgIdx] + p0 = [target.keypoints[m.trainIdx].pt for m in matches] + p1 = [self.frame_points[m.queryIdx].pt for m in matches] + p0, p1 = np.float32((p0, p1)) + H, status = cv2.findHomography(p0, p1, cv2.RANSAC, 3.0) + status = status.ravel() != 0 + if status.sum() < MIN_MATCH_COUNT: + continue + p0, p1 = p0[status], p1[status] + + x0, y0, x1, y1 = target.rect + quad = np.float32([[x0, y0], [x1, y0], [x1, y1], [x0, y1]]) + quad = cv2.perspectiveTransform(quad.reshape(1, -1, 2), H).reshape(-1, 2) + + track = TrackedTarget(target=target, p0=p0, p1=p1, H=H, quad=quad) + tracked.append(track) + tracked.sort(key = lambda t: len(t.p0), reverse=True) + return tracked + + def detect_features(self, frame): + '''detect_features(self, frame) -> keypoints, descrs''' + keypoints, descrs = self.detector.detectAndCompute(frame, None) + if descrs is None: # detectAndCompute returns descs=None if not keypoints found + descrs = [] + return keypoints, descrs \ No newline at end of file diff --git a/modules/python/test/test_fitline.py b/modules/python/test/test_fitline.py new file mode 100644 index 0000000000..05719b74f1 --- /dev/null +++ b/modules/python/test/test_fitline.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +''' +Robust line fitting. +================== + +Example of using cv2.fitLine function for fitting line +to points in presence of outliers. + +Switch through different M-estimator functions and see, +how well the robust functions fit the line even +in case of ~50% of outliers. + +''' + +# Python 2/3 compatibility +from __future__ import print_function +import sys +PY3 = sys.version_info[0] == 3 + +import numpy as np +import cv2 + +from tests_common import NewOpenCVTests + +w, h = 512, 256 + +def toint(p): + return tuple(map(int, p)) + +def sample_line(p1, p2, n, noise=0.0): + np.random.seed(10) + p1 = np.float32(p1) + t = np.random.rand(n,1) + return p1 + (p2-p1)*t + np.random.normal(size=(n, 2))*noise + +dist_func_names = ['CV_DIST_L2', 'CV_DIST_L1', 'CV_DIST_L12', 'CV_DIST_FAIR', 'CV_DIST_WELSCH', 'CV_DIST_HUBER'] + +class fitline_test(NewOpenCVTests): + + def test_fitline(self): + + noise = 5 + n = 200 + r = 5 / 100.0 + outn = int(n*r) + + p0, p1 = (90, 80), (w-90, h-80) + line_points = sample_line(p0, p1, n-outn, noise) + outliers = np.random.rand(outn, 2) * (w, h) + points = np.vstack([line_points, outliers]) + + lines = [] + + for name in dist_func_names: + func = getattr(cv2.cv, name) + vx, vy, cx, cy = cv2.fitLine(np.float32(points), func, 0, 0.01, 0.01) + line = [float(vx), float(vy), float(cx), float(cy)] + lines.append(line) + + eps = 0.05 + + refVec = (np.float32(p1) - p0) / cv2.norm(np.float32(p1) - p0) + + for i in range(len(lines)): + self.assertLessEqual(cv2.norm(refVec - lines[i][0:2], cv2.NORM_L2), eps) \ No newline at end of file diff --git a/modules/python/test/test_gaussian_mix.py b/modules/python/test/test_gaussian_mix.py new file mode 100644 index 0000000000..498cf3862f --- /dev/null +++ b/modules/python/test/test_gaussian_mix.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +# Python 2/3 compatibility +from __future__ import print_function +import sys +PY3 = sys.version_info[0] == 3 + +if PY3: + xrange = range + +import numpy as np +from numpy import random +import cv2 + +def make_gaussians(cluster_n, img_size): + points = [] + ref_distrs = [] + for i in xrange(cluster_n): + mean = (0.1 + 0.8*random.rand(2)) * img_size + a = (random.rand(2, 2)-0.5)*img_size*0.1 + cov = np.dot(a.T, a) + img_size*0.05*np.eye(2) + n = 100 + random.randint(900) + pts = random.multivariate_normal(mean, cov, n) + points.append( pts ) + ref_distrs.append( (mean, cov) ) + points = np.float32( np.vstack(points) ) + return points, ref_distrs + +from tests_common import NewOpenCVTests + +class gaussian_mix_test(NewOpenCVTests): + + def test_gaussian_mix(self): + + np.random.seed(10) + cluster_n = 5 + img_size = 512 + + points, ref_distrs = make_gaussians(cluster_n, img_size) + + em = cv2.EM(cluster_n,cv2.EM_COV_MAT_GENERIC) + em.train(points) + means = em.getMat("means") + covs = em.getMatVector("covs") # Known bug: https://github.com/Itseez/opencv/pull/4232 + found_distrs = zip(means, covs) + + matches_count = 0 + + meanEps = 0.05 + covEps = 0.1 + + for i in range(cluster_n): + for j in range(cluster_n): + if (cv2.norm(means[i] - ref_distrs[j][0], cv2.NORM_L2) / cv2.norm(ref_distrs[j][0], cv2.NORM_L2) < meanEps and + cv2.norm(covs[i] - ref_distrs[j][1], cv2.NORM_L2) / cv2.norm(ref_distrs[j][1], cv2.NORM_L2) < covEps): + matches_count += 1 + + self.assertEqual(matches_count, cluster_n) \ No newline at end of file diff --git a/modules/python/test/test_grabcut.py b/modules/python/test/test_grabcut.py new file mode 100644 index 0000000000..38211f7d89 --- /dev/null +++ b/modules/python/test/test_grabcut.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +''' +=============================================================================== +Interactive Image Segmentation using GrabCut algorithm. +=============================================================================== +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 +import sys + +from tests_common import NewOpenCVTests + +class grabcut_test(NewOpenCVTests): + + def verify(self, mask, exp): + + maxDiffRatio = 0.02 + expArea = np.count_nonzero(exp) + nonIntersectArea = np.count_nonzero(mask != exp) + curRatio = float(nonIntersectArea) / expArea + return curRatio < maxDiffRatio + + def scaleMask(self, mask): + + return np.where((mask==cv2.GC_FGD) + (mask==cv2.GC_PR_FGD),255,0).astype('uint8') + + def test_grabcut(self): + + img = self.get_sample('cv/shared/airplane.png') + mask_prob = self.get_sample("cv/grabcut/mask_probpy.png", 0) + exp_mask1 = self.get_sample("cv/grabcut/exp_mask1py.png", 0) + exp_mask2 = self.get_sample("cv/grabcut/exp_mask2py.png", 0) + + if img is None: + self.assertTrue(False, 'Missing test data') + + rect = (24, 126, 459, 168) + mask = np.zeros(img.shape[:2], dtype = np.uint8) + bgdModel = np.zeros((1,65),np.float64) + fgdModel = np.zeros((1,65),np.float64) + cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 0, cv2.GC_INIT_WITH_RECT) + cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 2, cv2.GC_EVAL) + + if mask_prob is None: + mask_prob = mask.copy() + cv2.imwrite(self.extraTestDataPath + '/cv/grabcut/mask_probpy.png', mask_prob) + if exp_mask1 is None: + exp_mask1 = self.scaleMask(mask) + cv2.imwrite(self.extraTestDataPath + '/cv/grabcut/exp_mask1py.png', exp_mask1) + + self.assertEqual(self.verify(self.scaleMask(mask), exp_mask1), True) + + mask = mask_prob + bgdModel = np.zeros((1,65),np.float64) + fgdModel = np.zeros((1,65),np.float64) + cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 0, cv2.GC_INIT_WITH_MASK) + cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 1, cv2.GC_EVAL) + + if exp_mask2 is None: + exp_mask2 = self.scaleMask(mask) + cv2.imwrite(self.extraTestDataPath + '/cv/grabcut/exp_mask2py.png', exp_mask2) + + self.assertEqual(self.verify(self.scaleMask(mask), exp_mask2), True) \ No newline at end of file diff --git a/modules/python/test/test_houghcircles.py b/modules/python/test/test_houghcircles.py new file mode 100644 index 0000000000..6cf7d74ebb --- /dev/null +++ b/modules/python/test/test_houghcircles.py @@ -0,0 +1,81 @@ +#!/usr/bin/python + +''' +This example illustrates how to use cv2.HoughCircles() function. +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import cv2 +import numpy as np +import sys +from numpy import pi, sin, cos + +from tests_common import NewOpenCVTests + +def circleApproximation(circle): + + nPoints = 30 + phi = 0 + dPhi = 2*pi / nPoints + contour = [] + for i in range(nPoints): + contour.append(([circle[0] + circle[2]*cos(i*dPhi), + circle[1] + circle[2]*sin(i*dPhi)])) + + return np.array(contour).astype(int) + +def convContoursIntersectiponRate(c1, c2): + + s1 = cv2.contourArea(c1) + s2 = cv2.contourArea(c2) + + s, _ = cv2.intersectConvexConvex(c1, c2) + + return 2*s/(s1+s2) + +class houghcircles_test(NewOpenCVTests): + + def test_houghcircles(self): + + fn = "samples/data/board.jpg" + + src = self.get_sample(fn, 1) + img = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) + img = cv2.medianBlur(img, 5) + + circles = cv2.HoughCircles(img, cv2.cv.CV_HOUGH_GRADIENT, 1, 10, np.array([]), 100, 30, 1, 30)[0] + + testCircles = [[38, 181, 17.6], + [99.7, 166, 13.12], + [142.7, 160, 13.52], + [223.6, 110, 8.62], + [79.1, 206.7, 8.62], + [47.5, 351.6, 11.64], + [189.5, 354.4, 11.64], + [189.8, 298.9, 10.64], + [189.5, 252.4, 14.62], + [252.5, 393.4, 15.62], + [602.9, 467.5, 11.42], + [222, 210.4, 9.12], + [263.1, 216.7, 9.12], + [359.8, 222.6, 9.12], + [518.9, 120.9, 9.12], + [413.8, 113.4, 9.12], + [489, 127.2, 9.12], + [448.4, 121.3, 9.12], + [384.6, 128.9, 8.62]] + + matches_counter = 0 + + for i in range(len(testCircles)): + for j in range(len(circles)): + + tstCircle = circleApproximation(testCircles[i]) + circle = circleApproximation(circles[j]) + if convContoursIntersectiponRate(tstCircle, circle) > 0.6: + matches_counter += 1 + + self.assertGreater(float(matches_counter) / len(testCircles), .5) + self.assertLess(float(len(circles) - matches_counter) / len(circles), .75) \ No newline at end of file diff --git a/modules/python/test/test_houghlines.py b/modules/python/test/test_houghlines.py new file mode 100644 index 0000000000..081c84984d --- /dev/null +++ b/modules/python/test/test_houghlines.py @@ -0,0 +1,65 @@ +#!/usr/bin/python + +''' +This example illustrates how to use Hough Transform to find lines +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import cv2 +import numpy as np +import sys +import math + +from tests_common import NewOpenCVTests + +def linesDiff(line1, line2): + + norm1 = cv2.norm(line1 - line2, cv2.NORM_L2) + line3 = line1[2:4] + line1[0:2] + norm2 = cv2.norm(line3 - line2, cv2.NORM_L2) + + return min(norm1, norm2) + +class houghlines_test(NewOpenCVTests): + + def test_houghlines(self): + + fn = "/samples/data/pic1.png" + + src = self.get_sample(fn) + dst = cv2.Canny(src, 50, 200) + + lines = cv2.HoughLinesP(dst, 1, math.pi/180.0, 40, np.array([]), 50, 10)[0,:,:] + + eps = 5 + testLines = [ + #rect1 + [ 232, 25, 43, 25], + [ 43, 129, 232, 129], + [ 43, 129, 43, 25], + [232, 129, 232, 25], + #rect2 + [251, 86, 314, 183], + [252, 86, 323, 40], + [315, 183, 386, 137], + [324, 40, 386, 136], + #triangle + [245, 205, 377, 205], + [244, 206, 305, 278], + [306, 279, 377, 205], + #rect3 + [153, 177, 196, 177], + [153, 277, 153, 179], + [153, 277, 196, 277], + [196, 177, 196, 277]] + + matches_counter = 0 + + for i in range(len(testLines)): + for j in range(len(lines)): + if linesDiff(testLines[i], lines[j]) < eps: + matches_counter += 1 + + self.assertGreater(float(matches_counter) / len(testLines), .7) \ No newline at end of file diff --git a/modules/python/test/test_kmeans.py b/modules/python/test/test_kmeans.py new file mode 100644 index 0000000000..8cee11c675 --- /dev/null +++ b/modules/python/test/test_kmeans.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python + +''' +K-means clusterization test +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 +from numpy import random +import sys +PY3 = sys.version_info[0] == 3 +if PY3: + xrange = range + +from tests_common import NewOpenCVTests + +def make_gaussians(cluster_n, img_size): + points = [] + ref_distrs = [] + sizes = [] + for i in xrange(cluster_n): + mean = (0.1 + 0.8*random.rand(2)) * img_size + a = (random.rand(2, 2)-0.5)*img_size*0.1 + cov = np.dot(a.T, a) + img_size*0.05*np.eye(2) + n = 100 + random.randint(900) + pts = random.multivariate_normal(mean, cov, n) + points.append( pts ) + ref_distrs.append( (mean, cov) ) + sizes.append(n) + points = np.float32( np.vstack(points) ) + return points, ref_distrs, sizes + +def getMainLabelConfidence(labels, nLabels): + + n = len(labels) + labelsDict = dict.fromkeys(range(nLabels), 0) + labelsConfDict = dict.fromkeys(range(nLabels)) + + for i in range(n): + labelsDict[labels[i][0]] += 1 + + for i in range(nLabels): + labelsConfDict[i] = float(labelsDict[i]) / n + + return max(labelsConfDict.values()) + +class kmeans_test(NewOpenCVTests): + + def test_kmeans(self): + + np.random.seed(10) + + cluster_n = 5 + img_size = 512 + + points, _, clusterSizes = make_gaussians(cluster_n, img_size) + + term_crit = (cv2.TERM_CRITERIA_EPS, 30, 0.1) + ret, labels, centers = cv2.kmeans(points, cluster_n, term_crit, 10, 0) + + self.assertEqual(len(centers), cluster_n) + + offset = 0 + for i in range(cluster_n): + confidence = getMainLabelConfidence(labels[offset : (offset + clusterSizes[i])], cluster_n) + offset += clusterSizes[i] + self.assertGreater(confidence, 0.9) \ No newline at end of file diff --git a/modules/python/test/test_letter_recog.py b/modules/python/test/test_letter_recog.py new file mode 100644 index 0000000000..05f879978e --- /dev/null +++ b/modules/python/test/test_letter_recog.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python + +''' +The sample demonstrates how to train Random Trees classifier +(or Boosting classifier, or MLP, or Knearest, or Support Vector Machines) using the provided dataset. + +We use the sample database letter-recognition.data +from UCI Repository, here is the link: + +Newman, D.J. & Hettich, S. & Blake, C.L. & Merz, C.J. (1998). +UCI Repository of machine learning databases +[http://www.ics.uci.edu/~mlearn/MLRepository.html]. +Irvine, CA: University of California, Department of Information and Computer Science. + +The dataset consists of 20000 feature vectors along with the +responses - capital latin letters A..Z. +The first 10000 samples are used for training +and the remaining 10000 - to test the classifier. +====================================================== + Models: RTrees, KNearest, Boost, SVM, MLP +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 + +def load_base(fn): + a = np.loadtxt(fn, np.float32, delimiter=',', converters={ 0 : lambda ch : ord(ch)-ord('A') }) + samples, responses = a[:,1:], a[:,0] + return samples, responses + +class LetterStatModel(object): + class_n = 26 + train_ratio = 0.5 + + def load(self, fn): + self.model.load(fn) + def save(self, fn): + self.model.save(fn) + + def unroll_samples(self, samples): + sample_n, var_n = samples.shape + new_samples = np.zeros((sample_n * self.class_n, var_n+1), np.float32) + new_samples[:,:-1] = np.repeat(samples, self.class_n, axis=0) + new_samples[:,-1] = np.tile(np.arange(self.class_n), sample_n) + return new_samples + + def unroll_responses(self, responses): + sample_n = len(responses) + new_responses = np.zeros(sample_n*self.class_n, np.int32) + resp_idx = np.int32( responses + np.arange(sample_n)*self.class_n ) + new_responses[resp_idx] = 1 + return new_responses + +class RTrees(LetterStatModel): + def __init__(self): + self.model = cv2.RTrees() + + def train(self, samples, responses): + sample_n, var_n = samples.shape + params = dict(max_depth=20 ) + self.model.train(samples, cv2.CV_ROW_SAMPLE, responses.astype(int), params = params) + + def predict(self, samples): + return np.float32( [self.model.predict(s) for s in samples] ) + + +class KNearest(LetterStatModel): + def __init__(self): + self.model = cv2.KNearest() + + def train(self, samples, responses): + self.model.train(samples, responses) + + def predict(self, samples): + retval, results, neigh_resp, dists = self.model.find_nearest(samples, k = 10) + return results.ravel() + + +class Boost(LetterStatModel): + def __init__(self): + self.model = cv2.Boost() + + def train(self, samples, responses): + sample_n, var_n = samples.shape + new_samples = self.unroll_samples(samples) + new_responses = self.unroll_responses(responses) + var_types = np.array([cv2.CV_VAR_NUMERICAL] * var_n + [cv2.CV_VAR_CATEGORICAL, cv2.CV_VAR_CATEGORICAL], np.uint8) + params = dict(max_depth=10, weak_count=15) + self.model.train(new_samples, cv2.CV_ROW_SAMPLE, new_responses.astype(int), varType = var_types, params=params) + + def predict(self, samples): + new_samples = self.unroll_samples(samples) + pred = np.array( [self.model.predict(s) for s in new_samples] ) + pred = pred.reshape(-1, self.class_n).argmax(1) + return pred + + +class SVM(LetterStatModel): + def __init__(self): + self.model = cv2.SVM() + + def train(self, samples, responses): + params = dict( kernel_type = cv2.SVM_RBF, + svm_type = cv2.SVM_C_SVC, + C = 1, + gamma = .1 ) + self.model.train(samples, responses.astype(int), params = params) + + def predict(self, samples): + return self.model.predict_all(samples).ravel() + + +class MLP(LetterStatModel): + def __init__(self): + self.model = cv2.ANN_MLP() + + def train(self, samples, responses): + sample_n, var_n = samples.shape + new_responses = self.unroll_responses(responses).reshape(-1, self.class_n) + layer_sizes = np.int32([var_n, 100, 100, self.class_n]) + + self.model.create(layer_sizes, cv2.ANN_MLP_SIGMOID_SYM, 2, 1) + params = dict( train_method = cv2.ANN_MLP_TRAIN_PARAMS_BACKPROP, + bp_moment_scale = 0.0, + bp_dw_scale = 0.001, + term_crit = (cv2.TERM_CRITERIA_COUNT, 20, 0.01) ) + self.model.train(samples, np.float32(new_responses), None, params = params) + + def predict(self, samples): + ret, resp = self.model.predict(samples) + return resp.argmax(-1) + +from tests_common import NewOpenCVTests + +class letter_recog_test(NewOpenCVTests): + + def test_letter_recog(self): + + eps = 0.01 + + models = [RTrees, KNearest, Boost, SVM, MLP] + models = dict( [(cls.__name__.lower(), cls) for cls in models] ) + testErrors = {RTrees: (98.930000, 92.390000), KNearest: (94.960000, 92.010000), + Boost: (85.970000, 74.920000), SVM: (99.780000, 95.680000), MLP: (90.060000, 87.410000)} + + for model in models: + Model = models[model] + classifier = Model() + + samples, responses = load_base(self.repoPath + '/samples/data/letter-recognition.data') + train_n = int(len(samples)*classifier.train_ratio) + + classifier.train(samples[:train_n], responses[:train_n]) + train_rate = np.mean(classifier.predict(samples[:train_n]) == responses[:train_n].astype(int)) + test_rate = np.mean(classifier.predict(samples[train_n:]) == responses[train_n:].astype(int)) + + self.assertLess(train_rate - testErrors[Model][0], eps) + self.assertLess(test_rate - testErrors[Model][1], eps) \ No newline at end of file diff --git a/modules/python/test/test_lk_homography.py b/modules/python/test/test_lk_homography.py new file mode 100644 index 0000000000..8e526d0de7 --- /dev/null +++ b/modules/python/test/test_lk_homography.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +''' +Lucas-Kanade homography tracker test +=============================== +Uses goodFeaturesToTrack for track initialization and back-tracking for match verification +between frames. Finds homography between reference and current views. +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 + +#local modules +from tst_scene_render import TestSceneRender +from tests_common import NewOpenCVTests, isPointInRect + +lk_params = dict( winSize = (19, 19), + maxLevel = 2, + criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) + +feature_params = dict( maxCorners = 1000, + qualityLevel = 0.01, + minDistance = 8, + blockSize = 19 ) + +def checkedTrace(img0, img1, p0, back_threshold = 1.0): + p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params) + p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params) + d = abs(p0-p0r).reshape(-1, 2).max(-1) + status = d < back_threshold + return p1, status + +class lk_homography_test(NewOpenCVTests): + + render = None + framesCounter = 0 + frame = frame0 = None + p0 = None + p1 = None + gray0 = gray1 = None + numFeaturesInRectOnStart = 0 + + def test_lk_homography(self): + self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), + self.get_sample('samples/data/box.png'), noise = 0.1, speed = 1.0) + + frame = self.render.getNextFrame() + frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + self.frame0 = frame.copy() + self.p0 = cv2.goodFeaturesToTrack(frame_gray, **feature_params) + + isForegroundHomographyFound = False + + if self.p0 is not None: + self.p1 = self.p0 + self.gray0 = frame_gray + self.gray1 = frame_gray + currRect = self.render.getCurrentRect() + for (x,y) in self.p0[:,0]: + if isPointInRect((x,y), currRect): + self.numFeaturesInRectOnStart += 1 + + while self.framesCounter < 200: + self.framesCounter += 1 + frame = self.render.getNextFrame() + frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + if self.p0 is not None: + p2, trace_status = checkedTrace(self.gray1, frame_gray, self.p1) + + self.p1 = p2[trace_status].copy() + self.p0 = self.p0[trace_status].copy() + self.gray1 = frame_gray + + if len(self.p0) < 4: + self.p0 = None + continue + H, status = cv2.findHomography(self.p0, self.p1, cv2.RANSAC, 5.0) + + goodPointsInRect = 0 + goodPointsOutsideRect = 0 + for (x0, y0), (x1, y1), good in zip(self.p0[:,0], self.p1[:,0], status[:,0]): + if good: + if isPointInRect((x1,y1), self.render.getCurrentRect()): + goodPointsInRect += 1 + else: goodPointsOutsideRect += 1 + + if goodPointsOutsideRect < goodPointsInRect: + isForegroundHomographyFound = True + self.assertGreater(float(goodPointsInRect) / (self.numFeaturesInRectOnStart + 1), 0.6) + else: + p = cv2.goodFeaturesToTrack(frame_gray, **feature_params) + + self.assertEqual(isForegroundHomographyFound, True) \ No newline at end of file diff --git a/modules/python/test/test_lk_track.py b/modules/python/test/test_lk_track.py new file mode 100644 index 0000000000..ccc67a5128 --- /dev/null +++ b/modules/python/test/test_lk_track.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python + +''' +Lucas-Kanade tracker +==================== + +Lucas-Kanade sparse optical flow demo. Uses goodFeaturesToTrack +for track initialization and back-tracking for match verification +between frames. +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 + +#local modules +from tst_scene_render import TestSceneRender +from tests_common import NewOpenCVTests, intersectionRate, isPointInRect + +lk_params = dict( winSize = (15, 15), + maxLevel = 2, + criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03)) + +feature_params = dict( maxCorners = 500, + qualityLevel = 0.3, + minDistance = 7, + blockSize = 7 ) + +def getRectFromPoints(points): + + distances = [] + for point in points: + distances.append(cv2.norm(point, cv2.NORM_L2)) + + x0, y0 = points[np.argmin(distances)] + x1, y1 = points[np.argmax(distances)] + + return np.array([x0, y0, x1, y1]) + + +class lk_track_test(NewOpenCVTests): + + track_len = 10 + detect_interval = 5 + tracks = [] + frame_idx = 0 + render = None + + def test_lk_track(self): + + self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), self.get_sample('samples/data/box.png')) + self.runTracker() + + def runTracker(self): + foregroundPointsNum = 0 + + while True: + frame = self.render.getNextFrame() + frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) + + if len(self.tracks) > 0: + img0, img1 = self.prev_gray, frame_gray + p0 = np.float32([tr[-1][0] for tr in self.tracks]).reshape(-1, 1, 2) + p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params) + p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params) + d = abs(p0-p0r).reshape(-1, 2).max(-1) + good = d < 1 + new_tracks = [] + for tr, (x, y), good_flag in zip(self.tracks, p1.reshape(-1, 2), good): + if not good_flag: + continue + tr.append([(x, y), self.frame_idx]) + if len(tr) > self.track_len: + del tr[0] + new_tracks.append(tr) + self.tracks = new_tracks + + if self.frame_idx % self.detect_interval == 0: + goodTracksCount = 0 + for tr in self.tracks: + oldRect = self.render.getRectInTime(self.render.timeStep * tr[0][1]) + newRect = self.render.getRectInTime(self.render.timeStep * tr[-1][1]) + if isPointInRect(tr[0][0], oldRect) and isPointInRect(tr[-1][0], newRect): + goodTracksCount += 1 + + if self.frame_idx == self.detect_interval: + foregroundPointsNum = goodTracksCount + + fgIndex = float(foregroundPointsNum) / (foregroundPointsNum + 1) + fgRate = float(goodTracksCount) / (len(self.tracks) + 1) + + if self.frame_idx > 0: + self.assertGreater(fgIndex, 0.9) + self.assertGreater(fgRate, 0.2) + + mask = np.zeros_like(frame_gray) + mask[:] = 255 + for x, y in [np.int32(tr[-1][0]) for tr in self.tracks]: + cv2.circle(mask, (x, y), 5, 0, -1) + p = cv2.goodFeaturesToTrack(frame_gray, mask = mask, **feature_params) + if p is not None: + for x, y in np.float32(p).reshape(-1, 2): + self.tracks.append([[(x, y), self.frame_idx]]) + + self.frame_idx += 1 + self.prev_gray = frame_gray + + if self.frame_idx > 300: + break \ No newline at end of file diff --git a/modules/python/test/test_morphology.py b/modules/python/test/test_morphology.py new file mode 100644 index 0000000000..309c80cfd2 --- /dev/null +++ b/modules/python/test/test_morphology.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +''' +Morphology operations. +''' + +# Python 2/3 compatibility +from __future__ import print_function +import sys +PY3 = sys.version_info[0] == 3 + +import numpy as np +import cv2 + +from tests_common import NewOpenCVTests + +class morphology_test(NewOpenCVTests): + + def test_morphology(self): + + fn = 'samples/data/rubberwhale1.png' + img = self.get_sample(fn) + + modes = ['erode/dilate', 'open/close', 'blackhat/tophat', 'gradient'] + str_modes = ['ellipse', 'rect', 'cross'] + + referenceHashes = { modes[0]: '071a526425b79e45b4d0d71ef51b0562', modes[1] : '071a526425b79e45b4d0d71ef51b0562', + modes[2] : '427e89f581b7df1b60a831b1ed4c8618', modes[3] : '0dd8ad251088a63d0dd022bcdc57361c'} + + def update(cur_mode): + cur_str_mode = str_modes[0] + sz = 10 + iters = 1 + opers = cur_mode.split('/') + if len(opers) > 1: + sz = sz - 10 + op = opers[sz > 0] + sz = abs(sz) + else: + op = opers[0] + sz = sz*2+1 + + str_name = 'MORPH_' + cur_str_mode.upper() + oper_name = 'MORPH_' + op.upper() + + st = cv2.getStructuringElement(getattr(cv2, str_name), (sz, sz)) + return cv2.morphologyEx(img, getattr(cv2, oper_name), st, iterations=iters) + + for mode in modes: + res = update(mode) + self.assertEqual(self.hashimg(res), referenceHashes[mode]) \ No newline at end of file diff --git a/modules/python/test/test_mser.py b/modules/python/test/test_mser.py new file mode 100644 index 0000000000..dfdb30a8ed --- /dev/null +++ b/modules/python/test/test_mser.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +''' +MSER detector test +''' +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 + +from tests_common import NewOpenCVTests + +class mser_test(NewOpenCVTests): + def test_mser(self): + + img = self.get_sample('cv/mser/puzzle.png', 0) + smallImg = [ + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], + [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255] + ] + thresharr = [ 0, 70, 120, 180, 255 ] + kDelta = 5 + np.random.seed(10) + + for i in range(100): + + use_big_image = int(np.random.rand(1,1)*7) != 0 + invert = int(np.random.rand(1,1)*2) != 0 + binarize = int(np.random.rand(1,1)*5) != 0 if use_big_image else False + blur = int(np.random.rand(1,1)*2) != 0 + thresh = thresharr[int(np.random.rand(1,1)*5)] + src0 = img if use_big_image else np.array(smallImg).astype('uint8') + src = src0.copy() + + kMinArea = 256 if use_big_image else 10 + kMaxArea = int(src.shape[0]*src.shape[1]/4) + + mserExtractor = cv2.MSER(kDelta, kMinArea, kMaxArea) + if invert: + cv2.bitwise_not(src, src) + if binarize: + _, src = cv2.threshold(src, thresh, 255, cv2.THRESH_BINARY) + if blur: + src = cv2.GaussianBlur(src, (5, 5), 1.5, 1.5) + minRegs = 7 if use_big_image else 2 + maxRegs = 1000 if use_big_image else 15 + if binarize and (thresh == 0 or thresh == 255): + minRegs = maxRegs = 0 + msers = mserExtractor.detect(src) + nmsers = len(msers) + self.assertLessEqual(minRegs, nmsers) + self.assertGreaterEqual(maxRegs, nmsers) \ No newline at end of file diff --git a/modules/python/test/test_peopledetect.py b/modules/python/test/test_peopledetect.py new file mode 100644 index 0000000000..fb0a9e9cae --- /dev/null +++ b/modules/python/test/test_peopledetect.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +''' +example to detect upright people in images using HOG features +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 + + +def inside(r, q): + rx, ry, rw, rh = r + qx, qy, qw, qh = q + return rx > qx and ry > qy and rx + rw < qx + qw and ry + rh < qy + qh + +from tests_common import NewOpenCVTests, intersectionRate + +class peopledetect_test(NewOpenCVTests): + def test_peopledetect(self): + + hog = cv2.HOGDescriptor() + hog.setSVMDetector( cv2.HOGDescriptor_getDefaultPeopleDetector() ) + + dirPath = 'samples/data/' + samples = ['basketball1.png', 'basketball2.png'] + + testPeople = [ + [[23, 76, 164, 477], [440, 22, 637, 478]], + [[23, 76, 164, 477], [440, 22, 637, 478]] + ] + + eps = 0.5 + + for sample in samples: + + img = self.get_sample(dirPath + sample, 0) + + found, w = hog.detectMultiScale(img, winStride=(8,8), padding=(32,32), scale=1.05) + found_filtered = [] + for ri, r in enumerate(found): + for qi, q in enumerate(found): + if ri != qi and inside(r, q): + break + else: + found_filtered.append(r) + + matches = 0 + + for i in range(len(found_filtered)): + for j in range(len(testPeople)): + + found_rect = (found_filtered[i][0], found_filtered[i][1], + found_filtered[i][0] + found_filtered[i][2], + found_filtered[i][1] + found_filtered[i][3]) + + if intersectionRate(found_rect, testPeople[j][0]) > eps or intersectionRate(found_rect, testPeople[j][1]) > eps: + matches += 1 + + self.assertGreater(matches, 0) \ No newline at end of file diff --git a/modules/python/test/test_squares.py b/modules/python/test/test_squares.py new file mode 100644 index 0000000000..3b3fbb6d9d --- /dev/null +++ b/modules/python/test/test_squares.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +''' +Simple "Square Detector" program. + +Loads several images sequentially and tries to find squares in each image. +''' + +# Python 2/3 compatibility +import sys +PY3 = sys.version_info[0] == 3 + +if PY3: + xrange = range + +import numpy as np +import cv2 + + +def angle_cos(p0, p1, p2): + d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float') + return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) ) + +def find_squares(img): + img = cv2.GaussianBlur(img, (5, 5), 0) + squares = [] + for gray in cv2.split(img): + for thrs in xrange(0, 255, 26): + if thrs == 0: + bin = cv2.Canny(gray, 0, 50, apertureSize=5) + bin = cv2.dilate(bin, None) + else: + retval, bin = cv2.threshold(gray, thrs, 255, cv2.THRESH_BINARY) + contours, hierarchy = cv2.findContours(bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) + for cnt in contours: + cnt_len = cv2.arcLength(cnt, True) + cnt = cv2.approxPolyDP(cnt, 0.02*cnt_len, True) + if len(cnt) == 4 and cv2.contourArea(cnt) > 1000 and cv2.isContourConvex(cnt): + cnt = cnt.reshape(-1, 2) + max_cos = np.max([angle_cos( cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4] ) for i in xrange(4)]) + if max_cos < 0.1 and filterSquares(squares, cnt): + squares.append(cnt) + + return squares + +def intersectionRate(s1, s2): + area, intersection = cv2.intersectConvexConvex(np.array(s1), np.array(s2)) + return 2 * area / (cv2.contourArea(np.array(s1)) + cv2.contourArea(np.array(s2))) + +def filterSquares(squares, square): + + for i in range(len(squares)): + if intersectionRate(squares[i], square) > 0.95: + return False + + return True + +from tests_common import NewOpenCVTests + +class squares_test(NewOpenCVTests): + + def test_squares(self): + + img = self.get_sample('samples/data/pic1.png') + squares = find_squares(img) + + testSquares = [ + [[43, 25], + [43, 129], + [232, 129], + [232, 25]], + + [[252, 87], + [324, 40], + [387, 137], + [315, 184]], + + [[154, 178], + [196, 180], + [198, 278], + [154, 278]], + + [[0, 0], + [400, 0], + [400, 300], + [0, 300]] + ] + + matches_counter = 0 + for i in range(len(squares)): + for j in range(len(testSquares)): + if intersectionRate(squares[i], testSquares[j]) > 0.9: + matches_counter += 1 + + self.assertGreater(matches_counter / len(testSquares), 0.9) + self.assertLess( (len(squares) - matches_counter) / len(squares), 0.2) \ No newline at end of file diff --git a/modules/python/test/test_texture_flow.py b/modules/python/test/test_texture_flow.py new file mode 100644 index 0000000000..7dc3b07040 --- /dev/null +++ b/modules/python/test/test_texture_flow.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +''' +Texture flow direction estimation. + +Sample shows how cv2.cornerEigenValsAndVecs function can be used +to estimate image texture flow direction. +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 +import sys + +from tests_common import NewOpenCVTests + + +class texture_flow_test(NewOpenCVTests): + + def test_texture_flow(self): + + img = self.get_sample('samples/data/pic6.png') + + gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + h, w = img.shape[:2] + + eigen = cv2.cornerEigenValsAndVecs(gray, 15, 3) + eigen = eigen.reshape(h, w, 3, 2) # [[e1, e2], v1, v2] + flow = eigen[:,:,2] + + vis = img.copy() + vis[:] = (192 + np.uint32(vis)) / 2 + d = 80 + points = np.dstack( np.mgrid[d/2:w:d, d/2:h:d] ).reshape(-1, 2) + + textureVectors = [] + + for x, y in np.int32(points): + textureVectors.append(np.int32(flow[y, x]*d)) + + eps = 0.05 + + testTextureVectors = [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], + [-38, 70], [-79, 3], [0, 0], [0, 0], [-39, 69], [-79, -1], + [0, 0], [0, 0], [0, -79], [17, -78], [-48, -63], [65, -46], + [-69, -39], [-48, -63], [-45, 66]] + + for i in range(len(textureVectors)): + self.assertLessEqual(cv2.norm(textureVectors[i] - testTextureVectors[i], cv2.NORM_L2), eps) \ No newline at end of file diff --git a/modules/python/test/test_watershed.py b/modules/python/test/test_watershed.py new file mode 100644 index 0000000000..0a1d222f41 --- /dev/null +++ b/modules/python/test/test_watershed.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +''' +Watershed segmentation test +''' + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +import cv2 + +from tests_common import NewOpenCVTests + +class watershed_test(NewOpenCVTests): + def test_watershed(self): + + img = self.get_sample('cv/inpaint/orig.png') + markers = self.get_sample('cv/watershed/wshed_exp.png', 0) + refSegments = self.get_sample('cv/watershed/wshed_segments.png') + + if img is None or markers is None: + self.assertEqual(0, 1, 'Missing test data') + + colors = np.int32( list(np.ndindex(3, 3, 3)) ) * 122 + cv2.watershed(img, np.int32(markers)) + segments = colors[np.maximum(markers, 0)] + + if refSegments is None: + refSegments = segments.copy() + cv2.imwrite(self.extraTestDataPath + '/cv/watershed/wshed_segments.png', refSegments) + + self.assertLess(cv2.norm(segments - refSegments, cv2.NORM_L1) / 255.0, 50) \ No newline at end of file diff --git a/modules/python/test/tests_common.py b/modules/python/test/tests_common.py new file mode 100644 index 0000000000..3a636b255c --- /dev/null +++ b/modules/python/test/tests_common.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import unittest +import sys +import hashlib +import os +import numpy as np +import cv2 + +# Python 3 moved urlopen to urllib.requests +try: + from urllib.request import urlopen +except ImportError: + from urllib import urlopen + +class NewOpenCVTests(unittest.TestCase): + + # path to local repository folder containing 'samples' folder + repoPath = None + extraTestDataPath = None + # github repository url + repoUrl = 'https://raw.github.com/Itseez/opencv/master' + + def get_sample(self, filename, iscolor = cv2.IMREAD_COLOR): + if not filename in self.image_cache: + filedata = None + if NewOpenCVTests.repoPath is not None: + candidate = NewOpenCVTests.repoPath + '/' + filename + if os.path.isfile(candidate): + with open(candidate, 'rb') as f: + filedata = f.read() + if NewOpenCVTests.extraTestDataPath is not None: + candidate = NewOpenCVTests.extraTestDataPath + '/' + filename + if os.path.isfile(candidate): + with open(candidate, 'rb') as f: + filedata = f.read() + if filedata is None: + return None#filedata = urlopen(NewOpenCVTests.repoUrl + '/' + filename).read() + self.image_cache[filename] = cv2.imdecode(np.fromstring(filedata, dtype=np.uint8), iscolor) + return self.image_cache[filename] + + def setUp(self): + self.image_cache = {} + + def hashimg(self, im): + """ Compute a hash for an image, useful for image comparisons """ + return hashlib.md5(im.tostring()).hexdigest() + + if sys.version_info[:2] == (2, 6): + def assertLess(self, a, b, msg=None): + if not a < b: + self.fail('%s not less than %s' % (repr(a), repr(b))) + + def assertLessEqual(self, a, b, msg=None): + if not a <= b: + self.fail('%s not less than or equal to %s' % (repr(a), repr(b))) + + def assertGreater(self, a, b, msg=None): + if not a > b: + self.fail('%s not greater than %s' % (repr(a), repr(b))) + +def intersectionRate(s1, s2): + + x1, y1, x2, y2 = s1 + s1 = np.array([[x1, y1], [x2,y1], [x2, y2], [x1, y2]]) + + x1, y1, x2, y2 = s2 + s2 = np.array([[x1, y1], [x2,y1], [x2, y2], [x1, y2]]) + + area, intersection = cv2.intersectConvexConvex(s1, s2) + return 2 * area / (cv2.contourArea(s1) + cv2.contourArea(s2)) + +def isPointInRect(p, rect): + if rect[0] <= p[0] and rect[1] <=p[1] and p[0] <= rect[2] and p[1] <= rect[3]: + return True + else: + return False \ No newline at end of file diff --git a/modules/python/test/tst_scene_render.py b/modules/python/test/tst_scene_render.py new file mode 100644 index 0000000000..49cde80d25 --- /dev/null +++ b/modules/python/test/tst_scene_render.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python + + +# Python 2/3 compatibility +from __future__ import print_function + +import numpy as np +from numpy import pi, sin, cos + +import cv2 + +defaultSize = 512 + +class TestSceneRender(): + + def __init__(self, bgImg = None, fgImg = None, deformation = False, noise = 0.0, speed = 0.25, **params): + self.time = 0.0 + self.timeStep = 1.0 / 30.0 + self.foreground = fgImg + self.deformation = deformation + self.noise = noise + self.speed = speed + + if bgImg is not None: + self.sceneBg = bgImg.copy() + else: + self.sceneBg = np.zeros(defaultSize, defaultSize, np.uint8) + + self.w = self.sceneBg.shape[0] + self.h = self.sceneBg.shape[1] + + if fgImg is not None: + self.foreground = fgImg.copy() + self.center = self.currentCenter = (int(self.w/2 - fgImg.shape[0]/2), int(self.h/2 - fgImg.shape[1]/2)) + + self.xAmpl = self.sceneBg.shape[0] - (self.center[0] + fgImg.shape[0]) + self.yAmpl = self.sceneBg.shape[1] - (self.center[1] + fgImg.shape[1]) + + self.initialRect = np.array([ (self.h/2, self.w/2), (self.h/2, self.w/2 + self.w/10), + (self.h/2 + self.h/10, self.w/2 + self.w/10), (self.h/2 + self.h/10, self.w/2)]).astype(int) + self.currentRect = self.initialRect + np.random.seed(10) + + def getXOffset(self, time): + return int(self.xAmpl*cos(time*self.speed)) + + + def getYOffset(self, time): + return int(self.yAmpl*sin(time*self.speed)) + + def setInitialRect(self, rect): + self.initialRect = rect + + def getRectInTime(self, time): + + if self.foreground is not None: + tmp = np.array(self.center) + np.array((self.getXOffset(time), self.getYOffset(time))) + x0, y0 = tmp + x1, y1 = tmp + self.foreground.shape[0:2] + return np.array([y0, x0, y1, x1]) + else: + x0, y0 = self.initialRect[0] + np.array((self.getXOffset(time), self.getYOffset(time))) + x1, y1 = self.initialRect[2] + np.array((self.getXOffset(time), self.getYOffset(time))) + return np.array([y0, x0, y1, x1]) + + def getCurrentRect(self): + + if self.foreground is not None: + + x0 = self.currentCenter[0] + y0 = self.currentCenter[1] + x1 = self.currentCenter[0] + self.foreground.shape[0] + y1 = self.currentCenter[1] + self.foreground.shape[1] + return np.array([y0, x0, y1, x1]) + else: + x0, y0 = self.currentRect[0] + x1, y1 = self.currentRect[2] + return np.array([x0, y0, x1, y1]) + + def getNextFrame(self): + img = self.sceneBg.copy() + + if self.foreground is not None: + self.currentCenter = (self.center[0] + self.getXOffset(self.time), self.center[1] + self.getYOffset(self.time)) + img[self.currentCenter[0]:self.currentCenter[0]+self.foreground.shape[0], + self.currentCenter[1]:self.currentCenter[1]+self.foreground.shape[1]] = self.foreground + else: + self.currentRect = self.initialRect + np.int( 30*cos(self.time) + 50*sin(self.time/3)) + if self.deformation: + self.currentRect[1:3] += int(self.h/20*cos(self.time)) + cv2.fillConvexPoly(img, self.currentRect, (0, 0, 255)) + + self.time += self.timeStep + + if self.noise: + noise = np.zeros(self.sceneBg.shape, np.int8) + cv2.randn(noise, np.zeros(3), np.ones(3)*255*self.noise) + img = cv2.add(img, noise, dtype=cv2.CV_8UC3) + return img + + def resetTime(self): + self.time = 0.0 + + +if __name__ == '__main__': + + backGr = cv2.imread('../../../samples/data/lena.jpg') + + render = TestSceneRender(backGr, noise = 0.5) + + while True: + + img = render.getNextFrame() + cv2.imshow('img', img) + + ch = 0xFF & cv2.waitKey(3) + if ch == 27: + break + cv2.destroyAllWindows() \ No newline at end of file From aaa30dc5b6c65868a2c50fb7fdbdfc2836d694c4 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Thu, 25 Feb 2016 17:06:20 +0300 Subject: [PATCH 175/468] Make some tests less strict due to improvement of related algorithms in master branch --- modules/python/test/test_feature_homography.py | 2 +- modules/python/test/test_mser.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/python/test/test_feature_homography.py b/modules/python/test/test_feature_homography.py index 280945e98b..f417033883 100644 --- a/modules/python/test/test_feature_homography.py +++ b/modules/python/test/test_feature_homography.py @@ -43,7 +43,7 @@ class feature_homography_test(NewOpenCVTests): def test_feature_homography(self): self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), - self.get_sample('samples/data/box.png'), noise = 0.5, speed = 0.5) + self.get_sample('samples/data/box.png'), noise = 0.4, speed = 0.5) self.frame = self.render.getNextFrame() self.tracker = PlaneTracker() self.tracker.clear() diff --git a/modules/python/test/test_mser.py b/modules/python/test/test_mser.py index dfdb30a8ed..47c7db196f 100644 --- a/modules/python/test/test_mser.py +++ b/modules/python/test/test_mser.py @@ -40,7 +40,7 @@ class mser_test(NewOpenCVTests): use_big_image = int(np.random.rand(1,1)*7) != 0 invert = int(np.random.rand(1,1)*2) != 0 binarize = int(np.random.rand(1,1)*5) != 0 if use_big_image else False - blur = int(np.random.rand(1,1)*2) != 0 + blur = True #int(np.random.rand(1,1)*2) != 0 #binarized images are processed incorrectly thresh = thresharr[int(np.random.rand(1,1)*5)] src0 = img if use_big_image else np.array(smallImg).astype('uint8') src = src0.copy() From 25b4d8a1b5a5a1f90f5006999766fdbd12250ce9 Mon Sep 17 00:00:00 2001 From: Vitaly Tuzov Date: Thu, 25 Feb 2016 17:25:24 +0300 Subject: [PATCH 176/468] Added images necessary for tests --- modules/python/test/test_calibration.py | 4 ++-- modules/python/test/test_camshift.py | 2 +- modules/python/test/test_dft.py | 2 +- modules/python/test/test_digits.py | 2 +- modules/python/test/test_facedetect.py | 2 +- modules/python/test/test_feature_homography.py | 4 ++-- modules/python/test/test_houghcircles.py | 2 +- modules/python/test/test_houghlines.py | 2 +- modules/python/test/test_letter_recog.py | 2 +- modules/python/test/test_lk_homography.py | 4 ++-- modules/python/test/test_lk_track.py | 2 +- modules/python/test/test_morphology.py | 2 +- modules/python/test/test_peopledetect.py | 2 +- modules/python/test/test_squares.py | 2 +- modules/python/test/test_texture_flow.py | 2 +- modules/python/test/tst_scene_render.py | 17 ----------------- samples/python2/data/graf1.png | Bin 0 -> 951440 bytes samples/python2/data/pca_test1.jpg | Bin 0 -> 33227 bytes 18 files changed, 18 insertions(+), 35 deletions(-) create mode 100644 samples/python2/data/graf1.png create mode 100644 samples/python2/data/pca_test1.jpg diff --git a/modules/python/test/test_calibration.py b/modules/python/test/test_calibration.py index 665521862c..bb54cacdc4 100644 --- a/modules/python/test/test_calibration.py +++ b/modules/python/test/test_calibration.py @@ -21,9 +21,9 @@ class calibration_test(NewOpenCVTests): img_names = [] for i in range(1, 15): if i < 10: - img_names.append('samples/data/left0{}.jpg'.format(str(i))) + img_names.append('samples/cpp/left0{}.jpg'.format(str(i))) elif i != 10: - img_names.append('samples/data/left{}.jpg'.format(str(i))) + img_names.append('samples/cpp/left{}.jpg'.format(str(i))) square_size = 1.0 pattern_size = (9, 6) diff --git a/modules/python/test/test_camshift.py b/modules/python/test/test_camshift.py index a824320eff..6c7c189344 100644 --- a/modules/python/test/test_camshift.py +++ b/modules/python/test/test_camshift.py @@ -39,7 +39,7 @@ class camshift_test(NewOpenCVTests): def prepareRender(self): - self.render = TestSceneRender(self.get_sample('samples/data/pca_test1.jpg'), deformation = True) + self.render = TestSceneRender(self.get_sample('samples/python2/data/pca_test1.jpg'), deformation = True) def runTracker(self): diff --git a/modules/python/test/test_dft.py b/modules/python/test/test_dft.py index f796939970..9019a6a63c 100644 --- a/modules/python/test/test_dft.py +++ b/modules/python/test/test_dft.py @@ -16,7 +16,7 @@ from tests_common import NewOpenCVTests class dft_test(NewOpenCVTests): def test_dft(self): - img = self.get_sample('samples/data/rubberwhale1.png', 0) + img = self.get_sample('samples/gpu/rubberwhale1.png', 0) eps = 0.001 #test direct transform diff --git a/modules/python/test/test_digits.py b/modules/python/test/test_digits.py index 587c355e37..e30361e0eb 100644 --- a/modules/python/test/test_digits.py +++ b/modules/python/test/test_digits.py @@ -36,7 +36,7 @@ from numpy.linalg import norm SZ = 20 # size of each digit is SZ x SZ CLASS_N = 10 -DIGITS_FN = 'samples/data/digits.png' +DIGITS_FN = 'samples/python2/data/digits.png' def split2d(img, cell_size, flatten=True): h, w = img.shape[:2] diff --git a/modules/python/test/test_facedetect.py b/modules/python/test/test_facedetect.py index 8d64fde10f..094659712e 100644 --- a/modules/python/test/test_facedetect.py +++ b/modules/python/test/test_facedetect.py @@ -31,7 +31,7 @@ class facedetect_test(NewOpenCVTests): cascade = cv2.CascadeClassifier(cascade_fn) nested = cv2.CascadeClassifier(nested_fn) - samples = ['samples/data/lena.jpg', 'cv/cascadeandhog/images/mona-lisa.png'] + samples = ['samples/c/lena.jpg', 'cv/cascadeandhog/images/mona-lisa.png'] faces = [] eyes = [] diff --git a/modules/python/test/test_feature_homography.py b/modules/python/test/test_feature_homography.py index f417033883..a895be6f6a 100644 --- a/modules/python/test/test_feature_homography.py +++ b/modules/python/test/test_feature_homography.py @@ -42,8 +42,8 @@ class feature_homography_test(NewOpenCVTests): def test_feature_homography(self): - self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), - self.get_sample('samples/data/box.png'), noise = 0.4, speed = 0.5) + self.render = TestSceneRender(self.get_sample('samples/python2/data/graf1.png'), + self.get_sample('samples/c/box.png'), noise = 0.4, speed = 0.5) self.frame = self.render.getNextFrame() self.tracker = PlaneTracker() self.tracker.clear() diff --git a/modules/python/test/test_houghcircles.py b/modules/python/test/test_houghcircles.py index 6cf7d74ebb..32b474fc85 100644 --- a/modules/python/test/test_houghcircles.py +++ b/modules/python/test/test_houghcircles.py @@ -39,7 +39,7 @@ class houghcircles_test(NewOpenCVTests): def test_houghcircles(self): - fn = "samples/data/board.jpg" + fn = "samples/cpp/board.jpg" src = self.get_sample(fn, 1) img = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) diff --git a/modules/python/test/test_houghlines.py b/modules/python/test/test_houghlines.py index 081c84984d..993c113436 100644 --- a/modules/python/test/test_houghlines.py +++ b/modules/python/test/test_houghlines.py @@ -26,7 +26,7 @@ class houghlines_test(NewOpenCVTests): def test_houghlines(self): - fn = "/samples/data/pic1.png" + fn = "/samples/cpp/pic1.png" src = self.get_sample(fn) dst = cv2.Canny(src, 50, 200) diff --git a/modules/python/test/test_letter_recog.py b/modules/python/test/test_letter_recog.py index 05f879978e..d64d8e0993 100644 --- a/modules/python/test/test_letter_recog.py +++ b/modules/python/test/test_letter_recog.py @@ -150,7 +150,7 @@ class letter_recog_test(NewOpenCVTests): Model = models[model] classifier = Model() - samples, responses = load_base(self.repoPath + '/samples/data/letter-recognition.data') + samples, responses = load_base(self.repoPath + '/samples/cpp/letter-recognition.data') train_n = int(len(samples)*classifier.train_ratio) classifier.train(samples[:train_n], responses[:train_n]) diff --git a/modules/python/test/test_lk_homography.py b/modules/python/test/test_lk_homography.py index 8e526d0de7..b1d6285a9d 100644 --- a/modules/python/test/test_lk_homography.py +++ b/modules/python/test/test_lk_homography.py @@ -44,8 +44,8 @@ class lk_homography_test(NewOpenCVTests): numFeaturesInRectOnStart = 0 def test_lk_homography(self): - self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), - self.get_sample('samples/data/box.png'), noise = 0.1, speed = 1.0) + self.render = TestSceneRender(self.get_sample('samples/python2/data/graf1.png'), + self.get_sample('samples/c/box.png'), noise = 0.1, speed = 1.0) frame = self.render.getNextFrame() frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) diff --git a/modules/python/test/test_lk_track.py b/modules/python/test/test_lk_track.py index ccc67a5128..920351c5f2 100644 --- a/modules/python/test/test_lk_track.py +++ b/modules/python/test/test_lk_track.py @@ -50,7 +50,7 @@ class lk_track_test(NewOpenCVTests): def test_lk_track(self): - self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), self.get_sample('samples/data/box.png')) + self.render = TestSceneRender(self.get_sample('samples/python2/data/graf1.png'), self.get_sample('samples/c/box.png')) self.runTracker() def runTracker(self): diff --git a/modules/python/test/test_morphology.py b/modules/python/test/test_morphology.py index 309c80cfd2..1062801eac 100644 --- a/modules/python/test/test_morphology.py +++ b/modules/python/test/test_morphology.py @@ -18,7 +18,7 @@ class morphology_test(NewOpenCVTests): def test_morphology(self): - fn = 'samples/data/rubberwhale1.png' + fn = 'samples/gpu/rubberwhale1.png' img = self.get_sample(fn) modes = ['erode/dilate', 'open/close', 'blackhat/tophat', 'gradient'] diff --git a/modules/python/test/test_peopledetect.py b/modules/python/test/test_peopledetect.py index fb0a9e9cae..efb477d426 100644 --- a/modules/python/test/test_peopledetect.py +++ b/modules/python/test/test_peopledetect.py @@ -24,7 +24,7 @@ class peopledetect_test(NewOpenCVTests): hog = cv2.HOGDescriptor() hog.setSVMDetector( cv2.HOGDescriptor_getDefaultPeopleDetector() ) - dirPath = 'samples/data/' + dirPath = 'samples/gpu/' samples = ['basketball1.png', 'basketball2.png'] testPeople = [ diff --git a/modules/python/test/test_squares.py b/modules/python/test/test_squares.py index 3b3fbb6d9d..c933b358f4 100644 --- a/modules/python/test/test_squares.py +++ b/modules/python/test/test_squares.py @@ -61,7 +61,7 @@ class squares_test(NewOpenCVTests): def test_squares(self): - img = self.get_sample('samples/data/pic1.png') + img = self.get_sample('samples/cpp/pic1.png') squares = find_squares(img) testSquares = [ diff --git a/modules/python/test/test_texture_flow.py b/modules/python/test/test_texture_flow.py index 7dc3b07040..8dae6fabd4 100644 --- a/modules/python/test/test_texture_flow.py +++ b/modules/python/test/test_texture_flow.py @@ -21,7 +21,7 @@ class texture_flow_test(NewOpenCVTests): def test_texture_flow(self): - img = self.get_sample('samples/data/pic6.png') + img = self.get_sample('samples/cpp/pic6.png') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) h, w = img.shape[:2] diff --git a/modules/python/test/tst_scene_render.py b/modules/python/test/tst_scene_render.py index 49cde80d25..68e03acbad 100644 --- a/modules/python/test/tst_scene_render.py +++ b/modules/python/test/tst_scene_render.py @@ -100,20 +100,3 @@ class TestSceneRender(): def resetTime(self): self.time = 0.0 - - -if __name__ == '__main__': - - backGr = cv2.imread('../../../samples/data/lena.jpg') - - render = TestSceneRender(backGr, noise = 0.5) - - while True: - - img = render.getNextFrame() - cv2.imshow('img', img) - - ch = 0xFF & cv2.waitKey(3) - if ch == 27: - break - cv2.destroyAllWindows() \ No newline at end of file diff --git a/samples/python2/data/graf1.png b/samples/python2/data/graf1.png new file mode 100644 index 0000000000000000000000000000000000000000..67e347318648420262f7d4c1f528ab0f22e48109 GIT binary patch literal 951440 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�vUkQ9o^1S{i{|zm>i~`|ubM(=cA}7_G;~UFqJ{pTnlx)DR z^5MIccqEJ;V{b~${j-gOh(ATK5fKI>?La|8&&lHMAv0o{jjz+*vG!@|?XtaJ zYl=WieyYd>Qw#w?(G3*qcurt$!$zfi@&4eo!P=i1Yql|Sv<4i_MQNI(%G;?4hR5F9 zd@P=QzDE<=uKb+R2NsR*hEYXe39X29o|3{|LVrZZ)KXNC_L9JNm6O1$^vC6mz?0uU zf)#54R!_N-W#_zCW@_eaSoAq;kk^uU!5aEQKT54Qg8%?r6o54X6R`@W8kThY4xor- zfxgD=M1)1)iIBU3a48#sWNeWQ$13X`v@}i2*+5zP>dl`HqX3&PSF;5yMVPT^x0= zi>EFR|J=7-@21BL?p-)z6fJ2jsGCsOPbtq4ubpl6 zQ%vCAvT|$OJ#NzvYa+jQe@}3!G+(ZUv;?~}D5ft@ZE!{xYsrnIb1=zBC~3O2B`sPq zaf9W5)5|9ssp&!%DWHsxcGZ~MnO%_|=n`{F7<0q9NoE4E7;CM@tnIr}9#HO5oN%bj<6I9D*Q|7{BPK`K%MZvT!fLPf`KyZwan z!F+ZxAVQD8Xz&3GL8u3{0@&Yzh+c~&QO~wHNnj)9(8rM1ir*zr>&@IYc|JdWw7|gz zKM_}cBEox0lNp|z>x`?p$vOBGJf@#;b41hT6mfptQsB1ueER|o3EC>x`Wdd9T9mm6 zc0SB}(2is0G}~!gggBARm_L#K)1+t}zZrob*qB7Wa^7B4YfIsjr?UT`sa_V!^x5n? z#O{~pFU$b(hZ8TFKyX$1{ZiiIgOiYAu9NTZ+Tm4dX({lmtHsM-#x4RlBVBs@<7|4$ z&V?-4AH!wQa=2-FJ4HU;vPQuG$_tGyU$%KNK{)eY(6Lm8A^^Z(IVHB8uY0P=@irBV z0=Bqmnsop}1WwolDKF9=1&L7C5-%7_3$e4JWL&U)p#9cr_U?ykbAxY=Cp!upHt%IO z#3;XI)*lGoSY-vPZp>&wp*GF~swe|2fs#~K=JsW^zBHi3#{7A$^;eOp@u}Af^t>RD zy)vY&yQ5r-~3H#9YMOI`bN)7Qgg(v^GhWm_t8af4K&9gGKSe~iur?z*U@)W zh}IL8C~V(KX>6`c=q?{Aa_c_trVlptigN30-P1GH>4&26s`02j8pu`lYG; z#-)#|iu~fod!oeQ%@IZ54K?-694bo~L_XQ~-K$?dVvinGm=C|4+4oJ*)Z?_O(h9Kcl)2-!T@!i4pONFEDOhbFNXnlZ7)!xr6mB8b_FDJ_BcHa-e z5z7DwAwmO#3+^Gr^h^u*3+>r zX^Tghx7hicAJ0pKzLb*Zg;R_^*e$Gr(D5_`JauL#lQ>zi5Sq8QuW|DT;ibKz(7dCZ z5%UJL{4gkq*WtshNaPlaED~(3gCuAn+DGpbjUp$B5^9dsP4#}eD}e{ebI03W7kgP} z`K7$s33(=jjTvGaGk{=6WH!01ro#t?uq-03Qk3<12dV3^4otu5P z!u`lsdlE69`!Zs?P18jVpJR0;vO9mccnxUO5EBf7$VSgfbzMJ|boJ>DYCrOjSJOa? zgSG#&LFDg{bf_U$>fRtIrk2_V3Y*5R(OI0-b^O-sRJ#&2;`yL(Xsniz^LscC1%x0a zT51fUlv7d!kBkj4!8pce&c{9)S_IsUX-F=sFCDE?_C2S$F#zC>Mr?BcVMErp=(PAy z`Xi>a+!`Qo1rjgKR4FA42rrP3&h?>VBc5FyI1@HA#nx8yn1{4mgA_lA!4Zj+6i_Bf zy@iU8+batrYCL& z{*6zZvF?0-e?6q(QP!*q^cGl3lFjH7QDT~8vx>OGKW2H70WA8D}mXn&2U%;G`>8Gt0xo zTI7w)Llvrn_qWZg?JIf>KIDpo8}-uDEB4oPeROC!-V-|6|BPr!<{TY)cL;5vCG!m zcHGZ7T`eqFPx6DcolUWO{KL$SBftFPPFV^`0a?txY>~b_#l!T z5oKWXe1GqlnU!T3+E0mQQeVfZqft)TXjy1j5#W6U)^bw8C$?B^G1@wkxX>I83t~=Tkz_;1Y|{5+@AG~7W!gD9=V~EM%i|;QPuDU_98i<}~ zbgiVVF}hH_)WU>FM!kcyhhT-OvLAMOJq_IAx;U)4oOQdHnd;L0T+D9dy!(fEPSyso zJlweR{grS%j){i{irK9D>zWkXbkt9DM@LEe)9-Zndd2j+Z`75-+qNegcu&UVxq+jG zDTJXJjj7jf6O&9=*4B3iDrM*VFPo0I?o&VAI&=SIq~WED0H9Jg4&C4QnC{dJ*RmKC zRWWPO3S39g=+xjCMR`G|t;w+%q#qnE2=8Q=oBv-HAlwe*hxVdYW9g+w!$rIE47u|O z-zfq%iFmRW*70djClgIPH@C=4JM7BH-fAs-LNU+z+_Se(3JBKWPy79YPYr7zOlZvd zL2e$k1EEyJ8S-a@b`~0%i`1asAo;5mB6xIqetDPo?)q28!2R67^NgK~e=TQKjCk8_ zBYW#NM>AQc>*80jY+YNW!ISORMFO;b}JGVpaErXe{2A>W7NH-R%|NyIjw5- zl~_9(y2c?HYxxhWOJ#TEh>9Z3xInVCwUBgD;aD^w|L@qYFx7NZE!`AccF&Kh7PB8_CD*V7KlGrF!uuM5z#%PUNv z8_h|DDu}b#E|j`OTvdiDKAn&CJt{chd^@MuJfdKSdlQ+TUV_5ic{etx>s}e#gJg3RF%unoWfOPTN;le|sCtoM!`QHNLn`OY58SJT$v| zM;`7bQkvF_vwek)?7han;*2O7-+{4x5!#8`2Gvy`jc^7m1oo|waYI+{=9;SCd*P!x zF)Ek;#v(<<2AHmsy2_PQ-q*`wcmY*bImX(2VpzVHsVfB&6S{6!;mzM$Uapx}H-MN$ zcayLKqAHjqcPAvzNujoD^#M)i>RM-%+I)AveI}Zfg|$C6c50l)C)2gdU4ucOG8&5_ zKv4=|b_#SvDuWQ5uAXShk8mNW=S>n6{Iu{Fc@18a4)b5It#|0k0=O81?6SioL|vJpAT{fkk$1pOqeL738gp`t32hx3UF zoBhh(6Y{J_>B~YGsCLFJtnBN5M%CzPR2P{Lu=B zLB*8X;V>Pc(#IeGvy@1Qq0==^6AH@|8-%Y&+w@-}h~)3}XUF4L;e?&DZ)LqeEp8Yv z&*d6)TbwbuPsrbxcI}(IjFGc9%~Hb0Hzfy~ zGsTi$-3)q}vU0G%+u6>#I`BQYT8Nm#>q|RbRaI!>J?t|g?ANqbKR9aJ)K%W+^XiYJ z1nNUkt=FCgWd_*A+@tAbBTW;Kv``FVb(I%6)cpF>vGjW%A^2!YYh_YkHcSyrV|el* zs;Sh#6G_j-G&WrSHHDv2o1b37qXwT7%01;f-e1fX5Igzm$p|+G>IM1J&-@oWRNU&G z0v+uMYpfATKf3yRi4qfZyPC{_QiCce-?5Mlkf4_LtJ{}bWq}6+va|TBFD<*O2#y_- zM8;uaqwGG#YGFl!dE0t|c`?B}RIyA>qBsa=_mU$6AwKV5yp*2rFshpw!>^pcrz^g8 zX1J|FKG7W87S5A8dc)GX8HJy}*;cE}-j5jizVfNEM{3wg>Pfk|R{(#^EW4?!u#$*U z_M+X^cNL#qx8^;!i$#?SfuApBZ`}mHsH<=OybXqrA5HevpMjH$R*9?u8PE}>Yt1txTTlUybN~2x) z&ZU#}4@a|2xt2m|GrW%bmAa|4ea>B8ZVY8D7yHf@CnH|Xdox*Y4trvz!V6Xfho+M5 zWX^9bb$q|r{JOT(u|((Aaz1oU)azy^bFVpL$NZAv&miwrHokrsv( zMYwscNir!(n}Clv_i>%jWB{;nKwEPi?H z)qKQt@o!;U#HiQEu(g`X{HfpJexJqhulNGlRxk~=zXX#G#P>vz7Z?&wb$9;Cj_CvF z$$$vrHWi*G0g)$}6Hl$0%2>oUL?fr7D-V#`Wbm=pp!S$5-6>H^uM)Oyy!iIJWpD1X zw62vg@J~m>DH9K+_01+`(ZZDjbCX{4j$bl&!kL+mFgT(rGq2C->fwp|e0Q*kNrcn> zwqtCFzL9nw&{Cg230zpr_E~vavrCUC+2{cOhadLX`0W}{IFUbS%<1?=*;Lm<^(zJ= zCS_Ml4bZR!BXf`#=ZqtIZk|ZA0VZXqEtJqYYL~VWfrWtCAFs2JIuME(bQMUbmfY)m zyu0*~574fIf*s%7#Z9Gy;zog^z9w9`Nm`I|YivTppc*={f7<0*tfYqMtNls`&|CEy zM-$>LC6!X=lfBW%Z~IOSHL6gbfW~JwQOYLd*qTz&(S;N5P?5gfTK2LpxJwAlAI8$0KRH7(~;in%&h^v4%5 z%A2D%vI6#dx(ZHp_Aj&lq>iHQ>{v6{69e zw7EO!)c1PbS$ArD*(Lo!vQl|zP6`?jCrBT3kFnnTDw50%B~^1`>#MCu2K-`G4?Nn5 z)8hwEjflcJ>YeWMC6A<(NGIR?Yc<5|-wLI7?jLWb_ZcM-i6l7RH0T=h1SH-^uL?0d zv5~LF@Z?Ls2d~|t%ykxxFqh{u^#zs0RjGa{5osg4D1GMx(!yI)Kl|_d5N*BX)#M^6 z1Ed`$3WhSSWf5aWcHeB(1gkg}?6@6e4FU+(Mtz>Obtk>aEq|B1=F(R9mf^yubwfFwM%I0v zxM{TDz!kWE+HzTT@tf-mRuVQqsO7Da zo+t#Nk8)S@q_Hzotu7{J)c3v)eV+8Q@IK`_8?SkDkbK$j@i*)(m)2RHM z)&KJE{;&Atqk>WVe4Tlb`|@^gI7XA5#5*<`pCK0;2j$kUvkdl;T~(#BL`ZHBpjK4d zj$vfK3(5WrZ&?*Peo0Dz@LkYVv>y)J)@tT$hicOIcLF?18nX@2p!d&!%qVrRb@0qJ zbWbn}*V+Fo6ADHbulr5%5TFnWr*)%rD66`bU{0y&M%Q(R&1rmAazhzAd9B|D8$spUnBuf}yrn~?^J{q94VWPT z^xA06Hn>(%dMGuk-gcM02^s{1L#YfO{!+sPJ=l!sIE!+^{rk7PzI!mRbn)_NGSqrf z;|hbUrn;HHBPd7#00JWiv3c55qJ=NWnavl2&TdV)QUyF#k3~aP@tr{_Xe=3z-zHzF zRufh^O2e-iu|a!+OFBk5X0qLEN=j$Sw$G=x^>(W!=JrX!Q8WqQ_oP@vN7o&V4esu} zJkmYpGPmfx##*4aHou93JLsM)eJn5Q=h=5LDvb^4vNiW3dI(rHSBBOSR?8;3(3cW_ z=N363(hz+zLL!{cuYwxM4VMeQzPR7-j@%q33x#v5IZru?jw*c{AMEC2R+;*BY|mA; z@qJL-!qv;=dFZ0VzyiZ^x?EyWH^ziv@1W8_ckZ)W1k6oddV2K{=0WD};-5TpGzVKzoMo!`{VeJayA~Ef zN~dTiXJfNdDB^6{Ku~?lXvDxx=BvE~4G0h5k_&5(j=$dxrj}qXDX!!>+#g7*lcWjh zALVAZY1IJI$Lb^0C)=nA9?yp#G3q?b;D^1_!?HXT_hK4KRJ<5#IWL_%+nSSaelZ`4 zNF;h4OqB$l^=K9}Jd&+vU-`SbTfxryAKWEVz)DmE1z;5!ixanTZf^2FppAbkxU9D+ zZ@Q0W9Y@NIb?LnQGd>%VFn&fQ9;d|FH5&c8)K6O3`waHaW zo3BOr8f^6He*n;w25LYwqh`0MHlZN&W~5Q(2h~PCs@gwGS7q zlnZ5Ttr8?RrF6qLJF|u0HC-(geS!7U=eL(%%OUlDep`=mEo(kZEIXe*-PssR01@;| z1W9ClsLq!+EShQ+{S2*!YqPNP+I|8#YGai_PNUy9rH}r{3^lC>OjlQ84D3vV{kq|X zH-I^-^qj!T0w13JW*r1kuu{c*60@_nicO59Kz^t#U|y&zeqgZd>&-TrW)|SgKBug+ z))Q>V2Q-y!Ia>-mpTE3tm^)uMdV}~#Qe7G`&1T0Y(JBrKsL9R|b5Cj6%_-3%tu=x| zVAk@u=%~R6k)I6$0HJ)s?QQEU5E`|SC;ZtM3DHwk;U+5DEqEDtpWXBUsCCNGZW3eFYGhMI@#1I>;+Q-H5NWs^hQpV zOu{zjwyF12s>@AEjI0%BCfA(Ow9C6&9>YXiw05DvNSp+OLYf=EMB}uRtoBfQ!BXlL zJysF#KWE9uUHG@Nm7W)a1v>VS())w`cH}FO6(Mr^*8B=1_$CQZs5}#ql^i6LBKrKh zI1?}bi-!QM`$czW!X$Y{6Jurak+d0 zoMoE1ghl>YP$yj0)XZwiboOT>avGtuIXsUwpfFh7%G1rdnkLCgKM83``i)pX zPaqGL*HVLC4Gq!X_xzD>fdnCeNSpiJ-?hGpu)|RO<^#D$?^pqn>_{OI9U((e3}A74 zps^rCkZ}V`=+0-R9+rBfP!?nyg(Pb8VGI-bGBqQ)&Oy-*f zEhQ=AoE-e*&+(s!?txxMlaZgRwAKz^*EMCBO#3@;6zBB$$8z*iu11r-RNv9?+g%GF zIb|jlRdjvm1ushCr~LuTSE#n<^fe@xN_qxreo^zmg7||Mmw&&$f7oxyZHonFrqD8x zY8DDa#VKk&&(8QvZI@&Kw!>!*ULPj0DSh8KR^GmemNhfhM*Kji#cnUu&6R(A7{zQ4 zv%Us68rJjzFrfF0gu0fJD(I=9^i$SK6Oyj5GIBJI{Q(4>La=;aYt;O`Q^4;vv*bp+oD#tJAXxVFa2lw%)l=7OPT{fPO2P&-IWwm zb&bQ+W{YK~%T0r%hF-zZ$Rsu4Jn_mv=!V75C4u=Y+NNGTrJv#cTz_ z#gTGY`9|Nlx^q8SE9l|X1E@n~@Cj(GY)f!Ik_}7m0Q}%!I%@nR(U|Nr7~y{8HmuIP zf8(#MHz9EDR9V-O7a94?O8*FL-EB)kyW=rNW8F|yf|aYFnn-6qft6c(qrUtheFpkj zy8F4&US+W6H+3h7EyEwHU=cZe10nVf9&nC?7TN$d1ef}KaZz~0GU-KTr+aC~V*enn z>4M` zo;8{@;sT{W+JjJbw%!nFp#-T=fq0~=H1G67E^KQ%!0~3s^}=^akPc8#83Uuo{EaLN z-92`&j+<~?fIB<_tpCBm^`^j^QO-a9r#*MCu2vE5GlMw*YZm04cR(0kupg6F4n$B0 z#`B;g^@IOI-AxvLW%|wiWvtBA$7g|#YM8pgI+HVO&Umyfbc@fx8g+HB3-ue8Ryk&i zZeX(>l>IvMwX3{$EsVt~g#nh*+L{u_&~fH(8o1w~yW_h3L90}@CL6Fjga?Uq1BSw` zF{;1xNU~<_m(t*}kqCJ>lmlUBxEl3F8tL4fof!;e?VrfEolg4zhYU==l$&Os+W7kB zwO4)h_E5~$w11Sce-*oB5LE=N@%q>8U%S7rOq7@Br!ibf=Q3Ml#7yab+G;?a;bC$m zic}zNqe09T-gQ&*cj)UyUkw83KJ&EKi$F|@;i^TqLBO?v;@bhg;c2p+mJcz5Q4k$> z6vnouwclXlk3>w%@qI%9ZJAc)I7tvFrRMefvJL!VUtgqEWW$*0G&_(eIl?1yXE6w> zMO9k}r$h1N9zzWXq6IOr2E7}Cm+o^KH z$7F4!HGU3M5z&0);;W!iiZMwTe%0nNuX;s&kIKr3g->X-@ty`RFW63u*hsozBL3k? zBAhccl$@vME7qr7(kZjE>=W0JJi*3n#cAUbSqOjoIC$#ipx5mA&$-L8%e1ny_GEF+ zK~=LvR-i$s`u^9*bMt4VPBv}(MYyPuDJ&8Eh~&cm-*f+yQQep;F;GrU zzGYF0-l7)cbB3pjswy>Ay}?$cws=siiA}B;A3Vq%uAjmLSIg0}KAa`#l!@__%%3? zcSJHb+gN33*P+&5VZpgNsQRTRu@gy^ijn*g7J3B1Gh_H*wsFU(zMvf?r-R~&zVsbd z#}Qkn$PB8^O7ZQB-JP>Nu7FE{`Jj%IRDuVgyf_?4h%J7At$4NIoDuooXM`8Lofs6w zLe?Uf8iPU-HBEQkY0)MWJ$Q`7KbNCoX)lP`xfEzQ{Md3bV-fJ@A8eqv@@gAVS5}&l z^f{e14q4;MW>@^DG3|rt^}4LVt!1hQ0&5>X6MZ-?LF=49V_rXEmp6^qa`&0(Bw6>C60JJr~YO5$)kW(jo zpI_K6$q6H9CNIzq1tNJ`WpSb|^CSDp?HwqI>ZR+^Us?hE^d2{_mNHZ1LUrN`69G*O zalgWl`sv67@uy*X2=i!|80Vh|LtpuAiMrRZD!M~uLb+#alKjP8EFIJ-O+xa`|G z-<)e<&O)LgM-7itpy){dmE`90i)3XvcFzAQm=d(|Xg@=crg@t6l-#3f_X?|q{Y(I1 z1*lszR`y_Sb&w>}t@spCt+4VXV@N~8VzCP?pDKI@nOh^T>k%tbGu^l$9bg!JL=HgNJC>g zm_5H>J23(`^(DjvYDk#?M4c)qX4k!AZxXL$rs*dnPl)RlG#K73_;Y^BD1na$!4pM7 zj4)rP6%{2RvYwKpsdDK;MotHJhi=p$B%kn1H`_M)@8*hlv-jb#5fO<{C-GjBmNm>* z7jcg1>{Ztbze}h7d_RwX+am={rBzowe7isV_`o(G!gco6=$lU;k8I46GbfakRSs@M zT6me!a#(pwqfIn*V@h^)QM^;Gqm@HcY zJM}~XB8uTKf~G<6{D%ao@Tg7z-W@$ud{<4~@<{Thfv14M;EJJ;$lL92Q6fW{HvE`$ zujK7ok!zE&u_m$JP6Hk4MJzx>H>WEAl5z!zg|JJWID-Gve5AgdP5(*C-aE7JRdkS1 z-G_U715d)bZMR{P-yr=ysRN2Uec z{Il_h52ZX>=@h<4`Qf5Xezv?4yvMQbK#hk+sjsV;4_wcmpE{}NE;SvsoG@N|ygd9k zcS7}0+B8<8pYjfuE_+PD)sp71*A&NVT~4EARb~R`f|{COPL&Zi&WlS4@GmlXBJ0gb z(X!{x-!{da-pI3;ruRiRGx4z)6#Z&zIyd(E53&a1i0Qt|ZPkTA@_+^NPk6Fq1Cq&M8xT%;ty|h$% z!o(GWb;`>UnH@xU(C^IP=F_sqbHhL*jna$&*c1L8!3M~R^v z5aj+}k+tww_O=dgrb`Xc9s75qNA0m!B8?CrrCbU%$&5Z0A!p2{i+cY+unHd>BijxcMr;M_L~gQaWjjFYLT_-td&0!d(~`+PHP|2vqL#o z*Q=ztmxFxS#XA4fx!nru4ViByk6!K+*i`c`HYRyRhr&Yb)luSQz#bIt%P17ETB?kEQAVn(fqn5AOW z9-%QmYHN+Q_NrNwqKF-(HkFz+YS*q+TWv+PMva!5wQCi{o$n9#zi=Lp_c`bNJkQs4 zVF%_5_gn46edux8DvUO2CXAX1}nAPf~M zFRZ{(RZgI+gci7hqv}QiC=3`^fHVKWZ46BuRFdy4$-ZS47Ija!{&)TF!S&(wQETIv zhv2$79|6KP^ip?XIs0_+a%C=eB>F!=`E;TD3Wzg4F$2ry#+5PHHiua)9nk5_7|=?K zP-GY+1I$X`5J-Y5xR44xJ1`F(%WQ^pjs&trSX9wAj+vS`*c^g80XG*2tgH$Krgy8*;YAH65EwqXlzVxeZ_G``K#f z6#Em4eqP#50|Nq8!Mn-&p^{Gd&W)|AhUl#S7PfRBj#0nAWlDW0NjPmk3Kof^Cj+IX zAO$03xyix^8D3vz_OR={L=BNH1`DCmJbgP6(kUTrLRHIL_4s4(*(V8YM=)CsKx8_J zR+E^TGg4MT^~K`QvrxyAjjvbePB`3$Cc!iP$Q4DrpSAK#o-Km0t>NlAe$v~eircd8 zv3z#&H28;a=i`e3oE2DwM#3QYH2k#ViUbxr>q&6QR*U69P?QRQ0CkLCw1$NX*=|sh z?(0x^l0H4oXYG1vN6$-OjW&i5v?6fG)C2Uoy{hkn(gqi1ctHrCd^NOsBrQZPB)d7} zx%2t$Yx7icZ%Yd5KcD$|=&N5x&BAppe){TsTgX$n4j)$` z=-vM)x(P}j8J67}i(za{hB>3^b!Kao6}l1nl3VQR@=C&u9QxV|b@#nFtrWr&CKAH2 zx)b-v5OWxs`(KV~e%yLn#KN1^yT1HVY@&Yh!XYD$@byApP*Z{HB-D8Ox5ssM$3s(8-yjU;l%Zor%?tb1BR*5bRgO591--*rU#wus43it5qRK zv*nKKtaPoHIWt8dE6iIMYOUIoZE-TTVvdKUNdE`+1l4%i3?7-Wsqd!TJ^dR& zSQ{C!2e^d~2fx1RNf$rkD0V1zmzI|PRbMDyI{#{Qp0ok%oVe#Z^{1d8z*hm{d7T2F zJ0Kcs&!*l1U68X_K)|2T9U?L9EtQd%gk{`OMl~Mkxvgq53}~$^lO=5`r)2LjE`^&->A@+1<{MkktdZvv|LnSkEUD z#LSPG*b7BNmh)9ahCK&!)YBNwdoEa)SOA2Rn2jSL=23^6#^KheRfq6@o}|9%fwJ_a%-|}URA^7{3j3|_}%5| z&sihf?1uY{mt$9#q*7_fk$lKOafs66Y)+jAoAYmY^)ci&kQN83w!=k@XNxYC0{Wuh zVvJNT?tZtbsRC+tIJ5>peOH|uzFg=k+0tb7luZY}fd{ez5_>z@;SE&z5?$~5^12X$ zG{)+N|FJ{Y5=GklU2hwq^m*5WOMZRKS2H08=s6{^ynYa=$;~U)Z8%|veicR}D0V@L zo&9Ql1YHhuDFyudpvwZ?P%?$V=;5ZQYDZts*H|s}^?eBFHcc25G$@OCjpKq!$>9vW z9J*Q(%+Dc5&doepZLR*?4Ew7&+HaLUv%fNk(sRR{8)`U`^)cskBg5hlkJFwkz;!jX zv-0D&GdzFyXw+x={yR$wths|%Nu`3+$>kdZUkd4u8whuCTi1845CFP`oisRwY!>>p zvhoBgw5s|LP~gJ*cX>{6s75i*XGLF^yMoKhWHyDqA|muRJXeBqautI9R_?tZA^-Ot zD+FXQoF*4EmDj!VdZN1&A*`ZnGeGTP0F-DyckR=MKy6j+MM6J^waqEqix4Sra{_!Dq&)h>_@urNZKJAt8?dYb#4bT} zGw4-{bbChK&@{z=^F^yl+@gWJ#jC_V^m&Sq&5*l0Hl?9Ex zfX};RF$mf5P*qb#oN0EL-@jxeI~MEh9|yVN^V~p6&G?{@MOCJY8i8?furS^uqJ)6DVz>PF9kz zOkck6?pk7TLj!Ye$jLJQk84&Mxsl0l;js(t`m;H{;%rM=1DwsmH-JyzY;9FR!m?9h zPX*E7j3l8j{7^S8Q?=i=T3@v(+~Q=H=V^`U{NB`*UgP#7Kt+}9(T91Jy>=09+8zf|GA6rQVDle(Y$;FN^2kcOthm`uJs2cF?8% z!Pak%!IjMdl16!9Ptku*acT>#WzD`0~I=*shzP znz5$+QADUasKUj7i5Y7w7%}J^mK`sBwtN^kpVy{q`i>st_^D_GUehdE1jAzJK>=u& zdj?hx@Gr!*Tl0@rKB;YU_U`5wjN0LzIU-45p<}Lpb=Q}oSH~S9Z=-v@K_s!bd6ZJ& zHeSUQ5NG3N?@6Jp$4BL%Mj+z>5VXjN>ZZtaaoz$I@d2Gluk9RdGc-ie{->YP)td6Z zvFk;7z1+_%7cH4;{8RKmYq9$l30r@D$IJhPeB;RD8z-?7n}6-lSLv-gitg_^O-uj! z_NYVYd|@`hk2hSwIxk`5XlmLuio(j>rAO1_R?q$-t0_@@``gxoMM|^yUuXZ$XVral z*=Dm%N_DliLv^Tn;RMZyhfU92V7pS{Swx29#AIZr=t(Q(gV(23v=1&euY$`U6LEx@D!|DAuTV;TOg7F&V}MZ&m8I}V%I4cg3L`!O1W2JxWr>bS-U zZ!m56g!dg!E5g7&A&KT;14tZD&UlKpv5xn#|EZ%3L)#nLp=`c0rVN03u{xTh+zd<< zPevk=VHpt9+>Z8(Um?d;*V7^Y#;(paa@F;GbfS@-geewg?qqX5b>6T9rQp-WZ;|4* zg-9a+IXxs919c;jE2;Z&agyFPF*aFf+V&8-{LxbM^%u3T3`~|P`p!dG_i#JHtmB`(qwt`p_km^f;-AXT@|Kz ze3~xzR&GsBB>yEmv3U3 zsKdS#0ckS%j)<9q_-X1VC*z#~n>gL9AO!jW;AUUqgVWo}=R^H_L4PK`StJzqJT~FZ z#vuQ_+B6)jqok$B`_M#ts$x1PA<+a+uIx!!GMoL7(-Vzd0Cogo)vcqI1J594WB}E( zEU2iS4uVl?+P7npOFFxC{=Gv1vEAuQn*%wCyHM<|%D`C^P*gY>VUgP*tzl=Cm_KLU zB5nJn-KUR{8wrj_+jb$$?Bq`G7t4|~*@k9s%6BuKhY!RWhLM4-)e#cSpPb%`OT>QK z_@EBP<^6Q~tM~dieq|-GGj$p8Fhb4uP+>~S1**)zi^K2$pYN?0Xd!ACeG$e3f@CRb zS zn0SgNy#NK1zyvS%@6X~IG!?>;_(Yy?C@jC>jz||grHi4_^)_BSniAxcos#&&)j|#h zcxQ2vg9nvx%FZV_(Uf>SZEi&(CkEApra&*_6fYIjspX41Jg?^u`iqa%_jMEn$X6~K zJB}7C&(el9PMyZ=h3wxT#ppvn#ello?4yc%9NNfB8UzX)k=`ioI*V!oq!b2|v!UlB zMTuzpgb^AF>=0J|{ExUt&d&1gll8cAW*h92f(WDAI4pz!TOt66I$)G8$WU$ltKjcX z#5K0uKg&C}SxSs5BasY0pKWzqQ(iBRT~{f;YHg^#xw6ngaEdQ6pI=ajI@^EP+E%(s zO~BLzyfZfMf07>mb-~SZ{2dyQcVEsxstIIWKRBBrk43};8mZQ`9ybNkbP3fx>eqq zQk;D_Y--k3aZ!zpyc8Db(wH#6FmXYlbU;ShiDJ|i2T~1-X`2SMAH!^_t8Gt82%e0}JHHt$-k8wq!W@n;BvWPQa2r7~ca`-w7(24@frwYmclc~f=VF&_>@t{)hYD|VYBHC){`&|F_ z`L9TJ7jJMu~Kcoj1;F1VwQ{t4j_kS zB(mpT9uZ%K#*Jp$o?upRlK8H$wIodtJ5iB>5uids0TKZ5OYH|=`Y~`7WO~NBT-tZ@ z|4uPIGzJ`NN;dC#>v+h~i6NPl2xVsoutA;UH9Yqu}9`w3TMAb1Pg}oKC6Iw5C)1$&=BPY!1q|uq$H^LzR?Vre~ zncXLxe!IEHzV8obQ<|#9G2}ltcjK_$M1-|>g3Om{L?zR5zKuIE0}?OxrGZhpe}qb5 zPe>@zUTx4*7?4Q00PK`BF`$4j=I1LW;)Gj2fvmI%x&;=*ualtK&#i`{%2$8cu2+@+ zMsr;*zkaS;IuMD+0KX#!&(5D8{yQuGaMHcMvH0S;mOd`$RYtMgtwUp`FA`+zu77R9 zT`vC}vMB$J<;s0OJ-pD?6Yk%haT-mO7KKxT?Cl~%hXWL{fyfb7d&S1Xr#r*uxbl)( zyEU)J5EV$^o~D4>Vue|xKA3f3`Q+QHs(VpY(v8jaLuyzgfc_&<+QMD0x?<&B92hP& zQptFa;ay8+*>Rs{w?rC!r8{?pb7$9Pf$D1G=2I?dvWfaoPXP>_+vg$+H(vTu`drtL~IqtRraq)(ak7_W&@} z{J+Db3^Yzy<#%FE6hY@>d7zFqsMIhu6;Gdtn`as6!GvMuaTY+B;@&KSRPwv%a`ZtAY0#&E;kI@d=S zfzj_z4c`lGicK-E8I{6ZM*$Sp8}~7uodb(=UXKUgE@XKglL)>?6E74UJglPJWxq#B ztDN=(Qw)eO+S%g3D3|Q+E*^cbiRk;?M~@dSzRY=a94<}0dvP(;$6#~6;x(1KaFUI8`o z#Kch`v{ia{FVRYHg-tazBaK7RX^sHUH;=!U+SVqFu##ua5W|H0tINGw>iAbcDh>V! zIrz0c^LA)N0P?Y;iJfyT&%C@0@?i=hh6;#Z2=D39@ThU!a8t8FpS-$3jwcW{I5|V% zV4@ZvHRfeEG&v&%>zp`{#TGx5k_3A@h0@7*i%&L7V{2kaOn;W4W(N{W5*N>)!xQRh z#*X3;a}-h(cUy>#fE1liK=^TW>&K?1kiFksZRHn$qrV4pdYp;@|Naj0TV4*$?X?Xz zJjqT5u<~$!;KGE_BjDtko&`U`<+&ksD&}jM_VIKoRmmx;3rZ{`2pAbFJw!}PeP&_j zR(^oO>hOccXByGNPdFLMKeAfMbL$kLTR!2zGfK6BF#=!6@M`+c0~<3OK?R-;Hr?e9 zq(vV;PS{xZ+(`_}>2ZBqSxScQl@%7(3`L-L)Wu)6^2>666SsHu_acnY$mhn}x+N#s zy52BxxRE#-%_u|vMMGadd!H1g2Vei9BV`Y7Mht~WT_X4W)&YE6uhPG@-RE)(93Jk< z*Rx}f6)w(>S(KGIs-`Emyp@0C?CJJrV(P>y<}yXIlWyVN{o=t|og?%Ui7~3&0^YD9 zjK7dd4Sb3R-oRdQd|Xcv?=S7)+jCEx(5YirPKk%y{p<8f%S?#j{g&Vj?o@^ zU4;?QTaX~~Yml0+SfsHr(YMw9QJ2wwEmd1yjDkhm^IhiUCbq&f=OH3J_M9eKGL90#gP_x4z}wSh)VF+&duw7Q%dNeh<>-VGFq z^t`jUce{b}{d>;Kg&+T3ohk)1CcHDD_so>(LqrEOJ$_GOCbU%cO!@kkMia%O?8AhN zrc`M%IOjBf@Tjjz?uA?}uaXe!1!K92(VrLcqxn*Gh{JCQC<#==ckezwd?dlK5wGh zzLAB}uYOk@MH^v}=6?U3Ry<Zb@h?7l z{9zKr32CmlSFGC0Qz7n|Cb5>xPo3bT+T2=E{A=B*{uWEYD?@(b?2D}U#`f0dk^h<# zSZsqr&$Ne06Q^;kOXXZ4r0?WM7Tsy7s$%N&4kKBFez9RSUJ!d#b<&*TojioNua{OP(5 z|4W!xxBhqF_Na_l0DZ*ETmLP^2DZ!hUX@9)*K zVt5h-(ga~+%_ZA`jYp4f(Hqig`j|Ye_NLKm%@DOkhp8h#oW6%GIShT`_b0TV64T(} z)H@}wa6qo$>*b}Y7Z-t+*FT4&FKNpt%0z#@u}A1}nf3k|zf067WWOclG&{|4u>uv9H? z8rL$SHcLS>W`grqyipprE~r_eYig&z{}Av@YsB31dk*W#FZv{`v9`*}L{QW8&|$%? z5QPr!oE(LqKMj7$|F-LLulK8zE~S554;QV|t1IYAPfJ(nj)ept&XVkc7fX};mI41Z ze*YF#J_ljSxQ_!4908E#5}wz5fr0@x{dCZZ&Hed;_} z;ND15S7e?Qh~f!58@0Og>$+f*HDZU3YL@NrnIHj*-!IyP^8-yixgTPWf8->fhf#zF9An6`f{y}|J|cvR|3+@_hP7(LH|dNdD) zp*&B=(AEb*M$Km%_r8}oiIrlB^P!8WhZ|FV={{eHRwYG@4J;iN_NGQnHjIoBEIj@R z4jQ~MpAER7z~A!x;z>)0@80Nzyhu-+F*`7V-nuCTPXwY^UOt$i5zeoEi%m*pN`p9W zE_lKWmduN^QJtp#qnN{$7D_#gfQbP)>|Hzyi`pqoTvf=urG}$=O=LY6=Q^1ANzw^l&DXsK~Z^>$5@8Dtz zJhcM65@ALtelK(k62Pq3@Hj$DqJqZ?=^sYPywJ7LE6`v%29Yezd7sQP5~L4Od;Cb( zBk0$0`7~F~qsOd3EufvIU7CZ7phC7*tL)L-uch7R3R&&v%Lhv*9~#>YMq?BTdL%_V zy(`rUYqwn#Gkq@>a;{%{yr51N2O#ZuekP()?gMq~5{`62E3Cg;P->#=)R=Edt@+=- zy#%dZ@Dc2sYYDTB>oy)SEOH_u{e2wOar)M{n``bhqw1>ONr#@JU$|la-vwyMsW;f} z)Z&JqHhs+9tU!V4d1Gl3C=eXYVX4p|He4!X=V0UViV)yUc=Cv6$n*8fBp&gRr*C$7 zL1@BAR14sTtPlLbggGmDQik)45Iyd8J{uh^hnJZBsyU^+&TLyV>)r1y?mHDpV!|>d zPAYGK?n-$;vrS-0?I)=M`p>l~96Y&Gyb{GN1uH&=-&^lZIY|buXZu~xDw8N$fB8eu z47{{xFc_@~pl+323_3sK7tLwQ%eypQd~x}B!YxvS5DxEDTu6(F;NgHM^auwZF7bC< zo%Ih7r%~qYe6|}q3|@2+Yj_eyl=dDjbU*m_=@n(uCsNmvu94F3Z~|Ie61OOoM-e)M z#eEUi62uxm(?;9y<1v=Iw0>i`3BPK%5`z7#4tJ7#Tbk33Hu@KJ6|EaWh0w`Kj*gCr zvSUWiDIwC{331z%DUbVZ|&Y5mwNE=i4-?0~^ zX3llc_`O@a*s@;GKSnZ_9(!0_b>;5 zYDjGsx$klhVzNjO(8*frhOBK$RlJ4dMaVWi?WSu#jJ{r_yV`#hO;`0e5a})G4SyG> zL%qTL->`#)m<&B>6gW-M)6D5nb5*slzruLS`Hsl3k@Eb9)%3~Nt@5t#2x3tL*9#09 zW{|L98z+X880k?|XVC_0iz=bX=%*tXGb)m4iH;`_g?jFS~2a!pI9S3WF&%NI+be4f`-<7jITW#*<6iM-5 zOmo^urLSVkhstxi&l*1C!FYgX7+hC}?PCsshhFOU`F(XtoiW5)0i77OCMrWs>0m}4 z=z0{!@nxlNRARN-b3)HUKn$AUrSbkx9bTabHJD(gG`2dz^56Nd>toBS@{sH4>w{10 zqJMEWsp6ozVQp3UHq6#$)Ou=APsQ7g7njvhjKa=R?Z>TqJL?>LNbXn|cbJ>p6M8t4 zNoiynQHy?JoPy@Agcn(Eaj7;FdS8c*Pg~QbVrVI;=i_ zW(<`jnnnCaa$ye;_AwsCCV0Lzt;8-Q1rDS8pC9FnJ3OBr0#S$HZ^mey{aJn8-#T{~ zJ3P-c76%r5LmF~N;8jhbX;=b68U)ejyCD(6WDRl9WJ@BmDy&5OU7j61@Qo~NIQ@#l zf!`UIc|qN2jVJ@T1Ktd5=jp|};<=|J2O9Bi z^LuvodHToMdE;WM-!seN7!w>000#7Wdzn1k-QCS;d-3mpUr*_ByDmYgrPV^bP(+bJ z-wUw<*a$1{q~AI|cPs1neBk^ribH z5Do=EzL$v&cIF0F^R-YdYI&HFbl(Ly{wpUV_Q zq8#5j0eeSyZ63XDElZA{;HL0q2FBsR8*WDp*30hSRYankd(=JDKInc!1Q8w8<7i@i zM8tRakdGf2-B!|J_p2UmEi77jdHC?9&5YKqR~xjf!W!{o^T7<4&YxPlZ~a-A@OyF6 zb@Ah3YVUgS>UUZ3O`%~li8hFHcTS@Hsj1>51*y~hHs8RUybSC$_iNRGuKSdU!|nPs zN6@g~hF7qK@4p1BU1Q@jXDxGjY6AK{VVcuhZk2&Ca?vKf!1WOfg8}%U*N)m;?ep&! zqU+0(k$a1B6PJ%&j8&%$Gw%4+wLiaF79~wWT>azk_^y%$v$js2EWI@<-&P{dO{;5= z!)*j+ph(&=_3wNr1nRARM3kLuP~i_Ef65%O$#f@FogyG?V`In2supX zxaylDX-2a3byV*6(r}IID(a5zGE3$*)Iu;6aT~*%vk$iFSe`ot&;9wjbIzB*FH`x1 zJ844~P~&TA9>o9>tN+0K?eH?V0f-;b$y`Dv1DLcCa5bE0OQe4o00T@73r!p_NPARS*Ox`F4Vn;5QLrN;`q! zlW!P9O%4byNifNDc9M)83V;&v-fsM3m5N2iGd9mn)#?8O@Yw*+Z(m}-hTwCmt>M+( z*IbHMKdx4DuYX*hi$4Ch2F=MbaDFp|Q5{$94F&5MZkfr1zGHj|uH?nY*9Y(kC(?R+ zJUJ)XPs^CGog(v}RU!r%!L+ojs(>!HYLBX9f;L*0VcPEH2my>m-`u?Mu?O&S#@8JU z%QFV6C2DXHHBmV~p^7$t_Yq5vFfQ=0d7JDc#m?+W0Yfn+j(G|CaS3Fj1IiHp>@dcf zjgF)Ugs23&NW|`shBH`P>flNlXZQRXrt0bxC4MX}zBpKQ9QG>LHW%m_CBp*AW$Rx; zBIS`l0ezDJ&lhL4A!q*_z8@Uyo}B&4Ts&CXQ|f(&LdQO)%GcX9nRS4tZz3tHbqB;T$%cHcK`QUG{4%t;waFPE z;n{*SlRUZ;dUE(#9P z$B*YI2cK`{2LIiVPRMz2WkwTZSCe5qy!)=QNrtP zpW2MnQ*M};14VBX%YT}`6}d}ZBEbyq>z*c`Zd_6i*jT^Y~ntyDxh(kkBr%MZ!pP9f$Sl?D;tr!BIq0#-+l&_`$ zy!xRF4gMB79?g@#ZWW2{q4DH@C!E0)YX4?Ttc1R_F{cMLNeHdHp-S|7&AGz77rfP` ze6b#K(trIkL0_UP(hRHl9M5__daz5XwD-3fS+W)UXceH_8#CetqoWqyW1<47^sqA( zr`AxLwp`l&gy7@9BvAN#)f|msbGqE4$JwR#)4Y6xYv%SofBvk#2ff{3I=W~D1{OnYL=OlK0;_?EkQBA8dSx=C`K8VGQo{i848UAk|r4qb6A96{^Xro)DDHsxJr~MTMHCnw4&!>e2OEnqK$r#7P>L__(k)iQZg{JtZb?K407Xa6xDd-66U3Cl%A zYuK;iYnsezF<5mPy6JAi{~D1tZ0c1vhhX?A9$>ijW;tC!=joz93EguUvVSEV;<32n z^T1vR?V8yvwfuLPoHHGim{`IXXE+;l(9`9S5G>Qc;^!GO^g25D^dVrzS=fEFtLp-m zCpj~EA@-u+Im6`Au3fni#Z#FyZG3Q; z6TC88H^{6_9wy){6V(+UXDzv(a#~a^?AO1j?!ke?u+KjOo4+rP$C_-_XBPcAo1I<# zG|P4>+HvypD$=PUNSHaEwxG(b{_1GBIH8?%dpka^X>8z#^`eQsw@4%V<=pfsf){CH z_p$7e?RygcO2xMh@Bj!JM&Px>#I#?S(x8rnh%DJ>KICIzH04 zUfR2=x;_-W{%3jpX>u$#XE07gz$)WZ^8P(athoiHowTNg$NL7@vgvefOnyv!P{nBK z-{r+`79{wE(W;07-OrqXGSnvRE=|0J>??5_2oGP=rvY|i2FzNsbcj=_JNEMkgfS;k zm=?CFgGKa2*D{yVe)TT5NAWy>6UMvQMu+1-j3C7tp7+-AUo}jrN#+$B`icEc>?vYx zuon%6Kzl!CyC~Y?tp41Wu(nQ2)mFQuH6c`?;;Op;jb$wO_%L^Ip-r<8t80v7{sOi- zDKo?&1mUm7W5hG+AkOpv236UQ?8A@Np+#0JFE>}dP9=3F#%ZzM4qLhxks$~oq39UI zd7uI}+yD%4YO7a2r!HqFi#IvEBc#FlBJQ+=UV0$s+M=J48UPZ7bMR`MX!|`_eB(uh3&MT+~ZY@+(NR`B#meIP>2vv=e2Mt}#*% ziwec8)$%6;=9!q87`q5K`4(k1e@fSUp;e~$iy|*(oOmWi_~4kky_#4Qq|ui@nV6nh zu?<^`A`V!~j>z*+z4Uy#%p~Gw#buM#6RVm%aiccr`D$LaCa<96&Q_cBkMr#7tB}8S zdzbqim=oG`2Y@I{4TFy&k#D1PDMfcdG^6yLK533Gk{JpfSIiRD39~W&T zb?9YmdEmn}yY!*>cZci)q2U0?U=*B`5`Hn(4)A3gh=_<$$$%L=2jM3JK-yLSiZLfQ z_>`tqqBeOC{l&h#sZwtLA+^jlZ%l9KNEE$Jgo1hucQ8yrNE8xpU>uu>bVgAY=|;%S z`HYD!I!y*;i5l>~Pb>an11;JzB9)d;Q##IvxwuFK>RuVuP(W8jHZ5xK%`?N^!ERx; zL|ag(Rdp-Tj~N?<)?P*)fE#Hyh3pFK1MHA0Z*9cZ>ikVlC)N$Gwv?}`l>Y8gUR>&~ zfB(o&nr^jL`i>aper;mjxTuLChg;V_YinP%-5Rs(+{9fPyR9A*X3AgQ3Ga^AYdj#X8N$#1K}u z(~?~`-5&LQ3G@c@sRN?f7v*^1j&EyfpLEw8Qe=Z2iG{F1k{09WfC5~W|$GO1=y;UUaAP7(WN72=?u863 z+=rrf5P(&kWO2{app%u&06)xDo>mwduex?O_CyS&Z`@kx!ZuQ;AtxgagT|iwdNTo{ zmM-hFv;`ZCRT-1q%K4E`*c~QGvF7@yU&qJ zAD415W8-wx~1^Ri95u?tcqW#BnMtzWdfCC;w&`Mu~bqWKf7lJ!FW~zouMP5OMMv4Xw zo||hJjz8o}2&IAABB1}_qIC>dr!ppmb)~}*T6l1aG(7t=byIi(mM%J9yR5MO11)+< zj@}Kxo!0E76*o5kMlw~7j=g=@(suty(BX}m!2(GX$8}W@ za@0jfI+v*bvx^%+VuvOV{(h^gYXA4!*^;>n8}lfeOG!pFE77*&mb;jVbtp}5;iU8N zHognw?iu({`Eq0P&#Kmg-*}gs_T2~150_0(FK(F}GS33h?7|8+(2$mdUtzy9+8mWX zECyzxy%~)kPTBvh4KS=!j5{S_^t&}rhga5IAJUAP53?3O$&99W7Q zkH2TkAOTN7ZsP_yUBX~m9tOj-h!(Cpb+tDS7)UmUwlmlggYK3KlU8xehFcf@6)66V5)ruUw;DDX^8Uh811VW1@DHvm5-!S+W$F1H>UnRYGM;DpO zr+#BV3A}XA+WLNZH{7-J7>R$WDQ|P4GBI)gEvJ8{YtRmWP~z;KnBR>OfFd5>c026@ z`u4Tv{f>KN`i88n;8jp^vCC;;sS>@a|1{{te4=O{kq+>PjYN)IYZJV6u-akxr~IV zc5g>axWTCM)->PY;*0}MwudJJ9%?XDTGK-93&`zS?y9Py01_ybh=O&9ro;Rq`3M7Q z0{T#!iOgjd9!^g_D@;uVB9ujHymi7dgC)x;$TNz_`2?KbS?3?8A!5}1teDgzaG1h- z4^}7;i8&FyphPWN9c%>X(BDVTfe^C=cWMl z>l~%}ND=)dPazU>JGT) zn<4_)QgMQdruqQh(1ijGpFJ@s*?m8IQ1=l6lH>&C?5k>d7g1GB?Oaqnw5SM$0>mXG zU@=cAi7~Jo`(ZsCI$_uLi$vv1^q zZ?0u*Kv@YR=y}`vc3pc_9G@ySzm!c=cB?WlPDoQWU`T2hC`B7aY^(La&3pFlP&m?PtZ;3%P9s6LN+7Kb-^o z1daI>f9N%M{*9THs4cNN-`G;W5*Bj9r+yEpG6^}4%?-NRFkqj0G$8)H?$=Iu?8WPK z7L+&GA&U7AqRHQcH#D54I|{V=JHnNJI5=^8HtLz|(+bWFZtTraFt?0)Mc*&U2x6kd z@^b}t+URFy7YNSwd_OhB;KHD@;qK+v?qeI9Kfw+AO(_>uQs&&OERvgIxW=u)hIu`R4XQ zJr7FRp+d`Ip!onEVg?fdHxYEN7OkU=Q*lIp@PUE&s%x_X9Dry5H$a+xzpboA0vyeGY9|pWCk~xn8VWgkYw#JwCGO-9OkEqOr!a6Z7dg^WOk=LnDY< znGI8lD3pj|J!FdAZTr8N2(ZitF{DYKq#CL6p#J=?;oR`qzH0PSWC5;>A0i)L&}d;& z=$i4UnxWPasG4!V7gqsYHUm*J-1T?+X+NZPc$24R;Y-*>?^&$nzuy|yC;gU+0qvOuBf-7oJqXscd`pBJMx$3&Q z`Jfy%nLz`p^qdaNM4C=vp3GL3)uek(SUlzPJ_lA?Z4Zss!}>d3V6EAm8@6WmO&`c` z+P^ukwR0h?K*&C3?fFZG>f#&HCGtX3h++hMYJ?xVCnr|lQ5Km7M9xnBI*x&D`u z`)_$NA-BPn2lLL%KIqCODB$wwLC4y#gnxBMz}Bn7fP?+tDohJ$0oVUH)fYKfW;&B$ zaftw)1HyYDSL(=qNcyZg-Sme=;a^`l-060P`9+nkS0;vw^~N)^1K!7NXtu9I)#4ZJ zbDR%0CY<2p)dB!XM0i;VakNBHBLF4`SHGJa<1fx*FPJxLQ=kj$^{ZAdIrD z2C6EbHT`G+;WV>zBV3}WNkP2&f8Axz_8KV4+30%&=>V!^3- z8xym&RD#?$kz~|zQ9^Zx8x9EB!EkBLkB6gvdx{_TGBypKkW0hW@j@**eZ!889cQz} zqFk0^57$u@^|g04ShLl23>moLk@iP-U>j*qgkn5XMl<1et>4&z$8R0lbs4zz1V3>- zlECTo>%eoYjY^B5b>XkX#DVm!vJwzzEv|*AA)eBQtfc-DmZvm?AikO9j;4J*SzAlE z|END-GoPM02A(Kx0`nyFHaLo!1c9yInaL4!f#nt$2t{#C^>a2D7za#Zw5>ON8|NIi z-ShGZm6(LpIU=seF%*k)3MwsgYzkrc6YwY(@Myi7#%7+}{<)<&hGFnwaop`>t2t*m z=~(SB7ow}C7sY#k!icyxYZt*?i2^c=D8K(`_q)QqRzn+S?QiiIG0pmJN0!s}latK7 zf0H5SdhG|!d)1qCufO29FprMuy!k*QM0H8UsizBo%nd9OHC)N9WfE z?bp8g5&5&xg%cAxU@(=Uy=QjM2xPF)OD!sOxB*Qd8iWxA0wNlt31eFg z!KazRoe`{?J0Pg1vao^Y%vczjVK^JbM8q|Ex@9ebwF4b`#{TTV?J^z@`Fb{KV6BY+sv$(*NYj>NV`3WKmQdL*d|N%qxaAgZ8x zKxB^au)Zt1da-LZB9l0A>Ec$f5YMX*%mvn$Q+ulRtmH`}kR^~rX(FUyr@M7mT(bd~ z$53V@L;_5dm|KMqp=R6~Pxr^=8+P{A;yZ&GiGX@U<56JHqr2me{-0mneHpJ$uMcT2 zZf`wFn9~QbQ&H<9A<+>tgi|JM>nXx0AR{RprS>-5dKDVowtP_r`2a3Vk)lkH;G+n6 zn42q|)#MNU;QQ~q`PTkkEqfxCb?sp2ZJ>J`k9CY?IPEW>sJlg5qb(&mjutQO{CEUg z$Oe0mlXXtx$V4E|%ye)>M7PXfON&UR!c;&U&@ql>KJydUrf%ibJ+9*hU=VdJkT81B za0Fo8vGrxI`|d!btP_mxePQ%IngvLiH<>pVh20qAB`g7bZp)=yytXD1ktlgs9IwrT zN3iHR1{LPQ>8qV;Y6YHL4qDGgoB7`CII>5?C>J~3O%)y(-0bgNzVV&!{>gja{JW1n z`th$md^-FT4oHB;hi+A((~Ph$EXwC+I}cz|B+1Ca zxwHccSlE-NUm@x9=PzHpc-fZQv;_uA?z}rn=i=_HuFKt+FV06;E$00eWiC2pSa!%k z!xK<=5~C#ng~Ym(B;a5+fC>g2X*mvHqMQhfWIjmnlSd!F`~G`n77G^E!sKq5nSe;R z0rj02iPKd=bg+3J*3501NDvqSF<4$f`7n+B>CJj>Nze1VXMEqPwbnQ6y}7&D&6!eDwiL^zlGt%3 zCq@Fph=Cj!`3?Dz4uS*@B3YC~Y9K{6*;KRH-RyA>-?vuPJ3K=URwL(yI;kq)t>?M# z>-wJF9s5C*3pnYXnfp=>b3`P*eEIUHfB){|c0S$IXnO-@0?uo0q(mF-ax4eTX43)Za2nH@*#RvR zMM>0rzggYR{>Jk3W-b*;xK{3Nk|vo5kUkv&Mw>)JkbKn)FirD)A51C)e9f&;5(5T^ z2z>Qq(K2gY5&P&pCo-#hxCJJvC6q4+w%R z$`Fulf~;K4!=@u4p%h{_+vkAYr0Vo3OobPq0K~nwRkGv;^F^Hx%j^Z6B!&$ViP-{j z?&q*G7qHowGSUVZ1!p2*@j*^k)oh8wLN`Y%r6CQZ=@}G;K}(TxdVKNlr+@mR-+la< zLf!WEcz!9RkSMC`J&38rY-3;Q0&WbHlOV9*q1hgZIeqpH7(i4-wDKJN_IP8KF>`KPI85tQ#M2zG;ZOl1rU5)`byCD)J z3v&W6dFxF?u4z7E9oD{lcyYMB6%{0i$l;EfQdNV-n9K#-)8O*(P>a`!(=QgD7Y`vj zR=zvUvl9R`XVh119G={l-skKSL60ZUMNfB9U5_#5L-Vpcy|v-zw)=%o&!6L3Yk7j+ zF~|+vXB<6sGWTRx`K#Fj{-X`-AN3zg1I?lM1?eovSc;jntn03o!u5JLxgyIPZ zps0l4*3&{sG?5UrN&pVXZO%hg&)E6^rI{WxR6z@oQe*%CBvMkzS{OXLWfDp)g_8s4 zOmh!HAs|L^BKLuj1T@+hnMG@40-(cHuM7;tD477kh1UYGs8~di5?Q(p2cO`8SW0E$ zh)D2q(1<9arH~MY2LS%!?|wP=37#s;KHIi6hX~4jc63*f-3F!Kh^D1aL-J4<9?V$k zvaZIQ3H{mgd#%S$K7IYom;2qbCxQTpHga#Hu3|7q_@D;}N*|ON2{wa-XQVPu3y3VC zDkX+n+bc_?KYO-*@$6=MJR?K*;qF`*MdujMn-C?1g;UkCu9t0~2SzNV5^*1fiRc)a z1LtvFAGR|ih{v+j+f#Y_?QgvK)|_7d*&wlm(uWMO2 zK?-F=m@8q-v98Oq*5;jlWX`Oj;SN42S%gMrt)GeA^D+04%8GZK|jGIQEE)#KyCoI9>Z0qTh9#;juQ zHk}2DXpE6=lt5YQasaetT@f$)P6g}b@MoR7P?J$>?&2$9(x z_HC*Z1U}rB@HTDNWtnktHxW9wp+&fGYZnxyLj7_%mCBySn_HOsJH(Y@ggfB~1eHuu zoC)rMKn1vl_;q5hL`+lvQRjtK@yZhiJWb2V**a7su=-7S?C=7pv&?2 z?D>;#{K=pE$^ZC2|98*7b+cnjq(#c`3CxfC{^5teeevZN9K@NW=EPBR-*=)b; z%Tcfp6GLW1*z`GvS&VEkhPbxzXnx)w2--=D(lS_)v!*#y&A8eRsV+)fw)578ZzCTr zok_tba84Y;wA3=&ZY_N}fT$b}OU?uWQCSGB^#P(G8g&D-^U zxrOwH%Xz6Rw16^8x{nrZ%v91$NA!qrcK~3~QvaC`;s6`5dgU?;O-IjmFmYKAq^;j9Hf+e zb^y|KarX?vOlBcq6gD$uR$-r(9>j7}3iU5|`(5oXs&5j8kf>OhAw0*3+0feUkuo;Q zi2%gm=?<1aLJW+MAi;b*O}?4OyDgWQ6h!6$&Y(PEzI^rK$A9%VKmXY;=LlxvqBr-q zj}H&`Pi}2S0DB~2YSF|*fzf)^ldvLUrj)|HzhKUSrPf6c8j{0Wn{94`K#3~}1ky}% z$F!hisP*poli0TZ@<0Eh``e{3F_uW?LcI?+qeN@{^5sj;D2Jm6Lu8KO=dE8Zb@-Av z5^PLC2!L7(RssOG0B}`p`!2%F+_sj60*aIXSZifw^9(n_()LYAM&HAcP?$Lrw#(zX za@#uqVhSZ?(te3BELyJd9}!Ni$HQ{zuQMqV59`q#Y{s?b6**t`9i%)wp5b+0O7XkZ zqA#WJa4~2GAH4YDi+}i~ug;8zy58R2pKhP-pMQDt!#ts>& z47iBSeQ$j%H>XQ)=lK;LJ0dgEe0NXQVm{%kPLlZW3`0zFph#36ZEp5D0_X5_s7yt4 zZ(W7K9Kt2T&yP%!Lxcoi1PnJy5G*;yD6|lXibmMJZzY3REYPcHU3?gk!FBl*0pK?M zD$IqD78e0nP?`Bq4rxI_w%J098T7~fvyVP`=eys(zqu7;AXKekFw6juh_5&+#w0)j zjErIPszeJw78z#Dj7&*b>O#Oa!ZK9Y-5^qd1*P?7kO7v$2?>ye$OtWyfTINyF|uQ@ zE|MN_^{q*IG9UyxLm)6K1?N|n6Gdx#1H-ChV`d^FvIqnB85u6+DnO2mK}4cg&uDT` zJMX`H|98df+*>_WM%eaozU)t)nbTA)k=25S?X4wauImAuTm?iAhjmU-WO4kW!L$%Y?NGgeMWNH~X9n983tQut1i)=1mic*vx8?uz9RU zB8>F)Sl@p8&9A@pR;ec@y(uduhldCyP0wU54Ds`y{oU_=`{_{^f|xNuDx_mV72VBR zZ>c~GQYG9*-!T!xulGSlK~QD{Xk#!56AL0hFeY2yu6~3>OhAB007!;ZOpQQhLi#e? zRE4m(kq;zX2+aMGmZh$4Zqq>!2AuaZW))g(w6aq8bR&-$5FTOsE<%t|RVV`lhy&Gk zKf8^vj-;avl@bx@emb27(YEcPSXP(=m-2K`ZGCeK&wY-rx|Ujni%s_k4`W57U;rfr zOot@Rtv^g7ck0#`(TSc!Hu}Ng_sTuN-kA1&85wXzz$7F}B-zYNM6Qk*1dgMKWFO!m z#1^m*tKyhgWo0Q>V83S)(HfARSGv1$cpO7PJRmG5ur%~6zGghh4wT$U=Bgpd{i7?=jYfz$d#`1^PN z{@tJdEH4l6pfL_Wi4`Y?6e*{}Hv6fZ#-6h$0*X*kNa)jYjJUqf%n~?9-#MUgeR6y1 z+pCxx$-)4P4MVMgQ3*pmuFT3zk?!s4q7|u1l1M#a2R2zXH`}*ML;_-ZB4T1`V*(uJ zh@4sL0a%0~-Evw%iFCbo-Ulpx`&KPCVL4tpGb=MzcaP|Rk!W?vbShjUBC%(B@1`Pd zj>y;Z5HZ~xZuWhvrDWn5R{dAMa&;f(*p56bmKltPCfA4$17=pXE zgO=lI0fd)r6P1i>%NTU2nm`~HWge% zZRmPfmqn4i+4lGv#w;u_M#gjpYXhuRihX;GZL_Um8)$P_x7I342DoKfTmU=UT7L|SMR?!t&+n8zhu1oP|L>eHiStRvoT9;v63TY7=O@+c;5(RRODO^2D z2DsT$50Nt+bO;AVbZeJVv=EaJ;b`q~DaYv%3CW~I1-;Jigl_p>bY@bXpP zcf7grw6F4u9Q;*t-jK)>67-4*a1SR*VIz-em9>^?!veskxhGMrp@HFjBJhQWSB7y~xKt&hUi?xv=QZo_>G6Ol5mG_~*X&K50 z4gd&_5Lkl%h&+=p8FRL>9uNV-iHHH;|ILSwFCVH_Nd*9e2#0NNZS)9V3J4#Ss}cbW z1Q60lm@(Yq%NLKrbzPPx_jg}@@wgo1c(>*!c;5GYJ}xyNROzWZ6A)yWSte`YIkrN? z&dlUWkJ~xitJEq5C?|FS5MhUyVYn`*uOGf8$35m3AAhnxJ}6)eC(O<>!x4mxgiCKD zJy1yMDx&*&vrNbUM9)|Qz*7qDdw=%U*M9I%{@}^8Ta`+9sCA7*OB*%}VXdX$a(TV~ z>3{su=O2H*(2_ZPc0mFJCaTPH3`k$rB>|#``IO)UOdwz+K@SsV3y9%qfk6tAfifw; z&Tfv0WJh4}ykepc%pB=UEpBFg&%kV6buC)Ats{U)W^RrEDv0C>LnYxH-;YeQ!i^ zZEvo63=D83A4TvoUR$X9TKNDGB5A>2(XM9Kw zYZ74pHMPM2GedEo9RaHrM4PiQvB89J^hK$fMS!)KE-+FclL!bB0TdT90d7ubQlX*< zYXVH4$GYC|8{hxV@BR1x=3l<~&YQC&6AMC7Xk-8N-~aR%CLm`#B>YE zfVl4?(fht3ZCqvgmV*ULt>v}7CU%#`9K)O@Q;;$TyGu(d{QQ zel+cq1gzhaYwA8Vm zZN4U)5V0HrJRlZyb(oIxN^MrCP>xpaH+nPVjhV;PWm%Mzk+N`U(?9ynC%^i;_pm29 zUpQ3Q>AK$E+}#Cx<~Fwsv$5~iF3@%w6NYG2zu-2OH?xQa1Hp9T@)umm{cjBPPMQ<(_Gz%g?aw%n+XBM-dB-PUQJu)mO za_NZ)q7^V46Nof@2YU@(08e9^49JYBx@T8f>d?!`R3L+2eev=?T^>F<`fl;kZ3^&{ zlLC|Nkvv~Fv&|kp)kSbtgPKsHZN#v<1tYuFKEZfgUQrFd1Tt@JUycU=&hw<{GaXqM zs_IZwANGeV-Ug(xiqxuYyD(Re#DfF?D9>#IW1F+6EJ{A-zO{9&g=N2-*JB0J5n{BM zL1qkVrACGm9snm++avaj$|uZ7^UXGrk_vrng#=&*O&=u6Ko)dCMrDKv|mc5hV<2QKELa{O+?CAKcuZNH3I=) zI@(*`{}$HMryqaVF0VY80vHLI3X_LL_?&@KGGl9BI+u)O1k9W^3Pt29$qULizW?@H z?|kp>`4eSP5MdEcWH0C^URvuC{OJd;{`SW|{^&RF-5g4cu$g7OO|vvl$Rv=p+CT&i z<9rNWXqyjQ7A9dN$h~6PNY^DOv?k7BX(i4(vghERqN z5xllTuB(p>C`AFCC^B=7gb*U0J^&LEMTNK%J3#c_329DC0A)m^1Tvp>CFZzRWPyiA ziyUslrwNjBQN`)a(*em0(#a;(y09RN4x0gy2tXvI6s7HQR#}R!0N~-I+-w3)&tcIL z91?A2PGZD4W&oaBqf&zilt5{Mu^=H(L?PLFH^o6SIdv^F-7_KJP!G(DW0}zayXQX5 z7%F>3)(;vV4 z(Yv461^S+^&X?&vEtYzOWX954fD_G8*Lwf#{^`@Z^-yFHSOkSeACC{)zV&w5y!8UX z={Co_3^J%x1SDq8ZUe2u>~oY_rdcgTnar-NrewnH^@Hu>{{HFHx8B0+V}I?|1VbRB z4F&*-n^kjLy1On0zu-)VA3(dW<~%aACD)* zG@BV|)2l8*LZqTK5+XV#U=)Tm9LmDHbXp8FMA^KHBzxLrWrJ{MM`kBqY*)Mqln0uwh+H@clTfY$)9}Z+uxv7NZ2EY zh>J*J2OF~yrRX(&>p+>{2{GKKO=8Am0AUr7aLxhg5zNd$0xD6+my0%m@h{Jp6&xP1qd9JRFw=LGg0M~#)~eH4rx;B5B}gE z{}2D_Uw`l0->IdBP468eJ#zMe)93k;TQ5jel~o{uY{uiGKfdO^vF*@D4y2SAk&d$) zC8q%ZWKxl}l%=wp9@ z-6?}b$$al)CnQxw%t&OBa$G)z@#il;d)N1mW4;P|72`4EoN%_-fzH!jUmBIgQ(A{h zi=>*w06sihcMGZYq*A8YbOVHGIcC_Ewr&}ol#oozVS%u)y)3w#m;fYokrfmB816Zp zhb0$BjEH$S6e2)yL%rObX$JGpykn&72UJbb3UlM_gHSK!}Lu zVRIm$aur^#XR<_ha-c+XfSA^TeB>C6q*9hTzybmwahie@7Dx*pjKBzs)^Oj)PE3pp zi5UQZWAvZ_#S$mLv>2>>mArYH2m;a=`Dg#{U%YzpiXi}zP{Mt9Tkpz~=l8W#WkmuN zVhW)oa;AigbU;`TD-kObB5xxum!A80^}8>ub@Tq@%_n79MHd1TA|VzMaAagANE4+*9T73YSU3V0kPz18=I-{XFtJFj$ILnm%`t&8LYY*#C}m7a%V~uf z(}{o!dj_v-S?ce-^ZRdq_gnS;M0&O0a3GKnS4l#xi!AGhAAa)V|LaGeeDG0GNlb&l zBD?jn6aqj9gaEi^u>t`L39=^|5=I0IFgc5i5UR&W^xg|11XGIakAsWK!k!^4B^PTs zw~6XZL<#AEncp_b;a2=l{jO{5SvZ-+uFZ z-*(Q4otR#4=b!!Zx9`3CE_s%9Eqd}u-~jZ~qPNFfkBK-+p;D!f9Rne+usX;96~2C$ z0OYg3{^G?i{`wamzx%Phjv7mnXpI?m-Da#JeGXQ1?=!M*tzBB*#`)nQdW?j@G5TDRyhO*tN= za3ACI_>KAN?e(ieUC>h$rd`541OI=0l?Skhr7uUd)|EjLpRwLyRp;yplo%;OB;Ww% zX44OcgIN%9Ce49>B?DCoBJ{Qq6J;O?gG3mn1sGtK!|gte0w`g+S6Rk*EL@9fA5kb& z(&k>5Lm!c#h}Wfg5E2nRo*#**6lI~_hYFj-hi$w&?QiG&c&R&P_IW6)B))O~^pF1d zpM2-{z8eHwIg^%y3aeHLus}z~us}pr&4j=J5F%)o3!-O^q9v|?0s$f=i!paC5CERc zT%;&~3ui(KE6!cxoc@CCGxjZQCY523gtKkgw}n01mK^st3emG8SG1mj2T`JWsMx$ zn25&i94>{-ChDRhYFi(c$wH+P3P4CIz+pLF=B`@jhyc!_ZFtg=nVBYO3MYfM-S6-3 z-udqDKYj9)N-3ojrnWtbNFv%kWEzi9DKKWAohpDE4THVG8;5jl`a(>yGdc`0j} zUDf2O6_NmWSr(*ewoRKD=z4x9_Gw6jyp4Xbiy(?1Kr#apQ$QfhIo5T-bWuX4nNdWL_|mshW%NcOL{O14X?A21 zLWnD94sv$GAV4x3NMFTvMO1hxx{TImcV;1m-gW|9>Hz_Vk1>n@i&T&3-V*^F#W(?h zqf||cF`bfEF0(hrVA0vlFiA8l$WqD@W1^uD-5+i^`G)XtQ=YwXIvq~;$2Th;FRvee z@{1pR7N3;Eu{&GjNAG|9@PilY8^Ur&Ntvv|nPGDR<`@Hn5CJ9KM<60Ivtn>SxLI<# zO%XweZkAUAULp}qHvmjTRz(a&LKn9X;UsP_oUi`^hyjTNOpZX1ZjFG$JOIF45E2Z< zX5RxQN`)j#C*f0FGYNx;fPm)g%t)f1!32oGC^;RH%2IJ*mYCDGHb4L3B_^cxQVy5a ziwGCpM{Bd)Ub8lm+#se*If-zkK!L)r-g3qm|AG zN(%u`3q*|MQW!CFy3a%wo1Hn7!Dpw0wLoG7@-X)Z&Ai4cwbYRq#lQ94uRs6#&FuO3 zy1oAV@$u!0zCU{GNWL7F^S&i8;Sw;XJ0c95DhDd%&F_5s&9A+2f4Vu`-wc5uv<&)6 z6o#eNF!$ZxfA2Rx`m?{>KmU>`JlRuNi)wLivyHHUVYLVgFGaig_1sU$;emuiV$+Kf zAOb;zMHs==uAP7=TGx7zMC+qXn+!#Wh!GGV4KjQ>0Qw9T3I|IIpKDzca_*Cv3u*5I z8JG&|Y1j^cVQGe~wd3)ouE)%@Ir|u9F2vjAoZ!o%g4(86SrQNGl{vIr9jCuZ(jH-p1^T%X=g zvoXTMIT8U{-wj}!LB*r0%`x}!_Tjk3;l-2}wm-VP*e|k_Qg!wTITR*Aj0R(Z3IRqv z&HR8fc#UF##e{;Wk-|DMAYqIVF^B{p!t-)|{i~n<^5b9p!~9~` zj%Z#{sw_z9a~O0BphC#>`tkLXySp*WhRr^<3$80u;68>WOwVMDbjoC8B268WV$PmP z)51N>1AEqmZ%+lAx!Rmg)$3B7Kv`!;ty-6(o>phR`^Gmd=8KnK;Fttk+XHgedQH{S zn88dof+&JInhy^1z1LqPum2`vR3zKtrxA3v-fsbS5#uc zzVD@;q|`AiB5lsYB8b6^`#$<;nF6V^8?%hv5_pgy0@jQSCf@cPu31>nWjXbIS9L(T za!r|Vj3J_x4=CE}{LQeRJYGIRnJaq^(lQN>>+y&G?4N(*d*8N7&M1&7L`+)PeD*OD zfJLYE%qddb%raP*SZ)ppZc0Kx1~H}~KtNJrLB)-GjjOonoZp%mr!zxB>r&)yKY2JyoaWm#Dm5k@?E z8;m$-R|F=E>2}#+AFxl@jV2HiW^Da|fd~^bAfxw-ia_${PLSy{tOE?lDO3?k;`Hf6 z2tZ-Tw1huq#NIm)Ybg%q=(W~#GEc@N0v0*lEC6&k9spZi6QCvZ-edGAMFA+y9r?H0 z>%V>Z$!B+mT#pO@V}}_PSdxyVYCzE=0nWh3tvetwZD$Lj09TT$yE0;|h0_Nz6NvH> zi2#EYmIBk;Ok-NMb|E83nL83LQzox$qXE$2a2Ugmx@?yo#tC^m++jpr;8+ef$D4Yy zmZhr7`TR%-rLtKcy+1y*SFaz3Cx|e*_gPgj$!9WO0Xm-9xd@3?ULt+#yW{njzW8*h zS(p|+u&6I(M6koDRLy*H|K#rGZe7ik7(DtysdiD6`ljl$fxpbRz%#2*tYGLfxc)PIxF#>ZS&FMISh(G`^ zwF&}2kf&QrMgq!VGa?w62;B{ln0T~VND#v2S9X~2fJ~K=84)S01n%7;v9iwaL?A)S zv>3suwRCeKv^g>$F;%KiG55qI;$(9Nb`^o^_@A$chlmUZq{Fg)`oYKN$4k*-(apO^ z!5~6(%dPco7^R<7SR{cAItl_rx`k(q9hf~eltJilTb{w~d9=H?p5K4+_0PZj@RJWe z`u#t8CviYIn3HE9U}Vpk!a}S{1U78+vMMIchy(l3qZ}Y>8m*>Zqt)E}K{9~|N@a{?)*Is4>C?6YU?5o#0wJf6gtxGklv?Tl1mbRy5Gn=7 z#%WTt9*<5HqHw3b`0n@q>aYLm`OiJ%1FzQZTwb-Y|NO^4KiynEckfQ&iAcw%ePv9Ltk+S0@I}gf?P85+Wkoz9KDv-!xj#89sU>q$^aQxLxcKfLfA^JFKhIi&G5`caRSdmDxAX+G7LZux zIo*+x8IYJnECaF-RXa<~M9|Pi5GQdePlS{aOw2?PVUV`>ieCJL>&JCGlW{GCK^bi3 zy|0aIJUG@W4ZLAA@J$(z6tu>uE3D%Pd9x2(|#$*7nOtU*iqD2G} zA*KtO6$YBXV?zl^1os%U%m-fZ>FHz5rW0RY-237ezwq*lFEK_X2lFINz@-Dq?MLo{m*!YErB2q*-MF{B6xRdfiR{o-o`R5r!opyKt#R3x2}z zFWb%2=dWm5nqlib&pv9%GSA=q_P1WWdv|iETA$slZ@>4u$Iq@my?(asJBg4HW}2a6 zkQU%%Da-M&ufBB{qfIjahII!Jln4N=D$LkYl+C>xxg}X73^VI+E|NQ?x`t(M18ExYLai|PfX;y`d zzPG9ck;bq#Rs^I>O-{(eGBv&%X}Y*L>QoGq z=ZZzJ7Dx6ZN5{xg>G=njUwQb-yYKz>J-ZcR0XXgcn|D8a>A`EHBP9gsY|I@INsNe$ z2oM0EQkiwz+Cno|v^2x)wnHQ(F-WG70AyqWAyqAylpe@{$-$1#dt5)cJ>724-_JltQow>xBYE!|pld42?3onKP%~v8 zAw}<8;?slJq=)75`pNwCgO6`synE+`2ZZhhn4p>wLkPji1aEMgIcnkImZVhY2(WDA zMip^`-t8B^dH2nK{{G_+A5~$%f&kN8NYyh4GaP_`nGq!c5!eRi zAQpS1yq|6J3O!HFa9Nqdbiv++rA0yHuro$!VnLR_9<6O|-q9w7nQBe>f_C9jQ#J;w4 zTPDqHHf~Yrqeq`mlB%*uBqV_cv6dJ;h&zL`?A<{N3g4_ZIF0N{%s`@0AZ6c;IcCN{ z=m5sF`9ML_vhCeGrizh3i~(WZae&((5S|KAGLZnQR7^F)J6Bi#%m4g0-~01FKiogY z1eP(+b>DCQ>p%X3`>1t7kKyQ)%vm)rW;{-Ktcc)1nAW$`hF~H@fI^ZH3gGF(ERja! z&F%Wu&wugu4}W$0+iTgRfTl%wbZgDrk-~#nZlB$hQWj0ccK7PJswF(OHXc7+xi=|% zcb+25Gy1k8qKb-RN>#bDUf=YFl}jXLx+splx9#a%rilp!*6XKwsL5F8%A&hlj!~w{ zG7V3|oGcgwZ*j8{ybXJC>Bgu;@4`ixNs6~v3 z2||4g>w;0-iECgwGVP~L1kcYL5E3CGEX&2dueDA{-doQ^cOtCE<8phtMg$^A9K$^_ z5*$1M9FUe}*`kM!M1%C>)dhf>QyN)sZQoRhRVBrbDc@ft8qck=t1$5AHDhL{SPme!|t&6tyyP@Osw@_7QGGT z1(MBfE!Poyoeu;MBU2z52QdOUpm1T4^dZ7I&XNnawwDSP9g#d!q2ge5J<4(PU24Am zN8k9utFIo*ba^;NCNl#f0YYS99b?_EZ&-+w_I>B!XgjvkzTVQ_O9UitTjPvLdFwk6 z4GU62!R|w`xQ|lFXao)b(z=YcA1*2}j*-)}m{~@@xSA7nU)wStNAs;W1o7c8guL$0 zRwiYJs$}Mc$Ydb#Xf`cJVQ$+V89c^F`-I^8pFaL|+n-MLb~AI}n&_~Uc{&`v@YOGV z`Sq{gKOV^=11^AH{OZ^CbwAzSJo)64_uqT3-}aB5d`i$8Iu>!rWV&9V?M@UtkB}iU z#XfNyW{GYFNSUrj2?h^BD+jL39yZEU>s&5MeeuEb7kBR6y?<|-t5)H{TBXjDxdDYJ zm5CC&H)j{G&JD{p2YC-QGNzv?PKvL|~OE(z|z_G!l9zQ3@i&S&|d4edV>!zy0?5 z;d{O4o^c@l_&4uA`O5YE`*+39Cq6RB)4q`kB?Bt65~q9g*3FWXn(yu%DF{AO2#|nE zIfpcy5&@YNlH5&65UBMI%ovzKp8?$=h>)2wLqsBCw5AB9Xl6Q$9y?$%AqIel0x|#* zAtAG*XM#DL<0B)`5(iRnfLnkPDW!NI5(X1t048kP?T7FG9-SD-9BGm9a3Fsx>{q;Njf|{_NxDo;!Z>QEA=Z`tdv8WStL2 zI4RB*3)N+hei{Q!#Oa*PAJHO1vys_Z4Q@!tnUoGDKyCp@%yQ;s5GD~8LPoS06b|TE zsP$dY69^cX1=5KjArYCFA+gp45_+@3CC3;6nNaFHVtD#AEf{cTp1<(wt8aY!55Drn z*OscX_mx-x$r8iT(owJ@n0X|X>3~C+N|=Skb$?dtj4A8Z(+6T?@5D5QlL`W5;yIOz zkcsJ@kb)>8>TdgX3#5@?eZM#^S6ABl*tXS%Rn-h+nTnQ3x9G%4OrCp05GNvy-4O~T znuP~4)foI)mN6}z!h(^XetILyS|=ppTC7{u$s>C6G8L5U4j7z~t8E};m74d$hvmU@ zrug*f(==#f$aGMl*0%Xr_U%@Js`uxY>ALmJeN7L-N=gYV6@i4rM@W!ilBz2=+eJ`W z0I6;9>T6&4+yC&te(z8Jj5J#@t67Lk(I5TnU$hVo4o`4oE;)Rj<;4eAmzNs3p#(D4 zEQA1PfUe4|^`0;yMXQ;+C$XHaZ+`mIfBp4azZoAlZi<}@+&o=iw~@0j7inN)EIgH@ zN;GLn2NjuXwQW7+=@9eb&LMiX;Wzu%_C}|syW4=UbZ;v9Cg#OVm0E_O?O}h@ebD=)F@J37z?P+ivH2H(d5U`e^gzA}XiTwFo7& z2qy_mCLlBGy{pXl*@Bva_8w!_Dx&MDBfzsyZ=}wiM8pBv?QCj6CM{D%&b_V7#44Gf zb9s#RgU6r#(($Ggr6JKe^Km}@(KlZI%2&TK7@dJAkeG?aSsP0nz*4607O^ukl5!~{ z9nW*>7=lzdCq)#-^pQ5Y6M%KbH;5jo3Vn(n-@w{ByVZs0V*<`37n-eQA9SyNXj6H96%lniJ1t(8V)MLC}~D%F-A`&gbWXl2-zL9 zRGzt+hY#zJB#?T%xc8N>zkaOq)wC$FsAwt5bzggUSZkQD%nO9=+a@04=9Jefb&Kw? zuZV~c^8^G83G?9q12GLEV8p~Ms(tLIwIx_xN^cP?)8Wwjt*0emA7{0#jo5qc4smLf zhD1aRTf23qNw3N>iJ)627DDdffIU2$jYI_C03@c}U*BGT^5mnZ*H1^YbX;%N z>v7s^RjF;exj0k`xW;k!&iz8rWdyr0ETtr3OyzKK_wMm(ky5JaQc3wxssdB3Ow0%* zAd?QtR94nHk(L1H>4>Qxe(?0a{6GKghd=x&GZ99afT#yYicnJ@;bbXb?u42~V8FzE z8V0VyU^iA?w`sSXGbVUf;E9(xej z2nu5i1WY8ygoNBJ1EiFqlWGOP-aBU7_EqZSZo7G9!gNORgfRwy5D@^F+4-LnAawVD zu-?U}QYDmb5gBc@QmX?ZqS*is0ANAS3`Er$V35Jg1Kcu|DCit!<+ES=`q}!sM~_g{ z0{}|2tO=4kt6Gz>SIlWdDzZm%IIuB?`EbMvgr3Bb!;-^u0CM4)GhN=FuO1%w?PYyz z5wY34oyrOIG0)))FD1Oe(;Y$SM#45;zAHwcf%)nbyA+rFcHgAMy@25RLW9)*mC!3+g7t)SkFWg zWMzWv+wJKzUo36xOvubk?1as_q4hCF59DG-Qm171Vkq<0wu-GkY!l5=H^L+AavVLNJyeLPuHKn`Rkv4|KGOj z8@Ziw5RbDj6C<$)SR24z=91I|y{52N)J0)}!3=;1W_Y?b_q~YsKDN;iT+=OgN<;9W ziA#d@w)H#9(Q@40-i)=SDl^-F3tn=|o2Of0b;5c$^pz=LD$9OawH85~FXp>1Ufp?k z_38Bof*Q8wCCQr3@chsJELsCkdWQ zZ_hpd;OXNV=A!i&nKptMr&`@QC69q=kZCN5i43K?5y=>hBEnJtEr&+{u?S`iChx5= ziEx2H02tP}a&zn9q!W0AhZDqvKi;;V$NB_0WlBq}0-Rs^(igt=^)F9T834%;n8ak@ zh=c&{rlpu!BBRch!DyqWL!u;cU{Y9OK=(G!$36^cVn_lcDdrXsk)42vgc*cif{@4=glu3ZFiXRlp>$q9Nn!vF%iek-7AZvBogtYdiprECR_>0&Lp;9X6D0v- zdf&{Wxd`da&FRe_{p{J(Mm&Y(;p))at!Qcc=++|ovK(9MfW`s_Of-3;bTHVbI-UB? zgq(uO1VOZ?bpi$uvrLF!bR{Oykl0x3gc5sSS07a1czOBx&wc)Cs+Y^M%o7#rF>JRM z&6@kx?e>PoUNf>qo;m{f?Kbuk+^%K!eiK~~VhH9i&j3vH-Ve)SZS=mYata^}pcGa} z1|Y&Rdh%cVs#>k%j7f%w=ME`K5>7_}UjP<}{u6Kb!C0h9iO)C5c@tB4()= zAGL)BL27HQ)?TeWY7@k2l~8+C)u>f!tJ>OXZCb5O?W(;go_v3J{)60kz3%J2uIoJC z$5Gy^zL~EC>cj)Oghheaj2`Kv{e}ImH7oGWoBu#Gv5BFZ3V*S>K3T-k@&5XNwb_YO zl7D`*%-EjYlxT7)Dm&b1U6im(MjuZ%Zdt#NAu?IM#YM6u!?sBSC!^v2TCWeQJ+4xg zI=>e0&;7J#cY=TT=t5s_Ij7bqip`}D$emY#7bK8>df zKFge@D3ll@JFg)zt+|PwNDViPq=E;S3dDH_RnE~G0C^?r;H*hxnTcHlIzkNa8~bQp z5sHitqEXP3rDY|N^&*#zlx%No9WBKR<23BVdc2TnO4cdf7l)3m@1L*K2Hf+v-^EeA zw`oY#uWf(u`;bMM{3l6qTh%Ul^xJc9VQzMM+Cn|-_;fF}qpJF&c_Jef%V+keF?oHe zyc-v6N-wSLi2^S4f*@d1z2py0rGYdw$W|KY$N*JM1_0J^PB}U?1rz8$Ap-blRtG?l zFBUwIfLS4;KOJmW8wUPcU!|JA&hVcLyhB1CGu@;F)zOkA^jN|t+b~2sa_Utr$N$(a zoSmy8!BHFp2929?q6l7*{h#fpKki&D4?hY$OUrl^;Pp;t^n<%nqs$C17PoT?u}M=JULcNf`$X_ZQt?Cpj)MQDZ;ZZZOpDGrv2l}{`Awji zs8ZkCgPab_;hU9PoX%&J`Ucbr#LtnK*SjM1fP zm%TmlMevpKTvNnX>yiQW_xC^epVZ#Bb}7s=Aguh;dD^CuSITZ=+B+*{GyOsHan+`2 z`1Po!$0bPvd%b>#bm|jXRdsHy7~MnV1a4luP91Ly{;;Ls;2E@tB(p_#Ic^@gtmz9n zpk5Yye+$vY*uJ~VAw%$t)1?QbmkGJq?s?H#)HUENM3LVS7G-K;_@et&@AvJ^(A=cg=&|neF!{Rz=^MWq z9m&BY4IVu2)~2bF&)v8}$Y>n)TQ|t2M^n~bo;oeTpg+Mn6!}CQ$l`zz0CA_sBp`lV z+|Fj#59kK*K%s_y+5d%V)+EGW5w$NQ(l;L5Nt&}fNm93cM?X4%U*@p7oZ<-I=W3G$ zy)O`ugbUcK!DtX4UbN@W3P-+GgSszZG3zl4>j2&?ZcLR&K0Y~Y!dn&zqK2^G7Ojsp zLZ2U9PUdr=n4h45L7(sKG?77_3>l?*@tkpqvar?{CGrxyG>Ae;ClEjUhsN_khN+Mf z%FeoBON_5Aa3*Gl?||z1G;03e@|NY^U;iY}=QZ0}&f5(`ZT@#&Jt-y(-b8{Qs9FP0 zlvzpTCUUZ5iLTs)EcOba%$*81q5&g?sToRfl={P$-Q}epJtQqsj`&PVKa@HdU&yay z`|CAR6DNie`X+f)^~v#NN#4lKMwX^aw8Q+##IZJk9bs7kN*mvB%>HATKE72250tg` zh9%?DevS)}mej3{Y&jEZK>Uc95Riz@%6P`U85UVu@rR)QjD-Wbz0KD~t`PtuV*NPW z$um_x%!ZAhyy`r5G0FXtDw{T@N%^@#T>0P3+M__yo0s(9li?! zYCK&zQsnLS2oQ-^4h*^sCkgJZH;2R7v(#P}J0jmuLUiKkN|Uo~bm`UY3C|IXP(uz5 zUdYnAnAo5KPmM0|Vf*!Jweq?B#T?Jhe9&3+#gXaESLvIXsKA7r8wQ*97wwL4^7Gv} zDgnuFAK7cM0nt%}j#Q{kCIqLOJq5v?Jz%Ig>|IL9%sgf6X6JcX7 zP@uUzJ!rh@Vjk4={sll#!v;x@OW5_n^+^tD0OX|%Y>^UhI2_pddZ=+Vc4s!B;n-1q z^5Pjgh9B1I7vFfYxy>PAn*id;($Y#~BMg$?`^D=|XZllG`FkK@Hz9M=*Do-TbUZoX zDdE#x-#1aGc<;==o`LzSR$^{8MVR0_goTt(^Gz9^Z3g{Jt2?QQ2=A4cUQsboDr z9DOcnUx0%47$UkmT|K%}=!D)Hch|IX5XkL8ssVN76pH$z9xTdUUXAXAo#j}C9IktLh;^^3eTkasP#}er0c+l4 zk^O4KyJism%(z-(3daNIP^5R^_aI2#;9{Qt+~uOm_375D_KUwwdW%7w@-tYhoh$&j z@?ky&z&Lhhg35n?f7#qrgdY5kECt%UquZ$_6sbNr72hqZd6=GgO%E%y-&>bK)%z zgo{ryGWr#2YN$t3-yTTUVG)fJUv>>2Z;EweitYd&2(a)Hkdh^F(t6+MR5riz@>wz= zHY)ueCi-x+w(!QA1?>3U*VBa2`EC;8&4|*7h}{`Cs)12pWkFOS{AbdQIr{U_tt;A7`E^9+B;NbExW&IGEY5Jqz5vZh>6gwg4T8n)CAN7tRbI& z(^XR7GnwI8p7}$;qW!*DO1{AbFWL*ujN`9=Ep7-BF~GkdL5@=A)&gNUN7`u!XBV9e z07!HZK~rWDqg69VtB~q{tE~IKeeQ%Dy4ackW3XaOzj98j+Ag=luk@~WPe)%g6)blb zza1!U4y3%RX5e-~2?h1OO~1$NlL_}|dcrKMe(cs`ygD^o<}D)EfA7R+1c_Q(L1U&} z6!?-9KbV!Ot)MP9NZ*>N1926_xx8|OT^=i7e|s{twLNCyd8^x|>{k2K`C(A*yEiK1 zi_QQ2x8&=HENmHAAhWsnpl*+ha|ZBxQnKbr^3EU>rOuu4tM8vAS13Hdevc&sN(`DJ zMzijktcfK2eb=2|lARUY`^*{BKEODJTfuh%<$lViZ#Zpk>5a_YlKzt``Fx0U=0E$B z(Qz8<@$u?+zxYGThhACVd~pc4ycGup)@+#C4W5eN&9_F!6XJ1_WIsW$GNiUTx=)Bv zf;ahLc|ke=QH}w|6Uo0uLjl9f=X8BoF(I1qqJv6v{WMcNKNliC>}bg2dVA;UD)##F zo^!9Rs1Rwtcuxvxjo`ZrA}l%m{*B^^vuMc-mDSU&CB3Vjzuukg zZ2VqJC}jUI`62!#$cT6pv)#f$@1(<)-h)yt2@3S{D38@7xnoYpo%pErc~k2=HOy9$No@uRJ|D)BG!ViZ|QfMG_9IL+J*Wz6?4rwKunT68$J4MJx( z)-@5pN!F_vVrmL(rU3H6VC03t8gKy{$L>I(8<^Fz5p=!K#xQrjG5jjz z(4ZJnVna?XMmd7M!6eUzt&_=!+#TvP7~Si2brr5Pd>f~T52EjOrPlCf-O7Fw+faWLldMN4XVBkfEzj9q(&~w zF0MQg4?7C~cM^X2ApGD?b?8z*N=nzH;*lk{#XQME-=rLHcr~YoNnm6Ba=v?3(fYt4 z3+Ks9h8UQMUUVgo_QV539OHzN@tB_2wbRSGFW09pdD_qP=ED!GcTQvN_MWS0E^FZg zvI)-uZx+(t)X3l1uO#JEZ*@#~UnI}U3<7K?H9=rjt`UUNU@D2>=!f%-8lTdg{;zy4 za92@B74WI=y^C#f%O86dLeR(H>Y0|C1TwF{z&pT`hBU)jBb_}7(@DPSS2M19x|>TD zHM#x9SP1zDJkN~2pI6CB`TJTiry+%Oau8byqf-haBdvOnaEO=RuZwil6D1I$*4qHB z?AAIFNarIZ_6_5hN0BwgM>bw3Ck?ZP|zHUE!lWBW|91b~QU{H++4ag-}6O zuO1qyIT+G`>gK@U6d3zHT9%Q|T2t+{U8KJ1+CUJ+!7Z6K#c!(gX-MNCqYLb_Bp#K^ zi|hS)5|jTf@X9q5^IrZ9Kl^qRzLb0=|1Bp&g@$lIM$yyjdB8CgVqQI(! z{-Of_En~&37DNV8QqPlX)%Y82b^HEj(i5%B`LGK28*0X=v*a=Je}Qu>9Z%?0Y+Vq{ zQ(h-=Hbvf;Vk<67eH3Vm|Wk;_|oFD^%F!0yKYVkxsaOY)!)@Ul?Eq|2h&dwBfs2c z`*^sKcHyem#KPwg;JGL6_G94!NaiG>-6 zK*t;ubEk|KI%)9QU;uz3kS{tJfWiUv7Tkv5NA6_*=c2``3>1^gDq;h$FMI)I$1(BDFAW1iv*r zK+PJ2wATmG+xd5;dIAIV*3uQ3*#T+hKp=>yD3o{ReBgH1 zt1E`SxYGf0rukh3nikHAqvCcGMNA zbF`n;&0|~bCr{qt%Wa^ho8}WTY92Ds9#)=t{-g0O2=eBOvsasFT@npF-A%I2^<`Z< zy-#P&lQK1`$uH6&Bk?EidB@t9(%a8bU#I;%6r%q7p_QZ^{qx>*iO4wRld?}zUH3kS zW1q-4F?9X6PXZO*3wBo+l4^6RG=H*lsT=FG!0TXE=U|xP&`|lb=PsQum8x=4gvMI% zmHL$`F`TLM{rJ-3KKptXysFl9wJ{s((S9&7dv#k$&QCMopnGN8 zHv85yjSoN+BV*pCJ|mQD(A7D)#?JTA3r?wB`}ZIBK67*gZQbE%JNmk}p*5BM9u3FX z!uw!ZglWn#GT7ZQ=RQ&$&r{-F!f5NHBw+Lh9h}oXvUq;AP*JF#vY#c$-T0S9rKZAZ zj!Ow60ZF!URxC)Im^Rk`~0-#RCVgvpd^FRDmVdk@Rp-kkgN z=TYNLt|SYC)LkQUhB@ciduJh+z=z7;)GC^!(M-K%#{PHueP)&5HqKTCX!vuStgRNB zCvJgoo1g|xbIrAN*rk3?_6pWysjcRS4=jilvDhj9)HR`zc~IoH5i2DgB@lnunVbcn z)7myD5&mboHg34k@aDR$r!?b%-j_KDEm&~Cr2V9AM=|J3)f;19StiO9cr|72quu@Y zO;VXVxzr@~lNjGn81P^nx*)98UAg$V5<{ZJdkTO6yqu1ff{`GV`f*i(*2COpjt?P{!2vmY+BvSt1AnOt zKGw_ZQKkzG;iFtkW)qP8+#`CMZj0G#1`ojYUlXd^PsjMb-G74EcP?~5gm9TyIcN^bRoUGyX7eEQ1=_{awf<+W3wjFg}7|+O)e;zRfmLbWst+l=h zw~}#9cxlhGw9#?&aCk+1)x6EhI_;;Vbo>ByN;b;D(pL0%tREQf@2aKPn`lq+>35)qAwCHr@-K)x)8OC z0sB{9!Y_WR{QHy?ZU$juq%M)Hde=w&TZfY<^s*D9c4q*{Bq)VLQ;0zUNIrT%)U7jA z)M(GRFyG8etvjZAEKL_HDjmn-{{9y#*MBOk+MC}mWly*GRTw7kS>|Nnou+u9!d@4L zfq|z$tBIY^9gCgN-JvV1u(1%pxB}0|qp^#QgQE%$mN~HJJ+-?#e{=6@I@_iQsQQQ~ zB?HM#B`Goi2wQMe>n&P=AidjUZ;Q^F(E- zPwSsRpIzCwaAx56WT^vbdR!4kjS0$4=0sJHl5z_up$S5g@e|2n=r&@ZH>ibd9QKg! zS?XA6*jLbp~6V((g!0=~`4&u?~HS3KvPdDQ={$~92Ykf1U z9QJNj-^Z;#xFgWNwe6SdyG}ch9~sXZco#68Jnf(8DU|Qk*)-HmY=G|Rx0<3B+(ra- zHhv3G?C7nr7jb`y$YFrJARIVwc|)Vx+sx(=!jtsZzL zsPQiU1`#SD0i*J9*0Rx5JE@r)&x1%H?BW(W*SAfJR{lIz(v)O4>Dhb7^vFU_Xx0;i z^pUJfZSdFM&b(;6Z72IWBC58Sd~tV?T?o&K`IOW`Lw*I!i5 znyzObJUaXA+Ymwh27d2j%arQkow=}sS^x0hshzKvL31-5zm$SxXJ>NaT5B|Y)r_kE zcp?Cf0N|Y(CTH-ulam(QD(B0WudWWBkdpQ4@PDgY0W9_2Ukf{<)8ZvL;S%v!;G(oH z_^I4IMjhxk%O^GrcalJIfAxeYrN0d%D+hhCr};YiG_CU-iMl0v(aI+KRc3tVsfE;VdiZ)NWH%mfL^ZgS`ka^AQV@6-#ousu`v7+nV=13|HzIKH17v|1`0p1nhJ4Yja-_M*e1A zd8U-5ML?>9QKT)N>~0+kJLY?E6pn?CUO!-OuSey4+n+SqH5$$2+XOPHs@!<0IA^9{ zvnj0@6U$Ckz)(--zWz>Qa}NV(t5(Od@ltleTEDCw$SMNeNKef_R}Tm!B_7YGR`f$`=q(lg|rU)HFOD5y!`ryB%qP`5W$0tKzM8rWM zlZsf!`I&gw#pa#QV@&F3r5dNFCjc<;_BRtwtOFH14h!CPoZwS{S_9R>+KG@JJ~B(s z_7CUdDi?JgZRcARgR57AKaM^LNb#YT{u%qGYXKv#d+uDhj)0^Yb+b~2*npqeQb{ON zg6F$;*2$t<^^)UkZ;~Q#<|3v=QNiby0$Xhc3_7Zigv+Gn6sk3#-;B{eWYbhe%$~iUvqg-!j4TT8hU`U zXga&P6c1e^>B;A>hp+dj!mm6Yo&F}Dd@O`k&9`rV`}TBkT(BeTB4b$jQos97B*VKq z4DZ$|Xx}mNKZWY6JF1~EkE_a1Xdn`BY8Ef>XCwV|QSepUaozQr)z!w@&cA54CBNt4LHwDbLiRn!9v~Wc6u}jcBnY}oA&T#ut2;l%nvbe>|isazp_81({<2OGomEmAe7cF(<#jzVYDBV^^t{MF~CcO|of z+xu5-tSNq#c1klZj^4sXa<&+@j^UI`_4PgZt~Gu)-8gqXFLpw}yo7}a=tKrC3EW#* z4Edd(5RnQ4r{fWQZ_A(cVi#Z|~Ou=cY6eVUlyuX>E z4Qp_wPV!GE^;Ckd!moZ$7kznqNx1y9B<1Ps?!0{XpbR$baPf~aMj~b2mmly zvu^iB8`(?37-ENgRpH4XUylZGQI>z2EqDC>-jtfkdYI7I|OdWlpVI;P?zkLhA_ zCYQ5$Bb_nO-2NdTtU351%3tkeTE-~mXzz{YOA)%eogf?z1jpJ)JjdYTB!8fj>Rxju zN8Dmn-6x{aN_#x(;c*h{z`q>ltH(2X zpSAL!zQ6CD4YLLU2}?&UV9>kR^hhNBSCEqfJk<~^Br5rvlTw>*H(~>@vAwn*Tlcz; zceo*s7${R0`DJ6{s#N8CO>ifC!O@+C&()7w>??C%k0qH%3fsy}dGk+ zX!C!ibWtPL#IbU5hgDqZ!^uLlm?!x*)Y$La0O}6MVm@`lgyHvDNY_ASa%Q|u_=nJg z7bju+dLIA&YI@AI`}ZnjXMeZ$rXs-)qslpc%cV%D#n1fgG$%2a$1)ARaHOtnCszF^S5UW?oyl-$=0WU z`?-$dMm6;|1c!%|$pxv%KUv8`bQ9@EHBGITvoDjp!$s1k73XujoX+5fG5*ht8tWS( z6c{~$0U};d)z5%~ddxFx;p{93$pfulp0CGH#XdHv{CI*~3-*FAQ#6uG)|MpsWA3M9 z{2I!q$!Gh&Zm#6nmj*gEtGhKwP9<-Mff;CiXelXww*7esD1kHneTma>b@+_57 z`q?dgkxh(bR&=bCk-*!>2mlbmZcy-ch(#hMPq)8i9WufEY~!B<_y$2vFmViuQQyl1=_)wJ>}WBik&!h@Sj3lfs!yo|#TBUQ%F+Hfcy z)At)q-eh+$7Iw1#dIta2c7WnJjdkw9SjXw7&G3Wp%TR^$pr30lQlbnx2LpA&%qgVU zI>~u@R)9ApC7K*wD@b2PaB|W%T%^HrN$|#_vr>g;Y%}pwH&ghj9KO65qM!ieoK$Qb zHHGgmgsqLTim&SYkXJ;MJoSK^s zfg_<%Wk{rK!^kdwt){0b!9oLwxA+k8f-Gw>ml(=fZ@UviVrH|Ug3z|Yh81y4GIOQcV?D zY1swKqq*19iAr1wO#jRuWCi`jo+IwJS^#y%nm%4!(3#^NP z3kujxkb06J#jiM{z}rGaP0k1VxVs+h5q6zc9k!*D?J4KBz2y$}d-(Tyhn21lOVtP3 zY19t8esZ$Vf1*2Y_9|pXB|s*BChYh)c1}g