From 54449b614bb18eef0a8e15b8abade693c7a4d1ac Mon Sep 17 00:00:00 2001 From: inayd <121136285+inayd@users.noreply.github.com> Date: Tue, 3 Jan 2023 16:29:13 +0100 Subject: [PATCH 01/19] Fix occuring artifacts in fillPoly --- modules/imgproc/src/drawing.cpp | 59 +++++-- modules/imgproc/test/test_drawing.cpp | 233 ++++++++++++++++++++++++++ 2 files changed, 277 insertions(+), 15 deletions(-) diff --git a/modules/imgproc/src/drawing.cpp b/modules/imgproc/src/drawing.cpp index 0e938a644d..4fbcb11f21 100644 --- a/modules/imgproc/src/drawing.cpp +++ b/modules/imgproc/src/drawing.cpp @@ -63,7 +63,7 @@ CollectPolyEdges( Mat& img, const Point2l* v, int npts, int shift, Point offset=Point() ); static void -FillEdgeCollection( Mat& img, std::vector& edges, const void* color ); +FillEdgeCollection( Mat& img, std::vector& edges, const void* color, int line_type); static void PolyLine( Mat& img, const Point2l* v, int npts, bool closed, @@ -1031,7 +1031,7 @@ EllipseEx( Mat& img, Point2l center, Size2l axes, v.push_back(center); std::vector edges; CollectPolyEdges( img, &v[0], (int)v.size(), edges, color, line_type, XY_SHIFT ); - FillEdgeCollection( img, edges, color ); + FillEdgeCollection( img, edges, color, line_type ); } } @@ -1259,37 +1259,60 @@ CollectPolyEdges( Mat& img, const Point2l* v, int count, std::vector& pt1.x = (pt1.x + offset.x) << (XY_SHIFT - shift); pt1.y = (pt1.y + delta) >> shift; - if( line_type < CV_AA ) + Point2l pt0c(pt0), pt1c(pt1); + + if (line_type < CV_AA) { t0.y = pt0.y; t1.y = pt1.y; t0.x = (pt0.x + (XY_ONE >> 1)) >> XY_SHIFT; t1.x = (pt1.x + (XY_ONE >> 1)) >> XY_SHIFT; - Line( img, t0, t1, color, line_type ); + Line(img, t0, t1, color, line_type); + + // use clipped endpoints to create a more accurate PolyEdge + if ((unsigned)t0.x >= (unsigned)(img.cols) || + (unsigned)t1.x >= (unsigned)(img.cols) || + (unsigned)t0.y >= (unsigned)(img.rows) || + (unsigned)t1.y >= (unsigned)(img.rows)) + { + clipLine(img.size(), t0, t1); + + if (t0.y != t1.y) + { + pt0c.y = t0.y; pt1c.y = t1.y; + pt0c.x = (int64)(t0.x) << XY_SHIFT; + pt1c.x = (int64)(t1.x) << XY_SHIFT; + } + } + else + { + pt0c.x += XY_ONE >> 1; + pt1c.x += XY_ONE >> 1; + } } else { t0.x = pt0.x; t1.x = pt1.x; t0.y = pt0.y << XY_SHIFT; t1.y = pt1.y << XY_SHIFT; - LineAA( img, t0, t1, color ); + LineAA(img, t0, t1, color); } - if( pt0.y == pt1.y ) + if (pt0.y == pt1.y) continue; - if( pt0.y < pt1.y ) + edge.dx = (pt1c.x - pt0c.x) / (pt1c.y - pt0c.y); + if (pt0.y < pt1.y) { edge.y0 = (int)(pt0.y); edge.y1 = (int)(pt1.y); - edge.x = pt0.x; + edge.x = pt0c.x + (pt0.y - pt0c.y) * edge.dx; // correct starting point for clipped lines } else { edge.y0 = (int)(pt1.y); edge.y1 = (int)(pt0.y); - edge.x = pt1.x; + edge.x = pt1c.x + (pt1.y - pt1c.y) * edge.dx; // correct starting point for clipped lines } - edge.dx = (pt1.x - pt0.x) / (pt1.y - pt0.y); edges.push_back(edge); } } @@ -1306,7 +1329,7 @@ struct CmpEdges /**************** helper macros and functions for sequence/contour processing ***********/ static void -FillEdgeCollection( Mat& img, std::vector& edges, const void* color ) +FillEdgeCollection( Mat& img, std::vector& edges, const void* color, int line_type) { PolyEdge tmp; int i, y, total = (int)edges.size(); @@ -1315,6 +1338,12 @@ FillEdgeCollection( Mat& img, std::vector& edges, const void* color ) int y_max = INT_MIN, y_min = INT_MAX; int64 x_max = 0xFFFFFFFFFFFFFFFF, x_min = 0x7FFFFFFFFFFFFFFF; int pix_size = (int)img.elemSize(); + int delta; + + if (line_type < CV_AA) + delta = 0; + else + delta = XY_ONE - 1; if( total < 2 ) return; @@ -1394,12 +1423,12 @@ FillEdgeCollection( Mat& img, std::vector& edges, const void* color ) if (keep_prelast->x > prelast->x) { - x1 = (int)((prelast->x + XY_ONE - 1) >> XY_SHIFT); + x1 = (int)((prelast->x + delta) >> XY_SHIFT); x2 = (int)(keep_prelast->x >> XY_SHIFT); } else { - x1 = (int)((keep_prelast->x + XY_ONE - 1) >> XY_SHIFT); + x1 = (int)((keep_prelast->x + delta) >> XY_SHIFT); x2 = (int)(prelast->x >> XY_SHIFT); } @@ -1995,7 +2024,7 @@ void fillPoly( Mat& img, const Point** pts, const int* npts, int ncontours, CollectPolyEdges(img, _pts.data(), npts[i], edges, buf, line_type, shift, offset); } - FillEdgeCollection(img, edges, buf); + FillEdgeCollection(img, edges, buf, line_type); } @@ -2654,7 +2683,7 @@ cvDrawContours( void* _img, CvSeq* contour, } if( thickness < 0 ) - cv::FillEdgeCollection( img, edges, ext_buf ); + cv::FillEdgeCollection( img, edges, ext_buf, line_type); if( h_next && contour0 ) contour0->h_next = h_next; diff --git a/modules/imgproc/test/test_drawing.cpp b/modules/imgproc/test/test_drawing.cpp index 42aa386b5a..b4c4ce3c56 100644 --- a/modules/imgproc/test/test_drawing.cpp +++ b/modules/imgproc/test/test_drawing.cpp @@ -632,4 +632,237 @@ TEST(Drawing, fillpoly_circle) EXPECT_LT(diff_fp3, 1.); } +TEST(Drawing, fillpoly_fully) +{ + unsigned imageWidth = 256; + unsigned imageHeight = 256; + int type = CV_8UC1; + int shift = 0; + Point offset(0, 0); + cv::LineTypes lineType = LINE_4; + + int imageSizeOffset = 15; + + cv::Mat img(imageHeight, imageWidth, type); + img = 0; + + std::vector polygonPoints; + polygonPoints.push_back(cv::Point(100, -50)); + polygonPoints.push_back(cv::Point(imageSizeOffset, imageHeight - imageSizeOffset)); + polygonPoints.push_back(cv::Point(imageSizeOffset, imageSizeOffset)); + + // convert data + std::vector polygonPointPointers(polygonPoints.size()); + for (size_t i = 0; i < polygonPoints.size(); i++) + { + polygonPointPointers[i] = &polygonPoints[i]; + } + + const cv::Point** data = &polygonPointPointers.front(); + int size = (int)polygonPoints.size(); + const int* npts = &size; + int ncontours = 1; + + // generate image + cv::fillPoly(img, data, npts, ncontours, 255, lineType, shift, offset); + + // check for artifacts + { + cv::Mat binary = img < 128; + cv::Mat labelImage(binary.size(), CV_32S); + cv::Mat labelCentroids; + int labels = cv::connectedComponents(binary, labelImage, 4); + EXPECT_EQ(2, labels) << "artifacts occured"; + } + + // check if filling went over border + { + int xy_shift = 16, delta = offset.y + ((1 << shift) >> 1); + int xy_one = 1 << xy_shift; + + Point pt0(polygonPoints[polygonPoints.size() - 1]), pt1; + for (size_t i = 0; i < polygonPoints.size(); i++, pt0 = pt1) + { + pt1 = polygonPoints[i]; + + // offset/shift treated like in fillPoly + Point t0(pt0), t1(pt1); + + t0.x = (t0.x + offset.x) << (xy_shift - shift); + t0.y = (t0.y + delta) >> shift; + + t1.x = (t1.x + offset.x) << (xy_shift - shift); + t1.y = (t1.y + delta) >> shift; + + if (lineType < CV_AA) + { + t0.x = (t0.x + (xy_one >> 1)) >> xy_shift; + t1.x = (t1.x + (xy_one >> 1)) >> xy_shift; + + // LINE_4 to use the same type of line which is used in fillPoly + line(img, t0, t1, 0, 1, LINE_4, 0); + } + else + { + t0.x >>= (xy_shift); + t1.x >>= (xy_shift); + line(img, t0, t1, 0, 1, lineType, 0); + } + + } + cv::Mat binary = img < 254; + cv::Mat labelImage(binary.size(), CV_32S); + int labels = cv::connectedComponents(binary, labelImage, 4); + EXPECT_EQ(2, labels) << "filling went over the border"; + } +} + +PARAM_TEST_CASE(FillPolyFully, unsigned, unsigned, int, int, Point, cv::LineTypes) +{ + unsigned imageWidth; + unsigned imageHeight; + int type; + int shift; + Point offset; + cv::LineTypes lineType; + + virtual void SetUp() + { + imageWidth = GET_PARAM(0); + imageHeight = GET_PARAM(1); + type = GET_PARAM(2); + shift = GET_PARAM(3); + offset = GET_PARAM(4); + lineType = GET_PARAM(5); + } + + void draw_polygon(cv::Mat& img, const std::vector& polygonPoints) + { + // convert data + std::vector polygonPointPointers(polygonPoints.size()); + for (size_t i = 0; i < polygonPoints.size(); i++) + { + polygonPointPointers[i] = &polygonPoints[i]; + } + + const cv::Point** data = &polygonPointPointers.front(); + int size = (int)polygonPoints.size(); + const int* npts = &size; + int ncontours = 1; + + // generate image + cv::fillPoly(img, data, npts, ncontours, 255, lineType, shift, offset); + } + + void check_artifacts(cv::Mat& img) + { + // check for artifacts + cv::Mat binary = img < 128; + cv::Mat labelImage(binary.size(), CV_32S); + cv::Mat labelCentroids; + int labels = cv::connectedComponents(binary, labelImage, 4); + EXPECT_EQ(2, labels) << "artifacts occured"; + } + + void check_filling_over_border(cv::Mat& img, const std::vector& polygonPoints) + { + int xy_shift = 16, delta = offset.y + ((1 << shift) >> 1); + int xy_one = 1 << xy_shift; + + Point pt0(polygonPoints[polygonPoints.size() - 1]), pt1; + for (size_t i = 0; i < polygonPoints.size(); i++, pt0 = pt1) + { + pt1 = polygonPoints[i]; + + // offset/shift treated like in fillPoly + Point t0(pt0), t1(pt1); + + t0.x = (t0.x + offset.x) << (xy_shift - shift); + t0.y = (t0.y + delta) >> shift; + + t1.x = (t1.x + offset.x) << (xy_shift - shift); + t1.y = (t1.y + delta) >> shift; + + if (lineType < CV_AA) + { + t0.x = (t0.x + (xy_one >> 1)) >> xy_shift; + t1.x = (t1.x + (xy_one >> 1)) >> xy_shift; + + // LINE_4 to use the same type of line which is used in fillPoly + line(img, t0, t1, 0, 1, LINE_4, 0); + } + else + { + t0.x >>= (xy_shift); + t1.x >>= (xy_shift); + line(img, t0, t1, 0, 1, lineType, 0); + } + + } + cv::Mat binary = img < 254; + cv::Mat labelImage(binary.size(), CV_32S); + int labels = cv::connectedComponents(binary, labelImage, 4); + EXPECT_EQ(2, labels) << "filling went over the border"; + } + + void run_test(const std::vector& polygonPoints) + { + cv::Mat img(imageHeight, imageWidth, type); + img = 0; + + draw_polygon(img, polygonPoints); + check_artifacts(img); + check_filling_over_border(img, polygonPoints); + } +}; + +TEST_P(FillPolyFully, DISABLED_fillpoly_fully) +{ + int imageSizeOffset = 15; + + // testing for polygon with straight edge at left/right side + int positions1[2] = { imageSizeOffset, (int)imageWidth - imageSizeOffset }; + for (size_t i = 0; i < 2; i++) + { + for (int y = imageHeight + 50; y > -50; y -= 1) + { + // define polygon + std::vector polygonPoints; + polygonPoints.push_back(cv::Point(100, imageHeight - y)); + polygonPoints.push_back(cv::Point(positions1[i], positions1[1])); + polygonPoints.push_back(cv::Point(positions1[i], positions1[0])); + + run_test(polygonPoints); + } + } + + // testing for polygon with straight edge at top/bottom side + int positions2[2] = { imageSizeOffset, (int)imageHeight - imageSizeOffset }; + for (size_t i = 0; i < 2; i++) + { + for (int x = imageWidth + 50; x > -50; x -= 1) + { + // define polygon + std::vector polygonPoints; + polygonPoints.push_back(cv::Point(imageWidth - x, 100)); + polygonPoints.push_back(cv::Point(positions2[1], positions2[i])); + polygonPoints.push_back(cv::Point(positions2[0], positions2[i])); + + run_test(polygonPoints); + } + } +} + +INSTANTIATE_TEST_CASE_P( + FillPolyTest, FillPolyFully, + testing::Combine( + testing::Values(256), + testing::Values(256), + testing::Values(CV_8UC1), + testing::Values(0, 1, 2), + testing::Values(cv::Point(0, 0), cv::Point(10, 10)), + testing::Values(LINE_4, LINE_8, LINE_AA) + ) +); + }} // namespace From 7b7774476e92247c801309387df2ea64465976e3 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Sun, 8 Jan 2023 18:18:37 +0000 Subject: [PATCH 02/19] copyright: 2023 --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 3003954c3f..dad1a76d36 100644 --- a/LICENSE +++ b/LICENSE @@ -11,9 +11,9 @@ Copyright (C) 2000-2022, Intel Corporation, all rights reserved. Copyright (C) 2009-2011, Willow Garage Inc., 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-2022, OpenCV Foundation, all rights reserved. +Copyright (C) 2015-2023, OpenCV Foundation, all rights reserved. Copyright (C) 2015-2016, Itseez Inc., all rights reserved. -Copyright (C) 2019-2022, Xperience AI, all rights reserved. +Copyright (C) 2019-2023, Xperience AI, 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 a64b51dd94d6e7e8940cd0dfa5a0c91509c65368 Mon Sep 17 00:00:00 2001 From: Christoph Rackwitz Date: Mon, 9 Jan 2023 01:55:31 -0800 Subject: [PATCH 03/19] Merge pull request #23108 from crackwitz:issue-23107 Usage of imread(): magic number 0, unchecked result * docs: rewrite 0/1 to IMREAD_GRAYSCALE/IMREAD_COLOR in imread() * samples, apps: rewrite 0/1 to IMREAD_GRAYSCALE/IMREAD_COLOR in imread() * tests: rewrite 0/1 to IMREAD_GRAYSCALE/IMREAD_COLOR in imread() * doc/py_tutorials: check imread() result --- apps/traincascade/imagestorage.cpp | 2 +- .../py_calib3d/py_depthmap/py_depthmap.markdown | 4 ++-- .../py_epipolar_geometry.markdown | 4 ++-- .../py_core/py_basic_ops/py_basic_ops.markdown | 2 ++ .../py_image_arithmetics.markdown | 4 ++++ .../py_core/py_optimization/py_optimization.markdown | 1 + .../py_feature2d/py_brief/py_brief.markdown | 2 +- .../py_feature2d/py_fast/py_fast.markdown | 2 +- .../py_feature_homography.markdown | 4 ++-- doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown | 2 +- .../py_surf_intro/py_surf_intro.markdown | 2 +- .../py_imgproc/py_canny/py_canny.markdown | 3 ++- .../py_contour_features/py_contour_features.markdown | 3 ++- .../py_contours_begin/py_contours_begin.markdown | 1 + .../py_contours_more_functions.markdown | 7 +++++-- .../py_imgproc/py_filtering/py_filtering.markdown | 2 ++ .../py_geometric_transformations.markdown | 9 +++++++-- .../py_imgproc/py_grabcut/py_grabcut.markdown | 4 +++- .../py_imgproc/py_gradients/py_gradients.markdown | 6 ++++-- .../py_2d_histogram/py_2d_histogram.markdown | 3 +++ .../py_histogram_backprojection.markdown | 4 ++++ .../py_histogram_begins/py_histogram_begins.markdown | 10 +++++++--- .../py_histogram_equalization.markdown | 9 ++++++--- .../py_houghcircles/py_houghcircles.markdown | 3 ++- .../py_morphological_ops.markdown | 3 ++- .../py_imgproc/py_pyramids/py_pyramids.markdown | 3 +++ .../py_template_matching.markdown | 10 +++++++--- .../py_thresholding/py_thresholding.markdown | 12 ++++++++---- .../py_fourier_transform.markdown | 9 ++++++--- .../py_imgproc/py_watershed/py_watershed.markdown | 1 + .../py_photo/py_inpainting/py_inpainting.markdown | 2 +- .../linux_eclipse/linux_eclipse.markdown | 2 +- .../linux_gcc_cmake/linux_gcc_cmake.markdown | 2 +- modules/calib3d/test/test_chesscorners.cpp | 2 +- modules/calib3d/test/test_stereomatching.cpp | 12 ++++++------ .../features2d/test/test_descriptors_regression.cpp | 4 ++-- modules/imgcodecs/misc/java/test/ImgcodecsTest.java | 2 +- modules/imgproc/test/test_connectedcomponents.cpp | 2 +- modules/imgproc/test/test_imgproc_umat.cpp | 2 +- modules/imgproc/test/test_watershed.cpp | 2 +- .../src/org/opencv/test/OpenCVTestCase.java | 2 +- .../src/org/opencv/test/OpenCVTestCase.java | 2 +- modules/objdetect/test/test_cascadeandhog.cpp | 2 +- modules/photo/test/test_denoising.cpp | 2 +- modules/videoio/test/test_ffmpeg.cpp | 2 +- samples/cpp/3calibration.cpp | 4 ++-- samples/cpp/calibration.cpp | 4 ++-- samples/cpp/facedetect.cpp | 2 +- samples/cpp/pca.cpp | 2 +- samples/cpp/stereo_calib.cpp | 4 ++-- .../snippets/imgproc_HoughLinesCircles.cpp | 2 +- .../tutorial_code/snippets/imgproc_HoughLinesP.cpp | 2 +- .../cpp/tutorial_code/snippets/imgproc_calcHist.cpp | 2 +- .../tutorial_code/snippets/imgproc_drawContours.cpp | 2 +- samples/cpp/watershed.cpp | 2 +- samples/python/calibrate.py | 2 +- samples/python/mouse_and_match.py | 2 +- 57 files changed, 129 insertions(+), 74 deletions(-) diff --git a/apps/traincascade/imagestorage.cpp b/apps/traincascade/imagestorage.cpp index a133ccc3d4..f220e5c2b3 100644 --- a/apps/traincascade/imagestorage.cpp +++ b/apps/traincascade/imagestorage.cpp @@ -54,7 +54,7 @@ bool CvCascadeImageReader::NegReader::nextImg() size_t count = imgFilenames.size(); for( size_t i = 0; i < count; i++ ) { - src = imread( imgFilenames[last++], 0 ); + src = imread( imgFilenames[last++], IMREAD_GRAYSCALE ); if( src.empty() ){ last %= count; continue; diff --git a/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.markdown b/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.markdown index f0ea83122b..52d0c5933d 100644 --- a/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.markdown +++ b/doc/py_tutorials/py_calib3d/py_depthmap/py_depthmap.markdown @@ -41,8 +41,8 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -imgL = cv.imread('tsukuba_l.png',0) -imgR = cv.imread('tsukuba_r.png',0) +imgL = cv.imread('tsukuba_l.png', cv.IMREAD_GRAYSCALE) +imgR = cv.imread('tsukuba_r.png', cv.IMREAD_GRAYSCALE) stereo = cv.StereoBM_create(numDisparities=16, blockSize=15) disparity = stereo.compute(imgL,imgR) diff --git a/doc/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.markdown b/doc/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.markdown index 6b8d90882a..ada22222cb 100644 --- a/doc/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.markdown +++ b/doc/py_tutorials/py_calib3d/py_epipolar_geometry/py_epipolar_geometry.markdown @@ -76,8 +76,8 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img1 = cv.imread('myleft.jpg',0) #queryimage # left image -img2 = cv.imread('myright.jpg',0) #trainimage # right image +img1 = cv.imread('myleft.jpg', cv.IMREAD_GRAYSCALE) #queryimage # left image +img2 = cv.imread('myright.jpg', cv.IMREAD_GRAYSCALE) #trainimage # right image sift = cv.SIFT_create() diff --git a/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.markdown b/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.markdown index 4c6aa4bb92..1594f77200 100644 --- a/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.markdown +++ b/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.markdown @@ -25,6 +25,7 @@ Let's load a color image first: >>> import cv2 as cv >>> img = cv.imread('messi5.jpg') +>>> assert img is not None, "file could not be read, check with os.path.exists()" @endcode You can access a pixel value by its row and column coordinates. For BGR image, it returns an array of Blue, Green, Red values. For grayscale image, just corresponding intensity is returned. @@ -173,6 +174,7 @@ from matplotlib import pyplot as plt BLUE = [255,0,0] img1 = cv.imread('opencv-logo.png') +assert img1 is not None, "file could not be read, check with os.path.exists()" replicate = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REPLICATE) reflect = cv.copyMakeBorder(img1,10,10,10,10,cv.BORDER_REFLECT) diff --git a/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.markdown b/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.markdown index d08d974c2f..4b6e8bd3c1 100644 --- a/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.markdown +++ b/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.markdown @@ -50,6 +50,8 @@ Here \f$\gamma\f$ is taken as zero. @code{.py} img1 = cv.imread('ml.png') img2 = cv.imread('opencv-logo.png') +assert img1 is not None, "file could not be read, check with os.path.exists()" +assert img2 is not None, "file could not be read, check with os.path.exists()" dst = cv.addWeighted(img1,0.7,img2,0.3,0) @@ -76,6 +78,8 @@ bitwise operations as shown below: # Load two images img1 = cv.imread('messi5.jpg') img2 = cv.imread('opencv-logo-white.png') +assert img1 is not None, "file could not be read, check with os.path.exists()" +assert img2 is not None, "file could not be read, check with os.path.exists()" # I want to put logo on top-left corner, So I create a ROI rows,cols,channels = img2.shape diff --git a/doc/py_tutorials/py_core/py_optimization/py_optimization.markdown b/doc/py_tutorials/py_core/py_optimization/py_optimization.markdown index d24613a643..7d63ffadef 100644 --- a/doc/py_tutorials/py_core/py_optimization/py_optimization.markdown +++ b/doc/py_tutorials/py_core/py_optimization/py_optimization.markdown @@ -37,6 +37,7 @@ of odd sizes ranging from 5 to 49. (Don't worry about what the result will look goal): @code{.py} img1 = cv.imread('messi5.jpg') +assert img1 is not None, "file could not be read, check with os.path.exists()" e1 = cv.getTickCount() for i in range(5,49,2): diff --git a/doc/py_tutorials/py_feature2d/py_brief/py_brief.markdown b/doc/py_tutorials/py_feature2d/py_brief/py_brief.markdown index 4abcdc1bad..a34e7e7805 100644 --- a/doc/py_tutorials/py_feature2d/py_brief/py_brief.markdown +++ b/doc/py_tutorials/py_feature2d/py_brief/py_brief.markdown @@ -63,7 +63,7 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('simple.jpg',0) +img = cv.imread('simple.jpg', cv.IMREAD_GRAYSCALE) # Initiate FAST detector star = cv.xfeatures2d.StarDetector_create() diff --git a/doc/py_tutorials/py_feature2d/py_fast/py_fast.markdown b/doc/py_tutorials/py_feature2d/py_fast/py_fast.markdown index b1b8a81ca8..1d7b3e3911 100644 --- a/doc/py_tutorials/py_feature2d/py_fast/py_fast.markdown +++ b/doc/py_tutorials/py_feature2d/py_fast/py_fast.markdown @@ -98,7 +98,7 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('blox.jpg',0) # `/samples/data/blox.jpg` +img = cv.imread('blox.jpg', cv.IMREAD_GRAYSCALE) # `/samples/data/blox.jpg` # Initiate FAST object with default values fast = cv.FastFeatureDetector_create() diff --git a/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.markdown b/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.markdown index 6abac2c57b..4597c6bfcf 100644 --- a/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.markdown +++ b/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.markdown @@ -40,8 +40,8 @@ from matplotlib import pyplot as plt MIN_MATCH_COUNT = 10 -img1 = cv.imread('box.png',0) # queryImage -img2 = cv.imread('box_in_scene.png',0) # trainImage +img1 = cv.imread('box.png', cv.IMREAD_GRAYSCALE) # queryImage +img2 = cv.imread('box_in_scene.png', cv.IMREAD_GRAYSCALE) # trainImage # Initiate SIFT detector sift = cv.SIFT_create() diff --git a/doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown b/doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown index 55bc0f2903..73d01aaaa1 100644 --- a/doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown +++ b/doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown @@ -67,7 +67,7 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('simple.jpg',0) +img = cv.imread('simple.jpg', cv.IMREAD_GRAYSCALE) # Initiate ORB detector orb = cv.ORB_create() diff --git a/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.markdown b/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.markdown index fc980994c3..5bcd91cce8 100644 --- a/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.markdown +++ b/doc/py_tutorials/py_feature2d/py_surf_intro/py_surf_intro.markdown @@ -76,7 +76,7 @@ and descriptors. First we will see a simple demo on how to find SURF keypoints and descriptors and draw it. All examples are shown in Python terminal since it is just same as SIFT only. @code{.py} ->>> img = cv.imread('fly.png',0) +>>> img = cv.imread('fly.png', cv.IMREAD_GRAYSCALE) # Create SURF object. You can specify params here or later. # Here I set Hessian Threshold to 400 diff --git a/doc/py_tutorials/py_imgproc/py_canny/py_canny.markdown b/doc/py_tutorials/py_imgproc/py_canny/py_canny.markdown index d36e5784eb..8c651afb35 100644 --- a/doc/py_tutorials/py_imgproc/py_canny/py_canny.markdown +++ b/doc/py_tutorials/py_imgproc/py_canny/py_canny.markdown @@ -83,7 +83,8 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('messi5.jpg',0) +img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" edges = cv.Canny(img,100,200) plt.subplot(121),plt.imshow(img,cmap = 'gray') diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown b/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown index e8cfbd6597..91bab9461a 100644 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown +++ b/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown @@ -24,7 +24,8 @@ The function **cv.moments()** gives a dictionary of all moment values calculated import numpy as np import cv2 as cv -img = cv.imread('star.jpg',0) +img = cv.imread('star.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" ret,thresh = cv.threshold(img,127,255,0) im2,contours,hierarchy = cv.findContours(thresh, 1, 2) diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.markdown b/doc/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.markdown index 74d7b252a5..c10faf2608 100644 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.markdown +++ b/doc/py_tutorials/py_imgproc/py_contours/py_contours_begin/py_contours_begin.markdown @@ -29,6 +29,7 @@ import numpy as np import cv2 as cv im = cv.imread('test.jpg') +assert im is not None, "file could not be read, check with os.path.exists()" imgray = cv.cvtColor(im, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(imgray, 127, 255, 0) im2, contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE) diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown b/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown index 397a2a63a0..df4bac93d5 100644 --- a/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown +++ b/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown @@ -41,6 +41,7 @@ import cv2 as cv import numpy as np img = cv.imread('star.jpg') +assert img is not None, "file could not be read, check with os.path.exists()" img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) ret,thresh = cv.threshold(img_gray, 127, 255,0) im2,contours,hierarchy = cv.findContours(thresh,2,1) @@ -92,8 +93,10 @@ docs. import cv2 as cv import numpy as np -img1 = cv.imread('star.jpg',0) -img2 = cv.imread('star2.jpg',0) +img1 = cv.imread('star.jpg', cv.IMREAD_GRAYSCALE) +img2 = cv.imread('star2.jpg', cv.IMREAD_GRAYSCALE) +assert img1 is not None, "file could not be read, check with os.path.exists()" +assert img2 is not None, "file could not be read, check with os.path.exists()" ret, thresh = cv.threshold(img1, 127, 255,0) ret, thresh2 = cv.threshold(img2, 127, 255,0) diff --git a/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.markdown b/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.markdown index 1b626df94f..82ce0d45ab 100644 --- a/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.markdown +++ b/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.markdown @@ -29,6 +29,7 @@ import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('opencv_logo.png') +assert img is not None, "file could not be read, check with os.path.exists()" kernel = np.ones((5,5),np.float32)/25 dst = cv.filter2D(img,-1,kernel) @@ -70,6 +71,7 @@ import numpy as np from matplotlib import pyplot as plt img = cv.imread('opencv-logo-white.png') +assert img is not None, "file could not be read, check with os.path.exists()" blur = cv.blur(img,(5,5)) diff --git a/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown b/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown index add96f2962..6dd151fe96 100644 --- a/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown +++ b/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown @@ -28,6 +28,7 @@ import numpy as np import cv2 as cv img = cv.imread('messi5.jpg') +assert img is not None, "file could not be read, check with os.path.exists()" res = cv.resize(img,None,fx=2, fy=2, interpolation = cv.INTER_CUBIC) @@ -49,7 +50,8 @@ function. See the below example for a shift of (100,50): import numpy as np import cv2 as cv -img = cv.imread('messi5.jpg',0) +img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" rows,cols = img.shape M = np.float32([[1,0,100],[0,1,50]]) @@ -87,7 +89,8 @@ where: To find this transformation matrix, OpenCV provides a function, **cv.getRotationMatrix2D**. Check out the below example which rotates the image by 90 degree with respect to center without any scaling. @code{.py} -img = cv.imread('messi5.jpg',0) +img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" rows,cols = img.shape # cols-1 and rows-1 are the coordinate limits. @@ -108,6 +111,7 @@ which is to be passed to **cv.warpAffine**. Check the below example, and also look at the points I selected (which are marked in green color): @code{.py} img = cv.imread('drawing.png') +assert img is not None, "file could not be read, check with os.path.exists()" rows,cols,ch = img.shape pts1 = np.float32([[50,50],[200,50],[50,200]]) @@ -137,6 +141,7 @@ matrix. See the code below: @code{.py} img = cv.imread('sudoku.png') +assert img is not None, "file could not be read, check with os.path.exists()" rows,cols,ch = img.shape pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]]) diff --git a/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.markdown b/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.markdown index 7dc22d37aa..349ebac031 100644 --- a/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.markdown +++ b/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.markdown @@ -93,6 +93,7 @@ import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('messi5.jpg') +assert img is not None, "file could not be read, check with os.path.exists()" mask = np.zeros(img.shape[:2],np.uint8) bgdModel = np.zeros((1,65),np.float64) @@ -122,7 +123,8 @@ remaining background with gray. Then loaded that mask image in OpenCV, edited or got with corresponding values in newly added mask image. Check the code below:* @code{.py} # newmask is the mask image I manually labelled -newmask = cv.imread('newmask.png',0) +newmask = cv.imread('newmask.png', cv.IMREAD_GRAYSCALE) +assert newmask is not None, "file could not be read, check with os.path.exists()" # wherever it is marked white (sure foreground), change mask=1 # wherever it is marked black (sure background), change mask=0 diff --git a/doc/py_tutorials/py_imgproc/py_gradients/py_gradients.markdown b/doc/py_tutorials/py_imgproc/py_gradients/py_gradients.markdown index 0a52cd431c..0b9556f2bb 100644 --- a/doc/py_tutorials/py_imgproc/py_gradients/py_gradients.markdown +++ b/doc/py_tutorials/py_imgproc/py_gradients/py_gradients.markdown @@ -42,7 +42,8 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('dave.jpg',0) +img = cv.imread('dave.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" laplacian = cv.Laplacian(img,cv.CV_64F) sobelx = cv.Sobel(img,cv.CV_64F,1,0,ksize=5) @@ -79,7 +80,8 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('box.png',0) +img = cv.imread('box.png', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" # Output dtype = cv.CV_8U sobelx8u = cv.Sobel(img,cv.CV_8U,1,0,ksize=5) diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.markdown b/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.markdown index 492897255a..8e05a64080 100644 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.markdown +++ b/doc/py_tutorials/py_imgproc/py_histograms/py_2d_histogram/py_2d_histogram.markdown @@ -38,6 +38,7 @@ import numpy as np import cv2 as cv img = cv.imread('home.jpg') +assert img is not None, "file could not be read, check with os.path.exists()" hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV) hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256]) @@ -55,6 +56,7 @@ import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('home.jpg') +assert img is not None, "file could not be read, check with os.path.exists()" hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV) hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]]) @@ -89,6 +91,7 @@ import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('home.jpg') +assert img is not None, "file could not be read, check with os.path.exists()" hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV) hist = cv.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] ) diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.markdown b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.markdown index a235617914..dce31c376b 100644 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.markdown +++ b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_backprojection/py_histogram_backprojection.markdown @@ -38,10 +38,12 @@ import cv2 as cvfrom matplotlib import pyplot as plt #roi is the object or region of object we need to find roi = cv.imread('rose_red.png') +assert roi is not None, "file could not be read, check with os.path.exists()" hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV) #target is the image we search in target = cv.imread('rose.png') +assert target is not None, "file could not be read, check with os.path.exists()" hsvt = cv.cvtColor(target,cv.COLOR_BGR2HSV) # Find the histograms using calcHist. Can be done with np.histogram2d also @@ -85,9 +87,11 @@ import numpy as np import cv2 as cv roi = cv.imread('rose_red.png') +assert roi is not None, "file could not be read, check with os.path.exists()" hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV) target = cv.imread('rose.png') +assert target is not None, "file could not be read, check with os.path.exists()" hsvt = cv.cvtColor(target,cv.COLOR_BGR2HSV) # calculating object histogram diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.markdown b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.markdown index 8cb24139e8..5667cee36c 100644 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.markdown +++ b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_begins/py_histogram_begins.markdown @@ -77,7 +77,8 @@ and its parameters : So let's start with a sample image. Simply load an image in grayscale mode and find its full histogram. @code{.py} -img = cv.imread('home.jpg',0) +img = cv.imread('home.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" hist = cv.calcHist([img],[0],None,[256],[0,256]) @endcode hist is a 256x1 array, each value corresponds to number of pixels in that image with its @@ -121,7 +122,8 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('home.jpg',0) +img = cv.imread('home.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" plt.hist(img.ravel(),256,[0,256]); plt.show() @endcode You will get a plot as below : @@ -136,6 +138,7 @@ import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('home.jpg') +assert img is not None, "file could not be read, check with os.path.exists()" color = ('b','g','r') for i,col in enumerate(color): histr = cv.calcHist([img],[i],None,[256],[0,256]) @@ -164,7 +167,8 @@ We used cv.calcHist() to find the histogram of the full image. What if you want of some regions of an image? Just create a mask image with white color on the region you want to find histogram and black otherwise. Then pass this as the mask. @code{.py} -img = cv.imread('home.jpg',0) +img = cv.imread('home.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" # create a mask mask = np.zeros(img.shape[:2], np.uint8) diff --git a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.markdown b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.markdown index 99ef285b08..bc9c69a714 100644 --- a/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.markdown +++ b/doc/py_tutorials/py_imgproc/py_histograms/py_histogram_equalization/py_histogram_equalization.markdown @@ -30,7 +30,8 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('wiki.jpg',0) +img = cv.imread('wiki.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" hist,bins = np.histogram(img.flatten(),256,[0,256]) @@ -81,7 +82,8 @@ output is our histogram equalized image. Below is a simple code snippet showing its usage for same image we used : @code{.py} -img = cv.imread('wiki.jpg',0) +img = cv.imread('wiki.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" equ = cv.equalizeHist(img) res = np.hstack((img,equ)) #stacking images side-by-side cv.imwrite('res.png',res) @@ -124,7 +126,8 @@ Below code snippet shows how to apply CLAHE in OpenCV: import numpy as np import cv2 as cv -img = cv.imread('tsukuba_l.png',0) +img = cv.imread('tsukuba_l.png', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" # create a CLAHE object (Arguments are optional). clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) diff --git a/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.markdown b/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.markdown index 7a424e9daf..570ad9145c 100644 --- a/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.markdown +++ b/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.markdown @@ -23,7 +23,8 @@ explained in the documentation. So we directly go to the code. import numpy as np import cv2 as cv -img = cv.imread('opencv-logo-white.png',0) +img = cv.imread('opencv-logo-white.png', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" img = cv.medianBlur(img,5) cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR) diff --git a/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.markdown b/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.markdown index 84a62d14cd..f52a2ce411 100644 --- a/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.markdown +++ b/doc/py_tutorials/py_imgproc/py_morphological_ops/py_morphological_ops.markdown @@ -38,7 +38,8 @@ Here, as an example, I would use a 5x5 kernel with full of ones. Let's see it ho import cv2 as cv import numpy as np -img = cv.imread('j.png',0) +img = cv.imread('j.png', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" kernel = np.ones((5,5),np.uint8) erosion = cv.erode(img,kernel,iterations = 1) @endcode diff --git a/doc/py_tutorials/py_imgproc/py_pyramids/py_pyramids.markdown b/doc/py_tutorials/py_imgproc/py_pyramids/py_pyramids.markdown index 602ab29ad6..0470211fd3 100644 --- a/doc/py_tutorials/py_imgproc/py_pyramids/py_pyramids.markdown +++ b/doc/py_tutorials/py_imgproc/py_pyramids/py_pyramids.markdown @@ -31,6 +31,7 @@ Similarly while expanding, area becomes 4 times in each level. We can find Gauss **cv.pyrDown()** and **cv.pyrUp()** functions. @code{.py} img = cv.imread('messi5.jpg') +assert img is not None, "file could not be read, check with os.path.exists()" lower_reso = cv.pyrDown(higher_reso) @endcode Below is the 4 levels in an image pyramid. @@ -84,6 +85,8 @@ import numpy as np,sys A = cv.imread('apple.jpg') B = cv.imread('orange.jpg') +assert A is not None, "file could not be read, check with os.path.exists()" +assert B is not None, "file could not be read, check with os.path.exists()" # generate Gaussian pyramid for A G = A.copy() diff --git a/doc/py_tutorials/py_imgproc/py_template_matching/py_template_matching.markdown b/doc/py_tutorials/py_imgproc/py_template_matching/py_template_matching.markdown index 551f117879..1557118ab6 100644 --- a/doc/py_tutorials/py_imgproc/py_template_matching/py_template_matching.markdown +++ b/doc/py_tutorials/py_imgproc/py_template_matching/py_template_matching.markdown @@ -38,9 +38,11 @@ import cv2 as cv import numpy as np from matplotlib import pyplot as plt -img = cv.imread('messi5.jpg',0) +img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" img2 = img.copy() -template = cv.imread('template.jpg',0) +template = cv.imread('template.jpg', cv.IMREAD_GRAYSCALE) +assert template is not None, "file could not be read, check with os.path.exists()" w, h = template.shape[::-1] # All the 6 methods for comparison in a list @@ -113,8 +115,10 @@ import numpy as np from matplotlib import pyplot as plt img_rgb = cv.imread('mario.png') +assert img_rgb is not None, "file could not be read, check with os.path.exists()" img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY) -template = cv.imread('mario_coin.png',0) +template = cv.imread('mario_coin.png', cv.IMREAD_GRAYSCALE) +assert template is not None, "file could not be read, check with os.path.exists()" w, h = template.shape[::-1] res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED) diff --git a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown b/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown index f52e9c5db6..7a200725de 100644 --- a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown +++ b/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown @@ -37,7 +37,8 @@ import cv2 as cv import numpy as np from matplotlib import pyplot as plt -img = cv.imread('gradient.png',0) +img = cv.imread('gradient.png', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY) ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV) ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC) @@ -85,7 +86,8 @@ import cv2 as cv import numpy as np from matplotlib import pyplot as plt -img = cv.imread('sudoku.png',0) +img = cv.imread('sudoku.png', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" img = cv.medianBlur(img,5) ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY) @@ -133,7 +135,8 @@ import cv2 as cv import numpy as np from matplotlib import pyplot as plt -img = cv.imread('noisy2.png',0) +img = cv.imread('noisy2.png', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" # global thresholding ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY) @@ -183,7 +186,8 @@ where It actually finds a value of t which lies in between two peaks such that variances to both classes are minimal. It can be simply implemented in Python as follows: @code{.py} -img = cv.imread('noisy2.png',0) +img = cv.imread('noisy2.png', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" blur = cv.GaussianBlur(img,(5,5),0) # find normalized_histogram, and its cumulative distribution function diff --git a/doc/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.markdown b/doc/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.markdown index 6c4533a1b0..59337b1355 100644 --- a/doc/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.markdown +++ b/doc/py_tutorials/py_imgproc/py_transforms/py_fourier_transform/py_fourier_transform.markdown @@ -54,7 +54,8 @@ import cv2 as cv import numpy as np from matplotlib import pyplot as plt -img = cv.imread('messi5.jpg',0) +img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" f = np.fft.fft2(img) fshift = np.fft.fftshift(f) magnitude_spectrum = 20*np.log(np.abs(fshift)) @@ -121,7 +122,8 @@ import numpy as np import cv2 as cv from matplotlib import pyplot as plt -img = cv.imread('messi5.jpg',0) +img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE) +assert img is not None, "file could not be read, check with os.path.exists()" dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT) dft_shift = np.fft.fftshift(dft) @@ -184,7 +186,8 @@ So how do we find this optimal size ? OpenCV provides a function, **cv.getOptima this. It is applicable to both **cv.dft()** and **np.fft.fft2()**. Let's check their performance using IPython magic command %timeit. @code{.py} -In [16]: img = cv.imread('messi5.jpg',0) +In [15]: img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE) +In [16]: assert img is not None, "file could not be read, check with os.path.exists()" In [17]: rows,cols = img.shape In [18]: print("{} {}".format(rows,cols)) 342 548 diff --git a/doc/py_tutorials/py_imgproc/py_watershed/py_watershed.markdown b/doc/py_tutorials/py_imgproc/py_watershed/py_watershed.markdown index ad3c233f30..9536bf3e30 100644 --- a/doc/py_tutorials/py_imgproc/py_watershed/py_watershed.markdown +++ b/doc/py_tutorials/py_imgproc/py_watershed/py_watershed.markdown @@ -49,6 +49,7 @@ import cv2 as cv from matplotlib import pyplot as plt img = cv.imread('coins.png') +assert img is not None, "file could not be read, check with os.path.exists()" gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU) @endcode diff --git a/doc/py_tutorials/py_photo/py_inpainting/py_inpainting.markdown b/doc/py_tutorials/py_photo/py_inpainting/py_inpainting.markdown index 64fabe4564..dce4cf2e5f 100644 --- a/doc/py_tutorials/py_photo/py_inpainting/py_inpainting.markdown +++ b/doc/py_tutorials/py_photo/py_inpainting/py_inpainting.markdown @@ -56,7 +56,7 @@ import numpy as np import cv2 as cv img = cv.imread('messi_2.jpg') -mask = cv.imread('mask2.png',0) +mask = cv.imread('mask2.png', cv.IMREAD_GRAYSCALE) dst = cv.inpaint(img,mask,3,cv.INPAINT_TELEA) diff --git a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown index 66ca510efb..e20f50764b 100644 --- a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown +++ b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown @@ -55,7 +55,7 @@ Making a project int main( int argc, char** argv ) { Mat image; - image = imread( argv[1], 1 ); + image = imread( argv[1], IMREAD_COLOR ); if( argc != 2 || !image.data ) { diff --git a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.markdown b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.markdown index 0f4d1c8cce..f65540770a 100644 --- a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.markdown +++ b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.markdown @@ -35,7 +35,7 @@ int main(int argc, char** argv ) } Mat image; - image = imread( argv[1], 1 ); + image = imread( argv[1], IMREAD_COLOR ); if ( !image.data ) { diff --git a/modules/calib3d/test/test_chesscorners.cpp b/modules/calib3d/test/test_chesscorners.cpp index 3792ca1bc7..0e68dc4886 100644 --- a/modules/calib3d/test/test_chesscorners.cpp +++ b/modules/calib3d/test/test_chesscorners.cpp @@ -216,7 +216,7 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename ) /* read the image */ String img_file = board_list[idx * 2]; - Mat gray = imread( folder + img_file, 0); + Mat gray = imread( folder + img_file, IMREAD_GRAYSCALE); if( gray.empty() ) { diff --git a/modules/calib3d/test/test_stereomatching.cpp b/modules/calib3d/test/test_stereomatching.cpp index 4ea23ebff3..02d1823d2d 100644 --- a/modules/calib3d/test/test_stereomatching.cpp +++ b/modules/calib3d/test/test_stereomatching.cpp @@ -456,8 +456,8 @@ void CV_StereoMatchingTest::run(int) string datasetFullDirName = dataPath + DATASETS_DIR + datasetName + "/"; Mat leftImg = imread(datasetFullDirName + LEFT_IMG_NAME); Mat rightImg = imread(datasetFullDirName + RIGHT_IMG_NAME); - Mat trueLeftDisp = imread(datasetFullDirName + TRUE_LEFT_DISP_NAME, 0); - Mat trueRightDisp = imread(datasetFullDirName + TRUE_RIGHT_DISP_NAME, 0); + Mat trueLeftDisp = imread(datasetFullDirName + TRUE_LEFT_DISP_NAME, IMREAD_GRAYSCALE); + Mat trueRightDisp = imread(datasetFullDirName + TRUE_RIGHT_DISP_NAME, IMREAD_GRAYSCALE); Rect calcROI; if( leftImg.empty() || rightImg.empty() || trueLeftDisp.empty() ) @@ -835,9 +835,9 @@ TEST_P(Calib3d_StereoBM_BufferBM, memAllocsTest) const int SADWindowSize = get<1>(get<1>(GetParam())); String path = cvtest::TS::ptr()->get_data_path() + "cv/stereomatching/datasets/teddy/"; - Mat leftImg = imread(path + "im2.png", 0); + Mat leftImg = imread(path + "im2.png", IMREAD_GRAYSCALE); ASSERT_FALSE(leftImg.empty()); - Mat rightImg = imread(path + "im6.png", 0); + Mat rightImg = imread(path + "im6.png", IMREAD_GRAYSCALE); ASSERT_FALSE(rightImg.empty()); Mat leftDisp; { @@ -923,9 +923,9 @@ TEST(Calib3d_StereoSGBM, regression) { CV_StereoSGBMTest test; test.safe_run(); TEST(Calib3d_StereoSGBM_HH4, regression) { String path = cvtest::TS::ptr()->get_data_path() + "cv/stereomatching/datasets/teddy/"; - Mat leftImg = imread(path + "im2.png", 0); + Mat leftImg = imread(path + "im2.png", IMREAD_GRAYSCALE); ASSERT_FALSE(leftImg.empty()); - Mat rightImg = imread(path + "im6.png", 0); + Mat rightImg = imread(path + "im6.png", IMREAD_GRAYSCALE); ASSERT_FALSE(rightImg.empty()); Mat testData = imread(path + "disp2_hh4.png",-1); ASSERT_FALSE(testData.empty()); diff --git a/modules/features2d/test/test_descriptors_regression.cpp b/modules/features2d/test/test_descriptors_regression.cpp index 0de2b2bd55..b8d4a4755f 100644 --- a/modules/features2d/test/test_descriptors_regression.cpp +++ b/modules/features2d/test/test_descriptors_regression.cpp @@ -406,7 +406,7 @@ TEST( Features2d_DescriptorExtractor, batch_ORB ) for( i = 0; i < n; i++ ) { string imgname = format("%s/img%d.png", path.c_str(), i+1); - Mat img = imread(imgname, 0); + Mat img = imread(imgname, IMREAD_GRAYSCALE); imgs.push_back(img); } @@ -434,7 +434,7 @@ TEST( Features2d_DescriptorExtractor, batch_SIFT ) for( i = 0; i < n; i++ ) { string imgname = format("%s/img%d.png", path.c_str(), i+1); - Mat img = imread(imgname, 0); + Mat img = imread(imgname, IMREAD_GRAYSCALE); imgs.push_back(img); } diff --git a/modules/imgcodecs/misc/java/test/ImgcodecsTest.java b/modules/imgcodecs/misc/java/test/ImgcodecsTest.java index 8fe15d2536..ba22aac06e 100644 --- a/modules/imgcodecs/misc/java/test/ImgcodecsTest.java +++ b/modules/imgcodecs/misc/java/test/ImgcodecsTest.java @@ -45,7 +45,7 @@ public class ImgcodecsTest extends OpenCVTestCase { } public void testImreadStringInt() { - dst = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH, 0); + dst = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH, Imgcodecs.IMREAD_GRAYSCALE); assertFalse(dst.empty()); assertEquals(1, dst.channels()); assertTrue(512 == dst.cols()); diff --git a/modules/imgproc/test/test_connectedcomponents.cpp b/modules/imgproc/test/test_connectedcomponents.cpp index e1a6b761c7..8717217cdf 100644 --- a/modules/imgproc/test/test_connectedcomponents.cpp +++ b/modules/imgproc/test/test_connectedcomponents.cpp @@ -81,7 +81,7 @@ void CV_ConnectedComponentsTest::run(int /* start_from */) int ccltype[] = { cv::CCL_DEFAULT, cv::CCL_WU, cv::CCL_GRANA, cv::CCL_BOLELLI, cv::CCL_SAUF, cv::CCL_BBDT, cv::CCL_SPAGHETTI }; string exp_path = string(ts->get_data_path()) + "connectedcomponents/ccomp_exp.png"; - Mat exp = imread(exp_path, 0); + Mat exp = imread(exp_path, IMREAD_GRAYSCALE); Mat orig = imread(string(ts->get_data_path()) + "connectedcomponents/concentric_circles.png", 0); if (orig.empty()) diff --git a/modules/imgproc/test/test_imgproc_umat.cpp b/modules/imgproc/test/test_imgproc_umat.cpp index 08b85595cb..74bfdac621 100644 --- a/modules/imgproc/test/test_imgproc_umat.cpp +++ b/modules/imgproc/test/test_imgproc_umat.cpp @@ -53,7 +53,7 @@ protected: void run(int) { string imgpath = string(ts->get_data_path()) + "shared/lena.png"; - Mat img = imread(imgpath, 1), gray, smallimg, result; + Mat img = imread(imgpath, IMREAD_COLOR), gray, smallimg, result; UMat uimg = img.getUMat(ACCESS_READ), ugray, usmallimg, uresult; cvtColor(img, gray, COLOR_BGR2GRAY); diff --git a/modules/imgproc/test/test_watershed.cpp b/modules/imgproc/test/test_watershed.cpp index b9356f0eb9..42b6bbb6c7 100644 --- a/modules/imgproc/test/test_watershed.cpp +++ b/modules/imgproc/test/test_watershed.cpp @@ -59,7 +59,7 @@ CV_WatershedTest::~CV_WatershedTest() {} void CV_WatershedTest::run( int /* start_from */) { string exp_path = string(ts->get_data_path()) + "watershed/wshed_exp.png"; - Mat exp = imread(exp_path, 0); + Mat exp = imread(exp_path, IMREAD_GRAYSCALE); Mat orig = imread(string(ts->get_data_path()) + "inpaint/orig.png"); FileStorage fs(string(ts->get_data_path()) + "watershed/comp.xml", FileStorage::READ); diff --git a/modules/java/test/android_test/src/org/opencv/test/OpenCVTestCase.java b/modules/java/test/android_test/src/org/opencv/test/OpenCVTestCase.java index 802bb2daa4..0ebd0db538 100644 --- a/modules/java/test/android_test/src/org/opencv/test/OpenCVTestCase.java +++ b/modules/java/test/android_test/src/org/opencv/test/OpenCVTestCase.java @@ -149,7 +149,7 @@ public class OpenCVTestCase extends TestCase { rgba128 = new Mat(matSize, matSize, CvType.CV_8UC4, Scalar.all(128)); rgbLena = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH); - grayChess = Imgcodecs.imread(OpenCVTestRunner.CHESS_PATH, 0); + grayChess = Imgcodecs.imread(OpenCVTestRunner.CHESS_PATH, Imgcodecs.IMREAD_GRAYSCALE); gray255_32f_3d = new Mat(new int[]{matSize, matSize, matSize}, CvType.CV_32F, new Scalar(255.0)); diff --git a/modules/java/test/pure_test/src/org/opencv/test/OpenCVTestCase.java b/modules/java/test/pure_test/src/org/opencv/test/OpenCVTestCase.java index 3fd918dbfe..bd5546188a 100644 --- a/modules/java/test/pure_test/src/org/opencv/test/OpenCVTestCase.java +++ b/modules/java/test/pure_test/src/org/opencv/test/OpenCVTestCase.java @@ -175,7 +175,7 @@ public class OpenCVTestCase extends TestCase { rgba128 = new Mat(matSize, matSize, CvType.CV_8UC4, Scalar.all(128)); rgbLena = Imgcodecs.imread(OpenCVTestRunner.LENA_PATH); - grayChess = Imgcodecs.imread(OpenCVTestRunner.CHESS_PATH, 0); + grayChess = Imgcodecs.imread(OpenCVTestRunner.CHESS_PATH, Imgcodecs.IMREAD_GRAYSCALE); gray255_32f_3d = new Mat(new int[]{matSize, matSize, matSize}, CvType.CV_32F, new Scalar(255.0)); diff --git a/modules/objdetect/test/test_cascadeandhog.cpp b/modules/objdetect/test/test_cascadeandhog.cpp index e6bf9a23ca..e9fde88464 100644 --- a/modules/objdetect/test/test_cascadeandhog.cpp +++ b/modules/objdetect/test/test_cascadeandhog.cpp @@ -137,7 +137,7 @@ int CV_DetectorTest::prepareData( FileStorage& _fs ) String filename; it >> filename; imageFilenames.push_back(filename); - Mat img = imread( dataPath+filename, 1 ); + Mat img = imread( dataPath+filename, IMREAD_COLOR ); images.push_back( img ); } } diff --git a/modules/photo/test/test_denoising.cpp b/modules/photo/test/test_denoising.cpp index 2cd2e4be6c..fa330b85a0 100644 --- a/modules/photo/test/test_denoising.cpp +++ b/modules/photo/test/test_denoising.cpp @@ -157,7 +157,7 @@ TEST(Photo_White, issue_2646) TEST(Photo_Denoising, speed) { string imgname = string(cvtest::TS::ptr()->get_data_path()) + "shared/5MP.png"; - Mat src = imread(imgname, 0), dst; + Mat src = imread(imgname, IMREAD_GRAYSCALE), dst; double t = (double)getTickCount(); fastNlMeansDenoising(src, dst, 5, 7, 21); diff --git a/modules/videoio/test/test_ffmpeg.cpp b/modules/videoio/test/test_ffmpeg.cpp index 6acc65f177..53dea40418 100644 --- a/modules/videoio/test/test_ffmpeg.cpp +++ b/modules/videoio/test/test_ffmpeg.cpp @@ -194,7 +194,7 @@ public: { string filename = ts->get_data_path() + "readwrite/ordinary.bmp"; VideoCapture cap(filename, CAP_FFMPEG); - Mat img0 = imread(filename, 1); + Mat img0 = imread(filename, IMREAD_COLOR); Mat img, img_next; cap >> img; cap >> img_next; diff --git a/samples/cpp/3calibration.cpp b/samples/cpp/3calibration.cpp index 2495dbd041..115d6987b2 100644 --- a/samples/cpp/3calibration.cpp +++ b/samples/cpp/3calibration.cpp @@ -250,7 +250,7 @@ int main( int argc, char** argv ) { int k1 = k == 0 ? 2 : k == 1 ? 0 : 1; printf("%s\n", imageList[i*3+k].c_str()); - view = imread(imageList[i*3+k], 1); + view = imread(imageList[i*3+k], IMREAD_COLOR); if(!view.empty()) { @@ -338,7 +338,7 @@ int main( int argc, char** argv ) { int k1 = k == 0 ? 2 : k == 1 ? 0 : 1; int k2 = k == 0 ? 1 : k == 1 ? 0 : 2; - view = imread(imageList[i*3+k], 1); + view = imread(imageList[i*3+k], IMREAD_COLOR); if(view.empty()) continue; diff --git a/samples/cpp/calibration.cpp b/samples/cpp/calibration.cpp index 5d67600239..24c9b4417b 100644 --- a/samples/cpp/calibration.cpp +++ b/samples/cpp/calibration.cpp @@ -456,7 +456,7 @@ int main( int argc, char** argv ) view0.copyTo(view); } else if( i < (int)imageList.size() ) - view = imread(imageList[i], 1); + view = imread(imageList[i], IMREAD_COLOR); if(view.empty()) { @@ -581,7 +581,7 @@ int main( int argc, char** argv ) for( i = 0; i < (int)imageList.size(); i++ ) { - view = imread(imageList[i], 1); + view = imread(imageList[i], IMREAD_COLOR); if(view.empty()) continue; remap(view, rview, map1, map2, INTER_LINEAR); diff --git a/samples/cpp/facedetect.cpp b/samples/cpp/facedetect.cpp index 9c846faf48..144306c20e 100644 --- a/samples/cpp/facedetect.cpp +++ b/samples/cpp/facedetect.cpp @@ -145,7 +145,7 @@ int main( int argc, const char** argv ) len--; buf[len] = '\0'; cout << "file " << buf << endl; - image = imread( buf, 1 ); + image = imread( buf, IMREAD_COLOR ); if( !image.empty() ) { detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); diff --git a/samples/cpp/pca.cpp b/samples/cpp/pca.cpp index a5a1c54a92..96fd1e25b1 100644 --- a/samples/cpp/pca.cpp +++ b/samples/cpp/pca.cpp @@ -59,7 +59,7 @@ static void read_imgList(const string& filename, vector& images) { } string line; while (getline(file, line)) { - images.push_back(imread(line, 0)); + images.push_back(imread(line, IMREAD_GRAYSCALE)); } } diff --git a/samples/cpp/stereo_calib.cpp b/samples/cpp/stereo_calib.cpp index 9f5aa56ed6..bfc3b22d71 100644 --- a/samples/cpp/stereo_calib.cpp +++ b/samples/cpp/stereo_calib.cpp @@ -80,7 +80,7 @@ StereoCalib(const vector& imagelist, Size boardSize, float squareSize, b for( k = 0; k < 2; k++ ) { const string& filename = imagelist[i*2+k]; - Mat img = imread(filename, 0); + Mat img = imread(filename, IMREAD_GRAYSCALE); if(img.empty()) break; if( imageSize == Size() ) @@ -298,7 +298,7 @@ StereoCalib(const vector& imagelist, Size boardSize, float squareSize, b { for( k = 0; k < 2; k++ ) { - Mat img = imread(goodImageList[i*2+k], 0), rimg, cimg; + Mat img = imread(goodImageList[i*2+k], IMREAD_GRAYSCALE), rimg, cimg; remap(img, rimg, rmap[k][0], rmap[k][1], INTER_LINEAR); cvtColor(rimg, cimg, COLOR_GRAY2BGR); Mat canvasPart = !isVerticalStereo ? canvas(Rect(w*k, 0, w, h)) : canvas(Rect(0, h*k, w, h)); diff --git a/samples/cpp/tutorial_code/snippets/imgproc_HoughLinesCircles.cpp b/samples/cpp/tutorial_code/snippets/imgproc_HoughLinesCircles.cpp index 289484dca3..c343dd0a8f 100644 --- a/samples/cpp/tutorial_code/snippets/imgproc_HoughLinesCircles.cpp +++ b/samples/cpp/tutorial_code/snippets/imgproc_HoughLinesCircles.cpp @@ -8,7 +8,7 @@ using namespace std; int main(int argc, char** argv) { Mat img, gray; - if( argc != 2 || !(img=imread(argv[1], 1)).data) + if( argc != 2 || !(img=imread(argv[1], IMREAD_COLOR)).data) return -1; cvtColor(img, gray, COLOR_BGR2GRAY); // smooth it, otherwise a lot of false circles may be detected diff --git a/samples/cpp/tutorial_code/snippets/imgproc_HoughLinesP.cpp b/samples/cpp/tutorial_code/snippets/imgproc_HoughLinesP.cpp index e19d29abbb..986b1e79b5 100644 --- a/samples/cpp/tutorial_code/snippets/imgproc_HoughLinesP.cpp +++ b/samples/cpp/tutorial_code/snippets/imgproc_HoughLinesP.cpp @@ -7,7 +7,7 @@ using namespace std; int main(int argc, char** argv) { Mat src, dst, color_dst; - if( argc != 2 || !(src=imread(argv[1], 0)).data) + if( argc != 2 || !(src=imread(argv[1], IMREAD_GRAYSCALE)).data) return -1; Canny( src, dst, 50, 200, 3 ); diff --git a/samples/cpp/tutorial_code/snippets/imgproc_calcHist.cpp b/samples/cpp/tutorial_code/snippets/imgproc_calcHist.cpp index 9d1ca46033..274df040b6 100644 --- a/samples/cpp/tutorial_code/snippets/imgproc_calcHist.cpp +++ b/samples/cpp/tutorial_code/snippets/imgproc_calcHist.cpp @@ -6,7 +6,7 @@ using namespace cv; int main( int argc, char** argv ) { Mat src, hsv; - if( argc != 2 || !(src=imread(argv[1], 1)).data ) + if( argc != 2 || !(src=imread(argv[1], IMREAD_COLOR)).data ) return -1; cvtColor(src, hsv, COLOR_BGR2HSV); diff --git a/samples/cpp/tutorial_code/snippets/imgproc_drawContours.cpp b/samples/cpp/tutorial_code/snippets/imgproc_drawContours.cpp index 4dfcde668e..b90dfad840 100644 --- a/samples/cpp/tutorial_code/snippets/imgproc_drawContours.cpp +++ b/samples/cpp/tutorial_code/snippets/imgproc_drawContours.cpp @@ -9,7 +9,7 @@ int main( int argc, char** argv ) Mat src; // the first command-line parameter must be a filename of the binary // (black-n-white) image - if( argc != 2 || !(src=imread(argv[1], 0)).data) + if( argc != 2 || !(src=imread(argv[1], IMREAD_GRAYSCALE)).data) return -1; Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3); diff --git a/samples/cpp/watershed.cpp b/samples/cpp/watershed.cpp index 9c48ae0ee3..f5df8bebae 100644 --- a/samples/cpp/watershed.cpp +++ b/samples/cpp/watershed.cpp @@ -54,7 +54,7 @@ int main( int argc, char** argv ) return 0; } string filename = samples::findFile(parser.get("@input")); - Mat img0 = imread(filename, 1), imgGray; + Mat img0 = imread(filename, IMREAD_COLOR), imgGray; if( img0.empty() ) { diff --git a/samples/python/calibrate.py b/samples/python/calibrate.py index bca430b5a5..991a531ede 100755 --- a/samples/python/calibrate.py +++ b/samples/python/calibrate.py @@ -57,7 +57,7 @@ def main(): def processImage(fn): print('processing %s... ' % fn) - img = cv.imread(fn, 0) + img = cv.imread(fn, cv.IMREAD_GRAYSCALE) if img is None: print("Failed to load", fn) return None diff --git a/samples/python/mouse_and_match.py b/samples/python/mouse_and_match.py index 0bc2fce76e..9e33264df4 100755 --- a/samples/python/mouse_and_match.py +++ b/samples/python/mouse_and_match.py @@ -69,7 +69,7 @@ class App(): if ext == "png" or ext == "jpg" or ext == "bmp" or ext == "tiff" or ext == "pbm": print(infile) - img = cv.imread(infile,1) + img = cv.imread(infile, cv.IMREAD_COLOR) if img is None: continue self.sel = (0,0,0,0) From e0aa677388cba6afac06678afcac574867f2cea4 Mon Sep 17 00:00:00 2001 From: Yang Chao Date: Sun, 8 Jan 2023 02:30:24 +0800 Subject: [PATCH 04/19] Open CV_CPU_NEON_DOTPROD on Apple silicon devices --- modules/core/src/system.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index 9ea23b1f33..6ad2df7f94 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -243,6 +243,7 @@ std::wstring GetTempFileNameWinRT(std::wstring prefix) #if defined __MACH__ && defined __APPLE__ #include #include +#include #endif #endif @@ -627,6 +628,14 @@ struct HWFeatures #if (defined __ARM_FP && (((__ARM_FP & 0x2) != 0) && defined __ARM_NEON__)) have[CV_CPU_FP16] = true; #endif + #if (defined __ARM_FEATURE_DOTPROD) + int has_feat_dotprod = 0; + size_t has_feat_dotprod_size = sizeof(has_feat_dotprod); + sysctlbyname("hw.optional.arm.FEAT_DotProd", &has_feat_dotprod, &has_feat_dotprod_size, NULL, 0); + if (has_feat_dotprod) { + have[CV_CPU_NEON_DOTPROD] = true; + } + #endif #elif (defined __clang__) #if (defined __ARM_NEON__ || (defined __ARM_NEON && defined __aarch64__)) have[CV_CPU_NEON] = true; From 5bacd8753bc3add73f8f6cee9534c632de126d73 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Tue, 10 Jan 2023 00:59:58 +0000 Subject: [PATCH 05/19] build: eliminate GCC9 warning from sift.simd.hpp --- modules/features2d/src/sift.simd.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/features2d/src/sift.simd.hpp b/modules/features2d/src/sift.simd.hpp index 8a038612c4..d2fe0bb429 100644 --- a/modules/features2d/src/sift.simd.hpp +++ b/modules/features2d/src/sift.simd.hpp @@ -807,11 +807,18 @@ if( dstMat.type() == CV_32F ) __dst = v_min(v_max(v_cvt_f32(v_round(__dst * __nrm2)), __min), __max); v_store(dst + k, __dst); } +#endif +#if defined(__GNUC__) && __GNUC__ >= 9 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Waggressive-loop-optimizations" // iteration XX invokes undefined behavior #endif for( ; k < len; k++ ) { dst[k] = saturate_cast(rawDst[k]*nrm2); } +#if defined(__GNUC__) && __GNUC__ >= 9 +#pragma GCC diagnostic pop +#endif } else // CV_8U { @@ -831,9 +838,8 @@ else // CV_8U #endif #if defined(__GNUC__) && __GNUC__ >= 9 -// avoid warning "iteration 7 invokes undefined behavior" on Linux ARM64 #pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Waggressive-loop-optimizations" +#pragma GCC diagnostic ignored "-Waggressive-loop-optimizations" // iteration XX invokes undefined behavior #endif for( ; k < len; k++ ) { From 6a7d54f55074feb212a04a321663b1a897f3ad57 Mon Sep 17 00:00:00 2001 From: Ihsan Soydemir Date: Thu, 12 Jan 2023 17:54:40 +0100 Subject: [PATCH 06/19] Merge pull request #23128 from Isydmr:update-fastNlMeansDenoising-documentation Fix broken paper link for fastNlMeansDenoising * Fix broken link * Move citation to `opencv.bib` * Cite researchgate reference * Correct citation label * Use semantic scholar BibTex --- doc/opencv.bib | 7 +++++++ modules/photo/include/opencv2/photo.hpp | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/opencv.bib b/doc/opencv.bib index 6b5fedb49e..94e00197bc 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -1314,3 +1314,10 @@ journal = {IEEE transactions on pattern analysis and machine intelligence}, doi = {10.1109/TPAMI.2006.153} } +@article{Buades2005DenoisingIS, + title={Denoising image sequences does not require motion estimation}, + author={Antoni Buades and Bartomeu Coll and Jean-Michel Morel}, + journal={IEEE Conference on Advanced Video and Signal Based Surveillance, 2005.}, + year={2005}, + pages={70-74} +} diff --git a/modules/photo/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp index a457295a48..452fc56432 100644 --- a/modules/photo/include/opencv2/photo.hpp +++ b/modules/photo/include/opencv2/photo.hpp @@ -201,8 +201,8 @@ CV_EXPORTS_W void fastNlMeansDenoisingColored( InputArray src, OutputArray dst, /** @brief Modification of fastNlMeansDenoising function for images sequence where consecutive images have been captured in small period of time. For example video. This version of the function is for grayscale -images or for manual manipulation with colorspaces. For more details see - +images or for manual manipulation with colorspaces. See @cite Buades2005DenoisingIS for more details +(open access [here](https://static.aminer.org/pdf/PDF/000/317/196/spatio_temporal_wiener_filtering_of_image_sequences_using_a_parametric.pdf)). @param srcImgs Input 8-bit 1-channel, 2-channel, 3-channel or 4-channel images sequence. All images should have the same type and @@ -228,8 +228,8 @@ CV_EXPORTS_W void fastNlMeansDenoisingMulti( InputArrayOfArrays srcImgs, OutputA /** @brief Modification of fastNlMeansDenoising function for images sequence where consecutive images have been captured in small period of time. For example video. This version of the function is for grayscale -images or for manual manipulation with colorspaces. For more details see - +images or for manual manipulation with colorspaces. See @cite Buades2005DenoisingIS for more details +(open access [here](https://static.aminer.org/pdf/PDF/000/317/196/spatio_temporal_wiener_filtering_of_image_sequences_using_a_parametric.pdf)). @param srcImgs Input 8-bit or 16-bit (only with NORM_L1) 1-channel, 2-channel, 3-channel or 4-channel images sequence. All images should From f3a03aefad2aa1aa94dca27dad0d05f551085fad Mon Sep 17 00:00:00 2001 From: Rostislav Vasilikhin Date: Tue, 17 Jan 2023 23:06:39 +0100 Subject: [PATCH 07/19] cvIsInf(double) fix + regression test --- modules/core/include/opencv2/core/fast_math.hpp | 2 +- modules/core/test/test_math.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/modules/core/include/opencv2/core/fast_math.hpp b/modules/core/include/opencv2/core/fast_math.hpp index eb4fbe213b..47570f4cd2 100644 --- a/modules/core/include/opencv2/core/fast_math.hpp +++ b/modules/core/include/opencv2/core/fast_math.hpp @@ -295,7 +295,7 @@ CV_INLINE int cvIsInf( double value ) #elif defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__PPC64__) Cv64suf ieee754; ieee754.f = value; - return (ieee754.u & 0x7fffffff00000000) == + return (ieee754.u & 0x7fffffffffffffff) == 0x7ff0000000000000; #else Cv64suf ieee754; diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp index cbd0b7ceb3..9baf285e96 100644 --- a/modules/core/test/test_math.cpp +++ b/modules/core/test/test_math.cpp @@ -3992,6 +3992,13 @@ TEST(Core_FastMath, InlineNaN) EXPECT_EQ( cvIsNaN((double) NAN), 1); EXPECT_EQ( cvIsNaN((double) -NAN), 1); EXPECT_EQ( cvIsNaN(0.0), 0); + + // Regression: check the +/-Inf cases + Cv64suf suf; + suf.u = 0x7FF0000000000000UL; + EXPECT_EQ( cvIsNaN(suf.f), 0); + suf.u = 0xFFF0000000000000UL; + EXPECT_EQ( cvIsNaN(suf.f), 0); } TEST(Core_FastMath, InlineIsInf) @@ -4003,6 +4010,13 @@ TEST(Core_FastMath, InlineIsInf) EXPECT_EQ( cvIsInf((double) HUGE_VAL), 1); EXPECT_EQ( cvIsInf((double) -HUGE_VAL), 1); EXPECT_EQ( cvIsInf(0.0), 0); + + // Regression: check the cases of 0x7FF00000xxxxxxxx + Cv64suf suf; + suf.u = 0x7FF0000000000001UL; + EXPECT_EQ( cvIsInf(suf.f), 0); + suf.u = 0x7FF0000012345678UL; + EXPECT_EQ( cvIsInf(suf.f), 0); } }} // namespace From dbdd357b0af0778045b32a5b23275d6b77093a0f Mon Sep 17 00:00:00 2001 From: Funatomi Takuya Date: Tue, 29 Nov 2022 13:08:40 +0000 Subject: [PATCH 08/19] Extend USAC coverage. Add `estimateSE2(...)`, `estimateSE3(...)`, `estimateSIM2(...)`, `estimateSIM3(...)` for estimating an geometric transformation with rotation and translation (with scaling for SIM) using USAC: as alternative for `estimateAffinePartial2D` and `estimateAffine3D`. Modified test module. Remove unused variables. Remove initializer of unused variable. Add interfaces to accept UsacParams() and corresponding test codes. Revise test code. PartialNd removed Umeyama rewritten for code quality & speed comments & minors rise number of points fix, and +30% faster! only one number should be that big remove USAC code, leave fix only big number --- modules/calib3d/src/precomp.hpp | 2 ++ modules/calib3d/src/usac/local_optimization.cpp | 14 +++++++------- modules/calib3d/test/test_usac.cpp | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/calib3d/src/precomp.hpp b/modules/calib3d/src/precomp.hpp index f2cb7123c0..610deebfa9 100644 --- a/modules/calib3d/src/precomp.hpp +++ b/modules/calib3d/src/precomp.hpp @@ -53,6 +53,8 @@ #include "opencv2/core/ocl.hpp" +#include + #define GET_OPTIMIZED(func) (func) diff --git a/modules/calib3d/src/usac/local_optimization.cpp b/modules/calib3d/src/usac/local_optimization.cpp index ff8089bb8f..3964edec9a 100644 --- a/modules/calib3d/src/usac/local_optimization.cpp +++ b/modules/calib3d/src/usac/local_optimization.cpp @@ -20,7 +20,7 @@ protected: std::vector labeling_inliers; std::vector energies, weights; - std::vector used_edges; + std::set used_edges; std::vector gc_models; public: @@ -40,7 +40,7 @@ public: energies = std::vector(points_size); labeling_inliers = std::vector(points_size); - used_edges = std::vector(points_size*points_size); + used_edges = std::set(); gc_models = std::vector (estimator->getMaxNumSolutionsNonMinimal()); } @@ -115,7 +115,7 @@ private: energies[pt] = energy > 1 ? 1 : energy; } - std::fill(used_edges.begin(), used_edges.end(), false); + used_edges.clear(); bool has_edges = false; // Iterate through all points and set their edges @@ -125,12 +125,12 @@ private: // Iterate through all neighbors for (int actual_neighbor_idx : neighborhood_graph->getNeighbors(point_idx)) { if (actual_neighbor_idx == point_idx || - used_edges[actual_neighbor_idx*points_size + point_idx] || - used_edges[point_idx*points_size + actual_neighbor_idx]) + used_edges.count(actual_neighbor_idx*points_size + point_idx) > 0 || + used_edges.count(point_idx*points_size + actual_neighbor_idx) > 0) continue; - used_edges[actual_neighbor_idx*points_size + point_idx] = true; - used_edges[point_idx*points_size + actual_neighbor_idx] = true; + used_edges.insert(actual_neighbor_idx*points_size + point_idx); + used_edges.insert(point_idx*points_size + actual_neighbor_idx); double a = (0.5 * (energy + energies[actual_neighbor_idx])) * spatial_coherence, b = spatial_coherence, c = spatial_coherence, d = 0; diff --git a/modules/calib3d/test/test_usac.cpp b/modules/calib3d/test/test_usac.cpp index fc36e8c945..f7c4b9e4ce 100644 --- a/modules/calib3d/test/test_usac.cpp +++ b/modules/calib3d/test/test_usac.cpp @@ -416,7 +416,7 @@ TEST (usac_Affine2D, accuracy) { TEST(usac_testUsacParams, accuracy) { std::vector gt_inliers; - const int pts_size = 1500; + const int pts_size = 150000; cv::RNG &rng = cv::theRNG(); const cv::UsacParams usac_params = cv::UsacParams(); cv::Mat pts1, pts2, K1, K2, mask, model, rvec, tvec, R; From 53144ee0eb44063c6cfc0c86dd20f1f5ef013de9 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Wed, 18 Jan 2023 21:36:36 +0000 Subject: [PATCH 09/19] perf: drop runtime time adjustment calibration --- modules/ts/include/opencv2/ts/ts_perf.hpp | 3 -- modules/ts/src/ts_perf.cpp | 65 +---------------------- 2 files changed, 1 insertion(+), 67 deletions(-) diff --git a/modules/ts/include/opencv2/ts/ts_perf.hpp b/modules/ts/include/opencv2/ts/ts_perf.hpp index 8512ec16f5..5e1b7a4adb 100644 --- a/modules/ts/include/opencv2/ts/ts_perf.hpp +++ b/modules/ts/include/opencv2/ts/ts_perf.hpp @@ -454,9 +454,6 @@ private: performance_metrics metrics; void validateMetrics(); - static int64 _timeadjustment; - static int64 _calibrate(); - static void warmup_impl(cv::Mat m, WarmUpType wtype); static int getSizeInBytes(cv::InputArray a); static cv::Size getSize(cv::InputArray a); diff --git a/modules/ts/src/ts_perf.cpp b/modules/ts/src/ts_perf.cpp index 06abfe17b1..aad9d55628 100644 --- a/modules/ts/src/ts_perf.cpp +++ b/modules/ts/src/ts_perf.cpp @@ -26,7 +26,6 @@ using namespace perf; int64 TestBase::timeLimitDefault = 0; unsigned int TestBase::iterationsLimitDefault = UINT_MAX; -int64 TestBase::_timeadjustment = 0; // Item [0] will be considered the default implementation. static std::vector available_impls; @@ -1159,7 +1158,6 @@ void TestBase::Init(const std::vector & availableImpls, timeLimitDefault = param_time_limit == 0.0 ? 1 : (int64)(param_time_limit * cv::getTickFrequency()); iterationsLimitDefault = param_force_samples == 0 ? UINT_MAX : param_force_samples; - _timeadjustment = _calibrate(); } void TestBase::RecordRunParameters() @@ -1193,66 +1191,6 @@ enum PERF_STRATEGY TestBase::getCurrentModulePerformanceStrategy() return strategyForce == PERF_STRATEGY_DEFAULT ? strategyModule : strategyForce; } - -int64 TestBase::_calibrate() -{ - CV_TRACE_FUNCTION(); - if (iterationsLimitDefault <= 1) - return 0; - - class _helper : public ::perf::TestBase - { - public: - _helper() { testStrategy = PERF_STRATEGY_BASE; } - performance_metrics& getMetrics() { return calcMetrics(); } - virtual void TestBody() {} - virtual void PerfTestBody() - { - //the whole system warmup - SetUp(); - cv::Mat a(2048, 2048, CV_32S, cv::Scalar(1)); - cv::Mat b(2048, 2048, CV_32S, cv::Scalar(2)); - declare.time(30); - double s = 0; - declare.iterations(20); - minIters = nIters = 20; - for(; next() && startTimer(); stopTimer()) - s+=a.dot(b); - declare.time(s); - - //self calibration - SetUp(); - declare.iterations(1000); - minIters = nIters = 1000; - for(int iters = 0; next() && startTimer(); iters++, stopTimer()) { /*std::cout << iters << nIters << std::endl;*/ } - } - }; - - // Initialize ThreadPool - class _dummyParallel : public ParallelLoopBody - { - public: - void operator()(const cv::Range& range) const - { - // nothing - CV_UNUSED(range); - } - }; - parallel_for_(cv::Range(0, 1000), _dummyParallel()); - - _timeadjustment = 0; - _helper h; - h.PerfTestBody(); - double compensation = h.getMetrics().min; - if (getCurrentModulePerformanceStrategy() == PERF_STRATEGY_SIMPLE) - { - CV_Assert(compensation < 0.01 * cv::getTickFrequency()); - compensation = 0.0f; // simple strategy doesn't require any compensation - } - LOGD("Time compensation is %.0f", compensation); - return (int64)compensation; -} - #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable:4355) // 'this' : used in base member initializer list @@ -1561,9 +1499,8 @@ void TestBase::stopTimer() if (lastTime == 0) ADD_FAILURE() << " stopTimer() is called before startTimer()/next()"; lastTime = time - lastTime; + CV_Assert(lastTime >= 0); // TODO: CV_Check* for int64 totalTime += lastTime; - lastTime -= _timeadjustment; - if (lastTime < 0) lastTime = 0; times.push_back(lastTime); lastTime = 0; From 69020666fe3ee03e94c3b91bf46cb01c8475c071 Mon Sep 17 00:00:00 2001 From: Alexander Alekhin Date: Thu, 19 Dec 2019 14:26:48 +0300 Subject: [PATCH 10/19] test: reproducible results, enabled 2-channel tests, increased some thresholds --- modules/calib3d/test/test_homography.cpp | 83 ++++++-------------- modules/imgproc/test/test_color.cpp | 4 +- modules/imgproc/test/test_convhull.cpp | 2 +- modules/imgproc/test/test_imgwarp.cpp | 1 - modules/imgproc/test/test_imgwarp_strict.cpp | 6 +- modules/ts/src/ts.cpp | 15 +++- modules/video/test/test_estimaterigid.cpp | 4 +- 7 files changed, 43 insertions(+), 72 deletions(-) diff --git a/modules/calib3d/test/test_homography.cpp b/modules/calib3d/test/test_homography.cpp index 09478dae03..41188a066d 100644 --- a/modules/calib3d/test/test_homography.cpp +++ b/modules/calib3d/test/test_homography.cpp @@ -73,60 +73,27 @@ int METHOD[METHODS_COUNT] = {0, cv::RANSAC, cv::LMEDS, cv::RHO}; using namespace cv; using namespace std; -class CV_HomographyTest: public cvtest::ArrayTest -{ -public: - CV_HomographyTest(); - ~CV_HomographyTest(); - void run (int); +namespace HomographyTestUtils { -protected: +static const float max_diff = 0.032f; +static const float max_2diff = 0.020f; +static const int image_size = 100; +static const double reproj_threshold = 3.0; +static const double sigma = 0.01; - int method; - int image_size; - double reproj_threshold; - double sigma; - -private: - float max_diff, max_2diff; - bool check_matrix_size(const cv::Mat& H); - bool check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type, double &diff); - int check_ransac_mask_1(const Mat& src, const Mat& mask); - int check_ransac_mask_2(const Mat& original_mask, const Mat& found_mask); - - void print_information_1(int j, int N, int method, const Mat& H); - void print_information_2(int j, int N, int method, const Mat& H, const Mat& H_res, int k, double diff); - void print_information_3(int method, int j, int N, const Mat& mask); - void print_information_4(int method, int j, int N, int k, int l, double diff); - void print_information_5(int method, int j, int N, int l, double diff); - void print_information_6(int method, int j, int N, int k, double diff, bool value); - void print_information_7(int method, int j, int N, int k, double diff, bool original_value, bool found_value); - void print_information_8(int method, int j, int N, int k, int l, double diff); -}; - -CV_HomographyTest::CV_HomographyTest() : max_diff(1e-2f), max_2diff(2e-2f) -{ - method = 0; - image_size = 100; - reproj_threshold = 3.0; - sigma = 0.01; -} - -CV_HomographyTest::~CV_HomographyTest() {} - -bool CV_HomographyTest::check_matrix_size(const cv::Mat& H) +static bool check_matrix_size(const cv::Mat& H) { return (H.rows == 3) && (H.cols == 3); } -bool CV_HomographyTest::check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type, double &diff) +static bool check_matrix_diff(const cv::Mat& original, const cv::Mat& found, const int norm_type, double &diff) { diff = cvtest::norm(original, found, norm_type); return diff <= max_diff; } -int CV_HomographyTest::check_ransac_mask_1(const Mat& src, const Mat& mask) +static int check_ransac_mask_1(const Mat& src, const Mat& mask) { if (!(mask.cols == 1) && (mask.rows == src.cols)) return 1; if (countNonZero(mask) < mask.rows) return 2; @@ -134,14 +101,14 @@ int CV_HomographyTest::check_ransac_mask_1(const Mat& src, const Mat& mask) return 0; } -int CV_HomographyTest::check_ransac_mask_2(const Mat& original_mask, const Mat& found_mask) +static int check_ransac_mask_2(const Mat& original_mask, const Mat& found_mask) { if (!(found_mask.cols == 1) && (found_mask.rows == original_mask.rows)) return 1; for (int i = 0; i < found_mask.rows; ++i) if (found_mask.at(i, 0) > 1) return 2; return 0; } -void CV_HomographyTest::print_information_1(int j, int N, int _method, const Mat& H) +static void print_information_1(int j, int N, int _method, const Mat& H) { cout << endl; cout << "Checking for homography matrix sizes..." << endl; cout << endl; cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector "; @@ -153,7 +120,7 @@ void CV_HomographyTest::print_information_1(int j, int N, int _method, const Mat cout << "Number of rows: " << H.rows << " Number of cols: " << H.cols << endl; cout << endl; } -void CV_HomographyTest::print_information_2(int j, int N, int _method, const Mat& H, const Mat& H_res, int k, double diff) +static void print_information_2(int j, int N, int _method, const Mat& H, const Mat& H_res, int k, double diff) { cout << endl; cout << "Checking for accuracy of homography matrix computing..." << endl; cout << endl; cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector "; @@ -169,7 +136,7 @@ void CV_HomographyTest::print_information_2(int j, int N, int _method, const Mat cout << "Maximum allowed difference: " << max_diff << endl; cout << endl; } -void CV_HomographyTest::print_information_3(int _method, int j, int N, const Mat& mask) +static void print_information_3(int _method, int j, int N, const Mat& mask) { cout << endl; cout << "Checking for inliers/outliers mask..." << endl; cout << endl; cout << "Type of srcPoints: "; if ((j>-1) && (j<2)) cout << "Mat of CV_32FC2"; else cout << "vector "; @@ -181,7 +148,7 @@ void CV_HomographyTest::print_information_3(int _method, int j, int N, const Mat cout << "Number of rows: " << mask.rows << " Number of cols: " << mask.cols << endl; cout << endl; } -void CV_HomographyTest::print_information_4(int _method, int j, int N, int k, int l, double diff) +static void print_information_4(int _method, int j, int N, int k, int l, double diff) { cout << endl; cout << "Checking for accuracy of reprojection error computing..." << endl; cout << endl; cout << "Method: "; if (_method == 0) cout << 0 << endl; else cout << "CV_LMEDS" << endl; @@ -195,7 +162,7 @@ void CV_HomographyTest::print_information_4(int _method, int j, int N, int k, in cout << "Maximum allowed difference: " << max_2diff << endl; cout << endl; } -void CV_HomographyTest::print_information_5(int _method, int j, int N, int l, double diff) +static void print_information_5(int _method, int j, int N, int l, double diff) { cout << endl; cout << "Checking for accuracy of reprojection error computing..." << endl; cout << endl; cout << "Method: "; if (_method == 0) cout << 0 << endl; else cout << "CV_LMEDS" << endl; @@ -208,7 +175,7 @@ void CV_HomographyTest::print_information_5(int _method, int j, int N, int l, do cout << "Maximum allowed difference: " << max_diff << endl; cout << endl; } -void CV_HomographyTest::print_information_6(int _method, int j, int N, int k, double diff, bool value) +static void print_information_6(int _method, int j, int N, int k, double diff, bool value) { cout << endl; cout << "Checking for inliers/outliers mask..." << endl; cout << endl; cout << "Method: "; if (_method == RANSAC) cout << "RANSAC" << endl; else if (_method == cv::RHO) cout << "RHO" << endl; else cout << _method << endl; @@ -221,7 +188,7 @@ void CV_HomographyTest::print_information_6(int _method, int j, int N, int k, do cout << "Value of found mask: "<< value << endl; cout << endl; } -void CV_HomographyTest::print_information_7(int _method, int j, int N, int k, double diff, bool original_value, bool found_value) +static void print_information_7(int _method, int j, int N, int k, double diff, bool original_value, bool found_value) { cout << endl; cout << "Checking for inliers/outliers mask..." << endl; cout << endl; cout << "Method: "; if (_method == RANSAC) cout << "RANSAC" << endl; else if (_method == cv::RHO) cout << "RHO" << endl; else cout << _method << endl; @@ -234,7 +201,7 @@ void CV_HomographyTest::print_information_7(int _method, int j, int N, int k, do cout << "Value of original mask: "<< original_value << " Value of found mask: " << found_value << endl; cout << endl; } -void CV_HomographyTest::print_information_8(int _method, int j, int N, int k, int l, double diff) +static void print_information_8(int _method, int j, int N, int k, int l, double diff) { cout << endl; cout << "Checking for reprojection error of inlier..." << endl; cout << endl; cout << "Method: "; if (_method == RANSAC) cout << "RANSAC" << endl; else if (_method == cv::RHO) cout << "RHO" << endl; else cout << _method << endl; @@ -248,11 +215,15 @@ void CV_HomographyTest::print_information_8(int _method, int j, int N, int k, in cout << "Maximum allowed difference: " << max_2diff << endl; cout << endl; } -void CV_HomographyTest::run(int) +} // HomographyTestUtils:: + + +TEST(Calib3d_Homography, accuracy) { + using namespace HomographyTestUtils; for (int N = MIN_COUNT_OF_POINTS; N <= MAX_COUNT_OF_POINTS; ++N) { - RNG& rng = ts->get_rng(); + RNG& rng = cv::theRNG(); float *src_data = new float [2*N]; @@ -308,7 +279,7 @@ void CV_HomographyTest::run(int) for (int i = 0; i < METHODS_COUNT; ++i) { - method = METHOD[i]; + const int method = METHOD[i]; switch (method) { case 0: @@ -411,7 +382,7 @@ void CV_HomographyTest::run(int) for (int i = 0; i < METHODS_COUNT; ++i) { - method = METHOD[i]; + const int method = METHOD[i]; switch (method) { case 0: @@ -573,8 +544,6 @@ void CV_HomographyTest::run(int) } } -TEST(Calib3d_Homography, accuracy) { CV_HomographyTest test; test.safe_run(); } - TEST(Calib3d_Homography, EKcase) { float pt1data[] = diff --git a/modules/imgproc/test/test_color.cpp b/modules/imgproc/test/test_color.cpp index a5499c7cc3..9cb1817b84 100644 --- a/modules/imgproc/test/test_color.cpp +++ b/modules/imgproc/test/test_color.cpp @@ -1077,7 +1077,7 @@ double CV_ColorLabTest::get_success_error_level( int /*test_case_idx*/, int i, i { int depth = test_mat[i][j].depth(); // j == 0 is for forward code, j == 1 is for inverse code - return (depth == CV_8U) ? (srgb ? 32 : 8) : + return (depth == CV_8U) ? (srgb ? 37 : 8) : //(depth == CV_16U) ? 32 : // 16u is disabled srgb ? ((j == 0) ? 0.4 : 0.0055) : 1e-3; } @@ -1256,7 +1256,7 @@ double CV_ColorLuvTest::get_success_error_level( int /*test_case_idx*/, int i, i { int depth = test_mat[i][j].depth(); // j == 0 is for forward code, j == 1 is for inverse code - return (depth == CV_8U) ? (srgb ? 36 : 8) : + return (depth == CV_8U) ? (srgb ? 37 : 8) : //(depth == CV_16U) ? 32 : // 16u is disabled 5e-2; } diff --git a/modules/imgproc/test/test_convhull.cpp b/modules/imgproc/test/test_convhull.cpp index e5f6bd8e63..75ec98f9c9 100644 --- a/modules/imgproc/test/test_convhull.cpp +++ b/modules/imgproc/test/test_convhull.cpp @@ -180,7 +180,7 @@ cvTsIsPointOnLineSegment(const cv::Point2f &x, const cv::Point2f &a, const cv::P double d2 = cvTsDist(cvPoint2D32f(x.x, x.y), cvPoint2D32f(b.x, b.y)); double d3 = cvTsDist(cvPoint2D32f(a.x, a.y), cvPoint2D32f(b.x, b.y)); - return (abs(d1 + d2 - d3) <= (1E-5)); + return (abs(d1 + d2 - d3) <= (1E-4)); } diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index 1257a472b7..227c0befc9 100644 --- a/modules/imgproc/test/test_imgwarp.cpp +++ b/modules/imgproc/test/test_imgwarp.cpp @@ -102,7 +102,6 @@ void CV_ImgWarpBaseTest::get_test_array_types_and_sizes( int test_case_idx, int cn = cvtest::randInt(rng) % 3 + 1; cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types ); depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F; - cn += cn == 2; types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn); if( test_array[INPUT].size() > 1 ) diff --git a/modules/imgproc/test/test_imgwarp_strict.cpp b/modules/imgproc/test/test_imgwarp_strict.cpp index 5ca3d09ec4..4b99331807 100644 --- a/modules/imgproc/test/test_imgwarp_strict.cpp +++ b/modules/imgproc/test/test_imgwarp_strict.cpp @@ -151,8 +151,6 @@ void CV_ImageWarpBaseTest::generate_test_data() depth = rng.uniform(0, CV_64F); int cn = rng.uniform(1, 4); - while (cn == 2) - cn = rng.uniform(1, 4); src.create(ssize, CV_MAKE_TYPE(depth, cn)); @@ -237,7 +235,7 @@ float CV_ImageWarpBaseTest::get_success_error_level(int _interpolation, int) con else if (_interpolation == INTER_LANCZOS4) return 1.0f; else if (_interpolation == INTER_NEAREST) - return 1.0f; + return 255.0f; // FIXIT: check is not reliable for Black/White (0/255) images else if (_interpolation == INTER_AREA) return 2.0f; else @@ -430,8 +428,6 @@ void CV_Resize_Test::generate_test_data() depth = rng.uniform(0, CV_64F); int cn = rng.uniform(1, 4); - while (cn == 2) - cn = rng.uniform(1, 4); src.create(ssize, CV_MAKE_TYPE(depth, cn)); diff --git a/modules/ts/src/ts.cpp b/modules/ts/src/ts.cpp index aed205fbf6..2a8c9ba001 100644 --- a/modules/ts/src/ts.cpp +++ b/modules/ts/src/ts.cpp @@ -621,20 +621,27 @@ void TS::set_gtest_status() void TS::update_context( BaseTest* test, int test_case_idx, bool update_ts_context ) { + CV_UNUSED(update_ts_context); + if( current_test_info.test != test ) { for( int i = 0; i <= CONSOLE_IDX; i++ ) output_buf[i] = string(); - rng = RNG(params.rng_seed); - current_test_info.rng_seed0 = current_test_info.rng_seed = rng.state; + } + + if (test_case_idx >= 0) + { + current_test_info.rng_seed = param_seed + test_case_idx; + current_test_info.rng_seed0 = current_test_info.rng_seed; + + rng = RNG(current_test_info.rng_seed); + cv::theRNG() = rng; } current_test_info.test = test; current_test_info.test_case_idx = test_case_idx; current_test_info.code = 0; cvSetErrStatus( CV_StsOk ); - if( update_ts_context ) - current_test_info.rng_seed = rng.state; } diff --git a/modules/video/test/test_estimaterigid.cpp b/modules/video/test/test_estimaterigid.cpp index 5fed70465f..74db11ff61 100644 --- a/modules/video/test/test_estimaterigid.cpp +++ b/modules/video/test/test_estimaterigid.cpp @@ -74,7 +74,7 @@ struct WrapAff2D bool CV_RigidTransform_Test::testNPoints(int from) { - cv::RNG rng = ts->get_rng(); + cv::RNG rng = cv::theRNG(); int progress = 0; int k, ntests = 10000; @@ -172,4 +172,4 @@ void CV_RigidTransform_Test::run( int start_from ) TEST(Video_RigidFlow, accuracy) { CV_RigidTransform_Test test; test.safe_run(); } -}} // namespace \ No newline at end of file +}} // namespace From 1833b034fec39f18f9a057c2e90d7ef1ba171e02 Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Thu, 19 Jan 2023 22:06:52 +0900 Subject: [PATCH 11/19] make test tolerate to rounding error --- modules/ts/src/cuda_test.cpp | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/modules/ts/src/cuda_test.cpp b/modules/ts/src/cuda_test.cpp index 39658c403a..28808ead2e 100644 --- a/modules/ts/src/cuda_test.cpp +++ b/modules/ts/src/cuda_test.cpp @@ -519,13 +519,35 @@ namespace cvtest int validCount = 0; - for (size_t i = 0; i < gold.size(); ++i) + if (actual.size() == gold.size()) { - const cv::KeyPoint& p1 = gold[i]; - const cv::KeyPoint& p2 = actual[i]; + for (size_t i = 0; i < gold.size(); ++i) + { + const cv::KeyPoint& p1 = gold[i]; + const cv::KeyPoint& p2 = actual[i]; - if (keyPointsEquals(p1, p2)) - ++validCount; + if (keyPointsEquals(p1, p2)) + ++validCount; + } + } + else + { + std::vector& shorter = gold; + std::vector& longer = actual; + if (actual.size() < gold.size()) + { + shorter = actual; + longer = gold; + } + for (size_t i = 0; i < shorter.size(); ++i) + { + const cv::KeyPoint& p1 = shorter[i]; + const cv::KeyPoint& p2 = longer[i]; + const cv::KeyPoint& p3 = longer[i+1]; + + if (keyPointsEquals(p1, p2) || keyPointsEquals(p1, p3)) + ++validCount; + } } return validCount; From 35c17f35bef25a8437ed2c659ed241862948a696 Mon Sep 17 00:00:00 2001 From: Labib Asari Date: Sat, 21 Jan 2023 00:16:48 +0530 Subject: [PATCH 12/19] removed redundant code --- modules/imgproc/src/distransform.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp index ccc39795ea..ba16905b3f 100644 --- a/modules/imgproc/src/distransform.cpp +++ b/modules/imgproc/src/distransform.cpp @@ -740,10 +740,8 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe if( maskSize != CV_DIST_MASK_3 && maskSize != CV_DIST_MASK_5 && maskSize != CV_DIST_MASK_PRECISE ) CV_Error( CV_StsBadSize, "Mask size should be 3 or 5 or 0 (precise)" ); - if( distType == CV_DIST_C || distType == CV_DIST_L1 ) - maskSize = !need_labels ? CV_DIST_MASK_3 : CV_DIST_MASK_5; - else if( distType == CV_DIST_L2 && need_labels ) - maskSize = CV_DIST_MASK_5; + if ((distType == CV_DIST_C || distType == CV_DIST_L1) && !need_labels) + maskSize = CV_DIST_MASK_3; if( maskSize == CV_DIST_MASK_PRECISE ) { From 4009bca59a3655cdc50e6dfa4a65e5a73fa415da Mon Sep 17 00:00:00 2001 From: Rostislav Vasilikhin Date: Mon, 23 Jan 2023 12:59:43 +0100 Subject: [PATCH 13/19] Merge pull request #23025 from savuor:backport3_stddev_calib_fix Backport of #22992 to 3.4 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake --- modules/calib3d/src/calibration.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/modules/calib3d/src/calibration.cpp b/modules/calib3d/src/calibration.cpp index ee1a751530..7081ee8b4d 100644 --- a/modules/calib3d/src/calibration.cpp +++ b/modules/calib3d/src/calibration.cpp @@ -1549,6 +1549,12 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, } } + Mat mask = cvarrToMat(solver.mask); + int nparams_nz = countNonZero(mask); + if (nparams_nz >= 2 * total) + CV_Error_(CV_StsBadArg, + ("There should be less vars to optimize (having %d) than the number of residuals (%d = 2 per point)", nparams_nz, 2 * total)); + // 2. initialize extrinsic parameters for( i = 0, pos = 0; i < nimages; i++, pos += ni ) { @@ -1651,27 +1657,24 @@ static double cvCalibrateCamera2Internal( const CvMat* objectPoints, { if( stdDevs ) { - Mat mask = cvarrToMat(solver.mask); - int nparams_nz = countNonZero(mask); Mat JtJinv, JtJN; JtJN.create(nparams_nz, nparams_nz, CV_64F); subMatrix(cvarrToMat(_JtJ), JtJN, mask, mask); completeSymm(JtJN, false); cv::invert(JtJN, JtJinv, DECOMP_SVD); - //sigma2 is deviation of the noise - //see any papers about variance of the least squares estimator for - //detailed description of the variance estimation methods - double sigma2 = norm(allErrors, NORM_L2SQR) / (total - nparams_nz); + // an explanation of that denominator correction can be found here: + // R. Hartley, A. Zisserman, Multiple View Geometry in Computer Vision, 2004, section 5.1.3, page 134 + // see the discussion for more details: https://github.com/opencv/opencv/pull/22992 + int nErrors = 2 * total - nparams_nz; + double sigma2 = norm(allErrors, NORM_L2SQR) / nErrors; Mat stdDevsM = cvarrToMat(stdDevs); int j = 0; for ( int s = 0; s < nparams; s++ ) + { + stdDevsM.at(s) = mask.data[s] ? std::sqrt(JtJinv.at(j,j) * sigma2) : 0.0; if( mask.data[s] ) - { - stdDevsM.at(s) = std::sqrt(JtJinv.at(j,j) * sigma2); j++; - } - else - stdDevsM.at(s) = 0.; + } } break; } From 186c18668c823a927dbafcc162b94f1b7781f57d Mon Sep 17 00:00:00 2001 From: Tomoaki Teshima Date: Mon, 23 Jan 2023 22:47:43 +0900 Subject: [PATCH 14/19] suppress warning --- modules/dnn/src/cuda4dnn/primitives/matmul.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/dnn/src/cuda4dnn/primitives/matmul.hpp b/modules/dnn/src/cuda4dnn/primitives/matmul.hpp index e4ab3d2721..f5aa7f0a7f 100644 --- a/modules/dnn/src/cuda4dnn/primitives/matmul.hpp +++ b/modules/dnn/src/cuda4dnn/primitives/matmul.hpp @@ -38,8 +38,8 @@ namespace cv { namespace dnn { namespace cuda4dnn { const std::vector>& outputs, csl::Workspace& workspace) override { - CV_Assert((inputs.size() == 2 && constTensor.empty() || - inputs.size() == 1 && !constTensor.empty()) && outputs.size() == 1); + CV_Assert(((inputs.size() == 2 && constTensor.empty()) || + (inputs.size() == 1 && !constTensor.empty())) && outputs.size() == 1); auto input1_wrapper = inputs[0].dynamicCast(); auto input1 = input1_wrapper->getView(); From cb7fe597a5f1424bb1f7f6b17d2d2a2d502aba2c Mon Sep 17 00:00:00 2001 From: Lilo Huang Date: Wed, 25 Jan 2023 12:49:08 +0800 Subject: [PATCH 15/19] Merge pull request #23172 from lilohuang:master Adding HEVC/H265 FourCC support to MSMF video writer * Adding HEVC/H265 fourcc to MSMF video writer Adding HEVC/H265 fourcc to MSMF video writer. I have verified it with my own video input stream, and it works well on my workstation. * Update video io testing * Adding macro fence to get rid of compiler error H265/HEVC encoder is only available in Windows or later. https://learn.microsoft.com/en-us/windows/win32/medfound/h-265---hevc-video-encoder * Update test_video_io.cpp --- modules/videoio/src/cap_msmf.cpp | 6 ++++++ modules/videoio/test/test_video_io.cpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp index 505814e96c..78eefc34a3 100644 --- a/modules/videoio/src/cap_msmf.cpp +++ b/modules/videoio/src/cap_msmf.cpp @@ -2469,6 +2469,12 @@ const GUID CvVideoWriter_MSMF::FourCC2GUID(int fourcc) #endif case CV_FOURCC_MACRO('H', '2', '6', '4'): return MFVideoFormat_H264; break; +#if defined(NTDDI_WIN10) + case CV_FOURCC_MACRO('H', '2', '6', '5'): + return MFVideoFormat_H265; break; + case CV_FOURCC_MACRO('H', 'E', 'V', 'C'): + return MFVideoFormat_HEVC; break; +#endif case CV_FOURCC_MACRO('M', '4', 'S', '2'): return MFVideoFormat_M4S2; break; case CV_FOURCC_MACRO('M', 'J', 'P', 'G'): diff --git a/modules/videoio/test/test_video_io.cpp b/modules/videoio/test/test_video_io.cpp index 595e1557ef..7d7944f5eb 100644 --- a/modules/videoio/test/test_video_io.cpp +++ b/modules/videoio/test/test_video_io.cpp @@ -388,6 +388,7 @@ static Ext_Fourcc_PSNR synthetic_params[] = { {"wmv", "WMV3", 30.f, CAP_MSMF}, {"wmv", "WVC1", 30.f, CAP_MSMF}, {"mov", "H264", 30.f, CAP_MSMF}, + // {"mov", "HEVC", 30.f, CAP_MSMF}, // excluded due to CI issue: https://github.com/opencv/opencv/pull/23172 #endif #ifdef HAVE_AVFOUNDATION @@ -991,6 +992,7 @@ static Ext_Fourcc_PSNR hw_codecs[] = { #ifdef _WIN32 {"mp4", "MPEG", 29.f, CAP_MSMF}, {"mp4", "H264", 29.f, CAP_MSMF}, + {"mp4", "HEVC", 29.f, CAP_MSMF}, #endif }; From bf29a4d7464ec587e8a6a566d495ac4636327d0d Mon Sep 17 00:00:00 2001 From: Yannis Guyon Date: Fri, 27 Jan 2023 13:02:46 +0100 Subject: [PATCH 16/19] Avoid double-checked locking with TSAN in parallel Omit the first check of the double-checked locking pattern in recordException() in parallel.cpp when CV_THREAD_SANITIZER is defined. This should only slow recordException() down when the thread sanitizer is used, and avoids the TSAN data race warning. --- modules/core/src/parallel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index a4a7baf0f6..efecefc4b4 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -263,7 +263,9 @@ namespace { void recordException(const cv::String& msg) #endif { +#ifndef CV_THREAD_SANITIZER if (!hasException) +#endif { cv::AutoLock lock(cv::getInitializationMutex()); if (!hasException) From 4d918ba40b5249358967b43f97f9462fafb6c9e5 Mon Sep 17 00:00:00 2001 From: Yuantao Feng Date: Fri, 27 Jan 2023 21:35:59 +0800 Subject: [PATCH 17/19] Merge pull request #23047 from fengyuentau:layer_norm dnn: add layer normalization for vision transformers * add layer norm onnx parser, impl and tests * add onnx graph simplifier for layer norm expanded * handle the case when constants are of type Initializer * add test case for layer norm expanded with initializers * use CV_Assert & CV_CheckType in place of CV_Assert_N; use forward_fallback for OCL_FP16 * use const ref / ref in parameters of invoker::run; extract inner const if from nested loop; use size_t in place of ull * template hasBias * remove trailing whitespace * use pointer parameter with null check; move normSize division & mean_square division outside of loop; use std::max to ensure positive value before std::sqrt * refactor implementation, optimize parallel_for * disable layer norm expanded * remove the removal of layer norm optional outputs --- .../dnn/include/opencv2/dnn/all_layers.hpp | 10 + modules/dnn/perf/perf_layer.cpp | 208 ++++++++++++++++++ modules/dnn/src/init.cpp | 1 + modules/dnn/src/layers/layer_norm.cpp | 176 +++++++++++++++ .../dnn/src/onnx/onnx_graph_simplifier.cpp | 159 +++++++++++++ modules/dnn/src/onnx/onnx_importer.cpp | 52 +++++ modules/dnn/test/test_onnx_importer.cpp | 30 +++ 7 files changed, 636 insertions(+) create mode 100644 modules/dnn/src/layers/layer_norm.cpp diff --git a/modules/dnn/include/opencv2/dnn/all_layers.hpp b/modules/dnn/include/opencv2/dnn/all_layers.hpp index 37af0ddea5..ae1d909660 100644 --- a/modules/dnn/include/opencv2/dnn/all_layers.hpp +++ b/modules/dnn/include/opencv2/dnn/all_layers.hpp @@ -1085,6 +1085,16 @@ CV__DNN_INLINE_NS_BEGIN static Ptr create(const LayerParams& params); }; + class CV_EXPORTS LayerNormLayer : public Layer + { + public: + bool hasBias; + int axis; + float epsilon; + + static Ptr create(const LayerParams& params); + }; + //! @} //! @} CV__DNN_INLINE_NS_END diff --git a/modules/dnn/perf/perf_layer.cpp b/modules/dnn/perf/perf_layer.cpp index ffe0240a18..38e35f1258 100644 --- a/modules/dnn/perf/perf_layer.cpp +++ b/modules/dnn/perf/perf_layer.cpp @@ -417,6 +417,212 @@ PERF_TEST_P_(Layer_ScatterND, DISABLED_ScatterND_add) test_layer({N, C, H , W}, "add"); } +struct Layer_LayerNorm : public TestBaseWithParam > +{ + void test_layer(const std::vector& x_shape) + { + int backendId = get<0>(GetParam()); + int targetId = get<1>(GetParam()); + + Mat x(x_shape, CV_32FC1); + Mat scale(x_shape.back(), 1, CV_32FC1); + Mat b(x_shape.back(), 1, CV_32FC1); + + randu(x, 0.f, 1.f); + randu(scale, 0.f, 1.f); + randu(b, 0.f, 1.f); + + + Net net; + LayerParams lp; + lp.type = "LayerNormalization"; + lp.name = "testLayer"; + lp.set("axis", 2); + lp.set("hasBias", true); + int id = net.addLayerToPrev(lp.name, lp.type, lp); + net.connect(0, 0, id, 0); + net.connect(0, 1, id, 1); + net.connect(0, 2, id, 2); + + // warmup + { + std::vector inpNames(3); + inpNames[0] = "x"; + inpNames[1] = "scale"; + inpNames[2] = "b"; + net.setInputsNames(inpNames); + net.setInput(x, inpNames[0]); + net.setInput(scale, inpNames[1]); + net.setInput(b, inpNames[2]); + + net.setPreferableBackend(backendId); + net.setPreferableTarget(targetId); + Mat out = net.forward(); + } + + TEST_CYCLE() + { + Mat res = net.forward(); + } + + SANITY_CHECK_NOTHING(); + } + + int N = 1; + int H = 50; + int W = 768; +}; + +PERF_TEST_P_(Layer_LayerNorm, LayerNorm) +{ + test_layer({N, H ,W}); +} + +struct Layer_LayerNormExpanded : public TestBaseWithParam > +{ + void test_layer(const std::vector& x_shape) + { + int backendId = get<0>(GetParam()); + int targetId = get<1>(GetParam()); + + Mat x(x_shape, CV_32FC1); + Mat scale(1, x_shape.back(), CV_32FC1); // transpose to pass shape check + Mat b(1, x_shape.back(), CV_32FC1); // transpose to pass shape check + + randu(x, 0.f, 1.f); + randu(scale, 0.f, 1.f); + randu(b, 0.f, 1.f); + + // sub graph structure: + // -> ReduceMean -> -> Pow(2) -> ReduceMean -> Add(epsilon) -> Sqrt -> + // x Sub Div -> Mul(scale) -> Add(bias) + // ---------------> -------------------------------------------------> + + Net net; + + LayerParams lp_rm; + lp_rm.type = "Reduce"; + lp_rm.name = "reducemean1"; + lp_rm.set("reduce", "AVE"); + std::vector deleteDims(1, x_shape.back()); + lp_rm.set("deleted_dims", DictValue::arrayInt(&deleteDims[0], deleteDims.size())); + std::vector targetDims(x_shape.begin(), x_shape.end()); + targetDims[x_shape.size() - 1] = 1; + lp_rm.set("target_dims", DictValue::arrayInt(&targetDims[0], targetDims.size())); + int id_rm = net.addLayerToPrev(lp_rm.name, lp_rm.type, lp_rm); + net.connect(0, 0, id_rm, 0); + + LayerParams lp_sub; + lp_sub.type = "NaryEltwise"; + lp_sub.name = "sub1"; + lp_sub.set("operation", "sub"); + int id_sub = net.addLayer(lp_sub.name, lp_sub.type, lp_sub); + net.connect(0, 0, id_sub, 0); + net.connect(id_rm, 0, id_sub, 1); + + Mat pow_const(1, 1, CV_32FC1); + pow_const.at(0) = 2.f; + LayerParams lp_pow_const; + lp_pow_const.type = "Const"; + lp_pow_const.name = "const1"; + lp_pow_const.blobs.push_back(pow_const); + int id_pow_const = net.addLayer(lp_pow_const.name, lp_pow_const.type, lp_pow_const); + LayerParams lp_pow; + lp_pow.type = "NaryEltwise"; + lp_pow.name = "pow1"; + lp_pow.set("operation", "pow"); + int id_pow = net.addLayer(lp_pow.name, lp_pow.type, lp_pow); + net.connect(id_sub, 0, id_pow, 0); + net.connect(id_pow_const, 0, id_pow, 1); + + LayerParams lp_rm1; + lp_rm1.type = "Reduce"; + lp_rm1.name = "reducemean2"; + lp_rm1.set("reduce", "AVE"); + lp_rm1.set("deleted_dims", DictValue::arrayInt(&deleteDims[0], deleteDims.size())); + lp_rm1.set("target_dims", DictValue::arrayInt(&targetDims[0], targetDims.size())); + int id_rm1 = net.addLayer(lp_rm1.name, lp_rm1.type, lp_rm1); + net.connect(id_pow, 0, id_rm1, 0); + + Mat add_const(1, 1, CV_32F); + add_const.at(0) = 1e-5; + LayerParams lp_add_const; + lp_add_const.type = "Const"; + lp_add_const.name = "const2"; + lp_add_const.blobs.push_back(add_const); + int id_add_const = net.addLayer(lp_add_const.name, lp_add_const.type, lp_add_const); + LayerParams lp_add; + lp_add.type = "NaryEltwise"; + lp_add.name = "add1"; + lp_add.set("operation", "add"); + int id_add = net.addLayer(lp_add.name, lp_add.type, lp_add); + net.connect(id_rm1, 0, id_add, 0); + net.connect(id_add_const, 0, id_add, 1); + + LayerParams lp_sqrt; + lp_sqrt.type = "Sqrt"; + lp_sqrt.name = "sqrt1"; + int id_sqrt = net.addLayer(lp_sqrt.name, lp_sqrt.type, lp_sqrt); + net.connect(id_add, 0, id_sqrt, 0); + + LayerParams lp_div; + lp_div.type = "NaryEltwise"; + lp_div.name = "div1"; + lp_div.set("operation", "div"); + int id_div = net.addLayer(lp_div.name, lp_div.type, lp_div); + net.connect(id_sub, 0, id_div, 0); + net.connect(id_sqrt, 0, id_div, 1); + + LayerParams lp_mul; + lp_mul.type = "NaryEltwise"; + lp_mul.name = "mul1"; + lp_mul.set("operation", "mul"); + int id_mul = net.addLayer(lp_mul.name, lp_mul.type, lp_mul); + net.connect(id_div, 0, id_mul, 0); + net.connect(0, 1, id_mul, 1); + + LayerParams lp_add1; + lp_add1.type = "NaryEltwise"; + lp_add1.name = "add2"; + lp_add1.set("operation", "add"); + int id_add1 = net.addLayer(lp_add1.name, lp_add1.type, lp_add1); + net.connect(id_mul, 0, id_add1, 0); + net.connect(0, 2, id_add1, 1); + + // warmup + { + std::vector inpNames(3); + inpNames[0] = "x"; + inpNames[1] = "scale"; + inpNames[2] = "b"; + net.setInputsNames(inpNames); + net.setInput(x, inpNames[0]); + net.setInput(scale, inpNames[1]); + net.setInput(b, inpNames[2]); + + net.setPreferableBackend(backendId); + net.setPreferableTarget(targetId); + Mat out = net.forward(); + } + + TEST_CYCLE() + { + Mat res = net.forward(); + } + + SANITY_CHECK_NOTHING(); + } + + int N = 1; + int H = 50; + int W = 768; +}; + +PERF_TEST_P_(Layer_LayerNormExpanded, DISABLED_LayerNormExpanded) +{ + test_layer({N, H ,W}); +} + INSTANTIATE_TEST_CASE_P(/**/, Layer_Slice, dnnBackendsAndTargets(false, false)); INSTANTIATE_TEST_CASE_P(/**/, Layer_NaryEltwise, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU))); #ifdef HAVE_CUDA @@ -424,5 +630,7 @@ INSTANTIATE_TEST_CASE_P(CUDA, Layer_NaryEltwise, testing::Values(std::make_tuple #endif INSTANTIATE_TEST_CASE_P(/**/, Layer_Scatter, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU))); INSTANTIATE_TEST_CASE_P(/**/, Layer_ScatterND, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU))); +INSTANTIATE_TEST_CASE_P(/**/, Layer_LayerNorm, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU))); +INSTANTIATE_TEST_CASE_P(/**/, Layer_LayerNormExpanded, testing::Values(std::make_tuple(DNN_BACKEND_OPENCV, DNN_TARGET_CPU))); } // namespace diff --git a/modules/dnn/src/init.cpp b/modules/dnn/src/init.cpp index d20f9dff8d..72eca9ed4e 100644 --- a/modules/dnn/src/init.cpp +++ b/modules/dnn/src/init.cpp @@ -154,6 +154,7 @@ void initializeLayerFactory() CV_DNN_REGISTER_LAYER_CLASS(Arg, ArgLayer); CV_DNN_REGISTER_LAYER_CLASS(Reciprocal, ReciprocalLayer); CV_DNN_REGISTER_LAYER_CLASS(Gather, GatherLayer); + CV_DNN_REGISTER_LAYER_CLASS(LayerNormalization, LayerNormLayer); CV_DNN_REGISTER_LAYER_CLASS(Crop, CropLayer); CV_DNN_REGISTER_LAYER_CLASS(Eltwise, EltwiseLayer); diff --git a/modules/dnn/src/layers/layer_norm.cpp b/modules/dnn/src/layers/layer_norm.cpp new file mode 100644 index 0000000000..a760766a3f --- /dev/null +++ b/modules/dnn/src/layers/layer_norm.cpp @@ -0,0 +1,176 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. + +#include "../precomp.hpp" +#include "layers_common.hpp" + +namespace cv { namespace dnn { + +class LayerNormLayerImpl CV_FINAL : public LayerNormLayer +{ +public: + LayerNormLayerImpl(const LayerParams& params) + { + setParamsFrom(params); + + // standard attr + axis = params.get("axis", 0); + epsilon = params.get("epsilon", 1e-5); + + // opencv attr + hasBias = params.get("hasBias", false); + } + + virtual bool supportBackend(int backendId) CV_OVERRIDE + { + return backendId == DNN_BACKEND_OPENCV; + } + + virtual bool getMemoryShapes(const std::vector &inputs, + const int requiredOutputs, + std::vector &outputs, + std::vector &internals) const CV_OVERRIDE + { + // check shapes of weight and bias if existed + // inputs >= 2 (X and Weight are requested, bias is optional) + CV_Check(inputs.size(), inputs.size() >= 2 && inputs.size() <= 3, "LayerNorm: require two (x, weight) or three (x, weight, bias) inputs"); + + auto x_shape = inputs[0]; + int x_ndims = static_cast(x_shape.size()); + + auto w_shape = inputs[1]; + // if axis == last_dim, scale and b are both 1d tensor (represented as 2d mat nx1) + int w_ndims = static_cast(w_shape.size()); + w_ndims = (axis == x_ndims - 1 && w_ndims == 2) ? w_ndims - 1 : w_ndims; + CV_CheckEQ(x_ndims - axis, w_ndims, "LayerNorm: shape of weight does not match with given axis and shape of input"); + for (int i = 0; i < w_ndims; ++i) + CV_CheckEQ(x_shape[axis+i], w_shape[i], "LayerNorm: weight dimensions does not match with input dimensions"); + if (hasBias) + { + CV_CheckEQ(inputs.size(), (size_t)3, ""); + auto b_shape = inputs[2]; + CV_CheckEQ(w_shape.size(), b_shape.size(), "LayerNorm: shape of weight does not match with shape of bias"); + for (size_t i = 0; i < w_shape.size(); ++i) + CV_CheckEQ(w_shape[i], b_shape[i], "LayerNorm: bias dimensions does not match with weight dimensions"); + } + + // only one output is needed; Mean & InvStdDev are not needed + // in inference and should beomitted in onnx importer + outputs.assign(1, inputs[0]); + return false; + } + + template + class LayerNormInvoker : public ParallelLoopBody + { + public: + const Mat& src; + const float* scaleData; + const float* biasData; + Mat& dst; + + float epsilon; + + int total; + int normSize; + float invNormSize; + + LayerNormInvoker(const Mat& src_, const Mat& scale, const Mat* b, Mat& dst_, int axis, float epsilon_) + : src(src_), scaleData(scale.ptr()), biasData(nullptr), dst(dst_), epsilon(epsilon_) + { + if (hasBias) + { + CV_Assert(b != nullptr); + CV_Assert(b->isContinuous()); + biasData = (const float*)b->ptr(); + } + + auto dstShape = shape(dst); + total = std::accumulate(dstShape.begin(), dstShape.begin() + axis, 1, std::multiplies()); + normSize = std::accumulate(dstShape.begin() + axis, dstShape.end(), 1, std::multiplies()); + invNormSize = 1.0f / normSize; + } + + static void run(const Mat& src, const Mat& scale, const Mat* b, Mat& dst, int axis, float epsilon) + { + CV_Assert(src.isContinuous()); + CV_Assert(dst.isContinuous()); + CV_CheckTypeEQ(src.type(), CV_32F, "DNN/LayerNorm: only support float32"); + CV_CheckTypeEQ(src.type(), dst.type(), ""); + CV_Assert(scale.isContinuous()); + + CV_CheckGE(epsilon, 0.0f, ""); + + LayerNormInvoker p(src, scale, b, dst, axis, epsilon); + + double nstripes = ((size_t)p.total * p.normSize) * (1 / 1024.0); + // double nstripes = ((size_t)p.total) * (1 / 1024.0); + parallel_for_(Range(0, p.total), p, nstripes); + } + + void operator()(const Range& r) const CV_OVERRIDE + { + int stripeStart = r.start; + int stripeEnd = r.end; + + const float* srcData = src.ptr(); + float* dstData = dst.ptr(); + + for (int ofs = stripeStart; ofs < stripeEnd; ++ofs) + { + const float* first = srcData + ofs * normSize; + float* dstFirst = dstData + ofs * normSize; + + float mean = 0; + float meanSquare = 0; + for (int h = 0; h < normSize; ++h) + { + float v = first[h]; + mean += v; + meanSquare += v * v; + } + mean *= invNormSize; + meanSquare = std::sqrt(std::max(0.f, meanSquare * invNormSize - mean * mean) + epsilon); + float invMeanSquare = 1.0f / meanSquare; + for (int h = 0; h < normSize; ++h) + { + float v = (first[h] - mean) * invMeanSquare * scaleData[h]; + if (hasBias) { + v = v + biasData[h]; + } + dstFirst[h] = v; + } + } + } + }; + + void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE + { + CV_TRACE_FUNCTION(); + CV_TRACE_ARG_VALUE(name, "name", name.c_str()); + + if (inputs_arr.depth() == CV_16S) + { + forward_fallback(inputs_arr, outputs_arr, internals_arr); + return; + } + + std::vector inputs, outputs; + inputs_arr.getMatVector(inputs); + outputs_arr.getMatVector(outputs); + + if (hasBias) { + LayerNormInvoker::run(inputs[0], inputs[1], &inputs[2], outputs[0], axis, epsilon); + } else { + LayerNormInvoker::run(inputs[0], inputs[1], nullptr, outputs[0], axis, epsilon); + } + } +}; + +Ptr LayerNormLayer::create(const LayerParams& params) +{ + return makePtr(params); +} + +}} // cv::dnn diff --git a/modules/dnn/src/onnx/onnx_graph_simplifier.cpp b/modules/dnn/src/onnx/onnx_graph_simplifier.cpp index 730c08b25c..c977a4761d 100644 --- a/modules/dnn/src/onnx/onnx_graph_simplifier.cpp +++ b/modules/dnn/src/onnx/onnx_graph_simplifier.cpp @@ -75,6 +75,28 @@ public: return makePtr(node); } + int getInputInitializerId(int node_id, int node_input_id) + { + auto node = getNode(node_id); + std::string node_input_name = node->getInputName(node_input_id); + for (int i = 0; i < numInitializers; ++i) + if (net.initializer(i).name() == node_input_name) + return i; + CV_Error(Error::StsParseError, "Initializer with name " + node_input_name + " not found"); + } + + Mat getMatFromInitializer(int idx) + { + const opencv_onnx::TensorProto& tensor_proto = net.initializer(idx); + return getMatFromTensor(tensor_proto); + } + + std::string getNameOfInitializer(int idx) const + { + const opencv_onnx::TensorProto& tensor_proto = net.initializer(idx); + return tensor_proto.name(); + } + virtual int getNumNodes() const CV_OVERRIDE { return numInputs + numInitializers + net.node_size(); @@ -110,6 +132,142 @@ private: opencv_onnx::GraphProto& net; }; +class LayerNormSubGraph : public Subgraph +{ +public: + LayerNormSubGraph() : axis(-1), epsilon(1e-5) + { + // -> ReduceMean -> -> Pow(2) -> ReduceMean -> Add(epsilon) -> Sqrt -> + // x Sub Div -> Mul(scale) -> Add(bias) + // ---------------> -------------------------------------------------> + // NOTE: Pow(2), Add(epsilon), Mul(scale), add(bias) can have constants as op_type Constant or Initializer + int input = addNodeToMatch(""); + int mean = addNodeToMatch("ReduceMean", input); + + int sub = addNodeToMatch("Sub", input, mean); + + int pow = addNodeToMatch("Pow", sub, addNodeToMatch("")); + int mean1 = addNodeToMatch("ReduceMean", pow); + int add = addNodeToMatch("Add", mean1, addNodeToMatch("")); + int sqrt = addNodeToMatch("Sqrt", add); + + int div = addNodeToMatch("Div", sub, sqrt); + int mul = addNodeToMatch("Mul", div, addNodeToMatch("")); + addNodeToMatch("Add", mul, addNodeToMatch("")); + + setFusedNode("LayerNormalization", input); + } + + static bool isWithInitializer(const std::vector& matchedNodesIds) + { + // if node.getType() is Constant, Constant nodes are placed between other nodes + if (matchedNodesIds[2] - matchedNodesIds[1] != 1) + return false; + // if Initializer, there is no nodes for constant between other nodes + return true; + } + + static float extractConstant(const Ptr& net, int node_id, int input_id, bool withInitializer) + { + if (withInitializer) + { + auto onnx_net = net.dynamicCast(); + int initializer_id = onnx_net->getInputInitializerId(node_id, input_id); + Mat const_mat = onnx_net->getMatFromInitializer(initializer_id); + return *const_mat.ptr(); + } else { + const Ptr node = net->getNode(node_id); + int constant_id = getInputNodeId(net, node, input_id); + Ptr constant_ptr = net->getNode(constant_id); + opencv_onnx::NodeProto* constant_node = constant_ptr.dynamicCast()->node; + opencv_onnx::TensorProto constant_proto = constant_node->attribute(0).t(); + Mat constant_mat = getMatFromTensor(constant_proto); + return *constant_mat.ptr(); + } + } + + static float extractAxis(const Ptr& net, int node_id) + { + Ptr mean_ptr = net->getNode(node_id); + opencv_onnx::NodeProto* mean_node = mean_ptr.dynamicCast()->node; + int axis_ = -1; + for (int i = 0; i < mean_node->attribute_size(); i++) + { + opencv_onnx::AttributeProto attr = mean_node->attribute(i); + if (attr.name() != "axes") + continue; + axis_ = static_cast(attr.ints(0)); + } + return axis_; + } + + static std::string getInputName(const Ptr& net, int node_id, int input_id, bool withInitializer) + { + if (withInitializer) + { + auto onnx_net = net.dynamicCast(); + int initializer_id = onnx_net->getInputInitializerId(node_id, input_id); + return onnx_net->getNameOfInitializer(initializer_id); + } else { + const auto node = net->getNode(node_id); + return node->getInputName(input_id); + } + } + + virtual bool match(const Ptr& net, int nodeId, + std::vector& matchedNodesIds, + std::vector& targetNodesIds) CV_OVERRIDE + { + if (Subgraph::match(net, nodeId, matchedNodesIds, targetNodesIds)) + { + withInitializer = isWithInitializer(matchedNodesIds); + + float pow_exp = extractConstant(net, matchedNodesIds[2], 1, withInitializer); + if (pow_exp - 2 > 1e-5) // not pow(2) + return false; + + int axis_mean1 = extractAxis(net, matchedNodesIds[0]); + int axis_mean2 = extractAxis(net, matchedNodesIds[3]); + if (axis_mean1 != axis_mean2) + return false; + axis = axis_mean1; + + epsilon = extractConstant(net, matchedNodesIds[4], 1, withInitializer); + + weight_name = getInputName(net, matchedNodesIds[7], 1, withInitializer); + bias_name = getInputName(net, matchedNodesIds[8], 1, withInitializer); + + return true; + } + return false; + } + + virtual void finalize(const Ptr&, + const Ptr& fusedNode, + std::vector >&) CV_OVERRIDE + { + opencv_onnx::NodeProto* node = fusedNode.dynamicCast()->node; + // axis + opencv_onnx::AttributeProto* attr_axis = node->add_attribute(); + attr_axis->set_name("axis"); + attr_axis->set_i(axis); + // epsilon + opencv_onnx::AttributeProto* attr_epsilon = node->add_attribute(); + attr_epsilon->set_name("epsilon"); + attr_epsilon->set_f(epsilon); + // add input + node->add_input(weight_name); + node->add_input(bias_name); + } + +protected: + int axis; + float epsilon; + bool withInitializer; + std::string weight_name; + std::string bias_name; +}; + class SoftMaxSubgraphBase : public Subgraph { public: @@ -746,6 +904,7 @@ public: void simplifySubgraphs(opencv_onnx::GraphProto& net) { std::vector > subgraphs; + subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); subgraphs.push_back(makePtr()); diff --git a/modules/dnn/src/onnx/onnx_importer.cpp b/modules/dnn/src/onnx/onnx_importer.cpp index fe4d4660f3..6fd40d0d16 100644 --- a/modules/dnn/src/onnx/onnx_importer.cpp +++ b/modules/dnn/src/onnx/onnx_importer.cpp @@ -190,6 +190,7 @@ private: void parseRange (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseScatter (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseTile (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); + void parseLayerNorm (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); void parseSimpleLayers (LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto); // Domain: com.microsoft @@ -3285,6 +3286,56 @@ void ONNXImporter::parseTile(LayerParams& layerParams, const opencv_onnx::NodePr } } +void ONNXImporter::parseLayerNorm(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) +{ + // validate axis and convert it if negative + auto inputDims = static_cast(outShapes[node_proto.input(0)].size()); + int axis = layerParams.get("axis", -1); + // axis: [-dims, dims) + CV_CheckGE(axis, -inputDims, "DNN/ONNXImporter: axis of LayerNormalization is out of range"); + CV_CheckLT(axis, inputDims, "DNN/ONNXImporter: axis of LayerNormalization is out of range"); + axis = (axis + inputDims) % inputDims; + layerParams.set("axis", axis); + + // check if bias existed + bool hasBias = false; + if (node_proto.input_size() > 2) + hasBias = true; + layerParams.set("hasBias", hasBias); + + // constants as constant inputs + for (size_t i = 1; i < node_proto.input_size(); i++) + { + if (layer_id.find(node_proto.input(i)) == layer_id.end()) + { + Mat blob = getBlob(node_proto, i); + + LayerParams constParams; + constParams.name = node_proto.input(i); + constParams.type = "Const"; + constParams.blobs.push_back(blob); + + opencv_onnx::NodeProto proto; + proto.add_output(constParams.name); + addLayer(constParams, proto); + } + } + + // Remove additional outputs (Mean, InvStdDev) + if (node_proto.output_size() > 1) + { + auto outputName = node_proto.output(0); + opencv_onnx::NodeProto node_proto_ = node_proto; + node_proto_.clear_output(); + node_proto_.add_output(outputName); + addLayer(layerParams, node_proto_); + } + else + { + addLayer(layerParams, node_proto); + } +} + void ONNXImporter::parseSimpleLayers(LayerParams& layerParams, const opencv_onnx::NodeProto& node_proto) { bool is_all_input_const = true; @@ -3987,6 +4038,7 @@ void ONNXImporter::buildDispatchMap_ONNX_AI(int opset_version) dispatch["SpaceToDepth"] = dispatch["DepthToSpace"] = &ONNXImporter::parseDepthToSpace; dispatch["ScatterElements"] = dispatch["Scatter"] = dispatch["ScatterND"] = &ONNXImporter::parseScatter; dispatch["Tile"] = &ONNXImporter::parseTile; + dispatch["LayerNormalization"] = &ONNXImporter::parseLayerNorm; dispatch["Equal"] = dispatch["Greater"] = dispatch["Less"] = dispatch["Pow"] = dispatch["Add"] = dispatch["Sub"] = dispatch["Mul"] = dispatch["Div"] = dispatch["GreaterOrEqual"] = diff --git a/modules/dnn/test/test_onnx_importer.cpp b/modules/dnn/test/test_onnx_importer.cpp index 0ffa252c71..ad2a3849d6 100644 --- a/modules/dnn/test/test_onnx_importer.cpp +++ b/modules/dnn/test/test_onnx_importer.cpp @@ -2416,6 +2416,36 @@ TEST_P(Test_ONNX_layers, Tile) testONNXModels("tile", pb); } +TEST_P(Test_ONNX_layers, LayerNorm) +{ + testONNXModels("test_layer_normalization_2d_axis0", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_2d_axis1", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_2d_axis_negative_1", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_2d_axis_negative_2", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_3d_axis0_epsilon", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_3d_axis1_epsilon", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_3d_axis2_epsilon", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_3d_axis_negative_1_epsilon", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_3d_axis_negative_2_epsilon", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_3d_axis_negative_3_epsilon", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_4d_axis0", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_4d_axis1", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_4d_axis2", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_4d_axis3", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_4d_axis_negative_1", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_4d_axis_negative_2", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_4d_axis_negative_3", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_4d_axis_negative_4", pb, 0, 0, false, true, 3); + testONNXModels("test_layer_normalization_default_axis", pb, 0, 0, false, true, 3); +} + +// for testing graph simplification +TEST_P(Test_ONNX_layers, LayerNormExpanded) +{ + testONNXModels("layer_norm_expanded"); + testONNXModels("layer_norm_expanded_with_initializers"); +} + INSTANTIATE_TEST_CASE_P(/**/, Test_ONNX_nets, dnnBackendsAndTargets()); }} // namespace From f45a12439ad2cd4aed10f21efd9ce6747bebbefc Mon Sep 17 00:00:00 2001 From: zihaomu Date: Sat, 28 Jan 2023 11:41:00 +0800 Subject: [PATCH 18/19] fix depth wise issue. --- .../depthwise_convolution.cpp | 83 ++++++++++--------- modules/dnn/test/test_onnx_importer.cpp | 5 ++ 2 files changed, 49 insertions(+), 39 deletions(-) diff --git a/modules/dnn/src/layers/fast_convolution/depthwise_convolution.cpp b/modules/dnn/src/layers/fast_convolution/depthwise_convolution.cpp index 4566c880c9..b690156941 100644 --- a/modules/dnn/src/layers/fast_convolution/depthwise_convolution.cpp +++ b/modules/dnn/src/layers/fast_convolution/depthwise_convolution.cpp @@ -29,7 +29,7 @@ static void depthWiseBlockConv2D(const float* wptr, const float w00_ = wptr[0], w01_ = wptr[1], w02_ = wptr[2], w10 = wptr[3], w11 = wptr[4], w12 = wptr[5], w20_ = wptr[6], w21_ = wptr[7], w22_ = wptr[8]; - int outW1 = min(outW, (width - dilation_w*(kernel_w - 1) + pad_l)/stride_w); + const int outW1 = min(outW, (width - dilation_w*(kernel_w - 1) + pad_l)/stride_w); float relu_coeff = relu ? relu[out_d] : 1.f, bias = biasptr[out_d]; for (int out_i = 0; out_i < outH; out_i++) @@ -67,35 +67,37 @@ static void depthWiseBlockConv2D(const float* wptr, #if CV_SIMD128 const int VEC_NLANES = 4; - - if (fusedAdd) - outW1 = max(out_j, outW1 - outW1%VEC_NLANES); - - v_float32x4 vw00 = v_setall_f32(w00); - v_float32x4 vw01 = v_setall_f32(w01); - v_float32x4 vw02 = v_setall_f32(w02); - v_float32x4 vw10 = v_setall_f32(w10); - v_float32x4 vw11 = v_setall_f32(w11); - v_float32x4 vw12 = v_setall_f32(w12); - v_float32x4 vw20 = v_setall_f32(w20); - v_float32x4 vw21 = v_setall_f32(w21); - v_float32x4 vw22 = v_setall_f32(w22); - v_float32x4 z = v_setzero_f32(); - v_float32x4 vbias = v_setall_f32(bias); - v_float32x4 vrc = v_setall_f32(relu_coeff); - - if (stride_w == 1 || (stride_w == 2 && dilation_w == 1)) + if ((stride_w == 1 || (stride_w == 2 && dilation_w == 1)) && (outW1 - out_j) >= VEC_NLANES) { - if( stride_w == 1 ) + v_float32x4 vw00 = v_setall_f32(w00); + v_float32x4 vw01 = v_setall_f32(w01); + v_float32x4 vw02 = v_setall_f32(w02); + v_float32x4 vw10 = v_setall_f32(w10); + v_float32x4 vw11 = v_setall_f32(w11); + v_float32x4 vw12 = v_setall_f32(w12); + v_float32x4 vw20 = v_setall_f32(w20); + v_float32x4 vw21 = v_setall_f32(w21); + v_float32x4 vw22 = v_setall_f32(w22); + v_float32x4 z = v_setzero_f32(); + v_float32x4 vbias = v_setall_f32(bias); + v_float32x4 vrc = v_setall_f32(relu_coeff); + + if (stride_w == 1) { - for( ; out_j < outW1; out_j += VEC_NLANES ) + for (; out_j < outW1; out_j += VEC_NLANES) { - if (out_j + VEC_NLANES > outW1) + // Tail processing. + if (out_j > outW1 - VEC_NLANES) { - if (out_j <= pad_l || outW1 - VEC_NLANES < 0) + // If fusedAdd is true, what is stored in outptr is not a meaningless value, + // but the number being added. And we should avoid use tail processing in this case. + // Because the tail process will make some elements compute twice, + // which will lead to result errors. + if (fusedAdd) break; out_j = outW1 - VEC_NLANES; } + int in_j = out_j * stride_w - pad_l; v_float32x4 v00 = v_load(imgptr0 + in_j), v01 = v_load(imgptr0 + in_j + dilation_w), @@ -119,11 +121,12 @@ static void depthWiseBlockConv2D(const float* wptr, } else // (stride_w == 2 && dilation_w == 1) { - for( ; out_j < outW1; out_j += VEC_NLANES ) + for (; out_j < outW1; out_j += VEC_NLANES) { - if (out_j + VEC_NLANES > outW1 && out_j > pad_l) + // Tail processing. + if (out_j > outW1 - VEC_NLANES) { - if (outW1 - VEC_NLANES < 0) + if (fusedAdd) break; out_j = outW1 - VEC_NLANES; } @@ -204,7 +207,7 @@ static void depthWiseBlockConv1D(const float* wptr, int out_d, int outW, bool fusedAdd) { const float w00_ = wptr[0], w01_ = wptr[1], w02_ = wptr[2]; - int outW1 = min(outW, (width - dilation_w * (kernel_w - 1) + pad_l)/stride_w); + const int outW1 = min(outW, (width - dilation_w * (kernel_w - 1) + pad_l)/stride_w); float relu_coeff = relu ? relu[out_d] : 1.f, bias = biasptr[out_d]; int out_j = 0; @@ -225,27 +228,27 @@ static void depthWiseBlockConv1D(const float* wptr, #if CV_SIMD128 const int VEC_NLANES = 4; - if (fusedAdd) - outW1 = max(out_j, outW1 - outW1%VEC_NLANES); - v_float32x4 vw00 = v_setall_f32(w00); - v_float32x4 vw01 = v_setall_f32(w01); - v_float32x4 vw02 = v_setall_f32(w02); - v_float32x4 z = v_setzero_f32(); - v_float32x4 vbias = v_setall_f32(bias); - v_float32x4 vrc = v_setall_f32(relu_coeff); - - if (stride_w == 1 || (stride_w == 2 && dilation_w == 1)) + if ((stride_w == 1 || (stride_w == 2 && dilation_w == 1)) && (outW1 - out_j) >= VEC_NLANES) { + v_float32x4 vw00 = v_setall_f32(w00); + v_float32x4 vw01 = v_setall_f32(w01); + v_float32x4 vw02 = v_setall_f32(w02); + v_float32x4 z = v_setzero_f32(); + v_float32x4 vbias = v_setall_f32(bias); + v_float32x4 vrc = v_setall_f32(relu_coeff); + if( stride_w == 1 ) { for( ; out_j < outW1; out_j += VEC_NLANES ) { + // Tail processing. if (out_j + VEC_NLANES > outW1) { - if (out_j <= pad_l || outW1 - VEC_NLANES < 0) + if (fusedAdd) break; out_j = outW1 - VEC_NLANES; } + int in_j = out_j * stride_w - pad_l; v_float32x4 v00 = v_load(imgptr0 + in_j), v01 = v_load(imgptr0 + in_j + dilation_w), @@ -263,12 +266,14 @@ static void depthWiseBlockConv1D(const float* wptr, { for( ; out_j < outW1; out_j += VEC_NLANES ) { + // Tail processing. if (out_j + VEC_NLANES > outW1) { - if (out_j <= pad_l || outW1 - VEC_NLANES < 0) + if (fusedAdd) break; out_j = outW1 - VEC_NLANES; } + int in_j = out_j * stride_w - pad_l; v_float32x4 v00, v01, v02, unused; diff --git a/modules/dnn/test/test_onnx_importer.cpp b/modules/dnn/test/test_onnx_importer.cpp index 0ffa252c71..a14210c692 100644 --- a/modules/dnn/test/test_onnx_importer.cpp +++ b/modules/dnn/test/test_onnx_importer.cpp @@ -1731,6 +1731,11 @@ TEST_P(Test_ONNX_layers, DepthWiseAdd) testONNXModels("depthwiseconv_add"); } +TEST_P(Test_ONNX_layers, DepthStride2) +{ + testONNXModels("depthwise_stride2"); +} + TEST_P(Test_ONNX_layers, SubFromConst) { testONNXModels("sub_from_const1"); From deaf632881ea697e5feaeea245816db053c58b37 Mon Sep 17 00:00:00 2001 From: Rostislav Vasilikhin Date: Sat, 28 Jan 2023 10:56:13 +0100 Subject: [PATCH 19/19] Merge pull request #23179 from savuor:port34_stddev_calib_fisheye Backport to 3.4 of the fisheye calibration uncertainty fix * uncertainties fix * trailing whitespace * comment added --- modules/calib3d/src/fisheye.cpp | 7 ++++++- modules/calib3d/test/test_fisheye.cpp | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/modules/calib3d/src/fisheye.cpp b/modules/calib3d/src/fisheye.cpp index a562bd2bb2..0e9034ca19 100644 --- a/modules/calib3d/src/fisheye.cpp +++ b/modules/calib3d/src/fisheye.cpp @@ -1527,13 +1527,18 @@ void cv::internal::EstimateUncertainties(InputArrayOfArrays objectPoints, InputA Vec sigma_x; meanStdDev(ex.reshape(1, 1), noArray(), sigma_x); - sigma_x *= sqrt(2.0 * (double)ex.total()/(2.0 * (double)ex.total() - 1.0)); Mat JJ2, ex3; ComputeJacobians(objectPoints, imagePoints, params, omc, Tc, check_cond, thresh_cond, JJ2, ex3); sqrt(JJ2.inv(), JJ2); + int nParams = JJ2.rows; + // an explanation of that denominator correction can be found here: + // R. Hartley, A. Zisserman, Multiple View Geometry in Computer Vision, 2004, section 5.1.3, page 134 + // see the discussion for more details: https://github.com/opencv/opencv/pull/22992 + sigma_x *= sqrt(2.0 * (double)ex.total()/(2.0 * (double)ex.total() - nParams)); + errors = 3 * sigma_x(0) * JJ2.diag(); rms = sqrt(norm(ex, NORM_L2SQR)/ex.total()); } diff --git a/modules/calib3d/test/test_fisheye.cpp b/modules/calib3d/test/test_fisheye.cpp index 2e12cd8985..789e4db4af 100644 --- a/modules/calib3d/test/test_fisheye.cpp +++ b/modules/calib3d/test/test_fisheye.cpp @@ -398,9 +398,9 @@ TEST_F(fisheyeTest, EstimateUncertainties) cv::internal::EstimateUncertainties(objectPoints, imagePoints, param, rvec, tvec, errors, err_std, thresh_cond, check_cond, rms); - EXPECT_MAT_NEAR(errors.f, cv::Vec2d(1.29837104202046, 1.31565641071524), 1e-10); - EXPECT_MAT_NEAR(errors.c, cv::Vec2d(0.890439368129246, 0.816096854937896), 1e-10); - EXPECT_MAT_NEAR(errors.k, cv::Vec4d(0.00516248605191506, 0.0168181467500934, 0.0213118690274604, 0.00916010877545648), 1e-10); + EXPECT_MAT_NEAR(errors.f, cv::Vec2d(1.34250246865020720, 1.36037536429654530), 1e-10); + EXPECT_MAT_NEAR(errors.c, cv::Vec2d(0.92070526160049848, 0.84383585812851514), 1e-10); + EXPECT_MAT_NEAR(errors.k, cv::Vec4d(0.0053379581373996041, 0.017389792901700545, 0.022036256089491224, 0.0094714594258908952), 1e-10); EXPECT_MAT_NEAR(err_std, cv::Vec2d(0.187475975266883, 0.185678953263995), 1e-10); CV_Assert(fabs(rms - 0.263782587133546) < 1e-10); CV_Assert(errors.alpha == 0);