From 44bf748479730ee5cc368b9df79e262974af0d6f Mon Sep 17 00:00:00 2001 From: YashasSamaga Date: Wed, 2 Sep 2020 12:18:41 +0530 Subject: [PATCH 1/7] do not allocate UMat in non-OpenCL targets --- modules/dnn/src/layers/permute_layer.cpp | 34 +++++++++++++----------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/modules/dnn/src/layers/permute_layer.cpp b/modules/dnn/src/layers/permute_layer.cpp index e08bfa0c5c..e3129556ba 100644 --- a/modules/dnn/src/layers/permute_layer.cpp +++ b/modules/dnn/src/layers/permute_layer.cpp @@ -174,21 +174,9 @@ public: computeStrides(shape(inputs[0]), shape(outputs[0])); #ifdef HAVE_OPENCL - if (uorder.empty()) - { - std::vector orderVec(_order.begin(), _order.end());; - Mat morder(1, orderVec.size(), CV_32SC1, &orderVec[0]); - - std::vector oldStrideVec(_oldStride.begin(), _oldStride.end()); - Mat mold_stride(1, _oldStride.size(), CV_32SC1, &oldStrideVec[0]); - - std::vector newStrideVec(_newStride.begin(), _newStride.end()); - Mat mnew_stride(1, newStrideVec.size(), CV_32SC1, &newStrideVec[0]); - - morder.copyTo(uorder); - mold_stride.copyTo(uold_stride); - mnew_stride.copyTo(unew_stride); - } + uorder.release(); + uold_stride.release(); + unew_stride.release(); #endif } @@ -276,6 +264,22 @@ public: if (!_needsPermute) return false; + if (uorder.empty()) + { + std::vector orderVec(_order.begin(), _order.end());; + Mat morder(1, orderVec.size(), CV_32SC1, &orderVec[0]); + + std::vector oldStrideVec(_oldStride.begin(), _oldStride.end()); + Mat mold_stride(1, _oldStride.size(), CV_32SC1, &oldStrideVec[0]); + + std::vector newStrideVec(_newStride.begin(), _newStride.end()); + Mat mnew_stride(1, newStrideVec.size(), CV_32SC1, &newStrideVec[0]); + + morder.copyTo(uorder); + mold_stride.copyTo(uold_stride); + mnew_stride.copyTo(unew_stride); + } + bool use_half = (inps.depth() == CV_16S); String opts = format("-DDtype=%s", use_half ? "half" : "float"); for (size_t i = 0; i < inputs.size(); i++) From 1df533c914c282f4c99d42307b9ee3b86df34caa Mon Sep 17 00:00:00 2001 From: YashasSamaga Date: Wed, 2 Sep 2020 14:25:36 +0530 Subject: [PATCH 2/7] fix typo in fusion tests --- modules/dnn/test/test_layers.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index d61f319f54..f9b0f62379 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -2343,7 +2343,7 @@ TEST_P(ConvolutionEltwiseActivationFusion, Accuracy) if (eltwiseOp != "sum" && weightedEltwise) throw SkipTestException("weighted eltwise not supported"); LayerParams eltwiseParams; - TestLayerFusion::makeDefaultTestEltwiseLayer(eltwiseParams, eltwiseOp, false); + TestLayerFusion::makeDefaultTestEltwiseLayer(eltwiseParams, eltwiseOp, weightedEltwise); std::string actType = get<3>(GetParam()); LayerParams activationParams; @@ -2353,7 +2353,7 @@ TEST_P(ConvolutionEltwiseActivationFusion, Accuracy) Target targetId = get<1>(get<4>(GetParam())); // bug: https://github.com/opencv/opencv/issues/17945 - if (eltwiseOp != "sum" && backendId == DNN_BACKEND_OPENCV && (targetId == DNN_TARGET_OPENCL || targetId == DNN_TARGET_OPENCL_FP16)) + if ((eltwiseOp != "sum" || weightedEltwise) && backendId == DNN_BACKEND_OPENCV && (targetId == DNN_TARGET_OPENCL || targetId == DNN_TARGET_OPENCL_FP16)) applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL); // bug: https://github.com/opencv/opencv/issues/17953 @@ -2440,7 +2440,7 @@ TEST_P(ConvolutionActivationEltwiseFusion, Accuracy) if (eltwiseOp != "sum" && weightedEltwise) throw SkipTestException("weighted eltwise not supported"); LayerParams eltwiseParams; - TestLayerFusion::makeDefaultTestEltwiseLayer(eltwiseParams, eltwiseOp, false); + TestLayerFusion::makeDefaultTestEltwiseLayer(eltwiseParams, eltwiseOp, weightedEltwise); Backend backendId = get<0>(get<4>(GetParam())); Target targetId = get<1>(get<4>(GetParam())); From 2349a097365fa77ee2d4a7dccd86e30f350fa2a2 Mon Sep 17 00:00:00 2001 From: Liubov Batanina Date: Mon, 31 Aug 2020 12:52:55 +0300 Subject: [PATCH 3/7] Support Reshape with zero dim --- modules/dnn/src/onnx/onnx_importer.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/dnn/src/onnx/onnx_importer.cpp b/modules/dnn/src/onnx/onnx_importer.cpp index 8cb2c5eda1..153d026e4b 100644 --- a/modules/dnn/src/onnx/onnx_importer.cpp +++ b/modules/dnn/src/onnx/onnx_importer.cpp @@ -335,6 +335,10 @@ void ONNXImporter::populateNet(Net dstNet) { inpShape[j] = tensorShape.dim(j).dim_value(); } + if (!inpShape.empty()) + { + inpShape[0] = std::max(inpShape[0], 1); // It's OK to have undetermined batch size + } outShapes[valueInfoProto.name()] = inpShape; } From 1f2c83845d77a4e47adaed0d868ceef368630520 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 1 Sep 2020 22:18:20 +0000 Subject: [PATCH 4/7] backport: checks and fixes from static code analyzers results original commit: 71f665bd8c3e39d6769aca1896237f836930f136 --- modules/calib3d/src/calibinit.cpp | 5 +++ modules/calib3d/src/calibration.cpp | 14 +++++--- modules/dnn/src/layers/convolution_layer.cpp | 3 ++ modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp | 2 +- .../flann/include/opencv2/flann/result_set.h | 5 ++- modules/flann/include/opencv2/flann/timer.h | 1 + modules/highgui/src/window_w32.cpp | 32 +++++++++---------- .../objdetect/src/cascadedetect_convert.cpp | 2 ++ 8 files changed, 42 insertions(+), 22 deletions(-) diff --git a/modules/calib3d/src/calibinit.cpp b/modules/calib3d/src/calibinit.cpp index 863f480b4b..8b857a347d 100644 --- a/modules/calib3d/src/calibinit.cpp +++ b/modules/calib3d/src/calibinit.cpp @@ -791,6 +791,7 @@ int ChessBoardDetector::orderFoundConnectedQuads(std::vector& q for (int i = 0; i < 4; i++) { + CV_DbgAssert(q); ChessBoardQuad *neighbor = q->neighbors[i]; switch(i) // adjust col, row for this quad { // start at top left, go clockwise @@ -1271,6 +1272,7 @@ int ChessBoardDetector::cleanFoundConnectedQuads(std::vector& q for (int i = 0; i < quad_count; ++i) { ChessBoardQuad *q = quad_group[i]; + CV_DbgAssert(q); for (int j = 0; j < 4; ++j) { if (q->neighbors[j] == q0) @@ -1328,6 +1330,7 @@ void ChessBoardDetector::findConnectedQuads(std::vector& out_gr stack.pop(); for (int k = 0; k < 4; k++ ) { + CV_DbgAssert(q); ChessBoardQuad *neighbor = q->neighbors[k]; if (neighbor && neighbor->count > 0 && neighbor->group_idx < 0 ) { @@ -1716,6 +1719,7 @@ void ChessBoardDetector::findQuadNeighbors() int k = 0; for (; k < 4; k++ ) { + CV_DbgAssert(q); if (!q->neighbors[k]) { if (normL2Sqr(closest_corner.pt - q->corners[k]->pt) < min_dist) @@ -2090,6 +2094,7 @@ void drawChessboardCorners( InputOutputArray image, Size patternSize, return; Mat corners = _corners.getMat(); const Point2f* corners_data = corners.ptr(0); + CV_DbgAssert(corners_data); int nelems = corners.checkVector(2, CV_32F, true); CV_Assert(nelems >= 0); diff --git a/modules/calib3d/src/calibration.cpp b/modules/calib3d/src/calibration.cpp index 052bce1170..710b1d7659 100644 --- a/modules/calib3d/src/calibration.cpp +++ b/modules/calib3d/src/calibration.cpp @@ -978,9 +978,9 @@ CV_IMPL void cvFindExtrinsicCameraParams2( const CvMat* objectPoints, int i, count; double a[9], ar[9]={1,0,0,0,1,0,0,0,1}, R[9]; - double MM[9], U[9], V[9], W[3]; + double MM[9] = { 0 }, U[9] = { 0 }, V[9] = { 0 }, W[3] = { 0 }; cv::Scalar Mc; - double param[6]; + double param[6] = { 0 }; CvMat matA = cvMat( 3, 3, CV_64F, a ); CvMat _Ar = cvMat( 3, 3, CV_64F, ar ); CvMat matR = cvMat( 3, 3, CV_64F, R ); @@ -1199,8 +1199,9 @@ CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints, CvMat matH = cvMat( 3, 3, CV_64F, H ); CvMat _f = cvMat( 2, 1, CV_64F, f ); - assert( CV_MAT_TYPE(npoints->type) == CV_32SC1 && - CV_IS_MAT_CONT(npoints->type) ); + CV_Assert(npoints); + CV_Assert(CV_MAT_TYPE(npoints->type) == CV_32SC1); + CV_Assert(CV_IS_MAT_CONT(npoints->type)); nimages = npoints->rows + npoints->cols - 1; if( (CV_MAT_TYPE(objectPoints->type) != CV_32FC3 && @@ -1221,6 +1222,9 @@ CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints, // extract vanishing points in order to obtain initial value for the focal length for( i = 0, pos = 0; i < nimages; i++, pos += ni ) { + CV_DbgAssert(npoints->data.i); + CV_DbgAssert(matA && matA->data.db); + CV_DbgAssert(_b && _b->data.db); double* Ap = matA->data.db + i*4; double* bp = _b->data.db + i*2; ni = npoints->data.i[i]; @@ -1231,6 +1235,7 @@ CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints, cvGetCols( imagePoints, &_m, pos, pos + ni ); cvFindHomography( &matM, &_m, &matH ); + CV_DbgAssert(_allH && _allH->data.db); memcpy( _allH->data.db + i*9, H, sizeof(H) ); H[0] -= H[6]*a[2]; H[1] -= H[7]*a[2]; H[2] -= H[8]*a[2]; @@ -3828,6 +3833,7 @@ static void adjust3rdMatrix(InputArrayOfArrays _imgpt1_0, double y1_ = 0, y2_ = 0, y1y1_ = 0, y1y2_ = 0; size_t n = imgpt1.size(); + CV_DbgAssert(n > 0); for( size_t i = 0; i < n; i++ ) { diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp index f8ce75a824..ddc318def2 100644 --- a/modules/dnn/src/layers/convolution_layer.cpp +++ b/modules/dnn/src/layers/convolution_layer.cpp @@ -546,6 +546,8 @@ public: std::vector dims = ieInpNode->get_shape(); CV_Assert(dims.size() == 4 || dims.size() == 5); std::shared_ptr ieWeights = nodes.size() > 1 ? nodes[1].dynamicCast()->node : nullptr; + if (nodes.size() > 1) + CV_Assert(ieWeights); // dynamic_cast should not fail const int inpCn = dims[1]; const int inpGroupCn = nodes.size() > 1 ? ieWeights->get_shape()[1] : blobs[0].size[1]; const int group = inpCn / inpGroupCn; @@ -653,6 +655,7 @@ public: ParallelConv() : input_(0), weights_(0), output_(0), ngroups_(0), nstripes_(0), biasvec_(0), reluslope_(0), activ_(0), is1x1_(false), useAVX(false), useAVX2(false), useAVX512(false) + , blk_size_cn(0) {} static void run( const Mat& input, Mat& output, const Mat& weights, diff --git a/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp b/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp index eda2e837c0..8de7ba26e2 100644 --- a/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp +++ b/modules/dnn/src/ocl4dnn/include/ocl4dnn.hpp @@ -433,7 +433,7 @@ class OCL4DNNInnerProduct UMat& top_data); private: OCL4DNNInnerProductConfig config_; - int32_t axis_; + //int32_t axis_; int32_t num_output_; int32_t M_; int32_t N_; diff --git a/modules/flann/include/opencv2/flann/result_set.h b/modules/flann/include/opencv2/flann/result_set.h index 02f827ada0..47ad231105 100644 --- a/modules/flann/include/opencv2/flann/result_set.h +++ b/modules/flann/include/opencv2/flann/result_set.h @@ -160,7 +160,8 @@ class KNNResultSet : public ResultSet DistanceType worst_distance_; public: - KNNResultSet(int capacity_) : capacity(capacity_), count(0) + KNNResultSet(int capacity_) + : indices(NULL), dists(NULL), capacity(capacity_), count(0), worst_distance_(0) { } @@ -186,6 +187,8 @@ public: void addPoint(DistanceType dist, int index) CV_OVERRIDE { + CV_DbgAssert(indices); + CV_DbgAssert(dists); if (dist >= worst_distance_) return; int i; for (i = count; i > 0; --i) { diff --git a/modules/flann/include/opencv2/flann/timer.h b/modules/flann/include/opencv2/flann/timer.h index 73795aa35b..7dc50a4777 100644 --- a/modules/flann/include/opencv2/flann/timer.h +++ b/modules/flann/include/opencv2/flann/timer.h @@ -60,6 +60,7 @@ public: * Constructor. */ StartStopTimer() + : startTime(0) { reset(); } diff --git a/modules/highgui/src/window_w32.cpp b/modules/highgui/src/window_w32.cpp index 46f580de85..28dbdc8569 100644 --- a/modules/highgui/src/window_w32.cpp +++ b/modules/highgui/src/window_w32.cpp @@ -429,6 +429,7 @@ icvSaveWindowPos( const char* name, CvRect rect ) CvRect cvGetWindowRect_W32(const char* name) { + RECT rect = { 0 }; CvRect result = cvRect(-1, -1, -1, -1); CV_FUNCNAME( "cvGetWindowRect_W32" ); @@ -443,7 +444,6 @@ CvRect cvGetWindowRect_W32(const char* name) if (!window) EXIT; // keep silence here - RECT rect; GetClientRect(window->hwnd, &rect); { POINT pt = {rect.left, rect.top}; @@ -513,7 +513,7 @@ void cvSetModeWindow_W32( const char* name, double prop_value)//Yannick Verdie if (window->status==CV_WINDOW_NORMAL && prop_value==CV_WINDOW_FULLSCREEN) { //save dimension - RECT rect; + RECT rect = { 0 }; GetWindowRect(window->frame, &rect); CvRect RectCV = cvRect(rect.left, rect.top,rect.right - rect.left, rect.bottom - rect.top); icvSaveWindowPos(window->name,RectCV ); @@ -1106,7 +1106,7 @@ static void icvScreenToClient( HWND hwnd, RECT* rect ) static RECT icvCalcWindowRect( CvWindow* window ) { const int gutter = 1; - RECT crect, trect, rect; + RECT crect = { 0 }, trect = { 0 } , rect = { 0 }; assert(window); @@ -1162,7 +1162,7 @@ static bool icvGetBitmapData( CvWindow* window, SIZE* size, int* channels, void* static void icvUpdateWindowPos( CvWindow* window ) { - RECT rect; + RECT rect = { 0 }; assert(window); if( (window->flags & CV_WINDOW_AUTOSIZE) && window->image ) @@ -1175,7 +1175,7 @@ static void icvUpdateWindowPos( CvWindow* window ) // toolbar may resize too for(i = 0; i < (window->toolbar.toolbar ? 2 : 1); i++) { - RECT rmw, rw = icvCalcWindowRect(window ); + RECT rmw = { 0 }, rw = icvCalcWindowRect(window ); MoveWindow(window->hwnd, rw.left, rw.top, rw.right - rw.left, rw.bottom - rw.top, FALSE); GetClientRect(window->hwnd, &rw); @@ -1362,7 +1362,7 @@ CV_IMPL void cvResizeWindow(const char* name, int width, int height ) int i; CvWindow* window; - RECT rmw, rw, rect; + RECT rmw = { 0 }, rw = { 0 }, rect = { 0 }; if( !name ) CV_ERROR( CV_StsNullPtr, "NULL name" ); @@ -1401,7 +1401,7 @@ CV_IMPL void cvMoveWindow( const char* name, int x, int y ) __BEGIN__; CvWindow* window; - RECT rect; + RECT rect = { 0 }; if( !name ) CV_ERROR( CV_StsNullPtr, "NULL name" ); @@ -1441,7 +1441,7 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) if( !(window->flags & CV_WINDOW_AUTOSIZE) ) { MINMAXINFO* minmax = (MINMAXINFO*)lParam; - RECT rect; + RECT rect = { 0 }; LRESULT retval = DefWindowProc(hwnd, uMsg, wParam, lParam); minmax->ptMinTrackSize.y = 100; @@ -1464,7 +1464,7 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) // Update the toolbar pos/size if(window->toolbar.toolbar) { - RECT rect; + RECT rect = { 0 }; GetWindowRect(window->toolbar.toolbar, &rect); MoveWindow(window->toolbar.toolbar, 0, 0, pos->cx, rect.bottom - rect.top, TRUE); } @@ -1480,7 +1480,7 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) // Snap window to screen edges with multi-monitor support. // Adi Shavit LPWINDOWPOS pos = (LPWINDOWPOS)lParam; - RECT rect; + RECT rect = { 0 }; GetWindowRect(window->frame, &rect); HMONITOR hMonitor; @@ -1531,7 +1531,7 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) pt.y = GET_Y_LPARAM( lParam ); ::ScreenToClient(hwnd, &pt); // Convert screen coordinates to client coordinates. - RECT rect; + RECT rect = { 0 }; GetClientRect( window->hwnd, &rect ); SIZE size = {0,0}; @@ -1558,7 +1558,7 @@ MainWindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) case WM_ERASEBKGND: { - RECT cr, tr, wrc; + RECT cr = { 0 }, tr = { 0 }, wrc = { 0 }; HRGN rgn, rgn1, rgn2; int ret; HDC hdc = (HDC)wParam; @@ -1738,7 +1738,7 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM window->on_mouse( event, pt.x, pt.y, flags, window->on_mouse_param ); } else { // Full window is displayed using different size. Scale coordinates to match underlying positions. - RECT rect; + RECT rect = { 0 }; SIZE size = {0, 0}; GetClientRect( window->hwnd, &rect ); @@ -1798,7 +1798,7 @@ static LRESULT CALLBACK HighGUIProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM } else { - RECT rect; + RECT rect = { 0 }; GetClientRect(window->hwnd, &rect); StretchBlt( hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, window->dc, 0, 0, size.cx, size.cy, SRCCOPY ); @@ -1955,7 +1955,7 @@ static LRESULT CALLBACK HGToolbarProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPAR for( ; trackbar != 0; trackbar = trackbar->next ) { - RECT rect; + RECT rect = { 0 }; SendMessage(window->toolbar.toolbar, TB_GETITEMRECT, (WPARAM)trackbar->id, (LPARAM)&rect); MoveWindow(trackbar->hwnd, rect.left + HG_BUDDY_WIDTH, rect.top, @@ -2180,7 +2180,7 @@ icvCreateTrackbar( const char* trackbar_name, const char* window_name, { TBBUTTON tbs = {}; TBBUTTONINFO tbis = {}; - RECT rect; + RECT rect = { 0 }; int bcount; int len = (int)strlen( trackbar_name ); diff --git a/modules/objdetect/src/cascadedetect_convert.cpp b/modules/objdetect/src/cascadedetect_convert.cpp index 1172cb7c8a..20701b9983 100644 --- a/modules/objdetect/src/cascadedetect_convert.cpp +++ b/modules/objdetect/src/cascadedetect_convert.cpp @@ -107,6 +107,8 @@ struct HaarClassifier struct HaarStageClassifier { + HaarStageClassifier() : threshold(0) {} + double threshold; std::vector weaks; }; From f6795d75a66bb108f4347877441a04a31816c782 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Fri, 4 Sep 2020 15:35:10 +0000 Subject: [PATCH 5/7] videoio: repair build of FFmpeg windows wrapper --- modules/videoio/src/cap_ffmpeg_impl.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp index ac6f9448e0..3974f4af34 100644 --- a/modules/videoio/src/cap_ffmpeg_impl.hpp +++ b/modules/videoio/src/cap_ffmpeg_impl.hpp @@ -484,7 +484,6 @@ struct CvCapture_FFMPEG bool setProperty(int, double); bool grabFrame(); bool retrieveFrame(int, unsigned char** data, int* step, int* width, int* height, int* cn); - void rotateFrame(cv::Mat &mat) const; void init(); From 20b23da8e2b38f26904b6dd60ba46d6575f6ad61 Mon Sep 17 00:00:00 2001 From: Danny <33044223+danielenricocahall@users.noreply.github.com> Date: Fri, 4 Sep 2020 13:01:05 -0400 Subject: [PATCH 6/7] Merge pull request #18061 from danielenricocahall:fix-kd-tree Fix KD Tree kNN Implementation * Make KDTree mode in kNN functional remove docs and revert change Make KDTree mode in kNN functional spacing Make KDTree mode in kNN functional fix window compilations warnings Make KDTree mode in kNN functional fix window compilations warnings Make KDTree mode in kNN functional casting Make KDTree mode in kNN functional formatting Make KDTree mode in kNN functional * test coding style --- modules/ml/src/kdtree.cpp | 3 +-- modules/ml/src/knearest.cpp | 17 ++---------- modules/ml/test/test_knearest.cpp | 45 +++++++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/modules/ml/src/kdtree.cpp b/modules/ml/src/kdtree.cpp index 1ab8400936..a80e12964a 100644 --- a/modules/ml/src/kdtree.cpp +++ b/modules/ml/src/kdtree.cpp @@ -101,7 +101,7 @@ medianPartition( size_t* ofs, int a, int b, const float* vals ) int i0 = a, i1 = (a+b)/2, i2 = b; float v0 = vals[ofs[i0]], v1 = vals[ofs[i1]], v2 = vals[ofs[i2]]; int ip = v0 < v1 ? (v1 < v2 ? i1 : v0 < v2 ? i2 : i0) : - v0 < v2 ? i0 : (v1 < v2 ? i2 : i1); + v0 < v2 ? (v1 == v0 ? i2 : i0): (v1 < v2 ? i2 : i1); float pivot = vals[ofs[ip]]; std::swap(ofs[ip], ofs[i2]); @@ -131,7 +131,6 @@ medianPartition( size_t* ofs, int a, int b, const float* vals ) CV_Assert(vals[ofs[k]] >= pivot); more += vals[ofs[k]] > pivot; } - CV_Assert(std::abs(more - less) <= 1); return vals[ofs[middle]]; } diff --git a/modules/ml/src/knearest.cpp b/modules/ml/src/knearest.cpp index ca23d0f4d6..3d8f9b5d2e 100644 --- a/modules/ml/src/knearest.cpp +++ b/modules/ml/src/knearest.cpp @@ -381,36 +381,23 @@ public: Mat res, nr, d; if( _results.needed() ) { - _results.create(testcount, 1, CV_32F); res = _results.getMat(); } if( _neighborResponses.needed() ) { - _neighborResponses.create(testcount, k, CV_32F); nr = _neighborResponses.getMat(); } if( _dists.needed() ) { - _dists.create(testcount, k, CV_32F); d = _dists.getMat(); } for (int i=0; ii) - { - _res = res.row(i); - } - if (nr.rows>i) - { - _nr = nr.row(i); - } - if (d.rows>i) - { - _d = d.row(i); - } tr.findNearest(test_samples.row(i), k, Emax, _res, _nr, _d, noArray()); + res.push_back(_res.t()); + _results.assign(res); } return result; // currently always 0 diff --git a/modules/ml/test/test_knearest.cpp b/modules/ml/test/test_knearest.cpp index 49e6b0d12a..80baed9626 100644 --- a/modules/ml/test/test_knearest.cpp +++ b/modules/ml/test/test_knearest.cpp @@ -37,18 +37,31 @@ TEST(ML_KNearest, accuracy) EXPECT_LE(err, 0.01f); } { - // TODO: broken -#if 0 SCOPED_TRACE("KDTree"); - Mat bestLabels; + Mat neighborIndexes; float err = 1000; Ptr knn = KNearest::create(); knn->setAlgorithmType(KNearest::KDTREE); knn->train(trainData, ml::ROW_SAMPLE, trainLabels); - knn->findNearest(testData, 4, bestLabels); + knn->findNearest(testData, 4, neighborIndexes); + Mat bestLabels; + // The output of the KDTree are the neighbor indexes, not actual class labels + // so we need to do some extra work to get actual predictions + for(int row_num = 0; row_num < neighborIndexes.rows; ++row_num){ + vector labels; + for(int index = 0; index < neighborIndexes.row(row_num).cols; ++index) { + labels.push_back(trainLabels.at(neighborIndexes.row(row_num).at(0, index) , 0)); + } + // computing the mode of the output class predictions to determine overall prediction + std::vector histogram(3,0); + for( int i=0; i<3; ++i ) + ++histogram[ static_cast(labels[i]) ]; + int bestLabel = static_cast(std::max_element( histogram.begin(), histogram.end() ) - histogram.begin()); + bestLabels.push_back(bestLabel); + } + bestLabels.convertTo(bestLabels, testLabels.type()); EXPECT_TRUE(calcErr( bestLabels, testLabels, sizes, err, true )); EXPECT_LE(err, 0.01f); -#endif } } @@ -74,4 +87,26 @@ TEST(ML_KNearest, regression_12347) EXPECT_EQ(2, zBestLabels.at(1,0)); } +TEST(ML_KNearest, bug_11877) +{ + Mat trainData = (Mat_(5,2) << 3, 3, 3, 3, 4, 4, 4, 4, 4, 4); + Mat trainLabels = (Mat_(5,1) << 0, 0, 1, 1, 1); + + Ptr knnKdt = KNearest::create(); + knnKdt->setAlgorithmType(KNearest::KDTREE); + knnKdt->setIsClassifier(true); + + knnKdt->train(trainData, ml::ROW_SAMPLE, trainLabels); + + Mat testData = (Mat_(2,2) << 3.1, 3.1, 4, 4.1); + Mat testLabels = (Mat_(2,1) << 0, 1); + Mat result; + + knnKdt->findNearest(testData, 1, result); + + EXPECT_EQ(1, int(result.at(0, 0))); + EXPECT_EQ(2, int(result.at(1, 0))); + EXPECT_EQ(0, trainLabels.at(result.at(0, 0), 0)); +} + }} // namespace From c31164bf1e8f26bd87c06af9f335d3beca022078 Mon Sep 17 00:00:00 2001 From: Danny <33044223+danielenricocahall@users.noreply.github.com> Date: Sat, 5 Sep 2020 14:52:10 -0400 Subject: [PATCH 7/7] Merge pull request #18126 from danielenricocahall:add-oob-error-sample-weighting Account for sample weights in calculating OOB Error * account for sample weights in oob error calculation * redefine oob error functions * fix ABI compatibility --- modules/ml/include/opencv2/ml.hpp | 9 ++++++ modules/ml/src/rtrees.cpp | 26 +++++++++++++++-- modules/ml/test/test_rtrees.cpp | 46 +++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 2 deletions(-) diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp index adbd84682e..396a792119 100644 --- a/modules/ml/include/opencv2/ml.hpp +++ b/modules/ml/include/opencv2/ml.hpp @@ -1294,6 +1294,15 @@ public: */ CV_WRAP void getVotes(InputArray samples, OutputArray results, int flags) const; + /** Returns the OOB error value, computed at the training stage when calcOOBError is set to true. + * If this flag was set to false, 0 is returned. The OOB error is also scaled by sample weighting. + */ +#if CV_VERSION_MAJOR == 3 + CV_WRAP double getOOBError() const; +#else + /*CV_WRAP*/ virtual double getOOBError() const = 0; +#endif + /** Creates the empty model. Use StatModel::train to train the model, StatModel::train to create and train the model, Algorithm::load to load the pre-trained model. diff --git a/modules/ml/src/rtrees.cpp b/modules/ml/src/rtrees.cpp index 27ec096bc0..1deee6f6c8 100644 --- a/modules/ml/src/rtrees.cpp +++ b/modules/ml/src/rtrees.cpp @@ -216,13 +216,14 @@ public: sample = Mat( nallvars, 1, CV_32F, psamples + sstep0*w->sidx[j], sstep1*sizeof(psamples[0]) ); double val = predictTrees(Range(treeidx, treeidx+1), sample, predictFlags); + double sample_weight = w->sample_weights[w->sidx[j]]; if( !_isClassifier ) { oobres[j] += val; oobcount[j]++; double true_val = w->ord_responses[w->sidx[j]]; double a = oobres[j]/oobcount[j] - true_val; - oobError += a*a; + oobError += sample_weight * a*a; val = (val - true_val)/max_response; ncorrect_responses += std::exp( -val*val ); } @@ -237,7 +238,7 @@ public: if( votes[best_class] < votes[k] ) best_class = k; int diff = best_class != w->cat_responses[w->sidx[j]]; - oobError += diff; + oobError += sample_weight * diff; ncorrect_responses += diff == 0; } } @@ -421,6 +422,10 @@ public: } } + double getOOBError() const { + return oobError; + } + RTreeParams rparams; double oobError; vector varImportance; @@ -505,6 +510,12 @@ public: const vector& getNodes() const CV_OVERRIDE { return impl.getNodes(); } const vector& getSplits() const CV_OVERRIDE { return impl.getSplits(); } const vector& getSubsets() const CV_OVERRIDE { return impl.getSubsets(); } +#if CV_VERSION_MAJOR == 3 + double getOOBError_() const { return impl.getOOBError(); } +#else + double getOOBError() const CV_OVERRIDE { return impl.getOOBError(); } +#endif + DTreesImplForRTrees impl; }; @@ -532,6 +543,17 @@ void RTrees::getVotes(InputArray input, OutputArray output, int flags) const return this_->getVotes_(input, output, flags); } +#if CV_VERSION_MAJOR == 3 +double RTrees::getOOBError() const +{ + CV_TRACE_FUNCTION(); + const RTreesImpl* this_ = dynamic_cast(this); + if(!this_) + CV_Error(Error::StsNotImplemented, "the class is not RTreesImpl"); + return this_->getOOBError_(); +} +#endif + }} // End of file. diff --git a/modules/ml/test/test_rtrees.cpp b/modules/ml/test/test_rtrees.cpp index ebf0c46557..1ec9b8d042 100644 --- a/modules/ml/test/test_rtrees.cpp +++ b/modules/ml/test/test_rtrees.cpp @@ -51,4 +51,50 @@ TEST(ML_RTrees, getVotes) EXPECT_EQ(result.at(0, predicted_class), rt->predict(test)); } +TEST(ML_RTrees, 11142_sample_weights_regression) +{ + int n = 3; + // RTrees for regression + Ptr rt = cv::ml::RTrees::create(); + //simple regression problem of x -> 2x + Mat data = (Mat_(n,1) << 1, 2, 3); + Mat values = (Mat_(n,1) << 2, 4, 6); + Mat weights = (Mat_(n, 1) << 10, 10, 10); + + Ptr trainData = TrainData::create(data, ml::ROW_SAMPLE, values); + rt->train(trainData); + double error_without_weights = round(rt->getOOBError()); + rt->clear(); + Ptr trainDataWithWeights = TrainData::create(data, ml::ROW_SAMPLE, values, Mat(), Mat(), weights ); + rt->train(trainDataWithWeights); + double error_with_weights = round(rt->getOOBError()); + // error with weights should be larger than error without weights + EXPECT_GE(error_with_weights, error_without_weights); +} + +TEST(ML_RTrees, 11142_sample_weights_classification) +{ + int n = 12; + // RTrees for classification + Ptr rt = cv::ml::RTrees::create(); + + Mat data(n, 4, CV_32F); + randu(data, 0, 10); + Mat labels = (Mat_(n,1) << 0,0,0,0, 1,1,1,1, 2,2,2,2); + Mat weights = (Mat_(n, 1) << 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10); + + rt->train(data, ml::ROW_SAMPLE, labels); + rt->clear(); + double error_without_weights = round(rt->getOOBError()); + Ptr trainDataWithWeights = TrainData::create(data, ml::ROW_SAMPLE, labels, Mat(), Mat(), weights ); + rt->train(data, ml::ROW_SAMPLE, labels); + double error_with_weights = round(rt->getOOBError()); + std::cout << error_without_weights << std::endl; + std::cout << error_with_weights << std::endl; + // error with weights should be larger than error without weights + EXPECT_GE(error_with_weights, error_without_weights); +} + + + }} // namespace