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/opencv.bib b/doc/opencv.bib index a7e11de4f3..412c5379f9 100644 --- a/doc/opencv.bib +++ b/doc/opencv.bib @@ -1376,3 +1376,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/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 f3c7f6fc31..e98b8a64b9 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) 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 0049d3131d..e96598b11e 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) 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 65f5b75401..fc278669b0 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) 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 6416b1806f..d1b9a2e18f 100644 --- a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown +++ b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown @@ -63,7 +63,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 ee3f1eb7f9..d08280db64 100644 --- a/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.markdown +++ b/doc/tutorials/introduction/linux_gcc_cmake/linux_gcc_cmake.markdown @@ -42,7 +42,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/3d/src/precomp.hpp b/modules/3d/src/precomp.hpp old mode 100644 new mode 100755 diff --git a/modules/3d/src/usac/local_optimization.cpp b/modules/3d/src/usac/local_optimization.cpp index ff8089bb8f..3964edec9a 100644 --- a/modules/3d/src/usac/local_optimization.cpp +++ b/modules/3d/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/3d/test/test_homography.cpp b/modules/3d/test/test_homography.cpp index 0fd5735a18..f2c069eaf3 100644 --- a/modules/3d/test/test_homography.cpp +++ b/modules/3d/test/test_homography.cpp @@ -74,60 +74,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; @@ -135,14 +102,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 "; @@ -154,7 +121,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 "; @@ -170,7 +137,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 "; @@ -182,7 +149,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; @@ -196,7 +163,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; @@ -209,7 +176,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; @@ -222,7 +189,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; @@ -235,7 +202,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; @@ -249,11 +216,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]; @@ -309,7 +280,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: @@ -412,7 +383,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: @@ -574,8 +545,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/3d/test/test_usac.cpp b/modules/3d/test/test_usac.cpp index 98aeaa712b..b687c0a7cd 100644 --- a/modules/3d/test/test_usac.cpp +++ b/modules/3d/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; diff --git a/modules/calib/src/calibration.cpp b/modules/calib/src/calibration.cpp index 5c25860d82..930dd4e6f2 100644 --- a/modules/calib/src/calibration.cpp +++ b/modules/calib/src/calibration.cpp @@ -404,6 +404,12 @@ static double calibrateCameraInternal( const Mat& objectPoints, mask[nparams - 1] = 0; } + int nparams_nz = countNonZero(mask); + + if (nparams_nz >= 2 * total) + CV_Error_(Error::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(int i = 0, pos = 0; i < nimages; i++ ) { @@ -572,26 +578,23 @@ static double calibrateCameraInternal( const Mat& objectPoints, if (!stdDevs.empty()) { - int nparams_nz = countNonZero(mask); JtJN.create(nparams_nz, nparams_nz, CV_64F); subMatrix(JtJ, JtJN, mask, mask); completeSymm(JtJN, false); //TODO: try DECOMP_CHOLESKY maybe? cv::invert(JtJN, JtJinv, DECOMP_EIG); - // 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 + double sigma2 = norm(allErrors, NORM_L2SQR) / (2 * total - nparams_nz); int j = 0; for ( int s = 0; s < nparams; s++ ) + { + stdDevs.at(s) = mask[s] ? std::sqrt(JtJinv.at(j, j) * sigma2) : 0.0; if( mask[s] ) - { - stdDevs.at(s) = std::sqrt(JtJinv.at(j,j) * sigma2); j++; - } - else - stdDevs.at(s) = 0.; + } } // 4. store the results diff --git a/modules/calib/test/test_calibration_hand_eye.cpp b/modules/calib/test/test_calibration_hand_eye.cpp index 36f20006a4..e091818b7c 100644 --- a/modules/calib/test/test_calibration_hand_eye.cpp +++ b/modules/calib/test/test_calibration_hand_eye.cpp @@ -426,9 +426,9 @@ public: eps_rvec_noise[CALIB_HAND_EYE_ANDREFF] = 1.0e-2; eps_rvec_noise[CALIB_HAND_EYE_DANIILIDIS] = 1.0e-2; - eps_tvec_noise[CALIB_HAND_EYE_TSAI] = 5.0e-2; - eps_tvec_noise[CALIB_HAND_EYE_PARK] = 5.0e-2; - eps_tvec_noise[CALIB_HAND_EYE_HORAUD] = 5.0e-2; + eps_tvec_noise[CALIB_HAND_EYE_TSAI] = 7.0e-2; + eps_tvec_noise[CALIB_HAND_EYE_PARK] = 7.0e-2; + eps_tvec_noise[CALIB_HAND_EYE_HORAUD] = 7.0e-2; if (eyeToHandConfig) { eps_tvec_noise[CALIB_HAND_EYE_ANDREFF] = 7.0e-2; @@ -453,7 +453,7 @@ void CV_CalibrateHandEyeTest::run(int) { ts->set_failed_test_info(cvtest::TS::OK); - RNG& rng = ts->get_rng(); + RNG& rng = cv::theRNG(); std::vector > vec_rvec_diff(5); std::vector > vec_tvec_diff(5); diff --git a/modules/calib/test/test_chesscorners.cpp b/modules/calib/test/test_chesscorners.cpp index b4d0628c87..7226da999a 100644 --- a/modules/calib/test/test_chesscorners.cpp +++ b/modules/calib/test/test_chesscorners.cpp @@ -224,7 +224,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/core/include/opencv2/core/fast_math.hpp b/modules/core/include/opencv2/core/fast_math.hpp index 9ee7dba672..47a2948222 100644 --- a/modules/core/include/opencv2/core/fast_math.hpp +++ b/modules/core/include/opencv2/core/fast_math.hpp @@ -306,7 +306,7 @@ CV_INLINE int cvIsInf( double value ) #elif defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__PPC64__) || defined(__loongarch64) Cv64suf ieee754; ieee754.f = value; - return (ieee754.u & 0x7fffffff00000000) == + return (ieee754.u & 0x7fffffffffffffff) == 0x7ff0000000000000; #else Cv64suf ieee754; diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp index 63c2ede775..c7c8b28f64 100644 --- a/modules/core/src/parallel.cpp +++ b/modules/core/src/parallel.cpp @@ -275,7 +275,9 @@ namespace { void recordException(const cv::String& msg) #endif { +#ifndef CV_THREAD_SANITIZER if (!hasException) +#endif { cv::AutoLock lock(cv::getInitializationMutex()); if (!hasException) diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp index 87c3d34000..a38d2716b7 100644 --- a/modules/core/src/system.cpp +++ b/modules/core/src/system.cpp @@ -247,6 +247,7 @@ std::wstring GetTempFileNameWinRT(std::wstring prefix) #if defined __MACH__ && defined __APPLE__ #include #include +#include #endif #endif @@ -635,6 +636,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; diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp index c23bf5c7eb..4f3ac72fd1 100644 --- a/modules/core/test/test_math.cpp +++ b/modules/core/test/test_math.cpp @@ -3997,6 +3997,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) @@ -4008,6 +4015,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 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/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(); 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/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/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_int8_layers.cpp b/modules/dnn/test/test_int8_layers.cpp index 3551ee239f..8b3cd01f29 100644 --- a/modules/dnn/test/test_int8_layers.cpp +++ b/modules/dnn/test/test_int8_layers.cpp @@ -974,6 +974,9 @@ TEST_P(Test_Int8_nets, opencv_face_detector) TEST_P(Test_Int8_nets, EfficientDet) { + if (cvtest::skipUnstableTests) + throw SkipTestException("Skip unstable test"); // detail: https://github.com/opencv/opencv/pull/23167 + applyTestTag(CV_TEST_TAG_DEBUG_VERYLONG); if (target == DNN_TARGET_OPENCL_FP16 && !ocl::Device::getDefault().isIntel()) applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16); diff --git a/modules/dnn/test/test_onnx_importer.cpp b/modules/dnn/test/test_onnx_importer.cpp index 0ffa252c71..f15b2018f7 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"); @@ -2416,6 +2421,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 diff --git a/modules/features2d/src/sift.simd.hpp b/modules/features2d/src/sift.simd.hpp index 3d809f67ed..674648da8b 100644 --- a/modules/features2d/src/sift.simd.hpp +++ b/modules/features2d/src/sift.simd.hpp @@ -960,11 +960,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 { @@ -984,9 +991,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++ ) { diff --git a/modules/features2d/test/test_descriptors_regression.cpp b/modules/features2d/test/test_descriptors_regression.cpp index 1a750feb8c..0258fea0f3 100644 --- a/modules/features2d/test/test_descriptors_regression.cpp +++ b/modules/features2d/test/test_descriptors_regression.cpp @@ -82,7 +82,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); } @@ -110,7 +110,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/src/distransform.cpp b/modules/imgproc/src/distransform.cpp old mode 100644 new mode 100755 index c0bd53bf7f..8eb62deb14 --- 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 ) { diff --git a/modules/imgproc/src/drawing.cpp b/modules/imgproc/src/drawing.cpp old mode 100644 new mode 100755 index 1a4303e22a..7f930cedfd --- 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, @@ -1049,7 +1049,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 ); } } @@ -1277,37 +1277,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::LINE_AA ) + Point2l pt0c(pt0), pt1c(pt1); + + if (line_type < cv::LINE_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); } } @@ -1324,7 +1347,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(); @@ -1333,6 +1356,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 < LINE_AA) + delta = 0; + else + delta = XY_ONE - 1; if( total < 2 ) return; @@ -1411,12 +1440,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); } @@ -2017,7 +2046,7 @@ void fillPoly( InputOutputArray _img, const Point** pts, const int* npts, int nc CollectPolyEdges(img, _pts.data(), npts[i], edges, buf, line_type, shift, offset); } - FillEdgeCollection(img, edges, buf); + FillEdgeCollection(img, edges, buf, line_type); } void polylines( InputOutputArray _img, const Point* const* pts, const int* npts, int ncontours, bool isClosed, @@ -2353,7 +2382,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_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_convhull.cpp b/modules/imgproc/test/test_convhull.cpp index 1ab4205f44..dfb2e34d3a 100644 --- a/modules/imgproc/test/test_convhull.cpp +++ b/modules/imgproc/test/test_convhull.cpp @@ -146,7 +146,7 @@ cvTsIsPointOnLineSegment(const cv::Point2f &x, const cv::Point2f &a, const cv::P double d2 = cvTsDist(x, b); double d3 = cvTsDist(a, b); - return (abs(d1 + d2 - d3) <= (1E-5)); + return (abs(d1 + d2 - d3) <= (1E-4)); } diff --git a/modules/imgproc/test/test_drawing.cpp b/modules/imgproc/test/test_drawing.cpp old mode 100644 new mode 100755 index a24dff4a6b..51c586ec10 --- a/modules/imgproc/test/test_drawing.cpp +++ b/modules/imgproc/test/test_drawing.cpp @@ -857,4 +857,239 @@ TEST(Drawing, ttf_text) } #endif + +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 < LINE_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 < LINE_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 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_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp index c1710268dd..30185b78cc 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 da8a197b3f..83a5e23781 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/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 7ed8a41ba8..8fe2f269ed 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 e318f1a56d..4151b899e3 100644 --- a/modules/objdetect/test/test_cascadeandhog.cpp +++ b/modules/objdetect/test/test_cascadeandhog.cpp @@ -138,7 +138,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/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp index c2e89a3858..cef4e4da59 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 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/stereo/test/test_stereomatching.cpp b/modules/stereo/test/test_stereomatching.cpp index 4ea23ebff3..02d1823d2d 100644 --- a/modules/stereo/test/test_stereomatching.cpp +++ b/modules/stereo/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/ts/include/opencv2/ts/ts_perf.hpp b/modules/ts/include/opencv2/ts/ts_perf.hpp index b79d75d5a6..5ca22d2b1e 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/cuda_test.cpp b/modules/ts/src/cuda_test.cpp index a50f2cc3ce..6b8d19cccf 100644 --- a/modules/ts/src/cuda_test.cpp +++ b/modules/ts/src/cuda_test.cpp @@ -522,13 +522,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; diff --git a/modules/ts/src/ts.cpp b/modules/ts/src/ts.cpp index 0e912bd4a0..eb6932499f 100644 --- a/modules/ts/src/ts.cpp +++ b/modules/ts/src/ts.cpp @@ -623,20 +623,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/ts/src/ts_perf.cpp b/modules/ts/src/ts_perf.cpp index 683ba8afae..958a2e300d 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; diff --git a/modules/video/test/test_estimaterigid.cpp b/modules/video/test/test_estimaterigid.cpp index 0b4179732f..6173c29c9d 100644 --- a/modules/video/test/test_estimaterigid.cpp +++ b/modules/video/test/test_estimaterigid.cpp @@ -83,7 +83,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; @@ -181,4 +181,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 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 bf027c10e9..70d34f16cb 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 @@ -995,6 +996,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 }; diff --git a/samples/cpp/3calibration.cpp b/samples/cpp/3calibration.cpp index f26a6cebce..1393af6a92 100644 --- a/samples/cpp/3calibration.cpp +++ b/samples/cpp/3calibration.cpp @@ -252,7 +252,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()) { @@ -340,7 +340,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 d80564c22c..ab622f18cd 100644 --- a/samples/cpp/calibration.cpp +++ b/samples/cpp/calibration.cpp @@ -497,7 +497,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()) { @@ -622,7 +622,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 b2c495200f..3eed082f79 100644 --- a/samples/cpp/stereo_calib.cpp +++ b/samples/cpp/stereo_calib.cpp @@ -82,7 +82,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() ) @@ -300,7 +300,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)