예제 #1
0
        /// <summary>
        /// Draw a set of detected ChArUco Diamond markers.
        /// </summary>
        /// <param name="image">input/output image. It must have 1 or 3 channels. The number of channels is not altered.</param>
        /// <param name="diamondCorners">positions of diamond corners in the same format returned by detectCharucoDiamond(). (e.g std::vector&lt;std::vector&lt;cv::Point2f&gt;&gt;). For N detected markers, the dimensions of this array should be Nx4. The order of the corners should be clockwise.</param>
        /// <param name="diamondIds">vector of identifiers for diamonds in diamondCorners, in the same format returned by detectCharucoDiamond() (e.g. std::vector&lt;Vec4i&gt;). Optional, if not provided, ids are not painted.</param>
        /// <param name="borderColor">color of marker borders. Rest of colors (text color and first corner color) are calculated based on this one.</param>
        public static void DrawDetectedDiamonds(InputArray image,
                                                Point2f[][] diamondCorners, IEnumerable <Vec4i>?diamondIds, Scalar borderColor)
        {
            if (image == null)
            {
                throw new ArgumentNullException(nameof(image));
            }
            if (diamondCorners == null)
            {
                throw new ArgumentNullException(nameof(diamondCorners));
            }

            using var cornersAddress = new ArrayAddress2 <Point2f>(diamondCorners);

            if (diamondIds == null)
            {
                NativeMethods.HandleException(
                    NativeMethods.aruco_drawDetectedDiamonds(image.CvPtr,
                                                             cornersAddress.GetPointer(), cornersAddress.GetDim1Length(), cornersAddress.GetDim2Lengths(),
                                                             IntPtr.Zero, borderColor));
            }
            else
            {
                using var ids = new VectorOfVec4i(diamondIds);

                NativeMethods.HandleException(
                    NativeMethods.aruco_drawDetectedDiamonds(image.CvPtr,
                                                             cornersAddress.GetPointer(), cornersAddress.GetDim1Length(), cornersAddress.GetDim2Lengths(),
                                                             ids.CvPtr, borderColor));
            }

            GC.KeepAlive(image);
        }
예제 #2
0
        /// <summary>
        /// Draw detected markers in image
        /// </summary>
        /// <param name="image">input/output image. It must have 1 or 3 channels. The number of channels is not altered.</param>
        /// <param name="corners">positions of marker corners on input image.
        /// For N detected markers, the dimensions of this array should be Nx4.The order of the corners should be clockwise.</param>
        /// <param name="ids">vector of identifiers for markers in markersCorners. Optional, if not provided, ids are not painted.</param>
        /// <param name="borderColor">color of marker borders. Rest of colors (text color and first corner color)
        ///  are calculated based on this one to improve visualization.</param>
        public static void DrawDetectedMarkers(InputArray image, Point2f[][] corners, IEnumerable <int>?ids, Scalar borderColor)
        {
            if (image == null)
            {
                throw new ArgumentNullException(nameof(image));
            }
            if (corners == null)
            {
                throw new ArgumentNullException(nameof(corners));
            }

            using (var cornersAddress = new ArrayAddress2 <Point2f>(corners))
            {
                if (ids == null)
                {
                    NativeMethods.aruco_drawDetectedMarkers(image.CvPtr, cornersAddress.Pointer, cornersAddress.Dim1Length, cornersAddress.Dim2Lengths, IntPtr.Zero, 0, borderColor);
                }
                else
                {
                    int[] idxArray = EnumerableEx.ToArray(ids);
                    NativeMethods.aruco_drawDetectedMarkers(image.CvPtr, cornersAddress.Pointer, cornersAddress.Dim1Length, cornersAddress.Dim2Lengths, idxArray, idxArray.Length, borderColor);
                }
                GC.KeepAlive(image);
            }
        }
예제 #3
0
        /// <summary>
        /// Try to stitch the given images.
        /// </summary>
        /// <param name="images">Input images.</param>
        /// <param name="rois">Region of interest rectangles.</param>
        /// <param name="pano">Final pano.</param>
        /// <returns>Status code.</returns>
        public Status Stitch(IEnumerable <Mat> images, Rect[][] rois, OutputArray pano)
        {
            if (images == null)
            {
                throw new ArgumentNullException(nameof(images));
            }
            if (rois == null)
            {
                throw new ArgumentNullException(nameof(rois));
            }
            if (pano == null)
            {
                throw new ArgumentNullException(nameof(pano));
            }
            pano.ThrowIfNotReady();

            var imagesPtrs = images.Select(x => x.CvPtr).ToArray();

            using var roisPointer = new ArrayAddress2 <Rect>(rois);
            NativeMethods.HandleException(
                NativeMethods.stitching_Stitcher_stitch2_MatArray(
                    ptr, imagesPtrs, imagesPtrs.Length,
                    roisPointer.GetPointer(), roisPointer.GetDim1Length(), roisPointer.GetDim2Lengths(),
                    pano.CvPtr, out var ret));

            pano.Fix();
            GC.KeepAlive(this);
            GC.KeepAlive(images);
            GC.KeepAlive(pano);
            return((Status)ret);
        }
예제 #4
0
        /// <summary>
        /// Try to stitch the given images.
        /// </summary>
        /// <param name="images">Input images.</param>
        /// <param name="rois">Region of interest rectangles.</param>
        /// <param name="pano">Final pano.</param>
        /// <returns>Status code.</returns>
        public Status Stitch(InputArray images, Rect[][] rois, OutputArray pano)
        {
            if (images == null)
            {
                throw new ArgumentNullException(nameof(images));
            }
            if (rois == null)
            {
                throw new ArgumentNullException(nameof(rois));
            }
            if (pano == null)
            {
                throw new ArgumentNullException(nameof(pano));
            }
            images.ThrowIfDisposed();
            pano.ThrowIfNotReady();

            using var roisPointer = new ArrayAddress2 <Rect>(rois);
            NativeMethods.HandleException(
                NativeMethods.stitching_Stitcher_stitch2_InputArray(
                    ptr, images.CvPtr,
                    roisPointer.GetPointer(), roisPointer.GetDim1Length(), roisPointer.GetDim2Lengths(),
                    pano.CvPtr, out var ret));

            pano.Fix();
            GC.KeepAlive(this);
            GC.KeepAlive(images);
            GC.KeepAlive(pano);
            return((Status)ret);
        }
예제 #5
0
        /// <summary>
        /// 指定サイズのヒストグラムを生成し,そのヒストグラムの参照を返す.
        /// </summary>
        /// <param name="sizes">ヒストグラム各次元のサイズを示す配列</param>
        /// <param name="type">ヒストグラム表現フォーマット</param>
        /// <param name="ranges">ヒストグラムのビン(bin)(値域)を示す配列.このパラメータの意味はパラメータuniformに依存している.
        /// このレンジは,ヒストグラムを計算したり,またどのヒストグラムのビンが入力画像のどの値やどのデータ要素に対応するかを決めるためのバックプロジェクションで用いられる.
        /// null の場合は,後から関数 cvSetHistBinRanges を用いて決定される.</param>
        /// <param name="uniform">一様性に関するフラグ</param>
#else
        /// <summary>
        /// Creates a histogram of the specified size and returns the pointer to the created histogram.
        /// </summary>
        /// <param name="sizes">Number of histogram dimensions. </param>
        /// <param name="type">Histogram representation format.</param>
        /// <param name="ranges">Array of ranges for histogram bins. Its meaning depends on the uniform parameter value. The ranges are used for when histogram is calculated or backprojected to determine, which histogram bin corresponds to which value/tuple of values from the input image[s]. </param>
        /// <param name="uniform">Uniformity flag.</param>
#endif
        public CvHistogram(int[] sizes, HistogramFormat type, float[][] ranges, bool uniform)
        {
            if (sizes == null)
            {
                throw new ArgumentNullException("sizes");
            }

            if (ranges == null)
            {
                ptr = NativeMethods.cvCreateHist(sizes.Length, sizes, type, IntPtr.Zero, uniform);
            }
            else
            {
                // float[][]をIntPtr[]に変換する
                using (var rangesPtr = new ArrayAddress2 <float>(ranges))
                {
                    ptr = NativeMethods.cvCreateHist(sizes.Length, sizes, type, rangesPtr.Pointer, uniform);
                }
            }
            if (ptr == IntPtr.Zero)
            {
                throw new OpenCvSharpException("Failed to create CvHistogram");
            }

            if (ranges != null)
            {
                SetBinRanges(ranges, uniform);
            }
            Type = type;
            NotifyMemoryPressure(SizeOf);
        }
예제 #6
0
        /// <summary>
        /// Try to stitch the given images.
        /// </summary>
        /// <param name="images">Input images.</param>
        /// <param name="rois">Region of interest rectangles.</param>
        /// <param name="pano">Final pano.</param>
        /// <returns>Status code.</returns>
        public Status Stitch(InputArray images, Rect[][] rois, OutputArray pano)
        {
            if (images == null)
            {
                throw new ArgumentNullException("images");
            }
            if (rois == null)
            {
                throw new ArgumentNullException("rois");
            }
            if (pano == null)
            {
                throw new ArgumentNullException("pano");
            }
            images.ThrowIfDisposed();
            pano.ThrowIfNotReady();

            using (var roisPointer = new ArrayAddress2 <Rect>(rois))
            {
                int status = NativeMethods.stitching_Stitcher_stitch2_InputArray(
                    ptr, images.CvPtr,
                    roisPointer.Pointer, roisPointer.Dim1Length, roisPointer.Dim2Lengths,
                    pano.CvPtr);
                pano.Fix();
                return((Status)status);
            }
        }
예제 #7
0
        /// <summary>
        /// Try to stitch the given images.
        /// </summary>
        /// <param name="images">Input images.</param>
        /// <param name="rois">Region of interest rectangles.</param>
        /// <param name="pano">Final pano.</param>
        /// <returns>Status code.</returns>
        public Status Stitch(IEnumerable <Mat> images, Rect[][] rois, OutputArray pano)
        {
            if (images == null)
            {
                throw new ArgumentNullException("images");
            }
            if (rois == null)
            {
                throw new ArgumentNullException("rois");
            }
            if (pano == null)
            {
                throw new ArgumentNullException("pano");
            }
            pano.ThrowIfNotReady();

            IntPtr[] imagesPtrs = EnumerableEx.SelectPtrs(images);

            using (var roisPointer = new ArrayAddress2 <Rect>(rois))
            {
                int status = NativeMethods.stitching_Stitcher_stitch2_MatArray(
                    ptr, imagesPtrs, imagesPtrs.Length,
                    roisPointer.Pointer, roisPointer.Dim1Length, roisPointer.Dim2Lengths,
                    pano.CvPtr);
                pano.Fix();
                return((Status)status);
            }
        }
예제 #8
0
        /// <summary>
        /// Detect ChArUco Diamond markers.
        /// </summary>
        /// <param name="image">input image necessary for corner subpixel.</param>
        /// <param name="markerCorners">list of detected marker corners from detectMarkers function.</param>
        /// <param name="markerIds">list of marker ids in markerCorners.</param>
        /// <param name="squareMarkerLengthRate">rate between square and marker length: squareMarkerLengthRate = squareLength/markerLength. The real units are not necessary.</param>
        /// <param name="diamondCorners">output list of detected diamond corners (4 corners per diamond). The order is the same than in marker corners: top left, top right, bottom right and bottom left. Similar format than the corners returned by detectMarkers (e.g std::vector&lt;std::vector&lt;cv::Point2f&gt;&gt;).</param>
        /// <param name="diamondIds">ids of the diamonds in diamondCorners. The id of each diamond is in fact of type Vec4i, so each diamond has 4 ids, which are the ids of the aruco markers composing the diamond.</param>
        /// <param name="cameraMatrix">Optional camera calibration matrix.</param>
        /// <param name="distCoeffs">Optional camera distortion coefficients.</param>
        public static void DetectCharucoDiamond(InputArray image, Point2f[][] markerCorners, IEnumerable <int> markerIds,
                                                float squareMarkerLengthRate, out Point2f[][] diamondCorners, out Vec4i[] diamondIds,
                                                InputArray?cameraMatrix = null, InputArray?distCoeffs = null)
        {
            if (image == null)
            {
                throw new ArgumentNullException(nameof(image));
            }
            if (markerCorners == null)
            {
                throw new ArgumentNullException(nameof(markerCorners));
            }
            if (markerIds == null)
            {
                throw new ArgumentNullException(nameof(markerIds));
            }

            if (cameraMatrix == null && distCoeffs != null)
            {
                throw new ArgumentNullException(nameof(cameraMatrix));
            }
            if (cameraMatrix != null && distCoeffs == null)
            {
                throw new ArgumentNullException(nameof(distCoeffs));
            }

            image.ThrowIfDisposed();

            cameraMatrix?.ThrowIfDisposed();
            distCoeffs?.ThrowIfDisposed();

            using var markerCornersAddress = new ArrayAddress2 <Point2f>(markerCorners);
            using var markerIdsVec         = new VectorOfInt32(markerIds);

            using var diamondCornersVec = new VectorOfVectorPoint2f();
            using var diamondIdsVec     = new VectorOfVec4i();

            NativeMethods.HandleException(
                NativeMethods.aruco_detectCharucoDiamond(
                    image.CvPtr, markerCornersAddress.GetPointer(), markerCornersAddress.GetDim1Length(), markerCornersAddress.GetDim2Lengths(),
                    markerIdsVec.CvPtr, squareMarkerLengthRate,
                    diamondCornersVec.CvPtr, diamondIdsVec.CvPtr,
                    cameraMatrix?.CvPtr ?? IntPtr.Zero, distCoeffs?.CvPtr ?? IntPtr.Zero));

            diamondCorners = diamondCornersVec.ToArray();
            diamondIds     = diamondIdsVec.ToArray();

            GC.KeepAlive(image);
            if (cameraMatrix != null)
            {
                GC.KeepAlive(cameraMatrix);
            }
            if (distCoeffs != null)
            {
                GC.KeepAlive(distCoeffs);
            }
        }
예제 #9
0
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="values"></param>
        public VectorOfVectorKeyPoint(KeyPoint[][] values)
        {
            if (values == null)
            {
                throw new ArgumentNullException(nameof(values));
            }

            using var aa = new ArrayAddress2 <KeyPoint>(values);
            ptr          = NativeMethods.vector_vector_KeyPoint_new3(
                aa.GetPointer(), aa.GetDim1Length(), aa.GetDim2Lengths());
        }
예제 #10
0
        /// <summary>
        ///
        /// </summary>
        public VectorOfVectorVec2i(Vec2i[][] source)
        {
            using (var srcPtr = new ArrayAddress2 <Vec2i>(source))
            {
                IntPtr[] sizes = new IntPtr[source.Length];
                for (int i = 0; i < source.Length; ++i)
                {
                    sizes[i] = new IntPtr(source[i].Length);
                }

                ptr = NativeMethods.vector_vector_Vec2i_new3(new IntPtr(source.Length), sizes, srcPtr);
            }
        }
예제 #11
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="values"></param>
        public VectorOfVectorKeyPoint(KeyPoint[][] values)
        {
            if (values == null)
            {
                throw new ArgumentNullException("values");
            }

            using (var aa = new ArrayAddress2 <KeyPoint>(values))
            {
                ptr = NativeMethods.vector_vector_KeyPoint_new3(
                    aa.Pointer, aa.Dim1Length, aa.Dim2Lengths);
            }
        }
예제 #12
0
        /// <summary>
        /// Pose estimation for single markers
        /// </summary>
        /// <param name="corners">corners vector of already detected markers corners.
        /// For each marker, its four corners are provided, (e.g std::vector&lt;std::vector&lt;cv::Point2f&gt;&gt; ).
        /// For N detected markers, the dimensions of this array should be Nx4. The order of the corners should be clockwise.</param>
        /// <param name="markerLength">the length of the markers' side. The returning translation vectors will
        /// be in the same unit.Normally, unit is meters.</param>
        /// <param name="cameraMatrix">input 3x3 floating-point camera matrix
        /// \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$</param>
        /// <param name="distortionCoefficients">vector of distortion coefficients
        /// \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements</param>
        /// <param name="rvec">array of output rotation vectors (@sa Rodrigues) (e.g. std::vector&lt;cv::Vec3d&gt;).
        /// Each element in rvecs corresponds to the specific marker in imgPoints.</param>
        /// <param name="tvec">array of output translation vectors (e.g. std::vector&lt;cv::Vec3d&gt;).
        /// Each element in tvecs corresponds to the specific marker in imgPoints.</param>
        /// <param name="objPoints">array of object points of all the marker corners</param>
        public static void EstimatePoseSingleMarkers(
            Point2f[][] corners,
            float markerLength,
            InputArray cameraMatrix,
            InputArray distortionCoefficients,
            OutputArray rvec,
            OutputArray tvec,
            OutputArray?objPoints = null)
        {
            if (corners == null)
            {
                throw new ArgumentNullException(nameof(corners));
            }
            if (cameraMatrix == null)
            {
                throw new ArgumentNullException(nameof(cameraMatrix));
            }
            if (distortionCoefficients == null)
            {
                throw new ArgumentNullException(nameof(distortionCoefficients));
            }
            if (rvec == null)
            {
                throw new ArgumentNullException(nameof(rvec));
            }
            if (tvec == null)
            {
                throw new ArgumentNullException(nameof(tvec));
            }

            cameraMatrix.ThrowIfDisposed();
            distortionCoefficients.ThrowIfDisposed();
            rvec.ThrowIfNotReady();
            tvec.ThrowIfNotReady();
            objPoints?.ThrowIfNotReady();

            using var cornersAddress = new ArrayAddress2 <Point2f>(corners);

            NativeMethods.HandleException(
                NativeMethods.aruco_estimatePoseSingleMarkers(
                    cornersAddress.GetPointer(), cornersAddress.GetDim1Length(), cornersAddress.GetDim2Lengths(),
                    markerLength, cameraMatrix.CvPtr, distortionCoefficients.CvPtr, rvec.CvPtr, tvec.CvPtr,
                    objPoints?.CvPtr ?? IntPtr.Zero));

            GC.KeepAlive(cameraMatrix);
            GC.KeepAlive(distortionCoefficients);
            rvec.Fix();
            tvec.Fix();
            objPoints?.Fix();
        }
예제 #13
0
        /// <summary>
        /// Converts std::vector to managed array
        /// </summary>
        /// <returns></returns>
        public float[][] ToArray()
        {
            int size1 = Size1;
            if (size1 == 0)
                return new float[0][];
            long[] size2 = Size2;

            var ret = new float[size1][];
            for (int i = 0; i < size1; i++)
            {
                ret[i] = new float[size2[i]];
            }
            using (var retPtr = new ArrayAddress2<float>(ret))
            {
                NativeMethods.vector_vector_float_copy(ptr, retPtr);
            }
            return ret;
        }
예제 #14
0
        public Status EstimateTransform(InputArray images, Rect[][] rois)
        {
            if (images == null)
            {
                throw new ArgumentNullException("images");
            }
            if (rois == null)
            {
                throw new ArgumentNullException("rois");
            }
            images.ThrowIfDisposed();

            using (var roisPointer = new ArrayAddress2 <Rect>(rois))
            {
                int status = NativeMethods.stitching_Stitcher_estimateTransform_InputArray2(
                    ptr, images.CvPtr,
                    roisPointer.Pointer, roisPointer.Dim1Length, roisPointer.Dim2Lengths);
                return((Status)status);
            }
        }
예제 #15
0
        /// <summary>
        /// Converts std::vector to managed array
        /// </summary>
        /// <returns></returns>
        public DMatch[][] ToArray()
        {
            int size1 = Size1;

            if (size1 == 0)
            {
                return(new DMatch[0][]);
            }
            long[] size2 = Size2;

            DMatch[][] ret = new DMatch[size1][];
            for (int i = 0; i < size1; i++)
            {
                ret[i] = new DMatch[size2[i]];
            }
            using (ArrayAddress2 <DMatch> retPtr = new ArrayAddress2 <DMatch>(ret))
            {
                NativeMethods.vector_vector_DMatch_copy(ptr, retPtr);
            }
            return(ret);
        }
예제 #16
0
        /// <summary>
        /// Converts std::vector to managed array
        /// </summary>
        /// <returns></returns>
        public Vec2i[][] ToArray()
        {
            int size1 = Size1;

            if (size1 == 0)
            {
                return(new Vec2i[0][]);
            }
            long[] size2 = Size2;

            Vec2i[][] ret = new Vec2i[size1][];
            for (int i = 0; i < size1; i++)
            {
                ret[i] = new Vec2i[size2[i]];
            }
            using (var retPtr = new ArrayAddress2 <Vec2i>(ret))
            {
                NativeMethods.vector_vector_Vec2i_copy(ptr, retPtr);
            }
            return(ret);
        }
예제 #17
0
        public Status EstimateTransform(IEnumerable <Mat> images, Rect[][] rois)
        {
            if (images == null)
            {
                throw new ArgumentNullException("images");
            }
            if (rois == null)
            {
                throw new ArgumentNullException("rois");
            }

            IntPtr[] imagesPtrs = EnumerableEx.SelectPtrs(images);

            using (var roisPointer = new ArrayAddress2 <Rect>(rois))
            {
                int status = NativeMethods.stitching_Stitcher_estimateTransform_MatArray2(
                    ptr, imagesPtrs, imagesPtrs.Length,
                    roisPointer.Pointer, roisPointer.Dim1Length, roisPointer.Dim2Lengths);
                return((Status)status);
            }
        }
예제 #18
0
        /// <summary>
        /// Converts std::vector to managed array
        /// </summary>
        /// <returns></returns>
        public Point[][] ToArray()
        {
            int size1 = Size1;

            if (size1 == 0)
            {
                return(new Point[0][]);
            }
            long[] size2 = Size2;

            Point[][] ret = new Point[size1][];
            for (int i = 0; i < size1; i++)
            {
                ret[i] = new Point[size2[i]];
            }
            using (ArrayAddress2 <Point> retPtr = new ArrayAddress2 <Point>(ret))
            {
                NativeMethods.vector_vector_Point_copy(ptr, retPtr);
            }
            return(ret);
        }
예제 #19
0
        /// <summary>
        /// Converts std::vector to managed array
        /// </summary>
        /// <returns></returns>
        public Point[][] ToArray()
        {
            var size1 = GetSize1();

            if (size1 == 0)
            {
                return(Array.Empty <Point[]>());
            }
            var size2 = GetSize2();

            var ret = new Point[size1][];

            for (var i = 0; i < size1; i++)
            {
                ret[i] = new Point[size2[i]];
            }

            using var retPtr = new ArrayAddress2 <Point>(ret);
            NativeMethods.vector_vector_Point_copy(ptr, retPtr.GetPointer());
            GC.KeepAlive(this);
            return(ret);
        }
예제 #20
0
        /// <summary>
        /// Converts std::vector to managed array
        /// </summary>
        /// <returns></returns>
        public double[][] ToArray()
        {
            int size1 = Size1;

            if (size1 == 0)
            {
                return(new double[0][]);
            }
            long[] size2 = Size2;

            var ret = new double[size1][];

            for (int i = 0; i < size1; i++)
            {
                ret[i] = new double[size2[i]];
            }
            using (var retPtr = new ArrayAddress2 <double>(ret))
            {
                NativeMethods.vector_vector_double_copy(ptr, retPtr);
            }
            return(ret);
        }
예제 #21
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="matches1to2"></param>
        /// <param name="correctMatches1to2Mask"></param>
        /// <returns>recallPrecisionCurve</returns>
        public static Point2f[] ComputeRecallPrecisionCurve(
            DMatch[][] matches1to2, byte[][] correctMatches1to2Mask)
        {
            if (matches1to2 == null)
            {
                throw new ArgumentNullException(nameof(matches1to2));
            }
            if (correctMatches1to2Mask == null)
            {
                throw new ArgumentNullException(nameof(correctMatches1to2Mask));
            }

            using var dm     = new ArrayAddress2 <DMatch>(matches1to2);
            using var cm     = new ArrayAddress2 <byte>(correctMatches1to2Mask);
            using var recall = new VectorOfPoint2f();
            NativeMethods.HandleException(
                NativeMethods.features2d_computeRecallPrecisionCurve(
                    dm.Pointer, dm.Dim1Length, dm.Dim2Lengths,
                    cm.Pointer, cm.Dim1Length, cm.Dim2Lengths,
                    recall.CvPtr));
            return(recall.ToArray());
        }
        /// <summary>
        /// Converts std::vector to managed array
        /// </summary>
        /// <returns></returns>
        public Point[][] ToArray()
        {
            var size1 = Size1;

            if (size1 == 0)
            {
                return(new Point[0][]);
            }
            var size2 = Size2;

            var ret = new Point[size1][];

            for (var i = 0; i < size1; i++)
            {
                ret[i] = new Point[size2[i]];
            }
            using (var retPtr = new ArrayAddress2 <Point>(ret))
            {
                NativeMethods.vector_vector_Point_copy(ptr, retPtr);
                GC.KeepAlive(this);
            }
            return(ret);
        }
        /// <summary>
        /// Converts std::vector to managed array
        /// </summary>
        /// <returns></returns>
        public DMatch[][] ToArray()
        {
            var size1 = Size1;

            if (size1 == 0)
            {
                return(Array.Empty <DMatch[]>());
            }
            var size2 = Size2;

            var ret = new DMatch[size1][];

            for (var i = 0; i < size1; i++)
            {
                ret[i] = new DMatch[size2[i]];
            }
            using (var retPtr = new ArrayAddress2 <DMatch>(ret))
            {
                NativeMethods.vector_vector_DMatch_copy(ptr, retPtr.GetPointer());
                GC.KeepAlive(this);
            }
            return(ret);
        }
예제 #24
0
        public Status EstimateTransform(InputArray images, Rect[][] rois)
        {
            if (images == null)
            {
                throw new ArgumentNullException(nameof(images));
            }
            if (rois == null)
            {
                throw new ArgumentNullException(nameof(rois));
            }
            images.ThrowIfDisposed();

            using var roisPointer = new ArrayAddress2 <Rect>(rois);
            NativeMethods.HandleException(
                NativeMethods.stitching_Stitcher_estimateTransform_InputArray2(
                    ptr, images.CvPtr,
                    roisPointer.GetPointer(), roisPointer.GetDim1Length(), roisPointer.GetDim2Lengths(),
                    out var ret));

            GC.KeepAlive(this);
            GC.KeepAlive(images);
            return((Status)ret);
        }
예제 #25
0
        public Status EstimateTransform(IEnumerable <Mat> images, Rect[][] rois)
        {
            if (images == null)
            {
                throw new ArgumentNullException(nameof(images));
            }
            if (rois == null)
            {
                throw new ArgumentNullException(nameof(rois));
            }

            var imagesPtrs = images.Select(x => x.CvPtr).ToArray();

            using var roisPointer = new ArrayAddress2 <Rect>(rois);
            NativeMethods.HandleException(
                NativeMethods.stitching_Stitcher_estimateTransform_MatArray2(
                    ptr, imagesPtrs, imagesPtrs.Length,
                    roisPointer.GetPointer(), roisPointer.GetDim1Length(), roisPointer.GetDim2Lengths(),
                    out var ret));

            GC.KeepAlive(this);
            GC.KeepAlive(images);
            return((Status)ret);
        }
예제 #26
0
        /// <summary>
        /// 入力ベクトルの近傍を探す
        /// </summary>
        /// <param name="samples">既知のサンプル (l*n)</param>
        /// <param name="k">探索する近傍の数の最大数</param>
        /// <param name="results"></param>
        /// <param name="neighbors"></param>
        /// <param name="neighborResponses">それぞれのサンプルの近傍 (l*k)</param>
        /// <param name="dist">サンプルから近傍までの距離</param>
        /// <returns></returns>
#else
        /// <summary>
        /// Finds the K nearest neighbors of samples
        /// </summary>
        /// <param name="samples">Known samples (l*n)</param>
        /// <param name="k">max neighbors to find</param>
        /// <param name="results"></param>
        /// <param name="neighbors"></param>
        /// <param name="neighborResponses">Neighbors for each samples (l*k)</param>
        /// <param name="dist">Distance from each sample to neighbors</param>
        /// <returns></returns>
#endif
        public virtual float FindNearest(
            CvMat samples,
            int k,
            CvMat results           = null,
            float[][] neighbors     = null,
            CvMat neighborResponses = null,
            CvMat dist = null)
        {
            if (samples == null)
            {
                throw new ArgumentNullException(nameof(samples));
            }

            if (neighbors == null)
            {
                return(NativeMethods.ml_CvKNearest_find_nearest_CvMat(
                           ptr,
                           samples.CvPtr,
                           k,
                           Cv2.ToPtr(results),
                           null,
                           Cv2.ToPtr(neighborResponses),
                           Cv2.ToPtr(dist)));
            }
            using (var aa = new ArrayAddress2 <Single>(neighbors))
            {
                return(NativeMethods.ml_CvKNearest_find_nearest_CvMat(
                           ptr,
                           samples.CvPtr,
                           k,
                           Cv2.ToPtr(results),
                           aa.Pointer,
                           Cv2.ToPtr(neighborResponses),
                           Cv2.ToPtr(dist)));
            }
        }
예제 #27
0
        /// <summary>
        /// 輪郭線,または内側が塗りつぶされた輪郭を描きます.
        /// </summary>
        /// <param name="image">出力画像</param>
        /// <param name="contours"> 入力される全輪郭.各輪郭は,点のベクトルとして格納されています.</param>
        /// <param name="contourIdx">描かれる輪郭を示します.これが負値の場合,すべての輪郭が描画されます.</param>
        /// <param name="color">輪郭の色.</param>
        /// <param name="thickness">輪郭線の太さ.これが負値の場合(例えば thickness=CV_FILLED ),輪郭の内側が塗りつぶされます.</param>
        /// <param name="lineType">線の連結性</param>
        /// <param name="hierarchy">階層に関するオプションの情報.これは,特定の輪郭だけを描画したい場合にのみ必要になります.</param>
        /// <param name="maxLevel">描画される輪郭の最大レベル.0ならば,指定された輪郭のみが描画されます.
        /// 1ならば,指定された輪郭と,それに入れ子になったすべての輪郭が描画されます.2ならば,指定された輪郭と,
        /// それに入れ子になったすべての輪郭,さらにそれに入れ子になったすべての輪郭が描画されます.このパラメータは, 
        /// hierarchy が有効な場合のみ考慮されます.</param>
        /// <param name="offset">輪郭をシフトするオプションパラメータ.指定された offset = (dx,dy) だけ,すべての描画輪郭がシフトされます.</param>
#else
        /// <summary>
        /// draws contours in the image
        /// </summary>
        /// <param name="image">Destination image.</param>
        /// <param name="contours">All the input contours. Each contour is stored as a point vector.</param>
        /// <param name="contourIdx">Parameter indicating a contour to draw. If it is negative, all the contours are drawn.</param>
        /// <param name="color">Color of the contours.</param>
        /// <param name="thickness">Thickness of lines the contours are drawn with. If it is negative (for example, thickness=CV_FILLED ), 
        /// the contour interiors are drawn.</param>
        /// <param name="lineType">Line connectivity. </param>
        /// <param name="hierarchy">Optional information about hierarchy. It is only needed if you want to draw only some of the contours</param>
        /// <param name="maxLevel">Maximal level for drawn contours. If it is 0, only the specified contour is drawn. 
        /// If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function draws the contours, 
        /// all the nested contours, all the nested-to-nested contours, and so on. This parameter is only taken into account 
        /// when there is hierarchy available.</param>
        /// <param name="offset">Optional contour shift parameter. Shift all the drawn contours by the specified offset = (dx, dy)</param>
#endif
        public static void DrawContours(
            InputOutputArray image,
            IEnumerable<IEnumerable<Point>> contours,
            int contourIdx,
            Scalar color,
            int thickness = 1,
            LineType lineType = LineType.Link8,
            IEnumerable<HierarchyIndex> hierarchy = null,
            int maxLevel = Int32.MaxValue,
            Point? offset = null)
        {
            if (image == null)
                throw new ArgumentNullException("image");
            if (contours == null)
                throw new ArgumentNullException("contours");
            image.ThrowIfNotReady();

            CvPoint offset0 = offset.GetValueOrDefault(new Point());
            Point[][] contoursArray = EnumerableEx.SelectToArray(contours, EnumerableEx.ToArray);
            int[] contourSize2 = EnumerableEx.SelectToArray(contoursArray, pts => pts.Length);
            using (var contoursPtr = new ArrayAddress2<Point>(contoursArray))
            {
                if (hierarchy == null)
                {
                    NativeMethods.imgproc_drawContours_vector(image.CvPtr, contoursPtr.Pointer, contoursArray.Length, contourSize2,
                        contourIdx, color, thickness, (int)lineType, IntPtr.Zero, 0, maxLevel, offset0);
                }
                else
                {
                    Vec4i[] hiearchyVecs = EnumerableEx.SelectToArray(hierarchy, hi => hi.ToVec4i());
                    NativeMethods.imgproc_drawContours_vector(image.CvPtr, contoursPtr.Pointer, contoursArray.Length, contourSize2,
                        contourIdx, color, thickness, (int)lineType, hiearchyVecs, hiearchyVecs.Length, maxLevel, offset0);
                }
            }

            image.Fix();
        }
예제 #28
0
        /// <summary>
        /// computes the joint dense histogram for a set of images.
        /// </summary>
        /// <param name="images"></param>
        /// <param name="channels"></param>
        /// <param name="hist"></param>
        /// <param name="backProject"></param>
        /// <param name="ranges"></param>
        /// <param name="uniform"></param>
        public static void CalcBackProject(Mat[] images,
            int[] channels, InputArray hist, OutputArray backProject, 
            Rangef[] ranges, bool uniform = true)
        {
            if (images == null)
                throw new ArgumentNullException("images");
            if (channels == null)
                throw new ArgumentNullException("channels");
            if (hist == null)
                throw new ArgumentNullException("hist");
            if (backProject == null)
                throw new ArgumentNullException("backProject");
            if (ranges == null)
                throw new ArgumentNullException("ranges");
            hist.ThrowIfDisposed();
            backProject.ThrowIfNotReady();

            IntPtr[] imagesPtr = EnumerableEx.SelectPtrs(images);
            float[][] rangesFloat = EnumerableEx.SelectToArray(
                ranges, r => new [] {r.Start, r.End});
            using (var rangesPtr = new ArrayAddress2<float>(rangesFloat))
            {
                NativeMethods.imgproc_calcBackProject(imagesPtr, images.Length, channels, hist.CvPtr,
                    backProject.CvPtr, rangesPtr, uniform ? 1 : 0);
            }
            backProject.Fix();
        }
예제 #29
0
        /// <summary>
        /// computes the joint dense histogram for a set of images.
        /// </summary>
        /// <param name="images"></param>
        /// <param name="channels"></param>
        /// <param name="mask"></param>
        /// <param name="hist"></param>
        /// <param name="dims"></param>
        /// <param name="histSize"></param>
        /// <param name="ranges"></param>
        /// <param name="uniform"></param>
        /// <param name="accumulate"></param>
        public static void CalcHist(Mat[] images,
            int[] channels, InputArray mask,
            OutputArray hist, int dims, int[] histSize,
            float[][] ranges, bool uniform = true, bool accumulate = false)
        {
            if (images == null)
                throw new ArgumentNullException("images");
            if (channels == null)
                throw new ArgumentNullException("channels");
            if (hist == null)
                throw new ArgumentNullException("hist");
            if (histSize == null)
                throw new ArgumentNullException("histSize");
            if (ranges == null)
                throw new ArgumentNullException("ranges");
            hist.ThrowIfNotReady();

            IntPtr[] imagesPtr = EnumerableEx.SelectPtrs(images);
            using (var rangesPtr = new ArrayAddress2<float>(ranges))
            {
                NativeMethods.imgproc_calcHist1(imagesPtr, images.Length, channels, ToPtr(mask), hist.CvPtr,
                    dims, histSize, rangesPtr, uniform ? 1 : 0, accumulate ? 1 : 0);
            }
            hist.Fix();
        }
예제 #30
0
        /// <summary>
        /// 指定サイズのヒストグラムを生成し,そのヒストグラムの参照を返す. 
        /// </summary>
        /// <param name="sizes">ヒストグラム各次元のサイズを示す配列</param>
        /// <param name="type">ヒストグラム表現フォーマット</param>
        /// <param name="ranges">ヒストグラムのビン(bin)(値域)を示す配列.このパラメータの意味はパラメータuniformに依存している.
        /// このレンジは,ヒストグラムを計算したり,またどのヒストグラムのビンが入力画像のどの値やどのデータ要素に対応するかを決めるためのバックプロジェクションで用いられる.
        /// null の場合は,後から関数 cvSetHistBinRanges を用いて決定される.</param>
        /// <param name="uniform">一様性に関するフラグ</param>
#else
        /// <summary>
        /// Creates a histogram of the specified size and returns the pointer to the created histogram.
        /// </summary>
        /// <param name="sizes">Number of histogram dimensions. </param>
        /// <param name="type">Histogram representation format.</param>
        /// <param name="ranges">Array of ranges for histogram bins. Its meaning depends on the uniform parameter value. The ranges are used for when histogram is calculated or backprojected to determine, which histogram bin corresponds to which value/tuple of values from the input image[s]. </param>
        /// <param name="uniform">Uniformity flag.</param>
#endif
        public CvHistogram(int[] sizes, HistogramFormat type, float[][] ranges, bool uniform)
        {
            if (sizes == null)
            {
                throw new ArgumentNullException("dims");
            }

            if (ranges == null)
            {
                this._ptr = CvInvoke.cvCreateHist(sizes.Length, sizes, type, IntPtr.Zero, uniform);
            }
            else
            {
                // float[][]をIntPtr[]に変換する
                using (var rangesPtr = new ArrayAddress2<float>(ranges))
                {
                    this._ptr = CvInvoke.cvCreateHist(sizes.Length, sizes, type, rangesPtr.Pointer, uniform);
                }
            }
            if (this._ptr == IntPtr.Zero)
            {
                throw new OpenCvSharpException("Failed to create CvHistogram");
            }

            if (ranges != null)
            {
                SetBinRanges(ranges, uniform);
            }
            this.Type = type;
            base.NotifyMemoryPressure(SizeOf);
        }
예제 #31
0
        /// <summary>
        /// 入力ベクトルの近傍を探す
        /// </summary>
        /// <param name="samples">既知のサンプル (l*n)</param>
        /// <param name="k">探索する近傍の数の最大数</param>
        /// <param name="results"></param>
        /// <param name="neighbors"></param>
        /// <param name="neighborResponses">それぞれのサンプルの近傍 (l*k)</param>
        /// <param name="dist">サンプルから近傍までの距離</param>
        /// <returns></returns>
#else
		/// <summary>
        /// Finds the K nearest neighbors of samples
        /// </summary>
        /// <param name="samples">Known samples (l*n)</param>
        /// <param name="k">max neighbors to find</param>
        /// <param name="results"></param>
        /// <param name="neighbors"></param>
        /// <param name="neighborResponses">Neighbors for each samples (l*k)</param>
        /// <param name="dist">Distance from each sample to neighbors</param>
        /// <returns></returns>
#endif
        public virtual float FindNearest(
            CvMat samples, 
            int k, 
            CvMat results = null,
            float[][] neighbors = null,
            CvMat neighborResponses = null, 
            CvMat dist = null)
        {
            if (samples == null)
                throw new ArgumentNullException("samples");
                        
            if (neighbors == null)
            {
                return NativeMethods.ml_CvKNearest_find_nearest_CvMat(
                    ptr,
                    samples.CvPtr, 
                    k, 
                    Cv2.ToPtr(results), 
                    null, 
                    Cv2.ToPtr(neighborResponses),
                    Cv2.ToPtr(dist));
            }
		    using (var aa = new ArrayAddress2<Single>(neighbors))
		    {
                return NativeMethods.ml_CvKNearest_find_nearest_CvMat(
		            ptr,
		            samples.CvPtr,
		            k,
		            Cv2.ToPtr(results),
		            aa.Pointer,
		            Cv2.ToPtr(neighborResponses),
		            Cv2.ToPtr(dist));
		    }
        }
예제 #32
0
        public Status EstimateTransform(InputArray images, Rect[][] rois)
        {
            if (images == null)
                throw new ArgumentNullException("images");
            if (rois == null)
                throw new ArgumentNullException("rois");
            images.ThrowIfDisposed();

            using (var roisPointer = new ArrayAddress2<Rect>(rois))
            {
                int status = NativeMethods.stitching_Stitcher_estimateTransform_InputArray2(
                    ptr, images.CvPtr,
                    roisPointer.Pointer, roisPointer.Dim1Length, roisPointer.Dim2Lengths);
                return (Status)status;
            }
        }
예제 #33
0
        /// <summary>
        /// initializes camera matrix from a few 3D points and the corresponding projections.
        /// </summary>
        /// <param name="objectPoints">Vector of vectors of the calibration pattern points in the calibration pattern coordinate space. In the old interface all the per-view vectors are concatenated.</param>
        /// <param name="imagePoints">Vector of vectors of the projections of the calibration pattern points. In the old interface all the per-view vectors are concatenated.</param>
        /// <param name="imageSize">Image size in pixels used to initialize the principal point.</param>
        /// <param name="aspectRatio">If it is zero or negative, both f_x and f_y are estimated independently. Otherwise, f_x = f_y * aspectRatio .</param>
        /// <returns></returns>
        public static Mat InitCameraMatrix2D(
            IEnumerable<IEnumerable<Point3d>> objectPoints,
            IEnumerable<IEnumerable<Point2d>> imagePoints,
            Size imageSize,
            double aspectRatio = 1.0)
        {
            if (objectPoints == null)
                throw new ArgumentNullException("objectPoints");
            if (imagePoints == null)
                throw new ArgumentNullException("imagePoints");

            using (var opArray = new ArrayAddress2<Point3d>(objectPoints))
            using (var ipArray = new ArrayAddress2<Point2d>(imagePoints))
            {
                IntPtr matPtr = NativeMethods.calib3d_initCameraMatrix2D_array(
                    opArray, opArray.Dim1Length, opArray.Dim2Lengths,
                    ipArray, ipArray.Dim1Length, ipArray.Dim2Lengths,
                    imageSize, aspectRatio);
                return new Mat(matPtr);
            }
        }
예제 #34
0
        /// <summary>
        /// 1つ,または複数のポリゴンで区切られた領域を塗りつぶします.
        /// </summary>
        /// <param name="img">画像</param>
        /// <param name="pts">ポリゴンの配列.各要素は,点の配列で表現されます.</param>
        /// <param name="color">ポリゴンの色.</param>
        /// <param name="lineType">ポリゴンの枠線の種類,</param>
        /// <param name="shift">ポリゴンの頂点座標において,小数点以下の桁を表すビット数.</param>
        /// <param name="offset"></param>
#else
        /// <summary>
        /// Fills the area bounded by one or more polygons
        /// </summary>
        /// <param name="img">Image</param>
        /// <param name="pts">Array of polygons, each represented as an array of points</param>
        /// <param name="color">Polygon color</param>
        /// <param name="lineType">Type of the polygon boundaries</param>
        /// <param name="shift">The number of fractional bits in the vertex coordinates</param>
        /// <param name="offset"></param>
#endif
        public static void FillPoly(Mat img, IEnumerable<IEnumerable<Point>> pts, Scalar color, 
            LineType lineType = LineType.Link8, int shift = 0, Point? offset = null)
        {
            if (img == null)
                throw new ArgumentNullException("img");
            img.ThrowIfDisposed();
            Point offset0 = offset.GetValueOrDefault(new Point());

            List<Point[]> ptsList = new List<Point[]>();
            List<int> nptsList = new List<int>();
            foreach (IEnumerable<Point> pts1 in pts)
            {
                Point[] pts1Arr = Util.ToArray(pts1);
                ptsList.Add(pts1Arr);
                nptsList.Add(pts1Arr.Length);
            }
            Point[][] ptsArr = ptsList.ToArray();
            int[] npts = nptsList.ToArray();
            int ncontours = ptsArr.Length;
            using (ArrayAddress2<Point> ptsPtr = new ArrayAddress2<Point>(ptsArr))
            {
                NativeMethods.core_fillPoly(img.CvPtr, ptsPtr.Pointer, npts, ncontours, color, (int)lineType, shift, offset0);
            }
        }
예제 #35
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="matches1to2"></param>
        /// <param name="correctMatches1to2Mask"></param>
        /// <returns>recallPrecisionCurve</returns>
        public static Point2f[] ComputeRecallPrecisionCurve(
            DMatch[][] matches1to2, byte[][] correctMatches1to2Mask)
        {
            if (matches1to2 == null)
                throw new ArgumentNullException(nameof(matches1to2));
            if (correctMatches1to2Mask == null)
                throw new ArgumentNullException(nameof(correctMatches1to2Mask));

            using (var dm = new ArrayAddress2<DMatch>(matches1to2))
            using (var cm = new ArrayAddress2<byte>(correctMatches1to2Mask))
            using (var recall = new VectorOfPoint2f())
            {
                NativeMethods.features2d_computeRecallPrecisionCurve(
                    dm.Pointer, dm.Dim1Length, dm.Dim2Lengths,
                    cm.Pointer, cm.Dim1Length, cm.Dim2Lengths,
                    recall.CvPtr);
                return recall.ToArray();
            }
        }
예제 #36
0
        /// <summary>
        /// Draws matches of keypints from two images on output image.
        /// </summary>
        /// <param name="img1"></param>
        /// <param name="keypoints1"></param>
        /// <param name="img2"></param>
        /// <param name="keypoints2"></param>
        /// <param name="matches1To2"></param>
        /// <param name="outImg"></param>
        /// <param name="matchColor"></param>
        /// <param name="singlePointColor"></param>
        /// <param name="matchesMask"></param>
        /// <param name="flags"></param>
        public static void DrawMatches(Mat img1, IEnumerable<KeyPoint> keypoints1,
            Mat img2, IEnumerable<KeyPoint> keypoints2,
            IEnumerable<IEnumerable<DMatch>> matches1To2, Mat outImg,
            Scalar? matchColor = null, Scalar? singlePointColor = null,
            IEnumerable<IEnumerable<byte>> matchesMask = null,
            DrawMatchesFlags flags = DrawMatchesFlags.Default)
        {
            if (img1 == null)
                throw new ArgumentNullException(nameof(img1));
            if (img2 == null)
                throw new ArgumentNullException(nameof(img2));
            if (outImg == null)
                throw new ArgumentNullException(nameof(outImg));
            if (keypoints1 == null)
                throw new ArgumentNullException(nameof(keypoints1));
            if (keypoints2 == null)
                throw new ArgumentNullException(nameof(keypoints2));
            if (matches1To2 == null)
                throw new ArgumentNullException(nameof(matches1To2));
            img1.ThrowIfDisposed();
            img2.ThrowIfDisposed();
            outImg.ThrowIfDisposed();

            KeyPoint[] keypoints1Array = EnumerableEx.ToArray(keypoints1);
            KeyPoint[] keypoints2Array = EnumerableEx.ToArray(keypoints2);
            DMatch[][] matches1To2Array = EnumerableEx.SelectToArray(matches1To2, EnumerableEx.ToArray);
            int matches1To2Size1 = matches1To2Array.Length;
            int[] matches1To2Size2 = EnumerableEx.SelectToArray(matches1To2Array, dm => dm.Length);
            Scalar matchColor0 = matchColor.GetValueOrDefault(Scalar.All(-1));
            Scalar singlePointColor0 = singlePointColor.GetValueOrDefault(Scalar.All(-1));

            using (var matches1To2Ptr = new ArrayAddress2<DMatch>(matches1To2Array))
            {
                if (matchesMask == null)
                {
                    NativeMethods.features2d_drawMatches2(img1.CvPtr, keypoints1Array, keypoints1Array.Length,
                        img2.CvPtr, keypoints2Array, keypoints2Array.Length,
                        matches1To2Ptr, matches1To2Size1, matches1To2Size2,
                        outImg.CvPtr, matchColor0, singlePointColor0, 
                        null, 0, null, (int)flags);
                }
                else
                {
                    byte[][] matchesMaskArray = EnumerableEx.SelectToArray(matchesMask, EnumerableEx.ToArray);
                    int matchesMaskSize1 = matches1To2Array.Length;
                    int[] matchesMaskSize2 = EnumerableEx.SelectToArray(matchesMaskArray, dm => dm.Length);
                    using (var matchesMaskPtr = new ArrayAddress2<byte>(matchesMaskArray))
                    {
                        NativeMethods.features2d_drawMatches2(img1.CvPtr, keypoints1Array, keypoints1Array.Length,
                            img2.CvPtr, keypoints2Array, keypoints2Array.Length,
                            matches1To2Ptr.Pointer, matches1To2Size1, matches1To2Size2,
                            outImg.CvPtr, matchColor0, singlePointColor0,
                            matchesMaskPtr, matchesMaskSize1, matchesMaskSize2, (int)flags);
                    }
                }
            }
        }
예제 #37
0
        /// <summary>
        /// draws one or more polygonal curves
        /// </summary>
        /// <param name="img"></param>
        /// <param name="pts"></param>
        /// <param name="isClosed"></param>
        /// <param name="color"></param>
        /// <param name="thickness"></param>
        /// <param name="lineType"></param>
        /// <param name="shift"></param>
        public static void Polylines(Mat img, IEnumerable<IEnumerable<Point>> pts, bool isClosed, Scalar color, 
            int thickness = 1, LineType lineType = LineType.Link8, int shift = 0)
        {
            if (img == null)
                throw new ArgumentNullException("img");
            img.ThrowIfDisposed();

            List<Point[]> ptsList = new List<Point[]>();
            List<int> nptsList = new List<int>();
            foreach (IEnumerable<Point> pts1 in pts)
            {
                Point[] pts1Arr = Util.ToArray(pts1);
                ptsList.Add(pts1Arr);
                nptsList.Add(pts1Arr.Length);
            }
            Point[][] ptsArr = ptsList.ToArray();
            int[] npts = nptsList.ToArray();
            int ncontours = ptsArr.Length;
            using (ArrayAddress2<Point> ptsPtr = new ArrayAddress2<Point>(ptsArr))
            {
                NativeMethods.core_polylines(img.CvPtr, ptsPtr.Pointer, npts, ncontours, isClosed ? 1 : 0, color, thickness, (int)lineType, shift);
            }
        }
예제 #38
0
        /// <summary>
        /// ポリゴン内部を塗りつぶす
        /// </summary>
        /// <param name="img">ポリゴンが描かれる画像.</param>
        /// <param name="pts">ポリゴンへのポインタ配列.</param>
        /// <param name="color">ポリゴンの色.</param>
        /// <param name="lineType">線の種類.</param>
        /// <param name="shift">頂点座標の小数点以下の桁を表すビット数.</param>
#else
        /// <summary>
        /// Fills polygons interior
        /// </summary>
        /// <param name="img">Image. </param>
        /// <param name="pts">Array of pointers to polygons. </param>
        /// <param name="color">Polygon color. </param>
        /// <param name="lineType">ype of the polygon boundaries.</param>
        /// <param name="shift">Number of fractional bits in the vertex coordinates. </param>
#endif
        public static void FillPoly(CvArr img, CvPoint[][] pts, CvScalar color, LineType lineType, int shift)
        {
            if (img == null)
                throw new ArgumentNullException("img");
            if (pts == null)
                throw new ArgumentNullException("pts");

            // npts
            int contours = pts.Length;
            int[] npts = new int[contours];
            for (int i = 0; i < contours; i++)
            {
                if (pts[i] == null)
                {
                    throw new ArgumentNullException(string.Format("pts[{0}]", i));
                }
                npts[i] = pts[i].Length;
            }

            using (var ptsPtr = new ArrayAddress2<CvPoint>(pts))
            {
                NativeMethods.cvFillPoly(img.CvPtr, ptsPtr.Pointer, npts, contours, color, lineType, shift);
            }
        }
예제 #39
0
        /// <summary>
        /// finds intrinsic and extrinsic camera parameters from several fews of a known calibration pattern.
        /// </summary>
        /// <param name="objectPoints">In the new interface it is a vector of vectors of calibration pattern points in the calibration pattern coordinate space. 
        /// The outer vector contains as many elements as the number of the pattern views. If the same calibration pattern is shown in each view and 
        /// it is fully visible, all the vectors will be the same. Although, it is possible to use partially occluded patterns, or even different patterns 
        /// in different views. Then, the vectors will be different. The points are 3D, but since they are in a pattern coordinate system, then, 
        /// if the rig is planar, it may make sense to put the model to a XY coordinate plane so that Z-coordinate of each input object point is 0.
        /// In the old interface all the vectors of object points from different views are concatenated together.</param>
        /// <param name="imagePoints">In the new interface it is a vector of vectors of the projections of calibration pattern points. 
        /// imagePoints.Count() and objectPoints.Count() and imagePoints[i].Count() must be equal to objectPoints[i].Count() for each i.</param>
        /// <param name="imageSize">Size of the image used only to initialize the intrinsic camera matrix.</param>
        /// <param name="cameraMatrix">Output 3x3 floating-point camera matrix. 
        /// If CV_CALIB_USE_INTRINSIC_GUESS and/or CV_CALIB_FIX_ASPECT_RATIO are specified, some or all of fx, fy, cx, cy must be 
        /// initialized before calling the function.</param>
        /// <param name="distCoeffs">Output vector of distortion coefficients (k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]]) of 4, 5, or 8 elements.</param>
        /// <param name="rvecs">Output vector of rotation vectors (see Rodrigues() ) estimated for each pattern view. That is, each k-th rotation vector 
        /// together with the corresponding k-th translation vector (see the next output parameter description) brings the calibration pattern 
        /// from the model coordinate space (in which object points are specified) to the world coordinate space, that is, a real position of the 
        /// calibration pattern in the k-th pattern view (k=0.. M -1)</param>
        /// <param name="tvecs">Output vector of translation vectors estimated for each pattern view.</param>
        /// <param name="flags">Different flags that may be zero or a combination of the CalibrationFlag values</param>
        /// <param name="criteria">Termination criteria for the iterative optimization algorithm.</param>
        /// <returns></returns>
        public static double CalibrateCamera(
            IEnumerable<IEnumerable<Point3d>> objectPoints,
            IEnumerable<IEnumerable<Point2d>> imagePoints,
            Size imageSize,
            double[,] cameraMatrix,
            double[] distCoeffs,
            out Vec3d[] rvecs,
            out Vec3d[] tvecs,
            CalibrationFlag flags = CalibrationFlag.Zero,
            TermCriteria? criteria = null)
        {
            if (objectPoints == null)
                throw new ArgumentNullException("objectPoints");
            if (objectPoints == null)
                throw new ArgumentNullException("objectPoints");
            if (cameraMatrix == null)
                throw new ArgumentNullException("cameraMatrix");
            if (distCoeffs == null)
                throw new ArgumentNullException("distCoeffs");

            TermCriteria criteria0 = criteria.GetValueOrDefault(
                new TermCriteria(CriteriaType.Iteration | CriteriaType.Epsilon, 30, Double.Epsilon));

            using (var op = new ArrayAddress2<Point3d>(objectPoints))
            using (var ip = new ArrayAddress2<Point2d>(imagePoints))
            using (var rvecsVec = new VectorOfMat())
            using (var tvecsVec = new VectorOfMat())
            {
                double ret = NativeMethods.calib3d_calibrateCamera_vector(
                    op.Pointer, op.Dim1Length, op.Dim2Lengths,
                    ip.Pointer, ip.Dim1Length, ip.Dim2Lengths,
                    imageSize, cameraMatrix, distCoeffs, distCoeffs.Length,
                    rvecsVec.CvPtr, tvecsVec.CvPtr, (int)flags, criteria0);
                Mat[] rvecsM = rvecsVec.ToArray();
                Mat[] tvecsM = tvecsVec.ToArray();
                rvecs = EnumerableEx.SelectToArray(rvecsM, m => m.Get<Vec3d>(0));
                tvecs = EnumerableEx.SelectToArray(tvecsM, m => m.Get<Vec3d>(0));
                return ret;
            }
        }
예제 #40
0
        /// <summary>
        /// finds intrinsic and extrinsic parameters of a stereo camera
        /// </summary>
        /// <param name="objectPoints">Vector of vectors of the calibration pattern points.</param>
        /// <param name="imagePoints1">Vector of vectors of the projections of the calibration pattern points, observed by the first camera.</param>
        /// <param name="imagePoints2">Vector of vectors of the projections of the calibration pattern points, observed by the second camera.</param>
        /// <param name="cameraMatrix1">Input/output first camera matrix</param>
        /// <param name="distCoeffs1">Input/output vector of distortion coefficients (k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6]]) of 4, 5, or 8 elements. 
        /// The output vector length depends on the flags.</param>
        /// <param name="cameraMatrix2"> Input/output second camera matrix. The parameter is similar to cameraMatrix1 .</param>
        /// <param name="distCoeffs2">Input/output lens distortion coefficients for the second camera. The parameter is similar to distCoeffs1 .</param>
        /// <param name="imageSize">Size of the image used only to initialize intrinsic camera matrix.</param>
        /// <param name="R">Output rotation matrix between the 1st and the 2nd camera coordinate systems.</param>
        /// <param name="T">Output translation vector between the coordinate systems of the cameras.</param>
        /// <param name="E">Output essential matrix.</param>
        /// <param name="F">Output fundamental matrix.</param>
        /// <param name="criteria">Termination criteria for the iterative optimization algorithm.</param>
        /// <param name="flags">Different flags that may be zero or a combination of the CalibrationFlag values</param>
        /// <returns></returns>
        public static double StereoCalibrate(IEnumerable<IEnumerable<Point3d>> objectPoints,
                                             IEnumerable<IEnumerable<Point2d>> imagePoints1,
                                             IEnumerable<IEnumerable<Point2d>> imagePoints2,
                                             double[,] cameraMatrix1, double[] distCoeffs1,
                                             double[,] cameraMatrix2, double[] distCoeffs2,
                                             Size imageSize, OutputArray R,
                                             OutputArray T, OutputArray E, OutputArray F,
                                             TermCriteria? criteria = null,
                                             CalibrationFlag flags = CalibrationFlag.FixIntrinsic)
        {
            if (objectPoints == null)
                throw new ArgumentNullException("objectPoints");
            if (imagePoints1 == null)
                throw new ArgumentNullException("imagePoints1");
            if (imagePoints2 == null)
                throw new ArgumentNullException("imagePoints2");
            if (cameraMatrix1 == null)
                throw new ArgumentNullException("cameraMatrix1");
            if (distCoeffs1 == null)
                throw new ArgumentNullException("distCoeffs1");
            if (cameraMatrix2 == null)
                throw new ArgumentNullException("cameraMatrix2");
            if (distCoeffs2 == null)
                throw new ArgumentNullException("distCoeffs2");

            TermCriteria criteria0 = criteria.GetValueOrDefault(
                new TermCriteria(CriteriaType.Iteration | CriteriaType.Epsilon, 30, 1e-6));

            using (var op = new ArrayAddress2<Point3d>(objectPoints))
            using (var ip1 = new ArrayAddress2<Point2d>(imagePoints1))
            using (var ip2 = new ArrayAddress2<Point2d>(imagePoints2))
            {
                return NativeMethods.calib3d_stereoCalibrate_array(
                        op.Pointer, op.Dim1Length, op.Dim2Lengths,
                        ip1.Pointer, ip1.Dim1Length, ip1.Dim2Lengths,
                        ip2.Pointer, ip2.Dim1Length, ip2.Dim2Lengths,
                        cameraMatrix1, distCoeffs1, distCoeffs1.Length,
                        cameraMatrix2, distCoeffs2, distCoeffs2.Length,
                        imageSize, ToPtr(R), ToPtr(T), ToPtr(E), ToPtr(F),
                        criteria0, (int)flags);
            }
        }
예제 #41
0
        /// <summary>
        /// Draws matches of keypints from two images on output image.
        /// </summary>
        /// <param name="img1"></param>
        /// <param name="keypoints1"></param>
        /// <param name="img2"></param>
        /// <param name="keypoints2"></param>
        /// <param name="matches1To2"></param>
        /// <param name="outImg"></param>
        /// <param name="matchColor"></param>
        /// <param name="singlePointColor"></param>
        /// <param name="matchesMask"></param>
        /// <param name="flags"></param>
        public static void DrawMatches(Mat img1, IEnumerable <KeyPoint> keypoints1,
                                       Mat img2, IEnumerable <KeyPoint> keypoints2,
                                       IEnumerable <IEnumerable <DMatch> > matches1To2, Mat outImg,
                                       Scalar?matchColor = null, Scalar?singlePointColor = null,
                                       IEnumerable <IEnumerable <byte> > matchesMask = null,
                                       DrawMatchesFlags flags = DrawMatchesFlags.Default)
        {
            if (img1 == null)
            {
                throw new ArgumentNullException("img1");
            }
            if (img2 == null)
            {
                throw new ArgumentNullException("img2");
            }
            if (outImg == null)
            {
                throw new ArgumentNullException("outImg");
            }
            if (keypoints1 == null)
            {
                throw new ArgumentNullException("keypoints1");
            }
            if (keypoints2 == null)
            {
                throw new ArgumentNullException("keypoints2");
            }
            if (matches1To2 == null)
            {
                throw new ArgumentNullException("matches1To2");
            }
            img1.ThrowIfDisposed();
            img2.ThrowIfDisposed();
            outImg.ThrowIfDisposed();

            KeyPoint[] keypoints1Array  = EnumerableEx.ToArray(keypoints1);
            KeyPoint[] keypoints2Array  = EnumerableEx.ToArray(keypoints2);
            DMatch[][] matches1To2Array = EnumerableEx.SelectToArray(matches1To2, EnumerableEx.ToArray);
            int        matches1To2Size1 = matches1To2Array.Length;

            int[]  matches1To2Size2  = EnumerableEx.SelectToArray(matches1To2Array, dm => dm.Length);
            Scalar matchColor0       = matchColor.GetValueOrDefault(Scalar.All(-1));
            Scalar singlePointColor0 = singlePointColor.GetValueOrDefault(Scalar.All(-1));

            using (var matches1To2Ptr = new ArrayAddress2 <DMatch>(matches1To2Array))
            {
                if (matchesMask == null)
                {
                    NativeMethods.features2d_drawMatches2(img1.CvPtr, keypoints1Array, keypoints1Array.Length,
                                                          img2.CvPtr, keypoints2Array, keypoints2Array.Length,
                                                          matches1To2Ptr, matches1To2Size1, matches1To2Size2,
                                                          outImg.CvPtr, matchColor0, singlePointColor0,
                                                          null, 0, null, (int)flags);
                }
                else
                {
                    byte[][] matchesMaskArray = EnumerableEx.SelectToArray(matchesMask, EnumerableEx.ToArray);
                    int      matchesMaskSize1 = matches1To2Array.Length;
                    int[]    matchesMaskSize2 = EnumerableEx.SelectToArray(matchesMaskArray, dm => dm.Length);
                    using (var matchesMaskPtr = new ArrayAddress2 <byte>(matchesMaskArray))
                    {
                        NativeMethods.features2d_drawMatches2(img1.CvPtr, keypoints1Array, keypoints1Array.Length,
                                                              img2.CvPtr, keypoints2Array, keypoints2Array.Length,
                                                              matches1To2Ptr.Pointer, matches1To2Size1, matches1To2Size2,
                                                              outImg.CvPtr, matchColor0, singlePointColor0,
                                                              matchesMaskPtr, matchesMaskSize1, matchesMaskSize2, (int)flags);
                    }
                }
            }
        }
예제 #42
0
        public Status EstimateTransform(IEnumerable<Mat> images, Rect[][] rois)
        {
            if (images == null)
                throw new ArgumentNullException("images");
            if (rois == null)
                throw new ArgumentNullException("rois");

            IntPtr[] imagesPtrs = EnumerableEx.SelectPtrs(images);

            using (var roisPointer = new ArrayAddress2<Rect>(rois))
            {
                int status = NativeMethods.stitching_Stitcher_estimateTransform_MatArray2(
                    ptr, imagesPtrs, imagesPtrs.Length,
                    roisPointer.Pointer, roisPointer.Dim1Length, roisPointer.Dim2Lengths);
                return (Status)status;
            }
        }
예제 #43
0
        /// <summary>
        /// Try to stitch the given images.
        /// </summary>
        /// <param name="images">Input images.</param>
        /// <param name="rois">Region of interest rectangles.</param>
        /// <param name="pano">Final pano.</param>
        /// <returns>Status code.</returns>
        public Status Stitch(IEnumerable<Mat> images, Rect[][] rois, OutputArray pano)
        {
            if (images == null)
                throw new ArgumentNullException("images");
            if (rois == null)
                throw new ArgumentNullException("rois");
            if (pano == null)
                throw new ArgumentNullException("pano");
            pano.ThrowIfNotReady();

            IntPtr[] imagesPtrs = EnumerableEx.SelectPtrs(images);

            using (var roisPointer = new ArrayAddress2<Rect>(rois))
            {
                int status = NativeMethods.stitching_Stitcher_stitch2_MatArray(
                    ptr, imagesPtrs, imagesPtrs.Length,
                    roisPointer.Pointer, roisPointer.Dim1Length, roisPointer.Dim2Lengths,
                    pano.CvPtr);
                pano.Fix();
                return (Status)status;
            }
        }
예제 #44
0
        /// <summary>
        /// 指定サイズのヒストグラムを生成し,そのヒストグラムの参照を返す. 
        /// </summary>
        /// <param name="sizes">ヒストグラム各次元のサイズを示す配列</param>
        /// <param name="type">ヒストグラム表現フォーマット</param>
        /// <param name="ranges">ヒストグラムのビン(bin)(値域)を示す配列.このパラメータの意味はパラメータuniformに依存している.
        /// このレンジは,ヒストグラムを計算したり,またどのヒストグラムのビンが入力画像のどの値やどのデータ要素に対応するかを決めるためのバックプロジェクションで用いられる.
        /// null の場合は,後から関数 cvSetHistBinRanges を用いて決定される.</param>
        /// <param name="uniform">一様性に関するフラグ</param>
#else
        /// <summary>
        /// Creates a histogram of the specified size and returns the pointer to the created histogram.
        /// </summary>
        /// <param name="sizes">Number of histogram dimensions. </param>
        /// <param name="type">Histogram representation format.</param>
        /// <param name="ranges">Array of ranges for histogram bins. Its meaning depends on the uniform parameter value. The ranges are used for when histogram is calculated or backprojected to determine, which histogram bin corresponds to which value/tuple of values from the input image[s]. </param>
        /// <param name="uniform">Uniformity flag.</param>
#endif
        public CvHistogram(int[] sizes, HistogramFormat type, float[][] ranges, bool uniform)
        {
            if (sizes == null)
                throw new ArgumentNullException("sizes");

            if (ranges == null)
            {
                ptr = NativeMethods.cvCreateHist(sizes.Length, sizes, type, IntPtr.Zero, uniform);
            }
            else
            {
                // float[][]をIntPtr[]に変換する
                using (var rangesPtr = new ArrayAddress2<float>(ranges))
                {
                    ptr = NativeMethods.cvCreateHist(sizes.Length, sizes, type, rangesPtr.Pointer, uniform);
                }
            }
            if (ptr == IntPtr.Zero)
            {
                throw new OpenCvSharpException("Failed to create CvHistogram");
            }

            if (ranges != null)
            {
                SetBinRanges(ranges, uniform);
            }
            Type = type;
        }
예제 #45
0
        /// <summary>
        /// Try to stitch the given images.
        /// </summary>
        /// <param name="images">Input images.</param>
        /// <param name="rois">Region of interest rectangles.</param>
        /// <param name="pano">Final pano.</param>
        /// <returns>Status code.</returns>
        public Status Stitch(InputArray images, Rect[][] rois, OutputArray pano)
        {
            if (images == null)
                throw new ArgumentNullException("images");
            if (rois == null)
                throw new ArgumentNullException("rois");
            if (pano == null)
                throw new ArgumentNullException("pano");
            images.ThrowIfDisposed();
            pano.ThrowIfNotReady();

            using (var roisPointer = new ArrayAddress2<Rect>(rois))
            {
                int status = NativeMethods.stitching_Stitcher_stitch2_InputArray(
                    ptr, images.CvPtr,
                    roisPointer.Pointer, roisPointer.Dim1Length, roisPointer.Dim2Lengths,
                    pano.CvPtr);
                pano.Fix();
                return (Status)status;
            }
        }
예제 #46
0
        /// <summary>
        /// 入力ベクトルの近傍を探す
        /// </summary>
        /// <param name="samples">既知のサンプル (l*n)</param>
        /// <param name="k">探索する近傍の数の最大数</param>
        /// <param name="results"></param>
        /// <param name="neighbors"></param>
        /// <param name="neighbor_responses">それぞれのサンプルの近傍 (l*k)</param>
        /// <param name="dist">サンプルから近傍までの距離</param>
        /// <returns></returns>
#else
		/// <summary>
        /// Finds the K nearest neighbors of samples
        /// </summary>
        /// <param name="samples">Known samples (l*n)</param>
        /// <param name="k">max neighbors to find</param>
        /// <param name="results"></param>
        /// <param name="neighbors"></param>
        /// <param name="neighborResponses">Neighbors for each samples (l*k)</param>
        /// <param name="dist">Distance from each sample to neighbors</param>
        /// <returns></returns>
#endif
        public virtual float FindNearest(CvMat samples, int k, CvMat results, float[][] neighbors, CvMat neighborResponses, CvMat dist)
        {
            if (samples == null)
			{
                throw new ArgumentNullException("samples");
			}
                        
            IntPtr resultsPtr = (results == null) ? IntPtr.Zero : results.CvPtr;
            IntPtr neighborResponsesPtr = (neighborResponses == null) ? IntPtr.Zero : neighborResponses.CvPtr;
            IntPtr distPtr = (dist == null) ? IntPtr.Zero : dist.CvPtr;

            if (neighbors == null)
            {
                return MLInvoke.CvKNearest_find_nearest(
                    ptr,
                    samples.CvPtr, 
                    k, 
                    resultsPtr, 
                    IntPtr.Zero, 
                    neighborResponsesPtr,
                    distPtr
                );
            }
            else
            {
                ArrayAddress2<Single> aa = new ArrayAddress2<Single>(neighbors);
				return MLInvoke.CvKNearest_find_nearest(
                    ptr,
                    samples.CvPtr, 
                    k, 
                    resultsPtr, 
                    aa.Pointer, 
                    neighborResponsesPtr,
                    distPtr
				);
            }
        }
예제 #47
0
        /// <summary>
        /// Draws the found matches of keypoints from two images.
        /// </summary>
        /// <param name="img1">First source image.</param>
        /// <param name="keypoints1">Keypoints from the first source image.</param>
        /// <param name="img2">Second source image.</param>
        /// <param name="keypoints2">Keypoints from the second source image.</param>
        /// <param name="matches1To2">Matches from the first image to the second one, which means that keypoints1[i]
        /// has a corresponding point in keypoints2[matches[i]] .</param>
        /// <param name="outImg">Output image. Its content depends on the flags value defining what is drawn in the
        /// output image. See possible flags bit values below.</param>
        /// <param name="matchColor">Color of matches (lines and connected keypoints). If matchColor==Scalar::all(-1),
        /// the color is generated randomly.</param>
        /// <param name="singlePointColor">Color of single keypoints (circles), which means that keypoints do not
        /// have the matches. If singlePointColor==Scalar::all(-1) , the color is generated randomly.</param>
        /// <param name="matchesMask">Mask determining which matches are drawn. If the mask is empty, all matches are drawn.</param>
        /// <param name="flags">Flags setting drawing features. Possible flags bit values are defined by DrawMatchesFlags.</param>
        public static void DrawMatchesKnn(
            Mat img1,
            IEnumerable <KeyPoint> keypoints1,
            Mat img2,
            IEnumerable <KeyPoint> keypoints2,
            IEnumerable <IEnumerable <DMatch> > matches1To2,
            Mat outImg,
            Scalar?matchColor       = null,
            Scalar?singlePointColor = null,
            IEnumerable <IEnumerable <byte> >?matchesMask = null,
            DrawMatchesFlags flags = DrawMatchesFlags.Default)
        {
            if (img1 == null)
            {
                throw new ArgumentNullException(nameof(img1));
            }
            if (img2 == null)
            {
                throw new ArgumentNullException(nameof(img2));
            }
            if (outImg == null)
            {
                throw new ArgumentNullException(nameof(outImg));
            }
            if (keypoints1 == null)
            {
                throw new ArgumentNullException(nameof(keypoints1));
            }
            if (keypoints2 == null)
            {
                throw new ArgumentNullException(nameof(keypoints2));
            }
            if (matches1To2 == null)
            {
                throw new ArgumentNullException(nameof(matches1To2));
            }
            img1.ThrowIfDisposed();
            img2.ThrowIfDisposed();
            outImg.ThrowIfDisposed();

            var keypoints1Array   = keypoints1 as KeyPoint[] ?? keypoints1.ToArray();
            var keypoints2Array   = keypoints2 as KeyPoint[] ?? keypoints2.ToArray();
            var matches1To2Array  = matches1To2.Select(m => m.ToArray()).ToArray();
            var matches1To2Size1  = matches1To2Array.Length;
            var matches1To2Size2  = matches1To2Array.Select(dm => dm.Length).ToArray();
            var matchColor0       = matchColor.GetValueOrDefault(Scalar.All(-1));
            var singlePointColor0 = singlePointColor.GetValueOrDefault(Scalar.All(-1));

            using var matches1To2Ptr = new ArrayAddress2 <DMatch>(matches1To2Array);
            if (matchesMask == null)
            {
                NativeMethods.HandleException(
                    NativeMethods.features2d_drawMatchesKnn(
                        img1.CvPtr, keypoints1Array, keypoints1Array.Length,
                        img2.CvPtr, keypoints2Array, keypoints2Array.Length,
                        matches1To2Ptr, matches1To2Size1, matches1To2Size2,
                        outImg.CvPtr, matchColor0, singlePointColor0,
                        null, 0, null, (int)flags));
            }
            else
            {
                var matchesMaskArray = matchesMask.Select(m => m.ToArray()).ToArray();
                var matchesMaskSize1 = matches1To2Array.Length;
                var matchesMaskSize2 = matchesMaskArray.Select(dm => dm.Length).ToArray();
                using var matchesMaskPtr = new ArrayAddress2 <byte>(matchesMaskArray);
                NativeMethods.HandleException(
                    NativeMethods.features2d_drawMatchesKnn(
                        img1.CvPtr, keypoints1Array, keypoints1Array.Length,
                        img2.CvPtr, keypoints2Array, keypoints2Array.Length,
                        matches1To2Ptr.Pointer, matches1To2Size1, matches1To2Size2,
                        outImg.CvPtr, matchColor0, singlePointColor0,
                        matchesMaskPtr, matchesMaskSize1, matchesMaskSize2, (int)flags));
            }
            GC.KeepAlive(img1);
            GC.KeepAlive(img2);
            GC.KeepAlive(outImg);
        }