diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index c7da395f0a..08f7e8ea06 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -402,8 +402,8 @@ endmacro() set(OCV_COMPILER_FAIL_REGEX "argument .* is not valid" # GCC 9+ (including support of unicode quotes) - "command line option .* is valid for .* but not for C\\+\\+" # GNU - "command line option .* is valid for .* but not for C" # GNU + "command[- ]line option .* is valid for .* but not for C\\+\\+" # GNU + "command[- ]line option .* is valid for .* but not for C" # GNU "unrecognized .*option" # GNU "unknown .*option" # Clang "ignoring unknown option" # MSVC 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 d192288721..285124d17c 100644 --- a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown +++ b/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown @@ -188,7 +188,7 @@ blur = cv.GaussianBlur(img,(5,5),0) # find normalized_histogram, and its cumulative distribution function hist = cv.calcHist([blur],[0],None,[256],[0,256]) -hist_norm = hist.ravel()/hist.max() +hist_norm = hist.ravel()/hist.sum() Q = hist_norm.cumsum() bins = np.arange(256) @@ -199,6 +199,8 @@ thresh = -1 for i in xrange(1,256): p1,p2 = np.hsplit(hist_norm,[i]) # probabilities q1,q2 = Q[i],Q[255]-Q[i] # cum sum of classes + if q1 < 1.e-6 or q2 < 1.e-6: + continue b1,b2 = np.hsplit(bins,[i]) # weights # finding means and variances diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp index d5b8318fb3..fa81fdbfec 100644 --- a/modules/calib3d/include/opencv2/calib3d.hpp +++ b/modules/calib3d/include/opencv2/calib3d.hpp @@ -2388,7 +2388,7 @@ CV_EXPORTS_W void filterSpeckles( InputOutputArray img, double newVal, //! computes valid disparity ROI from the valid ROIs of the rectified images (that are returned by cv::stereoRectify()) CV_EXPORTS_W Rect getValidDisparityROI( Rect roi1, Rect roi2, int minDisparity, int numberOfDisparities, - int SADWindowSize ); + int blockSize ); //! validates disparity using the left-right check. The matrix "cost" should be computed by the stereo correspondence algorithm CV_EXPORTS_W void validateDisparity( InputOutputArray disparity, InputArray cost, @@ -2813,8 +2813,8 @@ public: the smoother the disparity is. P1 is the penalty on the disparity change by plus or minus 1 between neighbor pixels. P2 is the penalty on the disparity change by more than 1 between neighbor pixels. The algorithm requires P2 \> P1 . See stereo_match.cpp sample where some reasonably good - P1 and P2 values are shown (like 8\*number_of_image_channels\*SADWindowSize\*SADWindowSize and - 32\*number_of_image_channels\*SADWindowSize\*SADWindowSize , respectively). + P1 and P2 values are shown (like 8\*number_of_image_channels\*blockSize\*blockSize and + 32\*number_of_image_channels\*blockSize\*blockSize , respectively). @param disp12MaxDiff Maximum allowed difference (in integer pixel units) in the left-right disparity check. Set it to a non-positive value to disable the check. @param preFilterCap Truncation value for the prefiltered image pixels. The algorithm first diff --git a/modules/calib3d/src/ap3p.cpp b/modules/calib3d/src/ap3p.cpp index cc48b6dac3..386a4499ef 100644 --- a/modules/calib3d/src/ap3p.cpp +++ b/modules/calib3d/src/ap3p.cpp @@ -46,7 +46,7 @@ void solveQuartic(const double *factors, double *realRoots) { complex sqrt_2m = sqrt(static_cast >(-2 * p4 / 3 + t)); double B_4A = -a3 / (4 * a4); double complex1 = 4 * p4 / 3 + t; -#if defined(__clang__) && defined(__arm__) && (__clang_major__ == 3 || __clang_minor__ == 4) && !defined(__ANDROID__) +#if defined(__clang__) && defined(__arm__) && (__clang_major__ == 3 || __clang_major__ == 4) && !defined(__ANDROID__) // details: https://github.com/opencv/opencv/issues/11135 // details: https://github.com/opencv/opencv/issues/11056 complex complex2 = 2 * q4; diff --git a/modules/dnn/src/layers/resize_layer.cpp b/modules/dnn/src/layers/resize_layer.cpp index eb8d35bf12..0c5f76baab 100644 --- a/modules/dnn/src/layers/resize_layer.cpp +++ b/modules/dnn/src/layers/resize_layer.cpp @@ -25,7 +25,9 @@ namespace cv { namespace dnn { class ResizeLayerImpl : public ResizeLayer { public: - ResizeLayerImpl(const LayerParams& params) : zoomFactorWidth(0), zoomFactorHeight(0), scaleWidth(0), scaleHeight(0) + ResizeLayerImpl(const LayerParams& params) : zoomFactorWidth(params.get("zoom_factor_x", params.get("zoom_factor", 0))), + zoomFactorHeight(params.get("zoom_factor_y", params.get("zoom_factor", 0))), + scaleWidth(0), scaleHeight(0) { setParamsFrom(params); outWidth = params.get("width", 0); @@ -33,13 +35,10 @@ public: if (params.has("zoom_factor")) { CV_Assert(!params.has("zoom_factor_x") && !params.has("zoom_factor_y")); - zoomFactorWidth = zoomFactorHeight = params.get("zoom_factor"); } else if (params.has("zoom_factor_x") || params.has("zoom_factor_y")) { CV_Assert(params.has("zoom_factor_x") && params.has("zoom_factor_y")); - zoomFactorWidth = params.get("zoom_factor_x"); - zoomFactorHeight = params.get("zoom_factor_y"); } interpolation = params.get("interpolation"); CV_Assert(interpolation == "nearest" || interpolation == "bilinear"); @@ -54,8 +53,8 @@ public: { CV_Assert_N(inputs.size() == 1, inputs[0].size() == 4); outputs.resize(1, inputs[0]); - outputs[0][2] = outHeight > 0 ? outHeight : (outputs[0][2] * zoomFactorHeight); - outputs[0][3] = outWidth > 0 ? outWidth : (outputs[0][3] * zoomFactorWidth); + outputs[0][2] = zoomFactorHeight > 0 ? (outputs[0][2] * zoomFactorHeight) : outHeight; + outputs[0][3] = zoomFactorWidth > 0 ? (outputs[0][3] * zoomFactorWidth) : outWidth; // We can work in-place (do nothing) if input shape == output shape. return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]); } @@ -82,11 +81,8 @@ public: inputs_arr.getMatVector(inputs); outputs_arr.getMatVector(outputs); - if (!outWidth && !outHeight) - { - outHeight = outputs[0].size[2]; - outWidth = outputs[0].size[3]; - } + outHeight = outputs[0].size[2]; + outWidth = outputs[0].size[3]; if (alignCorners && outHeight > 1) scaleHeight = static_cast(inputs[0].size[2] - 1) / (outHeight - 1); else @@ -214,7 +210,7 @@ public: ieLayer.setType("Interp"); ieLayer.getParameters()["pad_beg"] = 0; ieLayer.getParameters()["pad_end"] = 0; - ieLayer.getParameters()["align_corners"] = false; + ieLayer.getParameters()["align_corners"] = alignCorners; } else CV_Error(Error::StsNotImplemented, "Unsupported interpolation: " + interpolation); @@ -238,7 +234,7 @@ public: attrs.pads_begin.push_back(0); attrs.pads_end.push_back(0); attrs.axes = ngraph::AxisSet{2, 3}; - attrs.align_corners = false; + attrs.align_corners = alignCorners; if (interpolation == "nearest") { attrs.mode = "nearest"; @@ -257,7 +253,8 @@ public: #endif // HAVE_DNN_NGRAPH protected: - int outWidth, outHeight, zoomFactorWidth, zoomFactorHeight; + int outWidth, outHeight; + const int zoomFactorWidth, zoomFactorHeight; String interpolation; float scaleWidth, scaleHeight; bool alignCorners; @@ -281,79 +278,18 @@ public: { CV_Assert_N(inputs.size() == 1, inputs[0].size() == 4); outputs.resize(1, inputs[0]); - outputs[0][2] = outHeight > 0 ? outHeight : (1 + zoomFactorHeight * (outputs[0][2] - 1)); - outputs[0][3] = outWidth > 0 ? outWidth : (1 + zoomFactorWidth * (outputs[0][3] - 1)); + outputs[0][2] = zoomFactorHeight > 0 ? (1 + zoomFactorHeight * (outputs[0][2] - 1)) : outHeight; + outputs[0][3] = zoomFactorWidth > 0 ? (1 + zoomFactorWidth * (outputs[0][3] - 1)) : outWidth; // We can work in-place (do nothing) if input shape == output shape. return (outputs[0][2] == inputs[0][2]) && (outputs[0][3] == inputs[0][3]); } - - virtual bool supportBackend(int backendId) CV_OVERRIDE - { -#ifdef HAVE_INF_ENGINE - if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 - || backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH) - return true; -#endif - return backendId == DNN_BACKEND_OPENCV || - backendId == DNN_BACKEND_CUDA; - } - - virtual void finalize(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr) CV_OVERRIDE - { - std::vector inputs, outputs; - inputs_arr.getMatVector(inputs); - outputs_arr.getMatVector(outputs); - - if (!outWidth && !outHeight) - { - outHeight = outputs[0].size[2]; - outWidth = outputs[0].size[3]; - } - int inpHeight = inputs[0].size[2]; - int inpWidth = inputs[0].size[3]; - scaleHeight = (outHeight > 1) ? (static_cast(inpHeight - 1) / (outHeight - 1)) : 0.f; - scaleWidth = (outWidth > 1) ? (static_cast(inpWidth - 1) / (outWidth - 1)) : 0.f; - } - -#ifdef HAVE_INF_ENGINE - virtual Ptr initInfEngine(const std::vector >&) CV_OVERRIDE - { - InferenceEngine::Builder::Layer ieLayer(name); - ieLayer.setName(name); - ieLayer.setType("Interp"); - ieLayer.getParameters()["pad_beg"] = 0; - ieLayer.getParameters()["pad_end"] = 0; - ieLayer.getParameters()["width"] = outWidth; - ieLayer.getParameters()["height"] = outHeight; - ieLayer.setInputPorts(std::vector(1)); - ieLayer.setOutputPorts(std::vector(1)); - return Ptr(new InfEngineBackendNode(ieLayer)); - } -#endif // HAVE_INF_ENGINE - -#ifdef HAVE_DNN_NGRAPH - virtual Ptr initNgraph(const std::vector >& inputs, - const std::vector >& nodes) CV_OVERRIDE - { - auto& ieInpNode = nodes[0].dynamicCast()->node; - ngraph::op::InterpolateAttrs attrs; - attrs.pads_begin.push_back(0); - attrs.pads_end.push_back(0); - attrs.axes = ngraph::AxisSet{2, 3}; - attrs.mode = "linear"; - std::vector shape = {outHeight, outWidth}; - auto out_shape = std::make_shared(ngraph::element::i64, ngraph::Shape{2}, shape.data()); - auto interp = std::make_shared(ieInpNode, out_shape, attrs); - return Ptr(new InfEngineNgraphNode(interp)); - } -#endif // HAVE_DNN_NGRAPH - }; Ptr InterpLayer::create(const LayerParams& params) { LayerParams lp(params); lp.set("interpolation", "bilinear"); + lp.set("align_corners", true); return Ptr(new InterpLayerImpl(lp)); } diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index 8fe7f33c88..584e7bce36 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -1760,4 +1760,35 @@ INSTANTIATE_TEST_CASE_P(/**/, Layer_Test_Eltwise_unequal, Combine( dnnBackendsAndTargets() )); +typedef testing::TestWithParam > Layer_Test_Resize; +TEST_P(Layer_Test_Resize, change_input) +{ + int backendId = get<0>(GetParam()); + int targetId = get<1>(GetParam()); + + Net net; + LayerParams lp; + lp.type = "Resize"; + lp.name = "testLayer"; + lp.set("zoom_factor", 2); + lp.set("interpolation", "nearest"); + net.addLayerToPrev(lp.name, lp.type, lp); + + for (int i = 0; i < 2; ++i) + { + Mat inp(4 + i, 5 + i, CV_8UC3), ref; + randu(inp, 0, 255); + resize(inp, ref, Size(0, 0), 2, 2, INTER_NEAREST); + ref = blobFromImage(ref); + + net.setInput(blobFromImage(inp)); + net.setPreferableBackend(backendId); + net.setPreferableTarget(targetId); + Mat out = net.forward(); + normAssert(out, ref); + } +} + +INSTANTIATE_TEST_CASE_P(/**/, Layer_Test_Resize, dnnBackendsAndTargets()); + }} // namespace diff --git a/modules/highgui/src/window_QT.cpp b/modules/highgui/src/window_QT.cpp index 6a7e800e03..ce0ab58f49 100644 --- a/modules/highgui/src/window_QT.cpp +++ b/modules/highgui/src/window_QT.cpp @@ -54,9 +54,12 @@ #include #endif +// Get GL_PERSPECTIVE_CORRECTION_HINT definition, not available in GLES 2 or +// OpenGL 3 core profile or later #ifdef HAVE_QT_OPENGL - #if defined Q_WS_X11 /* Qt4 */ || defined Q_OS_LINUX /* Qt5 */ - #include + #if defined Q_WS_X11 /* Qt4 */ || \ + (!defined(QT_OPENGL_ES_2) && defined Q_OS_LINUX) /* Qt5 with desktop OpenGL */ + #include #endif #endif @@ -3225,7 +3228,9 @@ void OpenGlViewPort::updateGl() void OpenGlViewPort::initializeGL() { +#ifdef GL_PERSPECTIVE_CORRECTION_HINT glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); +#endif } void OpenGlViewPort::resizeGL(int w, int h) diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp index e5af81a060..221ee7833e 100644 --- a/modules/imgproc/include/opencv2/imgproc.hpp +++ b/modules/imgproc/include/opencv2/imgproc.hpp @@ -1446,7 +1446,7 @@ equal to sigmaX, if both sigmas are zeros, they are computed from ksize.width an respectively (see #getGaussianKernel for details); to fully control the result regardless of possible future modifications of all this semantics, it is recommended to specify all of ksize, sigmaX, and sigmaY. -@param borderType pixel extrapolation method, see #BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @sa sepFilter2D, filter2D, blur, boxFilter, bilateralFilter, medianBlur */ @@ -1507,7 +1507,7 @@ algorithms, and so on). If you need to compute pixel sums over variable-size win @param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel center. @param normalize flag, specifying whether the kernel is normalized by its area or not. -@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes. #BORDER_WRAP is not supported. @sa blur, bilateralFilter, GaussianBlur, medianBlur, integral */ CV_EXPORTS_W void boxFilter( InputArray src, OutputArray dst, int ddepth, @@ -1530,7 +1530,7 @@ variance and standard deviation around the neighborhood of a pixel. @param anchor kernel anchor point. The default value of Point(-1, -1) denotes that the anchor is at the kernel center. @param normalize flag, specifying whether the kernel is to be normalized by it's area or not. -@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes. #BORDER_WRAP is not supported. @sa boxFilter */ CV_EXPORTS_W void sqrBoxFilter( InputArray src, OutputArray dst, int ddepth, @@ -1553,7 +1553,7 @@ the depth should be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. @param ksize blurring kernel size. @param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel center. -@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes +@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes. #BORDER_WRAP is not supported. @sa boxFilter, bilateralFilter, GaussianBlur, medianBlur */ CV_EXPORTS_W void blur( InputArray src, OutputArray dst, @@ -1587,7 +1587,7 @@ separate color planes using split and process them individually. the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor is at the kernel center. @param delta optional value added to the filtered pixels before storing them in dst. -@param borderType pixel extrapolation method, see #BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @sa sepFilter2D, dft, matchTemplate */ CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth, @@ -1608,7 +1608,7 @@ kernel kernelY. The final result shifted by delta is stored in dst . @param anchor Anchor position within the kernel. The default value \f$(-1,-1)\f$ means that the anchor is at the kernel center. @param delta Value added to the filtered results before storing them. -@param borderType Pixel extrapolation method, see #BorderTypes +@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @sa filter2D, Sobel, GaussianBlur, boxFilter, blur */ CV_EXPORTS_W void sepFilter2D( InputArray src, OutputArray dst, int ddepth, @@ -1661,7 +1661,7 @@ The second case corresponds to a kernel of: @param scale optional scale factor for the computed derivative values; by default, no scaling is applied (see #getDerivKernels for details). @param delta optional delta value that is added to the results prior to storing them in dst. -@param borderType pixel extrapolation method, see #BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @sa Scharr, Laplacian, sepFilter2D, filter2D, GaussianBlur, cartToPolar */ CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth, @@ -1682,7 +1682,8 @@ Sobel( src, dy, CV_16SC1, 0, 1, 3 ); @param dx output image with first-order derivative in x. @param dy output image with first-order derivative in y. @param ksize size of Sobel kernel. It must be 3. -@param borderType pixel extrapolation method, see #BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes. + Only #BORDER_DEFAULT=#BORDER_REFLECT_101 and #BORDER_REPLICATE are supported. @sa Sobel */ @@ -1710,7 +1711,7 @@ is equivalent to @param scale optional scale factor for the computed derivative values; by default, no scaling is applied (see #getDerivKernels for details). @param delta optional delta value that is added to the results prior to storing them in dst. -@param borderType pixel extrapolation method, see #BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @sa cartToPolar */ CV_EXPORTS_W void Scharr( InputArray src, OutputArray dst, int ddepth, @@ -1741,7 +1742,7 @@ details. The size must be positive and odd. @param scale Optional scale factor for the computed Laplacian values. By default, no scaling is applied. See #getDerivKernels for details. @param delta Optional delta value that is added to the results prior to storing them in dst . -@param borderType Pixel extrapolation method, see #BorderTypes +@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @sa Sobel, Scharr */ CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth, @@ -1810,7 +1811,7 @@ of the formulae in the cornerEigenValsAndVecs description. src . @param blockSize Neighborhood size (see the details on #cornerEigenValsAndVecs ). @param ksize Aperture parameter for the Sobel operator. -@param borderType Pixel extrapolation method. See #BorderTypes. +@param borderType Pixel extrapolation method. See #BorderTypes. #BORDER_WRAP is not supported. */ CV_EXPORTS_W void cornerMinEigenVal( InputArray src, OutputArray dst, int blockSize, int ksize = 3, @@ -1833,7 +1834,7 @@ size as src . @param blockSize Neighborhood size (see the details on #cornerEigenValsAndVecs ). @param ksize Aperture parameter for the Sobel operator. @param k Harris detector free parameter. See the formula above. -@param borderType Pixel extrapolation method. See #BorderTypes. +@param borderType Pixel extrapolation method. See #BorderTypes. #BORDER_WRAP is not supported. */ CV_EXPORTS_W void cornerHarris( InputArray src, OutputArray dst, int blockSize, int ksize, double k, @@ -1861,7 +1862,7 @@ The output of the function can be used for robust edge or corner detection. @param dst Image to store the results. It has the same size as src and the type CV_32FC(6) . @param blockSize Neighborhood size (see details below). @param ksize Aperture parameter for the Sobel operator. -@param borderType Pixel extrapolation method. See #BorderTypes. +@param borderType Pixel extrapolation method. See #BorderTypes. #BORDER_WRAP is not supported. @sa cornerMinEigenVal, cornerHarris, preCornerDetect */ @@ -1890,7 +1891,7 @@ The corners can be found as local maximums of the functions, as shown below: @param src Source single-channel 8-bit of floating-point image. @param dst Output image that has the type CV_32F and the same size as src . @param ksize %Aperture size of the Sobel . -@param borderType Pixel extrapolation method. See #BorderTypes. +@param borderType Pixel extrapolation method. See #BorderTypes. #BORDER_WRAP is not supported. */ CV_EXPORTS_W void preCornerDetect( InputArray src, OutputArray dst, int ksize, int borderType = BORDER_DEFAULT ); @@ -2154,7 +2155,7 @@ structuring element is used. Kernel can be created using #getStructuringElement. @param anchor position of the anchor within the element; default value (-1, -1) means that the anchor is at the element center. @param iterations number of times erosion is applied. -@param borderType pixel extrapolation method, see #BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @param borderValue border value in case of a constant border @sa dilate, morphologyEx, getStructuringElement */ @@ -2186,7 +2187,7 @@ structuring element is used. Kernel can be created using #getStructuringElement @param anchor position of the anchor within the element; default value (-1, -1) means that the anchor is at the element center. @param iterations number of times dilation is applied. -@param borderType pixel extrapolation method, see #BorderTypes +@param borderType pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not suported. @param borderValue border value in case of a constant border @sa erode, morphologyEx, getStructuringElement */ @@ -2211,7 +2212,7 @@ CV_8U, CV_16U, CV_16S, CV_32F or CV_64F. @param anchor Anchor position with the kernel. Negative values mean that the anchor is at the kernel center. @param iterations Number of times erosion and dilation are applied. -@param borderType Pixel extrapolation method, see #BorderTypes +@param borderType Pixel extrapolation method, see #BorderTypes. #BORDER_WRAP is not supported. @param borderValue Border value in case of a constant border. The default value has a special meaning. @sa dilate, erode, getStructuringElement diff --git a/modules/imgproc/src/drawing.cpp b/modules/imgproc/src/drawing.cpp index 44c3b463ff..7d70aa7667 100644 --- a/modules/imgproc/src/drawing.cpp +++ b/modules/imgproc/src/drawing.cpp @@ -308,7 +308,7 @@ LineAA( Mat& img, Point2l pt1, Point2l pt2, const void* color ) int nch = img.channels(); uchar* ptr = img.ptr(); size_t step = img.step; - Size2l size(img.size()); + Size2l size0(img.size()), size = size0; if( !((nch == 1 || nch == 3 || nch == 4) && img.depth() == CV_8U) ) { @@ -316,15 +316,8 @@ LineAA( Mat& img, Point2l pt1, Point2l pt2, const void* color ) return; } - pt1.x -= XY_ONE*2; - pt1.y -= XY_ONE*2; - pt2.x -= XY_ONE*2; - pt2.y -= XY_ONE*2; - ptr += img.step*2 + 2*nch; - - size.width = ((size.width - 5) << XY_SHIFT) + 1; - size.height = ((size.height - 5) << XY_SHIFT) + 1; - + size.width <<= XY_SHIFT; + size.height <<= XY_SHIFT; if( !clipLine( size, pt1, pt2 )) return; @@ -403,171 +396,160 @@ LineAA( Mat& img, Point2l pt1, Point2l pt2, const void* color ) if( nch == 3 ) { - #define ICV_PUT_POINT() \ + #define ICV_PUT_POINT(x, y) \ { \ + uchar* tptr = ptr + (x)*3 + (y)*step; \ _cb = tptr[0]; \ _cb += ((cb - _cb)*a + 127)>> 8;\ + _cb += ((cb - _cb)*a + 127)>> 8;\ _cg = tptr[1]; \ _cg += ((cg - _cg)*a + 127)>> 8;\ + _cg += ((cg - _cg)*a + 127)>> 8;\ _cr = tptr[2]; \ _cr += ((cr - _cr)*a + 127)>> 8;\ + _cr += ((cr - _cr)*a + 127)>> 8;\ tptr[0] = (uchar)_cb; \ tptr[1] = (uchar)_cg; \ tptr[2] = (uchar)_cr; \ } if( ax > ay ) { - ptr += (pt1.x >> XY_SHIFT) * 3; + int x = (int)(pt1.x >> XY_SHIFT); - while( ecount >= 0 ) + for( ; ecount >= 0; x++, pt1.y += y_step, scount++, ecount-- ) { - uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step; + if( (unsigned)x >= (unsigned)size0.width ) + continue; + int y = (int)((pt1.y >> XY_SHIFT) - 1); int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + (((ecount >= 2) + 1) & (ecount | 2))]; int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31; a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)y < (unsigned)size0.height ) + ICV_PUT_POINT(x, y) - tptr += step; a = (ep_corr * FilterTable[dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)(y+1) < (unsigned)size0.height ) + ICV_PUT_POINT(x, y+1) - tptr += step; a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); - - pt1.y += y_step; - ptr += 3; - scount++; - ecount--; + if( (unsigned)(y+2) < (unsigned)size0.height ) + ICV_PUT_POINT(x, y+2) } } else { - ptr += (pt1.y >> XY_SHIFT) * step; + int y = (int)(pt1.y >> XY_SHIFT); - while( ecount >= 0 ) + for( ; ecount >= 0; y++, pt1.x += x_step, scount++, ecount-- ) { - uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 3; - + if( (unsigned)y >= (unsigned)size0.height ) + continue; + int x = (int)((pt1.x >> XY_SHIFT) - 1); int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + (((ecount >= 2) + 1) & (ecount | 2))]; int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31; a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)x < (unsigned)size0.width ) + ICV_PUT_POINT(x, y) - tptr += 3; a = (ep_corr * FilterTable[dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)(x+1) < (unsigned)size0.width ) + ICV_PUT_POINT(x+1, y) - tptr += 3; a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); - - pt1.x += x_step; - ptr += step; - scount++; - ecount--; + if( (unsigned)(x+2) < (unsigned)size0.width ) + ICV_PUT_POINT(x+2, y) } } #undef ICV_PUT_POINT } else if(nch == 1) { - #define ICV_PUT_POINT() \ + #define ICV_PUT_POINT(x, y) \ { \ + uchar* tptr = ptr + (x) + (y) * step; \ _cb = tptr[0]; \ _cb += ((cb - _cb)*a + 127)>> 8;\ + _cb += ((cb - _cb)*a + 127)>> 8;\ tptr[0] = (uchar)_cb; \ } if( ax > ay ) { - ptr += (pt1.x >> XY_SHIFT); + int x = (int)(pt1.x >> XY_SHIFT); - while( ecount >= 0 ) + for( ; ecount >= 0; x++, pt1.y += y_step, scount++, ecount-- ) { - uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step; + if( (unsigned)x >= (unsigned)size0.width ) + continue; + int y = (int)((pt1.y >> XY_SHIFT) - 1); int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + (((ecount >= 2) + 1) & (ecount | 2))]; int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31; a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)y < (unsigned)size0.height ) + ICV_PUT_POINT(x, y) - tptr += step; a = (ep_corr * FilterTable[dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)(y+1) < (unsigned)size0.height ) + ICV_PUT_POINT(x, y+1) - tptr += step; a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); - - pt1.y += y_step; - ptr++; - scount++; - ecount--; + if( (unsigned)(y+2) < (unsigned)size0.height ) + ICV_PUT_POINT(x, y+2) } } else { - ptr += (pt1.y >> XY_SHIFT) * step; + int y = (int)(pt1.y >> XY_SHIFT); - while( ecount >= 0 ) + for( ; ecount >= 0; y++, pt1.x += x_step, scount++, ecount-- ) { - uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1); - + if( (unsigned)y >= (unsigned)size0.height ) + continue; + int x = (int)((pt1.x >> XY_SHIFT) - 1); int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + (((ecount >= 2) + 1) & (ecount | 2))]; int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31; a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)x < (unsigned)size0.width ) + ICV_PUT_POINT(x, y) - tptr++; a = (ep_corr * FilterTable[dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)(x+1) < (unsigned)size0.width ) + ICV_PUT_POINT(x+1, y) - tptr++; a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); - - pt1.x += x_step; - ptr += step; - scount++; - ecount--; + if( (unsigned)(x+2) < (unsigned)size0.width ) + ICV_PUT_POINT(x+2, y) } } #undef ICV_PUT_POINT } else { - #define ICV_PUT_POINT() \ + #define ICV_PUT_POINT(x, y) \ { \ + uchar* tptr = ptr + (x)*4 + (y)*step; \ _cb = tptr[0]; \ _cb += ((cb - _cb)*a + 127)>> 8;\ + _cb += ((cb - _cb)*a + 127)>> 8;\ _cg = tptr[1]; \ _cg += ((cg - _cg)*a + 127)>> 8;\ + _cg += ((cg - _cg)*a + 127)>> 8;\ _cr = tptr[2]; \ _cr += ((cr - _cr)*a + 127)>> 8;\ + _cr += ((cr - _cr)*a + 127)>> 8;\ _ca = tptr[3]; \ _ca += ((ca - _ca)*a + 127)>> 8;\ + _ca += ((ca - _ca)*a + 127)>> 8;\ tptr[0] = (uchar)_cb; \ tptr[1] = (uchar)_cg; \ tptr[2] = (uchar)_cr; \ @@ -575,66 +557,55 @@ LineAA( Mat& img, Point2l pt1, Point2l pt2, const void* color ) } if( ax > ay ) { - ptr += (pt1.x >> XY_SHIFT) * 4; + int x = (int)(pt1.x >> XY_SHIFT); - while( ecount >= 0 ) + for( ; ecount >= 0; x++, pt1.y += y_step, scount++, ecount-- ) { - uchar *tptr = ptr + ((pt1.y >> XY_SHIFT) - 1) * step; + if( (unsigned)x >= (unsigned)size0.width ) + continue; + int y = (int)((pt1.y >> XY_SHIFT) - 1); int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + (((ecount >= 2) + 1) & (ecount | 2))]; int a, dist = (pt1.y >> (XY_SHIFT - 5)) & 31; a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)y < (unsigned)size0.height ) + ICV_PUT_POINT(x, y) - tptr += step; a = (ep_corr * FilterTable[dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)(y+1) < (unsigned)size0.height ) + ICV_PUT_POINT(x, y+1) - tptr += step; a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); - - pt1.y += y_step; - ptr += 4; - scount++; - ecount--; + if( (unsigned)(y+2) < (unsigned)size0.height ) + ICV_PUT_POINT(x, y+2) } } else { - ptr += (pt1.y >> XY_SHIFT) * step; + int y = (int)(pt1.y >> XY_SHIFT); - while( ecount >= 0 ) + for( ; ecount >= 0; y++, pt1.x += x_step, scount++, ecount-- ) { - uchar *tptr = ptr + ((pt1.x >> XY_SHIFT) - 1) * 4; - + if( (unsigned)y >= (unsigned)size0.height ) + continue; + int x = (int)((pt1.x >> XY_SHIFT) - 1); int ep_corr = ep_table[(((scount >= 2) + 1) & (scount | 2)) * 3 + (((ecount >= 2) + 1) & (ecount | 2))]; int a, dist = (pt1.x >> (XY_SHIFT - 5)) & 31; a = (ep_corr * FilterTable[dist + 32] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)x < (unsigned)size0.width ) + ICV_PUT_POINT(x, y) - tptr += 4; a = (ep_corr * FilterTable[dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); + if( (unsigned)(x+1) < (unsigned)size0.width ) + ICV_PUT_POINT(x+1, y) - tptr += 4; a = (ep_corr * FilterTable[63 - dist] >> 8) & 0xff; - ICV_PUT_POINT(); - ICV_PUT_POINT(); - - pt1.x += x_step; - ptr += step; - scount++; - ecount--; + if( (unsigned)(x+2) < (unsigned)size0.width ) + ICV_PUT_POINT(x+2, y) } } #undef ICV_PUT_POINT diff --git a/modules/imgproc/src/resize.cpp b/modules/imgproc/src/resize.cpp index 7596217b73..43458cc153 100644 --- a/modules/imgproc/src/resize.cpp +++ b/modules/imgproc/src/resize.cpp @@ -1674,93 +1674,9 @@ struct HResizeLinearVecU8_X4 } } } - else if(cn < 9) - { - const int step = 8; - const int len0 = xmax & -step; - for( ; k <= (count - 2); k+=2 ) - { - const uchar *S0 = src[k]; - int *D0 = dst[k]; - const uchar *S1 = src[k+1]; - int *D1 = dst[k+1]; - - for( dx = 0; dx < len0; dx += cn ) - { - v_int16x8 a0 = v_load(alpha+dx*2); - v_int16x8 a1 = v_load(alpha+dx*2 + 8); - v_uint16x8 s0, s1; - v_zip(v_load_expand(S0+xofs[dx]), v_load_expand(S0+xofs[dx]+cn), s0, s1); - v_store(&D0[dx], v_dotprod(v_reinterpret_as_s16(s0), a0)); - v_store(&D0[dx+4], v_dotprod(v_reinterpret_as_s16(s1), a1)); - v_zip(v_load_expand(S1+xofs[dx]), v_load_expand(S1+xofs[dx]+cn), s0, s1); - v_store(&D1[dx], v_dotprod(v_reinterpret_as_s16(s0), a0)); - v_store(&D1[dx+4], v_dotprod(v_reinterpret_as_s16(s1), a1)); - } - } - for( ; k < count; k++ ) - { - const uchar *S = src[k]; - int *D = dst[k]; - for( dx = 0; dx < len0; dx += cn ) - { - v_int16x8 a0 = v_load(alpha+dx*2); - v_int16x8 a1 = v_load(alpha+dx*2 + 8); - v_uint16x8 s0, s1; - v_zip(v_load_expand(S+xofs[dx]), v_load_expand(S+xofs[dx]+cn), s0, s1); - v_store(&D[dx], v_dotprod(v_reinterpret_as_s16(s0), a0)); - v_store(&D[dx+4], v_dotprod(v_reinterpret_as_s16(s1), a1)); - } - } - } else { - const int step = 16; - const int len0 = (xmax - cn) & -step; - for( ; k <= (count - 2); k+=2 ) - { - const uchar *S0 = src[k]; - int *D0 = dst[k]; - const uchar *S1 = src[k+1]; - int *D1 = dst[k+1]; - - for( dx = 0; dx < len0; dx += step ) - { - v_int16x8 a0 = v_load(alpha+dx*2); - v_int16x8 a1 = v_load(alpha+dx*2 + 8); - v_int16x8 a2 = v_load(alpha+dx*2 + 16); - v_int16x8 a3 = v_load(alpha+dx*2 + 24); - v_uint8x16 s01, s23; - v_zip(v_lut(S0, xofs+dx), v_lut(S0+cn, xofs+dx), s01, s23); - v_store(&D0[dx], v_dotprod(v_reinterpret_as_s16(v_expand_low(s01)), a0)); - v_store(&D0[dx+4], v_dotprod(v_reinterpret_as_s16(v_expand_high(s01)), a1)); - v_store(&D0[dx+8], v_dotprod(v_reinterpret_as_s16(v_expand_low(s23)), a2)); - v_store(&D0[dx+12], v_dotprod(v_reinterpret_as_s16(v_expand_high(s23)), a3)); - v_zip(v_lut(S1, xofs+dx), v_lut(S1+cn, xofs+dx), s01, s23); - v_store(&D1[dx], v_dotprod(v_reinterpret_as_s16(v_expand_low(s01)), a0)); - v_store(&D1[dx+4], v_dotprod(v_reinterpret_as_s16(v_expand_high(s01)), a1)); - v_store(&D1[dx+8], v_dotprod(v_reinterpret_as_s16(v_expand_low(s23)), a2)); - v_store(&D1[dx+12], v_dotprod(v_reinterpret_as_s16(v_expand_high(s23)), a3)); - } - } - for( ; k < count; k++ ) - { - const uchar *S = src[k]; - int *D = dst[k]; - for( dx = 0; dx < len0; dx += step ) - { - v_int16x8 a0 = v_load(alpha+dx*2); - v_int16x8 a1 = v_load(alpha+dx*2 + 8); - v_int16x8 a2 = v_load(alpha+dx*2 + 16); - v_int16x8 a3 = v_load(alpha+dx*2 + 24); - v_uint8x16 s01, s23; - v_zip(v_lut(S, xofs+dx), v_lut(S+cn, xofs+dx), s01, s23); - v_store(&D[dx], v_dotprod(v_reinterpret_as_s16(v_expand_low(s01)), a0)); - v_store(&D[dx+4], v_dotprod(v_reinterpret_as_s16(v_expand_high(s01)), a1)); - v_store(&D[dx+8], v_dotprod(v_reinterpret_as_s16(v_expand_low(s23)), a2)); - v_store(&D[dx+12], v_dotprod(v_reinterpret_as_s16(v_expand_high(s23)), a3)); - } - } + return 0; // images with channels >4 are out of optimization scope } return dx; } diff --git a/modules/imgproc/test/test_drawing.cpp b/modules/imgproc/test/test_drawing.cpp index f18709448c..2796d35ba8 100644 --- a/modules/imgproc/test/test_drawing.cpp +++ b/modules/imgproc/test/test_drawing.cpp @@ -583,4 +583,14 @@ TEST(Drawing, line) ASSERT_THROW(line(mat, Point(1,1),Point(99,99),Scalar(255),0), cv::Exception); } +TEST(Drawing, regression_16308) +{ + Mat_ img(Size(100, 100), (uchar)0); + circle(img, Point(50, 50), 50, 255, 1, LINE_AA); + EXPECT_NE(0, (int)img.at(0, 50)); + EXPECT_NE(0, (int)img.at(50, 0)); + EXPECT_NE(0, (int)img.at(50, 99)); + EXPECT_NE(0, (int)img.at(99, 50)); +} + }} // namespace diff --git a/modules/objdetect/src/qrcode.cpp b/modules/objdetect/src/qrcode.cpp index a80fa16627..a01cb82432 100644 --- a/modules/objdetect/src/qrcode.cpp +++ b/modules/objdetect/src/qrcode.cpp @@ -2289,7 +2289,8 @@ bool QRCodeDetector::decodeMulti( CV_Assert((points.size().width % 4) == 0); vector< vector< Point2f > > src_points ; Mat qr_points = points.getMat(); - for (int i = 0; i < points.size().width ; i += 4) + qr_points = qr_points.reshape(2, 1); + for (int i = 0; i < qr_points.size().width ; i += 4) { vector tempMat = qr_points.colRange(i, i + 4); if (contourArea(tempMat) > 0.0) diff --git a/modules/objdetect/test/test_qrcode.cpp b/modules/objdetect/test/test_qrcode.cpp index d26323ea76..cda5a02311 100644 --- a/modules/objdetect/test/test_qrcode.cpp +++ b/modules/objdetect/test/test_qrcode.cpp @@ -481,6 +481,26 @@ INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Close, testing::ValuesIn(qrcode_i INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Monitor, testing::ValuesIn(qrcode_images_monitor)); INSTANTIATE_TEST_CASE_P(/**/, Objdetect_QRCode_Multi, testing::ValuesIn(qrcode_images_multiple)); +TEST(Objdetect_QRCode_decodeMulti, decode_regression_16491) +{ +#ifdef HAVE_QUIRC + Mat zero_image = Mat::zeros(256, 256, CV_8UC1); + Point corners_[] = {Point(16, 16), Point(128, 16), Point(128, 128), Point(16, 128), + Point(16, 16), Point(128, 16), Point(128, 128), Point(16, 128)}; + std::vector vec_corners; + int array_size = 8; + vec_corners.assign(corners_, corners_ + array_size); + std::vector decoded_info; + std::vector straight_barcode; + QRCodeDetector vec_qrcode; + EXPECT_NO_THROW(vec_qrcode.decodeMulti(zero_image, vec_corners, decoded_info, straight_barcode)); + + Mat mat_corners(2, 4, CV_32SC2, (void*)&vec_corners[0]); + QRCodeDetector mat_qrcode; + EXPECT_NO_THROW(mat_qrcode.decodeMulti(zero_image, mat_corners, decoded_info, straight_barcode)); +#endif +} + TEST(Objdetect_QRCode_basic, not_found_qrcode) { std::vector corners; diff --git a/modules/videoio/src/cap_avfoundation.mm b/modules/videoio/src/cap_avfoundation.mm index f1d1af3eec..9a61292ee8 100644 --- a/modules/videoio/src/cap_avfoundation.mm +++ b/modules/videoio/src/cap_avfoundation.mm @@ -39,6 +39,11 @@ #import #import +#define CV_CAP_MODE_BGR CV_FOURCC_MACRO('B','G','R','3') +#define CV_CAP_MODE_RGB CV_FOURCC_MACRO('R','G','B','3') +#define CV_CAP_MODE_GRAY CV_FOURCC_MACRO('G','R','E','Y') +#define CV_CAP_MODE_YUYV CV_FOURCC_MACRO('Y', 'U', 'Y', 'V') + /********************** Declaration of class headers ************************/ /***************************************************************************** @@ -128,37 +133,36 @@ class CvCaptureCAM : public CvCapture { *****************************************************************************/ class CvCaptureFile : public CvCapture { - public: +public: + CvCaptureFile(const char* filename) ; + ~CvCaptureFile(); + virtual bool grabFrame(); + virtual IplImage* retrieveFrame(int); + virtual double getProperty(int property_id) const; + virtual bool setProperty(int property_id, double value); + virtual int didStart(); +private: + AVAsset *mAsset; + AVAssetTrack *mAssetTrack; + AVAssetReader *mAssetReader; + AVAssetReaderTrackOutput *mTrackOutput; - CvCaptureFile(const char* filename) ; - ~CvCaptureFile(); - virtual bool grabFrame(); - virtual IplImage* retrieveFrame(int); - virtual IplImage* queryFrame(); - virtual double getProperty(int property_id) const; - virtual bool setProperty(int property_id, double value); - virtual int didStart(); + CMSampleBufferRef mCurrentSampleBuffer; + CVImageBufferRef mGrabbedPixels; + IplImage *mDeviceImage; + uint8_t *mOutImagedata; + IplImage *mOutImage; + size_t currSize; + uint32_t mMode; + int mFormat; - private: + bool setupReadingAt(CMTime position); + IplImage* retrieveFramePixelBuffer(); - AVAssetReader *mMovieReader; - char* imagedata; - IplImage* image; - char* bgr_imagedata; - IplImage* bgr_image; - size_t currSize; + CMTime mFrameTimestamp; + size_t mFrameNum; - IplImage* retrieveFramePixelBuffer(); - double getFPS(); - - int movieWidth; - int movieHeight; - double movieFPS; - double currentFPS; - double movieDuration; - int changedPos; - - int started; + int started; }; @@ -771,216 +775,320 @@ fromConnection:(AVCaptureConnection *)connection{ *****************************************************************************/ CvCaptureFile::CvCaptureFile(const char* filename) { + NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init]; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - - mMovieReader = nil; - image = NULL; - bgr_image = NULL; - imagedata = NULL; - bgr_imagedata = NULL; + mAsset = nil; + mAssetTrack = nil; + mAssetReader = nil; + mTrackOutput = nil; + mDeviceImage = NULL; + mOutImage = NULL; + mOutImagedata = NULL; currSize = 0; - - movieWidth = 0; - movieHeight = 0; - movieFPS = 0; - currentFPS = 0; - movieDuration = 0; - changedPos = 0; + mMode = CV_CAP_MODE_BGR; + mFormat = CV_8UC3; + mCurrentSampleBuffer = NULL; + mGrabbedPixels = NULL; + mFrameTimestamp = kCMTimeZero; + mFrameNum = 0; started = 0; - AVURLAsset *asset = [AVURLAsset URLAssetWithURL: - [NSURL fileURLWithPath: [NSString stringWithUTF8String:filename]] - options:nil]; + mAsset = [[AVAsset assetWithURL:[NSURL fileURLWithPath: @(filename)]] retain]; - AVAssetTrack* videoTrack = nil; - NSArray* tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; - if ([tracks count] == 1) - { - videoTrack = [tracks objectAtIndex:0]; - - movieWidth = videoTrack.naturalSize.width; - movieHeight = videoTrack.naturalSize.height; - movieFPS = videoTrack.nominalFrameRate; - - currentFPS = movieFPS; //Debugging !! should be getFPS(); - //Debugging. need to be checked - - // In ms - movieDuration = videoTrack.timeRange.duration.value/videoTrack.timeRange.duration.timescale * 1000; - - started = 1; - NSError* error = nil; - mMovieReader = [[AVAssetReader alloc] initWithAsset:asset error:&error]; - if (error) - NSLog(@"%@", [error localizedDescription]); - - NSDictionary* videoSettings = - [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] - forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey]; - - [mMovieReader addOutput:[AVAssetReaderTrackOutput - assetReaderTrackOutputWithTrack:videoTrack - outputSettings:videoSettings]]; - [mMovieReader startReading]; + if ( mAsset == nil ) { + fprintf(stderr, "OpenCV: Couldn't read movie file \"%s\"\n", filename); + [localpool drain]; + started = 0; + return; } - /* - // Asynchronously open the video in another thread. Always fail. - [asset loadValuesAsynchronouslyForKeys:[NSArray arrayWithObject:@"tracks"] completionHandler: - ^{ - // The completion block goes here. - dispatch_async(dispatch_get_main_queue(), - ^{ - AVAssetTrack* ::videoTrack = nil; - NSArray* ::tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; - if ([tracks count] == 1) - { - videoTrack = [tracks objectAtIndex:0]; + NSArray *tracks = [mAsset tracksWithMediaType:AVMediaTypeVideo]; + if ([tracks count] == 0) { + fprintf(stderr, "OpenCV: Couldn't read video stream from file \"%s\"\n", filename); + [localpool drain]; + started = 0; + return; + } + + mAssetTrack = [tracks[0] retain]; + + if ( ! setupReadingAt(kCMTimeZero) ) { + fprintf(stderr, "OpenCV: Couldn't read movie file \"%s\"\n", filename); + [localpool drain]; + started = 0; + return; + } - movieWidth = videoTrack.naturalSize.width; - movieHeight = videoTrack.naturalSize.height; - movieFPS = videoTrack.nominalFrameRate; - currentFPS = movieFPS; //Debugging !! should be getFPS(); - //Debugging. need to be checked - movieDuration = videoTrack.timeRange.duration.value/videoTrack.timeRange.duration.timescale * 1000; started = 1; - - NSError* ::error = nil; - // mMovieReader is a member variable - mMovieReader = [[AVAssetReader alloc] initWithAsset:asset error:&error]; - if (error) - NSLog(@"%@", [error localizedDescription]); - - NSDictionary* ::videoSettings = - [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] -forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey]; - -[mMovieReader addOutput:[AVAssetReaderTrackOutput -assetReaderTrackOutputWithTrack:videoTrack -outputSettings:videoSettings]]; -[mMovieReader startReading]; -} -}); - -}]; - */ - -[localpool drain]; + [localpool drain]; } CvCaptureFile::~CvCaptureFile() { + NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init]; + + free(mOutImagedata); + cvReleaseImage(&mOutImage); + cvReleaseImage(&mDeviceImage); + [mAssetReader release]; + [mTrackOutput release]; + [mAssetTrack release]; + [mAsset release]; + CVBufferRelease(mGrabbedPixels); + if ( mCurrentSampleBuffer ) { + CFRelease(mCurrentSampleBuffer); + } - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - if (imagedata != NULL) free(imagedata); - if (bgr_imagedata != NULL) free(bgr_imagedata); - cvReleaseImage(&image); - cvReleaseImage(&bgr_image); - [mMovieReader release]; [localpool drain]; } +bool CvCaptureFile::setupReadingAt(CMTime position) { + if (mAssetReader) { + if (mAssetReader.status == AVAssetReaderStatusReading) { + [mAssetReader cancelReading]; + } + [mAssetReader release]; + mAssetReader = nil; + } + if (mTrackOutput) { + [mTrackOutput release]; + mTrackOutput = nil; + } + + // Capture in a pixel format that can be converted efficiently to the output mode. + OSType pixelFormat; + if (mMode == CV_CAP_MODE_BGR || mMode == CV_CAP_MODE_RGB) { + pixelFormat = kCVPixelFormatType_32BGRA; + mFormat = CV_8UC3; + } else if (mMode == CV_CAP_MODE_GRAY) { + pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; + mFormat = CV_8UC1; + } else if (mMode == CV_CAP_MODE_YUYV) { + pixelFormat = kCVPixelFormatType_422YpCbCr8; + mFormat = CV_8UC2; + } else { + fprintf(stderr, "VIDEOIO ERROR: AVF Mac: Unsupported mode: %d\n", mMode); + return false; + } + + NSDictionary *settings = + @{ + (id)kCVPixelBufferPixelFormatTypeKey: @(pixelFormat) + }; + mTrackOutput = [[AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack: mAssetTrack + outputSettings: settings] retain]; + + if ( !mTrackOutput ) { + fprintf(stderr, "OpenCV: error in [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:outputSettings:]\n"); + return false; + } + + NSError *error = nil; + mAssetReader = [[AVAssetReader assetReaderWithAsset: mAsset + error: &error] retain]; + if ( error ) { + fprintf(stderr, "OpenCV: error in [AVAssetReader assetReaderWithAsset:error:]\n"); + NSLog(@"OpenCV: %@", error.localizedDescription); + return false; + } + + mAssetReader.timeRange = CMTimeRangeMake(position, kCMTimePositiveInfinity); + mFrameTimestamp = position; + mFrameNum = round((mFrameTimestamp.value * mAssetTrack.nominalFrameRate) / double(mFrameTimestamp.timescale)); + [mAssetReader addOutput: mTrackOutput]; + return [mAssetReader startReading]; +} + int CvCaptureFile::didStart() { return started; } bool CvCaptureFile::grabFrame() { + NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init]; - //everything is done in queryFrame; - currentFPS = movieFPS; - return 1; - - - /* - double t1 = getProperty(CV_CAP_PROP_POS_MSEC); - [mCaptureSession stepForward]; - double t2 = getProperty(CV_CAP_PROP_POS_MSEC); - if (t2>t1 && !changedPos) { - currentFPS = 1000.0/(t2-t1); - } else { - currentFPS = movieFPS; - } - changedPos = 0; - - */ + CVBufferRelease(mGrabbedPixels); + if ( mCurrentSampleBuffer ) { + CFRelease(mCurrentSampleBuffer); + } + mCurrentSampleBuffer = [mTrackOutput copyNextSampleBuffer]; + mGrabbedPixels = CMSampleBufferGetImageBuffer(mCurrentSampleBuffer); + CVBufferRetain(mGrabbedPixels); + mFrameTimestamp = CMSampleBufferGetOutputPresentationTimeStamp(mCurrentSampleBuffer); + mFrameNum++; + bool isReading = (mAssetReader.status == AVAssetReaderStatusReading); + [localpool drain]; + return isReading; } - IplImage* CvCaptureFile::retrieveFramePixelBuffer() { - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - - if (mMovieReader.status != AVAssetReaderStatusReading){ - - return NULL; + if ( ! mGrabbedPixels ) { + return 0; } + NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init]; - AVAssetReaderOutput * output = [mMovieReader.outputs objectAtIndex:0]; - CMSampleBufferRef sampleBuffer = [output copyNextSampleBuffer]; - if (!sampleBuffer) { - [localpool drain]; - return NULL; - } - CVPixelBufferRef frame = CMSampleBufferGetImageBuffer(sampleBuffer); - CVPixelBufferRef pixels = CVBufferRetain(frame); + CVPixelBufferLockBaseAddress(mGrabbedPixels, 0); + void *baseaddress; + size_t width, height, rowBytes; - CVPixelBufferLockBaseAddress(pixels, 0); - - uint32_t* baseaddress = (uint32_t*)CVPixelBufferGetBaseAddress(pixels); - size_t width = CVPixelBufferGetWidth(pixels); - size_t height = CVPixelBufferGetHeight(pixels); - size_t rowBytes = CVPixelBufferGetBytesPerRow(pixels); - - if (rowBytes != 0) { - - if (currSize != rowBytes*height*sizeof(char)) { - currSize = rowBytes*height*sizeof(char); - if (imagedata != NULL) free(imagedata); - if (bgr_imagedata != NULL) free(bgr_imagedata); - imagedata = (char*)malloc(currSize); - bgr_imagedata = (char*)malloc(currSize); - } - - memcpy(imagedata, baseaddress, currSize); - - if (image == NULL) { - image = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, 4); - } - - image->width = (int)width; - image->height = (int)height; - image->nChannels = 4; - image->depth = IPL_DEPTH_8U; - image->widthStep = (int)rowBytes; - image->imageData = imagedata; - image->imageSize = (int)currSize; - - - if (bgr_image == NULL) { - bgr_image = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, 3); - } - - bgr_image->width = (int)width; - bgr_image->height = (int)height; - bgr_image->nChannels = 3; - bgr_image->depth = IPL_DEPTH_8U; - bgr_image->widthStep = (int)rowBytes; - bgr_image->imageData = bgr_imagedata; - bgr_image->imageSize = (int)currSize; - - cvCvtColor(image, bgr_image,CV_BGRA2BGR); + OSType pixelFormat = CVPixelBufferGetPixelFormatType(mGrabbedPixels); + if (CVPixelBufferIsPlanar(mGrabbedPixels)) { + baseaddress = CVPixelBufferGetBaseAddressOfPlane(mGrabbedPixels, 0); + width = CVPixelBufferGetWidthOfPlane(mGrabbedPixels, 0); + height = CVPixelBufferGetHeightOfPlane(mGrabbedPixels, 0); + rowBytes = CVPixelBufferGetBytesPerRowOfPlane(mGrabbedPixels, 0); + } else { + baseaddress = CVPixelBufferGetBaseAddress(mGrabbedPixels); + width = CVPixelBufferGetWidth(mGrabbedPixels); + height = CVPixelBufferGetHeight(mGrabbedPixels); + rowBytes = CVPixelBufferGetBytesPerRow(mGrabbedPixels); } - CVPixelBufferUnlockBaseAddress(pixels, 0); - CVBufferRelease(pixels); - CMSampleBufferInvalidate(sampleBuffer); - CFRelease(sampleBuffer); + if ( rowBytes == 0 ) { + fprintf(stderr, "OpenCV: error: rowBytes == 0\n"); + CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0); + CVBufferRelease(mGrabbedPixels); + mGrabbedPixels = NULL; + return 0; + } + + int outChannels; + if (mMode == CV_CAP_MODE_BGR || mMode == CV_CAP_MODE_RGB) { + outChannels = 3; + } else if (mMode == CV_CAP_MODE_GRAY) { + outChannels = 1; + } else if (mMode == CV_CAP_MODE_YUYV) { + outChannels = 2; + } else { + fprintf(stderr, "VIDEOIO ERROR: AVF Mac: Unsupported mode: %d\n", mMode); + CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0); + CVBufferRelease(mGrabbedPixels); + mGrabbedPixels = NULL; + return 0; + } + + if ( currSize != width*outChannels*height ) { + currSize = width*outChannels*height; + free(mOutImagedata); + mOutImagedata = reinterpret_cast(malloc(currSize)); + } + + if (mOutImage == NULL) { + mOutImage = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, outChannels); + } + mOutImage->width = int(width); + mOutImage->height = int(height); + mOutImage->nChannels = outChannels; + mOutImage->depth = IPL_DEPTH_8U; + mOutImage->widthStep = int(width*outChannels); + mOutImage->imageData = reinterpret_cast(mOutImagedata); + mOutImage->imageSize = int(currSize); + + int deviceChannels; + int cvtCode; + + if ( pixelFormat == kCVPixelFormatType_32BGRA ) { + deviceChannels = 4; + + if (mMode == CV_CAP_MODE_BGR) { + cvtCode = CV_BGRA2BGR; + } else if (mMode == CV_CAP_MODE_RGB) { + cvtCode = CV_BGRA2RGB; + } else if (mMode == CV_CAP_MODE_GRAY) { + cvtCode = CV_BGRA2GRAY; + } else { + CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0); + CVBufferRelease(mGrabbedPixels); + mGrabbedPixels = NULL; + fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n"); + return 0; + } + } else if ( pixelFormat == kCVPixelFormatType_24RGB ) { + deviceChannels = 3; + + if (mMode == CV_CAP_MODE_BGR) { + cvtCode = CV_RGB2BGR; + } else if (mMode == CV_CAP_MODE_RGB) { + cvtCode = 0; + } else if (mMode == CV_CAP_MODE_GRAY) { + cvtCode = CV_RGB2GRAY; + } else { + CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0); + CVBufferRelease(mGrabbedPixels); + mGrabbedPixels = NULL; + fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n"); + return 0; + } + } else if ( pixelFormat == kCVPixelFormatType_422YpCbCr8 ) { // 422 (2vuy, UYVY) + deviceChannels = 2; + + if (mMode == CV_CAP_MODE_BGR) { + cvtCode = CV_YUV2BGR_UYVY; + } else if (mMode == CV_CAP_MODE_RGB) { + cvtCode = CV_YUV2RGB_UYVY; + } else if (mMode == CV_CAP_MODE_GRAY) { + cvtCode = CV_YUV2GRAY_UYVY; + } else if (mMode == CV_CAP_MODE_YUYV) { + cvtCode = -1; // Copy + } else { + CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0); + CVBufferRelease(mGrabbedPixels); + mGrabbedPixels = NULL; + fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n"); + return 0; + } + } else if ( pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange || // 420v + pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ) { // 420f + height = height * 3 / 2; + deviceChannels = 1; + + if (mMode == CV_CAP_MODE_BGR) { + cvtCode = CV_YUV2BGR_YV12; + } else if (mMode == CV_CAP_MODE_RGB) { + cvtCode = CV_YUV2RGB_YV12; + } else if (mMode == CV_CAP_MODE_GRAY) { + cvtCode = CV_YUV2GRAY_420; + } else { + CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0); + CVBufferRelease(mGrabbedPixels); + mGrabbedPixels = NULL; + fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n"); + return 0; + } + } else { + char pfBuf[] = { (char)pixelFormat, (char)(pixelFormat >> 8), + (char)(pixelFormat >> 16), (char)(pixelFormat >> 24), '\0' }; + fprintf(stderr, "OpenCV: unsupported pixel format '%s'\n", pfBuf); + CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0); + CVBufferRelease(mGrabbedPixels); + mGrabbedPixels = NULL; + return 0; + } + + if (mDeviceImage == NULL) { + mDeviceImage = cvCreateImageHeader(cvSize(int(width),int(height)), IPL_DEPTH_8U, deviceChannels); + } + mDeviceImage->width = int(width); + mDeviceImage->height = int(height); + mDeviceImage->nChannels = deviceChannels; + mDeviceImage->depth = IPL_DEPTH_8U; + mDeviceImage->widthStep = int(rowBytes); + mDeviceImage->imageData = reinterpret_cast(baseaddress); + mDeviceImage->imageSize = int(rowBytes*height); + + if (cvtCode == -1) { + cv::cvarrToMat(mDeviceImage).copyTo(cv::cvarrToMat(mOutImage)); + } else { + cvCvtColor(mDeviceImage, mOutImage, cvtCode); + } + + CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0); [localpool drain]; - return bgr_image; + + return mOutImage; } @@ -988,123 +1096,88 @@ IplImage* CvCaptureFile::retrieveFrame(int) { return retrieveFramePixelBuffer(); } -IplImage* CvCaptureFile::queryFrame() { - grabFrame(); - return retrieveFrame(0); +double CvCaptureFile::getProperty(int property_id) const{ + if (mAsset == nil) return 0; + + CMTime t; + + switch (property_id) { + case CV_CAP_PROP_POS_MSEC: + return mFrameTimestamp.value * 1000.0 / mFrameTimestamp.timescale; + case CV_CAP_PROP_POS_FRAMES: + return mAssetTrack.nominalFrameRate > 0 ? mFrameNum : 0; + case CV_CAP_PROP_POS_AVI_RATIO: + t = [mAsset duration]; + return (mFrameTimestamp.value * t.timescale) / double(mFrameTimestamp.timescale * t.value); + case CV_CAP_PROP_FRAME_WIDTH: + return mAssetTrack.naturalSize.width; + case CV_CAP_PROP_FRAME_HEIGHT: + return mAssetTrack.naturalSize.height; + case CV_CAP_PROP_FPS: + return mAssetTrack.nominalFrameRate; + case CV_CAP_PROP_FRAME_COUNT: + t = [mAsset duration]; + return round((t.value * mAssetTrack.nominalFrameRate) / double(t.timescale)); + case CV_CAP_PROP_FORMAT: + return mFormat; + case CV_CAP_PROP_FOURCC: + return mMode; + default: + break; + } + + return 0; } -double CvCaptureFile::getFPS() { +bool CvCaptureFile::setProperty(int property_id, double value) { + if (mAsset == nil) return false; - /* - if (mCaptureSession == nil) return 0; - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - double now = getProperty(CV_CAP_PROP_POS_MSEC); - double retval = 0; - if (now == 0) { - [mCaptureSession stepForward]; - double t2 = getProperty(CV_CAP_PROP_POS_MSEC); - [mCaptureSession stepBackward]; - retval = 1000.0 / (t2-now); - } else { - [mCaptureSession stepBackward]; - double t2 = getProperty(CV_CAP_PROP_POS_MSEC); - [mCaptureSession stepForward]; - retval = 1000.0 / (now-t2); - } - [localpool drain]; - return retval; - */ - return 30.0; //TODO: Debugging -} + NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; -double CvCaptureFile::getProperty(int /*property_id*/) const{ + bool retval = false; + CMTime t; - /* - if (mCaptureSession == nil) return 0; - - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - - double retval; - QTTime t; - - switch (property_id) { - case CV_CAP_PROP_POS_MSEC: - [[mCaptureSession attributeForKey:QTMovieCurrentTimeAttribute] getValue:&t]; - retval = t.timeValue * 1000.0 / t.timeScale; - break; - case CV_CAP_PROP_POS_FRAMES: - retval = movieFPS * getProperty(CV_CAP_PROP_POS_MSEC) / 1000; - break; - case CV_CAP_PROP_POS_AVI_RATIO: - retval = (getProperty(CV_CAP_PROP_POS_MSEC)) / (movieDuration ); - break; - case CV_CAP_PROP_FRAME_WIDTH: - retval = movieWidth; - break; - case CV_CAP_PROP_FRAME_HEIGHT: - retval = movieHeight; - break; - case CV_CAP_PROP_FPS: - retval = currentFPS; - break; - case CV_CAP_PROP_FOURCC: - default: - retval = 0; - } - - [localpool drain]; - return retval; - */ - return 1.0; //Debugging -} - -bool CvCaptureFile::setProperty(int /*property_id*/, double /*value*/) { - - /* - if (mCaptureSession == nil) return false; - - NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init]; - - bool retval = false; - QTTime t; - - double ms; - - switch (property_id) { - case CV_CAP_PROP_POS_MSEC: - [[mCaptureSession attributeForKey:QTMovieCurrentTimeAttribute] getValue:&t]; - t.timeValue = value * t.timeScale / 1000; - [mCaptureSession setCurrentTime:t]; - changedPos = 1; - retval = true; - break; - case CV_CAP_PROP_POS_FRAMES: - ms = (value*1000.0 -5)/ currentFPS; - retval = setProperty(CV_CAP_PROP_POS_MSEC, ms); - break; - case CV_CAP_PROP_POS_AVI_RATIO: - ms = value * movieDuration; - retval = setProperty(CV_CAP_PROP_POS_MSEC, ms); - break; - case CV_CAP_PROP_FRAME_WIDTH: - //retval = movieWidth; - break; - case CV_CAP_PROP_FRAME_HEIGHT: - //retval = movieHeight; - break; - case CV_CAP_PROP_FPS: - //etval = currentFPS; - break; - case CV_CAP_PROP_FOURCC: - default: - retval = false; + switch (property_id) { + case CV_CAP_PROP_POS_MSEC: + t = mAsset.duration; + t.value = value * t.timescale / 1000; + retval = setupReadingAt(t); + break; + case CV_CAP_PROP_POS_FRAMES: + retval = mAssetTrack.nominalFrameRate > 0 ? setupReadingAt(CMTimeMake(value, mAssetTrack.nominalFrameRate)) : false; + break; + case CV_CAP_PROP_POS_AVI_RATIO: + t = mAsset.duration; + t.value = round(t.value * value); + retval = setupReadingAt(t); + break; + case CV_CAP_PROP_FOURCC: + uint32_t mode; + mode = cvRound(value); + if (mMode == mode) { + retval = true; + } else { + switch (mode) { + case CV_CAP_MODE_BGR: + case CV_CAP_MODE_RGB: + case CV_CAP_MODE_GRAY: + case CV_CAP_MODE_YUYV: + mMode = mode; + retval = setupReadingAt(mFrameTimestamp); + break; + default: + fprintf(stderr, "VIDEOIO ERROR: AVF iOS: Unsupported mode: %d\n", mode); + retval=false; + break; + } + } + break; + default: + break; } [localpool drain]; - return retval; - */ - return true; }