Exemple #1
0
        /// <summary>
        /// Takes candidate shape and combined hull and returns best match
        /// </summary>
        /// <param name="areaSize">Area size</param>
        /// <param name="candidates">Candidates</param>
        /// <param name="hull">Hull</param>
        /// <returns></returns>
        private Point[] GetBestMatchingContour(double areaSize, List <Point[]> candidates, Point[] hull)
        {
            Point[] result = hull;
            if (candidates.Count == 1)
            {
                result = candidates[0];
            }
            else if (candidates.Count > 1)
            {
                List <Point> keys = new List <Point>();
                foreach (var c in candidates)
                {
                    keys.AddRange(c);
                }

                Point[] joinedCandidates = Cv2.ConvexHull(keys);
                Point[] joinedHull       = Cv2.ApproxPolyDP(joinedCandidates, Cv2.ArcLength(joinedCandidates, true) * 0.01, true);
                result = joinedHull;
            }

            // check further
            if (Settings.DropBadGuess)
            {
                double area = Cv2.ContourArea(result);
                if (area / areaSize < Settings.ExpectedArea * 0.75)
                {
                    result = null;
                }
            }

            return(result);
        }
        public override IEnumerable <ContourResult> DetectDocumentContours(Mat image, Mat sourceImage)
        {
            var contours = Cv2
                           .FindContoursAsArray(image, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);

            var results = new List <ContourResult>();

            foreach (var contour in contours)
            {
                var convexHull        = Cv2.ConvexHull(contour);
                var peri              = Cv2.ArcLength(convexHull, true);
                var simplifiedContour = Cv2.ApproxPolyDP(convexHull, _epsilon * peri, true);

                if (simplifiedContour != null)
                {
                    results.Add(new ContourResult
                    {
                        Score  = Score,
                        Points = simplifiedContour
                    });
                }
            }

            return(results);
        }
Exemple #3
0
        private static void DrawContours(IReadOnlyList <Point[]> contours, IList <Point[]> contoursPoly, Mat drawing)
        {
            var center = new Point2f[contours.Count];
            var radius = new float[contours.Count];

            for (var i = 0; i < contours.Count; i++)
            {
                if (Cv2.ContourArea(contours[i]) >= 5000)
                {
                    contoursPoly[i] = Cv2.ApproxPolyDP(contours[i], 3, true);
                    Cv2.MinEnclosingCircle(contoursPoly[i], out center[i], out radius[i]);
                    var tempContour = contours[i];

                    var hulls  = new Point[1][];
                    var hullsI = new int[1][];
                    hulls[0]  = Cv2.ConvexHull(tempContour);
                    hullsI[0] = Cv2.ConvexHullIndices(tempContour);

                    Cv2.DrawContours(drawing, hulls, -1, Scalar.Gold, 2);
                    if (hullsI[0].Length > 0)
                    {
                        var defects = Cv2.ConvexityDefects(tempContour, hullsI[0]);
                        if (defects.Length > 0)
                        {
                            for (var j = 1; j < defects.Length; j++)
                            {
                                var startIdx = defects[j][0];
                                var ptStart  = tempContour[startIdx];
                                var farIdx   = defects[j][2];
                                var ptFar    = tempContour[farIdx];

                                if (GetDistance(ptStart, ptFar) > 1000 && ptStart.Y < center[i].Y && radius[i] >= 70)
                                {
                                    Cv2.Circle(drawing, ptStart, 10, Scalar.Yellow, 2);
                                    Cv2.Line(drawing, ptStart, ptFar, Scalar.Pink, 2);

                                    _numberOfFingers++;
                                }
                            }

                            if (radius[i] > 50)
                            {
                                Cv2.DrawContours(drawing, contoursPoly, i, Scalar.Red);
                                Cv2.Circle(drawing, center[i], (int)radius[i], Scalar.White, 2);
                                Cv2.Circle(drawing, center[i], 5, Scalar.Red, 2);

                                if (Program.ControlMode)
                                {
                                    _posX = (int)(4 * (center[i].X - 100));
                                    _posY = (int)(4 * (center[i].Y - 100));
                                    WinApiUtils.SetCursorPos(_posX, _posY);
                                }
                            }
                        }
                    }
                }
            }
        }
Exemple #4
0
        static void Main(string[] args)
        {
            using (var sourceMat = new Mat("source.jpg"))
                using (var destinationMat = new Mat("destination.jpg"))
                    using (var hc = new CascadeClassifier("HaarCascade.xml"))
                        using (var facemark = FacemarkLBF.Create())
                        {
                            Console.WriteLine("Face detection starting..");
                            var sourceFaceRects = hc.DetectMultiScale(sourceMat);
                            if (sourceFaceRects == null || sourceFaceRects.Length == 0)
                            {
                                Console.WriteLine($"Source image: No faces detected.");
                                return;
                            }
                            Console.WriteLine($"Source image: detected {sourceFaceRects.Length} faces.");

                            var destFaceRects = hc.DetectMultiScale(destinationMat);
                            if (destFaceRects == null || destFaceRects.Length == 0)
                            {
                                Console.WriteLine($"Destination image: No faces detected.");
                                return;
                            }
                            Console.WriteLine($"Destination image: detected {destFaceRects.Length} faces.");

                            facemark.LoadModel("lbfmodel.yaml");
                            using (var sourceInput = InputArray.Create(sourceFaceRects))
                                using (var destInput = InputArray.Create(destFaceRects))
                                {
                                    facemark.Fit(sourceMat, sourceInput, out Point2f[][] sourceLandmarks);
                                    var sourcePoints = sourceLandmarks[0];

                                    facemark.Fit(destinationMat, destInput, out Point2f[][] destLandmarks);
                                    var destPoints = destLandmarks[0];

                                    var triangles = destPoints.Take(60).GetDelaunayTriangles();
                                    var warps     = triangles.GetWarps(sourcePoints.Take(60), destPoints.Take(60));

                                    using (var warpedMat = sourceMat.ApplyWarps(destinationMat.Width, destinationMat.Height, warps))
                                        using (var mask = new Mat(destinationMat.Size(), MatType.CV_8UC3))
                                            using (var result = new Mat(destinationMat.Size(), MatType.CV_8UC3))
                                            {
                                                mask.SetTo(0);

                                                var convexHull = Cv2.ConvexHull(destPoints).Select(s => new Point(s.X, s.Y));
                                                Cv2.FillConvexPoly(mask, convexHull, Scalar.White);

                                                var rect   = Cv2.BoundingRect(convexHull);
                                                var center = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);

                                                Cv2.SeamlessClone(warpedMat, destinationMat, mask, center, result, SeamlessCloneMethods.NormalClone);
                                                var blured = result.MedianBlur(5);
                                                blured.SaveImage("result.png");
                                            }
                                }
                        }
            Console.WriteLine("Done");
        }
 private static OpenCvSharp.Point[] GetCNTHull(Mat image, out OpenCvSharp.Point[] contour)
 {
     HierarchyIndex[]      hierarchies;
     OpenCvSharp.Point[][] contours;
     image.FindContours(out contours, out hierarchies, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);
     contour = contours.MaxBy(x => Cv2.ContourArea(x)).FirstOrDefault();
     OpenCvSharp.Point[] hull = Cv2.ConvexHull(contour);
     return(hull);
 }
Exemple #6
0
        private void DetectHulls()
        {
            Point[] hulls_points       = Cv2.ConvexHull(HandArea, true);
            Rect    bounding_rectangle = Cv2.BoundingRect(hulls_points);
            Point   centerHand         = new Point(
                (bounding_rectangle.TopLeft.X + bounding_rectangle.BottomRight.X) / 2
                , (bounding_rectangle.TopLeft.X + bounding_rectangle.BottomRight.X) / 2
                );

            Cv2.Rectangle(TrackerVisualisation, bounding_rectangle, new Scalar(0, 255, 255), 2);
            Cv2.Circle(TrackerVisualisation, centerHand, 5, new Scalar(255, 0, 0));
        }
Exemple #7
0
        static void Main(string[] args)
        {
            string     filename = "qrTest2.jpg";
            Image      input    = Image.FromFile(filename);
            List <Tag> result   = Detector.detectTags(input, showProcessedInput: false);

            Mat dst = BitmapConverter.ToMat((Bitmap)input);

            foreach (Tag tag in result)
            {
                System.Drawing.Point[]   _points = tag.Polygon;
                List <OpenCvSharp.Point> points  = new List <OpenCvSharp.Point>();
                // Convertimos a array de puntos compatible con OpenCV
                foreach (System.Drawing.Point _point in _points)
                {
                    OpenCvSharp.Point point = new OpenCvSharp.Point(_point.X, _point.Y);
                    points.Add(point);
                }
                List <OpenCvSharp.Point> hull = new List <OpenCvSharp.Point>();

                // Si los puntos no forman un cuadrado hayamos la envolvente convexa
                if (points.Count > 4)
                {
                    Cv2.ConvexHull(InputArray.Create(points), OutputArray.Create(hull));
                }
                else
                {
                    hull = points;
                }

                // La pintamos sobre la imagen
                int n = hull.Count;
                for (int j = 0; j < n; j++)
                {
                    Cv2.Line(dst, hull[j], hull[(j + 1) % n], new Scalar(0, 0, 255), 6);
                }
                string text = Encoding.ASCII.GetString(tag.Data);
                Cv2.PutText(dst, text, points[2], HersheyFonts.HersheyDuplex, 2, new Scalar(0, 0, 255), 4);
            }

            // Redimensionamos y mostramos el resultado
            Mat resizedDst = new Mat();

            Cv2.Resize(dst, resizedDst, new OpenCvSharp.Size(1080, 720));
            using (new Window("Result", WindowMode.FreeRatio, resizedDst))
            {
                Cv2.WaitKey();
            }
        }
Exemple #8
0
        public static void Run()
        {
            Mat image = new Mat();

            frameSource = Cv2.CreateFrameSource_Camera(0);
            while (true)
            {
                //Grab the current frame
                frameSource.NextFrame(image);

                Mat gray = new Mat();
                Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY);

                Mat blur = new Mat();
                Cv2.GaussianBlur(gray, blur, new Size(19, 19), 0);

                Mat    threshImg = new Mat();
                double thresh    = Cv2.Threshold(gray, threshImg, 150, 255, ThresholdTypes.Otsu);

                Mat[] contours;

                Mat hierarchy = new Mat();
                Cv2.FindContours(threshImg, out contours, hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);
                double maxArea     = 100;
                Mat    handContour = new Mat();
                handContour = contours.OrderByDescending(x => (x.ContourArea())).ToList()[0];
                //foreach (var item in contours)
                //{
                //    if(item.ContourArea() > maxArea)
                //    {
                //        handContour = item;
                //        break;
                //    }
                //}

                Mat hull = new Mat();
                Cv2.ConvexHull(handContour, hull);

                Mat defects = new Mat();
                Cv2.ConvexityDefects(handContour, hull, defects);

                Cv2.ImShow("frame", hull);
                //Cv2.WaitKey(0);
                if (Cv2.WaitKey(1) == (int)ConsoleKey.Enter)
                {
                    break;
                }
            }
        }
Exemple #9
0
        //블럭화
        private void button1_Click(object sender, EventArgs e)
        {
            ((DataTable)dataGridView1.DataSource).Rows.Clear(); //Row값만 초기화
            int    counter  = 1;
            Mat    dst      = Threshold.Clone();
            double img_area = MyImage.Width * MyImage.Height;

            OpenCvSharp.Point[][] contours;  //윤곽선의 실제 값
            HierarchyIndex[]      hierarchy; // 윤곽선들의 계층 구조
            Mat preprocess_Value = new Mat();

            //색상 공간 변환
            Cv2.InRange(Threshold, new Scalar(threshold_Value, threshold_Value, threshold_Value),
                        new Scalar(255, 255, 255), preprocess_Value);

            //Cv2.FindContours(원본 배열, 검출된 윤곽선, 계층 구조, 검색 방법, 근사 방법, 오프셋)
            Cv2.FindContours(preprocess_Value, out contours, out hierarchy, RetrievalModes.Tree,
                             ContourApproximationModes.ApproxTC89KCOS);

            foreach (OpenCvSharp.Point[] p in contours)
            {
                double length = Cv2.ArcLength(p, true);                                         //길이
                double area   = Cv2.ContourArea(p, true);                                       //면적
                //if (length < 200 || length > 2000) continue; //길이가 너무 작은 윤관석 삭제
                Rect boundingRect           = Cv2.BoundingRect(p);                              //사각형 계산
                OpenCvSharp.Point[] hull    = Cv2.ConvexHull(p, true);                          //블록
                Moments             moments = Cv2.Moments(p, false);                            //중심점
                Cv2.Rectangle(dst, boundingRect, Scalar.Red, 2);                                //사각형 그리기
                                                                                                //Cv2.FillConvexPoly(dst, hull, Scalar.Red); //내부 채우기
                                                                                                //Cv2.Polylines(dst, new OpenCvSharp.Point[][] { hull }, true, Scalar.Red, 1); //다각형 그리기
                Cv2.DrawContours(dst, new OpenCvSharp.Point[][] { hull }, -1, Scalar.Black, 3); //윤곽석 그리기
                double mean = (boundingRect.Width + boundingRect.Height) / 2;
                table.Rows.Add(" " + counter++,
                               " " + (int)(moments.M10 / moments.M00) + ", " + (int)(moments.M01 / moments.M00),
                               " " + Math.Truncate(length * 10) / 10,
                               " " + Math.Abs(area - img_area),
                               " " + area,
                               " " + Math.Max(boundingRect.Width, boundingRect.Height),
                               " " + Math.Min(boundingRect.Width, boundingRect.Height),
                               " " + mean,
                               boundingRect);
            }
            pictureBox2.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(dst);
        }
Exemple #10
0
        public Mat _01_DetectGrid4(Mat imgWhiteB, Mat imgBlackW, byte thValue, out Point2d[] Q4fnd, bool DispB)
        {
            //Acquiring convex hull

            //Coordinate list of contour
            Point[][]        contours;
            HierarchyIndex[] hierarchy;
            Cv2.FindContours(imgBlackW, out contours, out hierarchy, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple);

            Size sz = imgWhiteB.Size();
            int  W = sz.Width, H = sz.Height, WW = (int)Math.Min(W * 0.4, H * 0.4);

            try{
                Mat checkImg = imgWhiteB.CvtColor(ColorConversionCodes.GRAY2BGR); //###### Gray->Color
                foreach (var PP in contours.Where(p => p.Count() >= 4))
                {
                    double Xmin = PP.Min(p => p.X);
                    double Xmax = PP.Max(p => p.X);
                    double Ymin = PP.Min(p => p.Y);
                    double Ymax = PP.Max(p => p.Y);
                    if ((Xmax - Xmin) < WW || (Ymax - Ymin) < WW)
                    {
                        continue;
                    }

                    //convex hull (clockwise:true counterclockwise)
                    var    P    = Cv2.ConvexHull(PP, clockwise: true).ToList();
                    double area = Cv2.ContourArea(P); //Area of convex hull
                    //if(area<WW*WW) continue;

                    List <Point2d> P2     = P.ConvertAll(q => new Point2d(q.X, q.Y));
                    Mat            stdImg = CorrectDistortion(imgWhiteB, P2, out Point2d[] Q4, DispB: false);
                    Q4fnd = Q4;
                    if (stdImg == null)
                    {
                        return(null);
                    }
                    return(stdImg);
                }
            }
            catch (Exception e) { WriteLine(e.Message + "\r" + e.StackTrace); }
            Q4fnd = null;
            return(null);
        }
        public void ConvexHull_Example()
        {
            using var src = new Mat("./TextSample.png");
            Cv2.ImShow("Source", src);

            using var gray = new Mat();
            Cv2.CvtColor(src, gray, ColorConversionCodes.BGRA2GRAY);

            using var threshImage = new Mat();
            Cv2.Threshold(gray, threshImage, 100, 255, ThresholdTypes.Binary);

            Point[][]        contours;
            HierarchyIndex[] hierarchyIndexes;
            Cv2.FindContours(
                threshImage,
                out contours,
                out hierarchyIndexes,
                mode: RetrievalModes.CComp,
                method: ContourApproximationModes.ApproxSimple);

            if (contours.Length == 0)
            {
                throw new NotSupportedException("검출된 윤곽선 없음.");
            }

            using var dst = new Mat();
            Cv2.CvtColor(threshImage, dst, ColorConversionCodes.GRAY2BGR);

            var contourIndex = 0;

            while ((contourIndex >= 0))
            {
                var contour = contours[contourIndex];

                contour = Cv2.ConvexHull(contour);
                Cv2.DrawContours(dst, contours, contourIndex, Scalar.Red);

                contourIndex = hierarchyIndexes[contourIndex].Next;
            }

            Cv2.ImShow("dst", dst);
            Cv2.WaitKey();
        }
Exemple #12
0
        public bool PlMask(Mat plImage, int threshold, out Mat edgeMask)
        {
            bool result = false;

            edgeMask = new Mat();

            try
            {
                Mat gray = new Mat();
                Cv2.CvtColor(plImage, gray, ColorConversionCodes.BGR2GRAY);
                Cv2.Threshold(gray, edgeMask, threshold, 255, ThresholdTypes.Binary);

                Cv2.ImShow("edgeMask", edgeMask);
                Cv2.WaitKey(0);

                Mat[] contours;
                var   hierarchy = new List <Point>();
                Cv2.FindContours(edgeMask, out contours, OutputArray.Create(hierarchy), RetrievalModes.External,
                                 ContourApproximationModes.ApproxSimple);

                var hulls = new List <Mat>();
                for (int j = 0; j < contours.Length; j++)
                {
                    Mat hull = new Mat();
                    Cv2.ConvexHull(contours[j], hull);
                    hulls.Add(hull);
                }

                edgeMask = Mat.Zeros(edgeMask.Size(), MatType.CV_8UC1);
                Cv2.DrawContours(edgeMask, hulls, -1, Scalar.White);

                Cv2.ImShow("edgeMask", edgeMask);
                Cv2.WaitKey(0);
                Cv2.DestroyAllWindows();

                result = true;
            }
            catch (Exception ex)
            {
            }

            return(result);
        }
    public void Extraer()
    {
        if (recuadros == null && (recuadros = FindObjectOfType <EncontrarRecuadros>()) == null)
        {
            return;
        }
        if (recuadros.recuadros.Count == 0)
        {
            return;
        }

        ClearTexturas();
        Point[][]        contornos  = recuadros.contornos;
        HierarchyIndex[] jerarquias = recuadros.jerarquiaContornos;

        Recuadro       recuadro  = recuadros.recuadros[indiceRecuadroSel % recuadros.recuadros.Count];
        HierarchyIndex jerarquia = jerarquias[recuadro.indiceContorno];

        Mat matUmbral = recuadros.matUmbralEscalado.Clone();

        Cv2.Dilate(matUmbral, matUmbral, new Mat(), null, 3);
        Cv2.Erode(matUmbral, matUmbral, new Mat(), null, 2);
        Cv2.CvtColor(matUmbral, matUmbral, ColorConversionCodes.GRAY2BGR);
        List <int> hijosDirectos = new List <int>();
        int        hijo          = jerarquia.Child;

        while (hijo != -1)
        {
            if (contornos[hijo].Length > 1)
            {
                hijosDirectos.Add(hijo);
            }
            hijo = jerarquias[hijo].Next;
        }
        Debug.Log(hijosDirectos.Aggregate("", (s, e) => $"{e}({contornos[e].Length})-{s}"));
        foreach (var i in hijosDirectos)
        {
            Cv2.DrawContours(matUmbral, contornos, i, colRojo);
            Cv2.Polylines(matUmbral, new Point[][] { Cv2.ConvexHull(contornos[i]) }, true, colVerde);
        }

        var texturaObjetos = OCVUnity.MatToTexture(matUmbral, GenerarTextura(matUmbral.Width, matUmbral.Height));
    }
Exemple #14
0
        public void ConvexHull()
        {
            var contour = new[]
            {
                // ‰š
                new Point(0, 0),
                new Point(0, 10),
                new Point(3, 10),
                new Point(3, 5),
                new Point(6, 5),
                new Point(6, 10),
                new Point(10, 10),
                new Point(10, 0),
            };
            var hull = Cv2.ConvexHull(contour);

            Assert.Equal(4, hull.Length);
            Assert.Equal(new Point(10, 0), hull[0]);
            Assert.Equal(new Point(10, 10), hull[1]);
            Assert.Equal(new Point(0, 10), hull[2]);
            Assert.Equal(new Point(0, 0), hull[3]);
        }
Exemple #15
0
        private void buttonSelectImage_Click2(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    List <OpenCvSharp.Point> rois = new List <OpenCvSharp.Point>(new OpenCvSharp.Point[] {
                        new OpenCvSharp.Point(35, 90), new OpenCvSharp.Point(400, 90), new OpenCvSharp.Point(850, 90), new OpenCvSharp.Point(1290, 90),
                        new OpenCvSharp.Point(35, 400), new OpenCvSharp.Point(400, 400), new OpenCvSharp.Point(850, 400), new OpenCvSharp.Point(1290, 400),
                        new OpenCvSharp.Point(35, 800), new OpenCvSharp.Point(400, 800), new OpenCvSharp.Point(850, 800), new OpenCvSharp.Point(1290, 800),
                        new OpenCvSharp.Point(35, 1230), new OpenCvSharp.Point(400, 1230), new OpenCvSharp.Point(850, 1230), new OpenCvSharp.Point(1290, 1230)
                    });
                    var files = Directory.GetFiles(Path.GetDirectoryName(openFileDialog1.FileName), "*.png").ToList();
                    if (files != null && files.Count > 0)
                    {
                        int index = files.IndexOf(openFileDialog1.FileName);
                        //using (var win = new Window())
                        //using (var win1 = new Window())
                        {
                            while (true)
                            {
                                Debug.WriteLine(files[index]);
                                Mat img = new Mat(files[index]);//load color image
                                Mat gray = new Mat(), laplacian = new Mat(), sobel = new Mat(), canny = new Mat();
                                Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);
                                //Cv2.GaussianBlur(gray, gray, new OpenCvSharp.Size(3, 3), 0);
                                Cv2.NamedWindow("img", WindowMode.Normal);
                                Cv2.ImShow("img", img);

                                foreach (var pt in rois)
                                {
                                    Rect roi      = new Rect(pt, new OpenCvSharp.Size(200, 200));
                                    Mat  original = img.Clone(roi);
                                    Mat  gray2    = gray.Clone(roi);
                                    Cv2.Canny(gray2, canny, 100, 300, 3);


                                    Mat[] contours1;
                                    var   hierarchy1 = new List <OpenCvSharp.Point>();
                                    Cv2.FindContours(canny, out contours1, OutputArray.Create(hierarchy1),
                                                     RetrievalModes.External,
                                                     ContourApproximationModes.ApproxSimple);

                                    var hulls1 = new List <Mat>();
                                    for (int j = 0; j < contours1.Length; j++)
                                    {
                                        Mat hull = new Mat();
                                        Cv2.ConvexHull(contours1[j], hull);
                                        if (hull.ContourArea() > 100)
                                        {
                                            hulls1.Add(hull);
                                        }
                                    }

                                    if (hulls1.Count > 0)
                                    {
                                        Mat drawing = Mat.Zeros(canny.Size(), MatType.CV_8UC1);
                                        Cv2.DrawContours(drawing, hulls1, -1, Scalar.White, -1);
                                        //Cv2.NamedWindow(pt.ToString() + " hulls", WindowMode.Normal);
                                        //Cv2.ImShow(pt.ToString() + " hulls", drawing);

                                        List <OpenCvSharp.Point> points = new List <OpenCvSharp.Point>();
                                        foreach (Mat hull in hulls1)
                                        {
                                            int m2Count            = (hull.Rows % 2 > 0) ? hull.Rows + 1 : hull.Rows;
                                            OpenCvSharp.Point[] p2 = new OpenCvSharp.Point[m2Count];
                                            hull.GetArray(0, 0, p2);
                                            Array.Resize(ref p2, hull.Rows);

                                            points.AddRange(p2.ToList());
                                        }
                                        Mat finalHull = new Mat();
                                        Cv2.ConvexHull(InputArray.Create(points), finalHull);

                                        if (finalHull.ContourArea() > 1000)
                                        {
                                            List <Mat> finalHulls = new List <Mat>();
                                            finalHulls.Add(finalHull);
                                            Mat mask = Mat.Zeros(drawing.Size(), MatType.CV_8UC1);
                                            Cv2.DrawContours(mask, finalHulls, -1, Scalar.White, -1);

                                            //Cv2.ImShow(pt.ToString() + " mask", mask);
                                            //Cv2.ImShow(pt.ToString() + " original", original);
                                            Mat masked = Mat.Zeros(original.Size(), original.Type());
                                            original.CopyTo(masked, mask);
                                            Cv2.ImShow(pt.ToString() + " masked", masked);
                                        }
                                    }
                                }



                                int c = Cv2.WaitKey(0);

                                if (c == 'n' && index < files.Count - 1)
                                {
                                    index++;
                                }
                                else if (c == 'p' && index > 0)
                                {
                                    index--;
                                }
                                else if (c == 27)
                                {
                                    break;
                                }
                                else
                                {
                                    index = 0;
                                }

                                Window.DestroyAllWindows();
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: " + ex.Message);
                }
            }
        }
Exemple #16
0
        private void buttonSelectImage1_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog1 = new OpenFileDialog();

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    List <OpenCvSharp.Point> rois = new List <OpenCvSharp.Point>(new OpenCvSharp.Point[] {
                        new OpenCvSharp.Point(35, 90), new OpenCvSharp.Point(400, 90), new OpenCvSharp.Point(850, 90), new OpenCvSharp.Point(1290, 90),
                        new OpenCvSharp.Point(35, 400), new OpenCvSharp.Point(400, 400), new OpenCvSharp.Point(850, 400), new OpenCvSharp.Point(1290, 400),
                        new OpenCvSharp.Point(35, 800), new OpenCvSharp.Point(400, 800), new OpenCvSharp.Point(850, 800), new OpenCvSharp.Point(1290, 800),
                        new OpenCvSharp.Point(35, 1230), new OpenCvSharp.Point(400, 1230), new OpenCvSharp.Point(850, 1230), new OpenCvSharp.Point(1290, 1230)
                    });
                    var files = Directory.GetFiles(Path.GetDirectoryName(openFileDialog1.FileName), "*.png").ToList();
                    if (files != null && files.Count > 0)
                    {
                        int index = files.IndexOf(openFileDialog1.FileName);
                        //using (var win = new Window())
                        //using (var win1 = new Window())
                        {
                            while (true)
                            {
                                ListBox listBoxTemp = new ListBox();
                                listBoxTemp.Items.Clear();
                                Debug.WriteLine(files[index]);
                                Mat img = new Mat(files[index]);//load color image
                                Mat gray = new Mat(), laplacian = new Mat(), sobel = new Mat(), canny = new Mat();
                                Cv2.CvtColor(img, gray, ColorConversionCodes.BGR2GRAY);
                                //Cv2.GaussianBlur(gray, gray, new OpenCvSharp.Size(3, 3), 0);

                                Cv2.Canny(gray, canny, 100, 300, 3);
                                Cv2.NamedWindow("img", WindowMode.Normal);
                                Cv2.NamedWindow("hulls", WindowMode.Normal);
                                Cv2.ImShow("img", img);

                                Mat[] contours1;
                                var   hierarchy1 = new List <OpenCvSharp.Point>();
                                Cv2.FindContours(canny, out contours1, OutputArray.Create(hierarchy1),
                                                 RetrievalModes.External,
                                                 ContourApproximationModes.ApproxSimple);

                                var hulls1 = new List <Mat>();
                                for (int j = 0; j < contours1.Length; j++)
                                {
                                    Mat hull = new Mat();
                                    Cv2.ConvexHull(contours1[j], hull);
                                    if (hull.ContourArea() > 100)
                                    {
                                        hulls1.Add(hull);
                                    }
                                }

                                if (hulls1.Count > 0)
                                {
                                    Mat drawing = Mat.Zeros(canny.Size(), MatType.CV_8UC1);
                                    Cv2.DrawContours(drawing, hulls1, -1, Scalar.White, -1);

                                    Cv2.ImShow("hulls", drawing);
                                }

                                goto wait;

                                Cv2.Laplacian(gray, laplacian, MatType.CV_32F);

                                foreach (var pt in rois)
                                {
                                    Rect          roi      = new Rect(pt, new OpenCvSharp.Size(200, 200));
                                    Mat           original = img.Clone(roi);
                                    Mat           temp     = laplacian.Clone(roi);
                                    MatOfFloat    matf     = new MatOfFloat(temp);
                                    var           indexer  = matf.GetIndexer();
                                    List <double> sums     = new List <double>();
                                    double        sum      = 0;
                                    for (int y = 0; y < 25; y++)
                                    {
                                        for (int x = 0; x < 25; x++)
                                        {
                                            float val = indexer[y, x];
                                            if (val >= 1)
                                            {
                                                sum += val;
                                            }
                                        }
                                    }
                                    sums.Add(sum);
                                    sum = 0;
                                    for (int y = 0; y < 25; y++)
                                    {
                                        for (int x = temp.Width - 25; x < temp.Width; x++)
                                        {
                                            float val = indexer[y, x];
                                            if (val >= 1)
                                            {
                                                sum += val;
                                            }
                                        }
                                    }
                                    sums.Add(sum);
                                    sum = 0;
                                    for (int y = temp.Height - 25; y < temp.Height; y++)
                                    {
                                        for (int x = temp.Width - 25; x < temp.Width; x++)
                                        {
                                            float val = indexer[y, x];
                                            if (val >= 1)
                                            {
                                                sum += val;
                                            }
                                        }
                                    }
                                    sums.Add(sum);
                                    sum = 0;
                                    for (int y = temp.Height - 25; y < temp.Height; y++)
                                    {
                                        for (int x = 0; x < 25; x++)
                                        {
                                            float val = indexer[y, x];
                                            if (val >= 1)
                                            {
                                                sum += val;
                                            }
                                        }
                                    }
                                    sums.Add(sum);
                                    sum = 0;
                                    for (int y = 88; y < 113; y++)
                                    {
                                        for (int x = 88; x < 113; x++)
                                        {
                                            float val = indexer[y, x];
                                            if (val >= 1)
                                            {
                                                sum += val;
                                            }
                                        }
                                    }
                                    sums.Add(sum);

                                    double avg   = sums.Average();
                                    double stdev = CalculateStdDev(sums);
                                    int    upper = (int)(avg + 1.5 * stdev);
                                    int    lower = (int)(avg - 1.5 * stdev);

                                    listBoxTemp.Items.Add(pt.ToString() + ": " + String.Join(",", sums.ToArray())
                                                          + "," + upper + "," + lower);
                                    if (sums[4] > upper || sums[4] < lower)
                                    {
                                        //Cv2.ImShow(pt.ToString(), temp);
                                        temp.ConvertTo(temp, MatType.CV_8UC1);

                                        Mat [] contours;
                                        var    hierarchy = new List <OpenCvSharp.Point>();
                                        Cv2.FindContours(temp, out contours, OutputArray.Create(hierarchy),
                                                         RetrievalModes.External,
                                                         ContourApproximationModes.ApproxSimple);

                                        var hulls = new List <Mat>();
                                        for (int j = 0; j < contours.Length; j++)
                                        {
                                            Mat hull = new Mat();
                                            Cv2.ConvexHull(contours[j], hull);
                                            if (hull.ContourArea() > 1000)
                                            {
                                                hulls.Add(hull);
                                            }
                                        }

                                        if (hulls.Count > 0)
                                        {
                                            Mat drawing = Mat.Zeros(temp.Size(), MatType.CV_8UC1);
                                            Cv2.DrawContours(drawing, contours, -1, Scalar.White, -1);
                                            Cv2.ImShow(pt.ToString() + " hulls", drawing);

                                            /*
                                             * List<OpenCvSharp.Point> points = new List<OpenCvSharp.Point>();
                                             * foreach (Mat hull in hulls)
                                             * {
                                             *  int m2Count = (hull.Rows % 2 > 0) ? hull.Rows + 1 : hull.Rows;
                                             *  OpenCvSharp.Point[] p2 = new OpenCvSharp.Point[m2Count];
                                             *  hull.GetArray(0, 0, p2);
                                             *  Array.Resize(ref p2, hull.Rows);
                                             *
                                             *  points.AddRange(p2.ToList());
                                             * }
                                             * Mat finalHull = new Mat();
                                             * Cv2.ConvexHull(InputArray.Create(points), finalHull);
                                             *
                                             * if (finalHull.ContourArea() > 1000)
                                             * {
                                             *  List<Mat> finalHulls = new List<Mat>();
                                             *  finalHulls.Add(finalHull);
                                             *  Mat mask = Mat.Zeros(temp.Size(), MatType.CV_8UC1);
                                             *  Cv2.DrawContours(mask, finalHulls, -1, Scalar.White, -1);
                                             *
                                             *  Cv2.ImShow(pt.ToString(), temp);
                                             *  Cv2.ImShow(pt.ToString() + " original", original);
                                             *  Cv2.ImShow(pt.ToString() + " mask", mask);
                                             *  //Mat masked = Mat.Zeros(original.Size(), original.Type()) ;
                                             *  //masked.CopyTo(original, mask);
                                             *  //Cv2.ImShow(pt.ToString() + " masked", masked);
                                             * }
                                             */
                                        }
                                    }
                                }


wait:

                                int c = Cv2.WaitKey(0);

                                if (c == 'n' && index < files.Count - 1)
                                {
                                    index++;
                                }
                                else if (c == 'p' && index > 0)
                                {
                                    index--;
                                }
                                else if (c == 27)
                                {
                                    break;
                                }
                                else
                                {
                                    index = 0;
                                }

                                Window.DestroyAllWindows();
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error: " + ex.Message);
                }
            }
        }
 public static double PerimeterHull(List <Point> points)
 {
     return(Perimeter(Cv2.ConvexHull(points)));
 }
Exemple #18
0
        // 主要内容,图像处理方法的api
        private Mat myOPENCV_run(Mat image_in, Mat image_out)
        {
            image_out = image_in;                          // 入图传给出图
            for (int i = 0; i < listBox2.Items.Count; i++) //执行 列表框2内的方法
            {
                switch ((MyOPENCV)myOPENCV_runlist[i, 0])  // 列表框2内的运行方法
                {
                case MyOPENCV.cvt_color:                   //颜色转换 (入图,出图,颜色转换符,)
                {
                    Cv2.CvtColor(image_out, image_out, (ColorConversionCodes)myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 2]);
                    break;
                }

                case MyOPENCV.boxfilter:    //方框滤波
                {
                    OpenCvSharp.Size size;
                    size.Width  = myOPENCV_runlist[i, 2];
                    size.Height = myOPENCV_runlist[i, 3];
                    Cv2.BoxFilter(image_out, image_out, myOPENCV_runlist[i, 1], size);
                    break;
                }

                case MyOPENCV.blur:     //均值滤波
                {
                    OpenCvSharp.Size size;
                    size.Width  = myOPENCV_runlist[i, 1];
                    size.Height = myOPENCV_runlist[i, 2];
                    Cv2.Blur(image_out, image_out, size);
                    break;
                }

                case MyOPENCV.gaussianblur:      // 高斯滤波
                {
                    OpenCvSharp.Size size;
                    double           sigmaX, sigmaY;
                    size.Width  = myOPENCV_runlist[i, 1];
                    size.Height = myOPENCV_runlist[i, 2];
                    sigmaX      = (double)myOPENCV_runlist[i, 3];
                    sigmaY      = (double)myOPENCV_runlist[i, 4];

                    Cv2.GaussianBlur(image_out, image_out, size, sigmaX, sigmaY);
                    break;
                }

                case MyOPENCV.medianblur:    //中值滤波
                {
                    Cv2.MedianBlur(image_in, image_out, myOPENCV_runlist[i, 1]);
                    break;
                }

                case MyOPENCV.bilateralfilter:    //双边滤波
                {
                    Mat    image_out2 = new Mat();
                    double sigmaColor, sigmaSpace;
                    sigmaColor = (double)myOPENCV_runlist[i, 2] * 2;
                    sigmaSpace = (double)myOPENCV_runlist[i, 3] / 2;
                    Cv2.BilateralFilter(image_out, image_out2, myOPENCV_runlist[i, 1], sigmaColor, sigmaSpace);
                    image_out = image_out2;
                    break;
                }

                case MyOPENCV.dilate:    //膨胀
                {
                    Mat image_element = new Mat();
                    OpenCvSharp.Size size;
                    size.Width    = myOPENCV_runlist[i, 2];
                    size.Height   = myOPENCV_runlist[i, 3];
                    image_element = Cv2.GetStructuringElement((MorphShapes)myOPENCV_runlist[i, 1], size);
                    Cv2.Dilate(image_out, image_out, image_element);
                    break;
                }

                case MyOPENCV.erode:    //腐蚀
                {
                    Mat image_element = new Mat();
                    OpenCvSharp.Size size;
                    size.Width    = myOPENCV_runlist[i, 2];
                    size.Height   = myOPENCV_runlist[i, 3];
                    image_element = Cv2.GetStructuringElement((MorphShapes)myOPENCV_runlist[i, 1], size);
                    Cv2.Erode(image_out, image_out, image_element);
                    break;
                }

                case MyOPENCV.morphologyex:    //高级形态学变换
                {
                    Mat image_element = new Mat();
                    OpenCvSharp.Size size;
                    size.Width    = myOPENCV_runlist[i, 3];
                    size.Height   = myOPENCV_runlist[i, 4];
                    image_element = Cv2.GetStructuringElement((MorphShapes)myOPENCV_runlist[i, 2], size);
                    Cv2.MorphologyEx(image_out, image_out, (MorphTypes)myOPENCV_runlist[i, 1], image_element);
                    break;
                }

                case MyOPENCV.floodfill:    //漫水填充
                {
                    OpenCvSharp.Point point;
                    point.X = myOPENCV_runlist[i, 1];
                    point.Y = myOPENCV_runlist[i, 2];
                    OpenCvSharp.Scalar scalar;
                    scalar = myOPENCV_runlist[i, 3];
                    Cv2.FloodFill(image_out, point, scalar);
                    break;
                }

                case MyOPENCV.pyrup:    //尺寸放大
                {
                    OpenCvSharp.Size size;
                    size.Width  = image_out.Cols * 2;
                    size.Height = image_out.Rows * 2;
                    Cv2.PyrUp(image_out, image_out, size);
                    break;
                }

                case MyOPENCV.pyrdown:    //尺寸缩小
                {
                    OpenCvSharp.Size size;
                    size.Width  = image_out.Cols / 2;
                    size.Height = image_out.Rows / 2;
                    Cv2.PyrDown(image_out, image_out, size);
                    break;
                }

                case MyOPENCV.resize:    //尺寸调整
                {
                    OpenCvSharp.Size   size;
                    InterpolationFlags interpolationFlags;
                    size.Width         = image_out.Cols * myOPENCV_runlist[i, 1] / 10;
                    size.Height        = image_out.Rows * myOPENCV_runlist[i, 2] / 10;
                    interpolationFlags = (InterpolationFlags)myOPENCV_runlist[i, 3];
                    Cv2.Resize(image_out, image_out, size, 0, 0, interpolationFlags);
                    break;
                }

                case MyOPENCV.threshold:    //固定阈值化
                {
                    Cv2.Threshold(image_out, image_out, myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 2], (ThresholdTypes)myOPENCV_runlist[i, 3]);
                    break;
                }

                case MyOPENCV.canny:    //边缘检测CANNY
                {
                    Mat image_out2 = new Mat();
                    Cv2.Canny(image_out, image_out2, myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 2], myOPENCV_runlist[i, 3]);
                    image_out = image_out2;
                    break;
                }

                case MyOPENCV.sobel:    //边缘检测SOBEL
                {
                    Cv2.Sobel(image_out, image_out, -1, myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 2], myOPENCV_runlist[i, 3]);
                    break;
                }

                case MyOPENCV.laplacian:    //边缘检测LAPLACIAN
                {
                    myOPENCV_runlist[i, 1] = 0;
                    Cv2.Laplacian(image_out, image_out, 0, myOPENCV_runlist[i, 2], myOPENCV_runlist[i, 3]);
                    break;
                }

                case MyOPENCV.scharr:    //边缘检测SCHARR
                {
                    Cv2.Scharr(image_out, image_out, -1, myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 2]);
                    break;
                }

                case MyOPENCV.convertscaleabs:    //图像快速增强
                {
                    double alpha, beta;
                    alpha = (double)myOPENCV_runlist[i, 1] / 10;
                    beta  = (double)myOPENCV_runlist[i, 2] / 10;
                    Cv2.ConvertScaleAbs(image_out, image_out, alpha, beta);
                    break;
                }

                case MyOPENCV.addweighted:    //图像融合
                {
                    Mat    image_in2 = new Mat(my_imagesource2);
                    double alpha, beta, gamma;
                    alpha = (double)myOPENCV_runlist[i, 1] / 10;
                    beta  = (double)myOPENCV_runlist[i, 2] / 10;
                    gamma = (double)myOPENCV_runlist[i, 3] / 10;
                    Cv2.AddWeighted(image_out, alpha, image_in2, beta, gamma, image_out);
                    break;
                }

                case MyOPENCV.houghlines:                                     //霍夫标准变换
                {
                    Scalar             scalar = new Scalar(0x00, 0xFF, 0x00); //绿色
                    LineSegmentPolar[] lines;
                    OpenCvSharp.Size   size = new OpenCvSharp.Size(image_out.Width, image_out.Height);
                    Mat image_out3          = new Mat(size, MatType.CV_8UC3);
                    lines = Cv2.HoughLines(image_out, 1, Cv2.PI / 180, myOPENCV_runlist[i, 1]);
                    for (int ii = 0; ii < lines.Length; ii++)
                    {
                        //double rho, theta;
                        OpenCvSharp.Point pt1, pt2;
                        double            a = Math.Cos(lines[ii].Theta), b = Math.Sin(lines[ii].Theta);
                        double            x0 = a * lines[ii].Rho, y0 = b * lines[ii].Rho;
                        pt1.X = (int)Math.Round(x0 + 1000 * (-b));
                        pt1.Y = (int)Math.Round(y0 + 1000 * (a));
                        pt2.X = (int)Math.Round(x0 - 1000 * (-b));
                        pt2.Y = (int)Math.Round(y0 - 1000 * (a));
                        Cv2.Line(image_out3, pt1, pt2, scalar, 1, LineTypes.AntiAlias);
                    }
                    if (myOPENCV_runlist[i, 2] == 0)
                    {
                        Cv2.AddWeighted(image_out3, (double)myOPENCV_runlist[i, 3] / 10, image_in, (double)myOPENCV_runlist[i, 4] / 10, 0, image_out);
                    }
                    else
                    {
                        image_out = image_out3;
                    }
                    break;
                }

                case MyOPENCV.houghlinep:                                     //霍夫累计概率变换
                {
                    Scalar             scalar = new Scalar(0x00, 0xFF, 0x00); //绿色
                    LineSegmentPoint[] lines;                                 // 线段检索
                    OpenCvSharp.Size   size = new OpenCvSharp.Size(image_out.Width, image_out.Height);
                    Mat image_out3          = new Mat(size, MatType.CV_8UC3);
                    lines = Cv2.HoughLinesP(image_out, 1, Cv2.PI / 180, myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 3], myOPENCV_runlist[i, 4]);
                    for (int ii = 0; ii < lines.Length; ii++)
                    {
                        OpenCvSharp.Point point1, point2;
                        point1.X = lines[i].P1.X;
                        point1.Y = lines[i].P1.Y;
                        point2.X = lines[i].P2.X;
                        point2.Y = lines[i].P2.Y;
                        Cv2.Line(image_out3, point1, point2, scalar, 1, LineTypes.AntiAlias);
                    }
                    if (myOPENCV_runlist[i, 2] == 0)
                    {
                        Cv2.AddWeighted(image_out3, 1, image_in, 0.8, 0, image_out);
                    }
                    else
                    {
                        image_out = image_out3;
                    }
                    break;
                }

                case MyOPENCV.houghcircles:                                 //霍夫圆变换
                {
                    Scalar           scalar = new Scalar(0x00, 0xFF, 0x00); //绿色
                    CircleSegment[]  circles;
                    OpenCvSharp.Size size = new OpenCvSharp.Size(image_out.Width, image_out.Height);
                    Mat image_out3        = new Mat(size, MatType.CV_8UC3);
                    circles = Cv2.HoughCircles(image_out, HoughMethods.Gradient, 1, myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 2], myOPENCV_runlist[i, 3], 0, myOPENCV_runlist[i, 4]);
                    for (int ii = 0; ii < circles.Length; ii++)
                    {
                        OpenCvSharp.Point center;
                        center.X = (int)Math.Round(circles[ii].Center.X);
                        center.Y = (int)Math.Round(circles[ii].Center.Y);
                        int radius = (int)Math.Round(circles[ii].Radius);
                        Cv2.Circle(image_out3, center.X, center.Y, radius, scalar);
                        Cv2.Circle(image_out3, center, radius, scalar);
                    }
                    Cv2.AddWeighted(image_out3, 1, image_in, 0.6, 0, image_out);

                    break;
                }

                case MyOPENCV.remap:    //重映射
                {
                    OpenCvSharp.Size size = new OpenCvSharp.Size(image_out.Width, image_out.Height);

                    Mat map_x = new Mat(size, MatType.CV_32FC1), map_y = new Mat(size, MatType.CV_32FC1);
                    for (int ii = 0; ii < image_out.Rows; ii++)
                    {
                        for (int jj = 0; jj < image_out.Cols; jj++)
                        {
                            if (myOPENCV_runlist[i, 1] == 0)
                            {
                                map_x.Set <float>(ii, jj, jj);                  //上下翻转
                                map_y.Set <float>(ii, jj, image_out.Rows - ii); //上下翻转
                            }
                            else if (myOPENCV_runlist[i, 1] == 1)
                            {
                                map_x.Set <float>(ii, jj, image_out.Cols - jj); //左右翻转
                                map_y.Set <float>(ii, jj, ii);                  //左右翻转
                            }
                            else if (myOPENCV_runlist[i, 1] == 2)
                            {
                                map_x.Set <float>(ii, jj, image_out.Cols - jj);       //上下左右翻转
                                map_y.Set <float>(ii, jj, image_out.Rows - ii);       //上下左右翻转
                            }
                            else if (myOPENCV_runlist[i, 1] == 3)
                            {
                                map_x.Set <float>(ii, jj, (float)myOPENCV_runlist[i, 2] / 10 * jj);       //放大缩小
                                map_y.Set <float>(ii, jj, (float)myOPENCV_runlist[i, 2] / 10 * ii);       //放大缩小
                            }
                        }
                    }
                    Cv2.Remap(image_out, image_out, map_x, map_y);
                    break;
                }

                case MyOPENCV.warpaffine:    //仿射变换
                {
                    if (0 == myOPENCV_runlist[i, 1])
                    {
                        Mat rot_mat = new Mat(2, 3, MatType.CV_32FC1);
                        OpenCvSharp.Point center = new OpenCvSharp.Point(image_out.Cols / 2, image_out.Rows / 2);
                        double            angle  = myOPENCV_runlist[i, 2];
                        double            scale  = (double)myOPENCV_runlist[i, 3] / 10;
                        ///// 通过上面的旋转细节信息求得旋转矩阵
                        rot_mat = Cv2.GetRotationMatrix2D(center, angle, scale);
                        ///// 旋转已扭曲图像
                        Cv2.WarpAffine(image_out, image_out, rot_mat, image_out.Size());
                    }
                    else
                    {
                        Point2f[] srcTri   = new Point2f[3];
                        Point2f[] dstTri   = new Point2f[3];
                        Mat       warp_mat = new Mat(2, 3, MatType.CV_32FC1);
                        Mat       warp_dst;
                        warp_dst  = Mat.Zeros(image_out.Rows, image_out.Cols, image_out.Type());
                        srcTri[0] = new Point2f(0, 0);
                        srcTri[1] = new Point2f(image_out.Cols, 0);
                        srcTri[2] = new Point2f(0, image_out.Rows);
                        dstTri[0] = new Point2f((float)(image_out.Cols * myOPENCV_runlist[i, 2] / 100), (float)(image_out.Rows * myOPENCV_runlist[i, 2] / 100));
                        dstTri[1] = new Point2f((float)(image_out.Cols * (1 - (float)myOPENCV_runlist[i, 3] / 100)), (float)(image_out.Rows * myOPENCV_runlist[i, 3] / 100));
                        dstTri[2] = new Point2f((float)(image_out.Cols * myOPENCV_runlist[i, 4] / 100), (float)(image_out.Rows * (1 - (float)myOPENCV_runlist[i, 4] / 100)));
                        warp_mat  = Cv2.GetAffineTransform(srcTri, dstTri);
                        Cv2.WarpAffine(image_out, image_out, warp_mat, image_out.Size());
                    }
                    break;
                }

                case MyOPENCV.equalizehist:    //直方图均衡化
                {
                    Cv2.EqualizeHist(image_out, image_out);
                    break;
                }

                case MyOPENCV.facedetection:         //人脸识别
                {
                    if (0 == myOPENCV_runlist[i, 1]) // 参数一为0 调用haar,其余数字调用lbp
                    {
                        var haarCascade = new CascadeClassifier(@"haarcascade_frontalface_alt.xml");
                        Mat haarResult  = DetectFace(image_out, haarCascade);
                        image_out = haarResult;
                    }
                    else
                    {
                        var lbpCascade = new CascadeClassifier(@"lbpcascade_frontalface.xml");
                        Mat lbpResult  = DetectFace(image_out, lbpCascade);
                        image_out = lbpResult;
                    }

                    break;
                }

                case MyOPENCV.matchtemplate:                                             // 模板匹配
                {
                    Mat originalMat = Cv2.ImRead(my_imagesource, ImreadModes.AnyColor);  //母图
                    Mat modelMat    = Cv2.ImRead(my_imagesource2, ImreadModes.AnyColor); //模板
                    Mat resultMat   = new Mat();                                         // 匹配结果

                    //resultMat.Create(mat1.Cols - modelMat.Cols + 1, mat1.Rows - modelMat.Cols + 1, MatType.CV_32FC1);//创建result的模板,就是MatchTemplate里的第三个参数
                    if (0 == myOPENCV_runlist[i, 1])
                    {
                        Cv2.MatchTemplate(originalMat, modelMat, resultMat, TemplateMatchModes.SqDiff);        //进行匹配(1母图,2模版子图,3返回的result,4匹配模式)
                    }
                    else if (1 == myOPENCV_runlist[i, 1])
                    {
                        Cv2.MatchTemplate(originalMat, modelMat, resultMat, TemplateMatchModes.SqDiffNormed);
                    }
                    else if (2 == myOPENCV_runlist[i, 1])
                    {
                        Cv2.MatchTemplate(originalMat, modelMat, resultMat, TemplateMatchModes.CCorr);
                    }
                    else if (3 == myOPENCV_runlist[i, 1])
                    {
                        Cv2.MatchTemplate(originalMat, modelMat, resultMat, TemplateMatchModes.CCorrNormed);
                    }
                    else if (4 == myOPENCV_runlist[i, 1])
                    {
                        Cv2.MatchTemplate(originalMat, modelMat, resultMat, TemplateMatchModes.CCoeff);
                    }
                    else if (5 == myOPENCV_runlist[i, 1])
                    {
                        Cv2.MatchTemplate(originalMat, modelMat, resultMat, TemplateMatchModes.CCoeffNormed);
                    }
                    OpenCvSharp.Point minLocation, maxLocation, matchLocation;
                    Cv2.MinMaxLoc(resultMat, out minLocation, out maxLocation);
                    matchLocation = maxLocation;
                    Mat mask = originalMat.Clone();

                    Cv2.Rectangle(mask, minLocation, new OpenCvSharp.Point(minLocation.X + modelMat.Cols, minLocation.Y + modelMat.Rows), Scalar.Green, 2);         //画出匹配的矩  (图像,最小点,最大点,颜色,线宽)

                    image_out = mask;
                    break;
                }

                case MyOPENCV.find_draw_contours:                                      // 找出并绘制轮廓
                {
                    Cv2.CvtColor(image_out, image_out, ColorConversionCodes.RGB2GRAY); //转换为灰度图
                    //Cv2.Blur(image_out, image_out, new OpenCvSharp.Size(2, 2));  //滤波

                    Cv2.Canny(image_out, image_out, 100, 200);              //Canny边缘检测

                    OpenCvSharp.Point[][] contours;
                    HierarchyIndex[]      hierarchly;
                    Cv2.FindContours(image_out, out contours, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); //获得轮廓

                    Mat    dst_Image = Mat.Zeros(image_out.Size(), image_out.Type());                                                                                    // 图片像素值归零
                    Random rnd       = new Random();
                    for (int j = 0; j < contours.Length; j++)
                    {
                        Scalar color = new Scalar(myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 2], myOPENCV_runlist[i, 3]);
                        //Scalar color = new Scalar(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
                        Cv2.DrawContours(dst_Image, contours, j, color, myOPENCV_runlist[i, 4], LineTypes.Link8, hierarchly);             //画出轮廓
                    }
                    image_out = dst_Image;
                    break;
                }

                case MyOPENCV.componentdefectdetecting:                                // 零件缺陷检测
                {
                    Cv2.CvtColor(image_out, image_out, ColorConversionCodes.RGB2GRAY); //转换为灰度图
                    //Cv2.Blur(image_out, image_out, new OpenCvSharp.Size(2, 2));  //滤波

                    Cv2.Canny(image_out, image_out, 100, 200);              //Canny边缘检测

                    OpenCvSharp.Point[][] contours;
                    HierarchyIndex[]      hierarchly;
                    Cv2.FindContours(image_out, out contours, out hierarchly, RetrievalModes.Tree, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0)); //获得轮廓

                    Mat    dst_Image = Mat.Zeros(image_out.Size(), image_out.Type());                                                                                    // 图片像素值归零
                    Random rnd       = new Random();
                    for (int j = 0; j < contours.Length; j++)
                    {
                        Scalar color = new Scalar(myOPENCV_runlist[i, 1], myOPENCV_runlist[i, 2], myOPENCV_runlist[i, 3]);
                        //Scalar color = new Scalar(rnd.Next(0, 255), rnd.Next(0, 255), rnd.Next(0, 255));
                        Cv2.DrawContours(dst_Image, contours, j, color, myOPENCV_runlist[i, 4], LineTypes.Link8, hierarchly);               //画出轮廓
                    }


                    Mat cnt = new Mat();
                    Cv2.ConvexHull(image_out, cnt);



                    break;
                }

                default: break;
                }
            }
            return(image_out);
        }
Exemple #19
0
        /// <summary>
        /// The magic is here
        /// </summary>
        private void CalculateOutput()
        {
            Mat matGray = null;

            // instead of regular Grayscale, we use BGR -> HSV and take Hue channel as
            // source
            if (Settings.GrayMode == ScannerSettings.ColorMode.HueGrayscale)
            {
                var   matHSV      = matInput_.CvtColor(ColorConversionCodes.RGB2HSV);
                Mat[] hsvChannels = matHSV.Split();
                matGray = hsvChannels[0];
            }
            // Alternative: just plain BGR -> Grayscale
            else
            {
                matGray = matInput_.CvtColor(ColorConversionCodes.BGR2GRAY);
            }

            // scale down if necessary
            var   matScaled = matGray;
            float sx = 1, sy = 1;

            if (Settings.Scale != 0)
            {
                if (matGray.Width > Settings.Scale)
                {
                    sx = (float)Settings.Scale / matGray.Width;
                }
                if (matGray.Height > Settings.Scale)
                {
                    sy = (float)Settings.Scale / matGray.Height;
                }

                matScaled = matGray.Resize(new Size(Math.Min(matGray.Width, Settings.Scale), Math.Min(matGray.Height, Settings.Scale)));
            }

            // reduce noise
            var matBlur = matScaled;

            if (Settings.NoiseReduction != 0)
            {
                int medianKernel = 11;

                // calculate kernel scale
                double kernelScale = Settings.NoiseReduction;
                if (0 == Settings.Scale)
                {
                    kernelScale *= Math.Max(matInput_.Width, matInput_.Height) / 512.0;
                }

                // apply scale
                medianKernel = (int)(medianKernel * kernelScale + 0.5);
                medianKernel = medianKernel - (medianKernel % 2) + 1;

                if (medianKernel > 1)
                {
                    matBlur = matScaled.MedianBlur(medianKernel);
                }
            }

            // detect edges with our 'adaptive' algorithm that computes bounds automatically with
            // image's mean value
            var matEdges = matBlur.AdaptiveEdges(Settings.EdgesTight);

            // now find contours
            Point[][]        contours;
            HierarchyIndex[] hierarchy;
            Cv2.FindContours(matEdges, out contours, out hierarchy, RetrievalModes.List, ContourApproximationModes.ApproxNone, null);

            // check contours and drop those we consider "noise", all others put into a single huge "key points" map
            // also, detect all almost-rectangular contours with big area and try to determine whether they're exact match
            List <Point>   keyPoints      = new List <Point>();
            List <Point[]> goodCandidates = new List <Point[]>();
            double         referenceArea  = matScaled.Width * matScaled.Height;

            foreach (Point[] contour in contours)
            {
                double length = Cv2.ArcLength(contour, true);

                // drop mini-contours
                if (length >= 25.0)
                {
                    Point[] approx = Cv2.ApproxPolyDP(contour, length * 0.01, true);
                    keyPoints.AddRange(approx);

                    if (approx.Length >= 4 && approx.Length <= 6)
                    {
                        double area = Cv2.ContourArea(approx);
                        if (area / referenceArea >= Settings.ExpectedArea)
                        {
                            goodCandidates.Add(approx);
                        }
                    }
                }
            }

            // compute convex hull, considering we presume having an image of a document on more or less
            // homogeneous background, this accumulated convex hull should be the document bounding contour
            Point[] hull        = Cv2.ConvexHull(keyPoints);
            Point[] hullContour = Cv2.ApproxPolyDP(hull, Cv2.ArcLength(hull, true) * 0.01, true);

            // find best guess for our contour
            Point[] paperContour = GetBestMatchingContour(matScaled.Width * matScaled.Height, goodCandidates, hullContour);
            if (null == paperContour)
            {
                shape_     = null;
                dirty_     = false;
                matOutput_ = matInput_;
                return;
            }

            // exact hit - we have 4 corners
            if (paperContour.Length == 4)
            {
                paperContour = SortCorners(paperContour);
            }
            // some hit: we either have 3 points or > 4 which we can try to make a 4-corner shape
            else if (paperContour.Length > 2)
            {
                // yet contour might contain too much points: along with calculation inaccuracies we might face a
                // bended piece of paper, missing corner etc.
                // the solution is to use bounding box
                RotatedRect bounds      = Cv2.MinAreaRect(paperContour);
                Point2f[]   points      = bounds.Points();
                Point[]     intPoints   = Array.ConvertAll(points, p => new Point(Math.Round(p.X), Math.Round(p.Y)));
                Point[]     fourCorners = SortCorners(intPoints);

                // array.ClosestElement is not efficient but we can live with it since it's quite few
                // elements to search for
                System.Func <Point, Point, double> distance = (Point x, Point y) => Point.Distance(x, y);
                Point[] closest = new Point[4];
                for (int i = 0; i < fourCorners.Length; ++i)
                {
                    closest[i] = paperContour.ClosestElement(fourCorners[i], distance);
                }

                paperContour = closest;
            }

            // scale contour back to input image coordinate space - if necessary
            if (sx != 1 || sy != 1)
            {
                for (int i = 0; i < paperContour.Length; ++i)
                {
                    Point2f pt = paperContour[i];
                    paperContour[i] = new Point2f(pt.X / sx, pt.Y / sy);
                }
            }

            // un-wrap
            var  matUnwrapped        = matInput_;
            bool needConvertionToBGR = true;

            if (paperContour.Length == 4)
            {
                matUnwrapped = matInput_.UnwrapShape(Array.ConvertAll(paperContour, p => new Point2f(p.X, p.Y)));

                // automatic color converter
                bool convertColor = (ScannerSettings.DecolorizationMode.Always == Settings.Decolorization);
                if (ScannerSettings.DecolorizationMode.Automatic == Settings.Decolorization)
                {
                    convertColor = !IsColored(matUnwrapped);
                }

                // perform color conversion to b&w
                if (convertColor)
                {
                    matUnwrapped = matUnwrapped.CvtColor(ColorConversionCodes.BGR2GRAY);

                    // we have some constants for Adaptive, but this can be improved with some 'educated guess' for the constants depending on input image
                    if (ScannerSettings.ScanType.Adaptive == Settings.ColorThreshold)
                    {
                        matUnwrapped = matUnwrapped.AdaptiveThreshold(255, AdaptiveThresholdTypes.MeanC, ThresholdTypes.Binary, 47, 25);
                    }
                    // Otsu doesn't need our help, decent on it's own
                    else
                    {
                        matUnwrapped = matUnwrapped.Threshold(0, 255, ThresholdTypes.Binary | ThresholdTypes.Otsu);
                    }
                }
                else
                {
                    needConvertionToBGR = false;
                }
            }

            // assign result
            shape_ = paperContour;

            matOutput_ = matUnwrapped;
            if (needConvertionToBGR)
            {
                matOutput_ = matOutput_.CvtColor(ColorConversionCodes.GRAY2BGR);                    // to make it compatible with input texture
            }
            // mark we're good
            dirty_ = false;
        }
        //MyMSER
        static List <Point[][]> My_MSER(int my_delta, int my_minArea, int my_maxArea, double my_maxVariation, Mat img, ref Mat img_rgb, int big_flag)
        {
            //img.SaveImage("img_detected.jpg");

            List <Point[][]> final_area = new List <Point[][]>();

            Point[][] contours;
            Rect[]    bboxes;
            MSER      mser = MSER.Create(delta: my_delta, minArea: my_minArea, maxArea: my_maxArea, maxVariation: my_maxVariation);

            mser.DetectRegions(img, out contours, out bboxes);

            //====================================Local Majority Vote

            // to speed up, create four shift image first
            var shift_mat = set_shift_image(ref img);

            Mat[] neighbor_img = new Mat[4];
            for (int i = 0; i < 4; i++)
            {
                neighbor_img[i] = new Mat();
                var imageCenter = new Point2f(img.Cols / 2f, img.Rows / 2f);
                var rotationMat = Cv2.GetRotationMatrix2D(imageCenter, 100, 1.3);
                Cv2.WarpAffine(img, neighbor_img[i], shift_mat[i], img.Size());
                //neighbor_img[i].SaveImage("./shift_image" + i + ".jpg");
            }

            //for each contour, apply local majority vote
            foreach (Point[] now_contour in contours)
            {
                OpenCvSharp.Point[][] temp = new Point[1][];

                Point[] Convex_hull = Cv2.ConvexHull(now_contour);
                Point[] Approx      = Cv2.ApproxPolyDP(now_contour, 0.5, true);

                RotatedRect rotateRect = Cv2.MinAreaRect(Approx);
                //Debug
                //Console.WriteLine(Cv2.ContourArea(Approx)+" "+ rotateRect.Size.Height / rotateRect.Size.Width+ " "+rotateRect.Size.Width / rotateRect.Size.Height);

                if (Cv2.ContourArea(Approx) > 10000 || (Cv2.ContourArea(Approx) < stop1_inner_defect_size_min || ((rotateRect.Size.Height / rotateRect.Size.Width)) > stop1_arclength_area_ratio || ((rotateRect.Size.Width / rotateRect.Size.Height)) > stop1_arclength_area_ratio))
                {
                    continue;
                }

                //======================intensity in the area
                temp[0] = Approx;
                double mean_in_area_temp = 0, min_in_area_temp = 0;
                Mat    mask_img_temp = Mat.Zeros(img.Size(), MatType.CV_8UC1);
                Cv2.DrawContours(mask_img_temp, temp, -1, 255, thickness: -1);//notice the difference between temp = Approx and Convex_hull
                mean_in_area_temp = img.Mean(mask_img_temp)[0];
                img.MinMaxLoc(out min_in_area_temp, out _, out _, out _, mask_img_temp);
                //Console.WriteLine(min_in_area_temp + " " + mean_in_area_temp);
                if (min_in_area_temp > 100 || mean_in_area_temp > 130)
                {
                    continue;
                }

                // Convex hull
                temp[0] = Approx;
                if (big_flag == 0)//small area: local majority vote
                {
                    //Cv2.Polylines(img_rgb, temp, true, new Scalar(0, 0, 255), 1);
                    //inside the area
                    double mean_in_area = 0, min_in_area = 0;
                    Mat    mask_img = Mat.Zeros(img.Size(), MatType.CV_8UC1);
                    Cv2.DrawContours(mask_img, temp, -1, 255, thickness: -1);//notice the difference between temp = Approx and Convex_hull
                    mean_in_area = img.Mean(mask_img)[0];
                    img.MinMaxLoc(out min_in_area, out _, out _, out _, mask_img);

                    //Console.WriteLine(min_in_area + " " + mean_in_area);

                    //test

                    /*
                     * Mat mask2 = img.LessThan(230);
                     * for (int i = 0; i < img.Cols; i++) {
                     *  for (int j = 0; j < img.Rows; j++)
                     *      if(mask2.At<bool>(i, j)==false)
                     *          Console.Write(mask2.At<bool>(i,j)+ " ");
                     *
                     *  Console.Write("\n");
                     *
                     * }
                     */
                    //neighbor
                    double[] mean_neighbor = { 255, 255, 255, 255 };
                    double[] min_neighbor  = { 255, 255, 255, 255 };
                    for (int i = 0; i < 4; i++)
                    {
                        //先把 img > 230 的變成 0,再餵進 shift 裡面
                        //先把 mask 乘上另一個mask(>230的mask)
                        //Mat mask_neighbor_img = neighbor_img[i].GreaterThan(0);
                        //Console.WriteLine(mask_neighbor_img.At<int>(0,1));
                        // create final mask
                        Mat mask2 = neighbor_img[i].LessThan(225).ToMat();
                        mask2.ConvertTo(mask2, MatType.CV_8U, 1.0 / 255.0);

                        Mat mask_final = Mat.Zeros(img.Size(), MatType.CV_8UC1);
                        mask_img.CopyTo(mask_final, mask2);

                        //mask_final.SaveImage("./mask" + i + ".jpg");

                        mean_neighbor[i] = neighbor_img[i].Mean(mask_final)[0];
                        //compute min:
                        //neighbor_img[i].MinMaxLoc(out min_neighbor[i], out _, out _, out _, mask_img);
                        //Console.WriteLine(min_neighbor[i] + " " + mean_neighbor[i]);
                    }
                    int vote = 0;
                    for (int i = 0; i < 4; i++)
                    {
                        if (mean_in_area > mean_neighbor[i])
                        {
                            vote++;
                        }
                    }
                    if (vote > 2 || min_in_area > 100 || mean_in_area > 130)
                    {
                        //Debug
                        //Console.WriteLine(vote + " " + min_in_area + " ", min_in_area);
                        continue;
                    }
                    else
                    {
                        //Cv2.Polylines(img_rgb, temp, true, new Scalar(0, 0, 255), 1);
                        //Console.WriteLine("--");
                        final_area.Add(temp);
                    }
                }
                else
                {
                    //Console.WriteLine("--");
                    //Cv2.Polylines(img_rgb, temp, true, new Scalar(0, 0, 255), 1);
                    final_area.Add(temp);
                }
            }
            Console.WriteLine(final_area.Count);
            return(final_area);
        }
Exemple #21
0
        public void GetDiffFrame(int width, int height, out double[] buf)
        {
            buf = new double[width * height];
            var frame = new Mat();
            var diff  = new Mat();

            if (capture.Read(frame))
            {
                frame = frame.Resize(new Size(width, height));
                Cv2.CvtColor(frame, frame, ColorConversionCodes.BGR2GRAY);
                if (PrevFrame != null)
                {
                    diff = frame.Clone();
                    Cv2.Absdiff(frame, PrevFrame, diff);
                    Cv2.Threshold(diff, diff, byte.MaxValue * 0.25, byte.MaxValue, ThresholdTypes.Binary);

                    Point[][]        contours;
                    HierarchyIndex[] hierarchyIndexes;
                    Cv2.FindContours(diff.Clone(), out contours, out hierarchyIndexes, RetrievalModes.List, ContourApproximationModes.ApproxTC89KCOS);
                    if (contours.Length > 0)
                    {
                        var points = new List <Point>();
                        for (int idx_cnt = 0; idx_cnt < contours.GetLength(0); ++idx_cnt)
                        {
                            if (hierarchyIndexes[idx_cnt].Parent != -1)
                            {
                                continue;
                            }
                            points.AddRange(contours[idx_cnt]);
                        }
                        Cv2.DrawContours(diff, new List <List <Point> >(new List <Point>[] { new List <Point>(Cv2.ConvexHull(points.ToArray())) }), 0, new Scalar(byte.MaxValue), -1);
                    }
                    var masked = diff.Clone();
                    frame.CopyTo(masked, diff);
                    Cv2.BitwiseOr(diff, PrevDiffFrame, diff);
                    Cv2.AddWeighted(masked, 0.5, diff, 0.5, 0, diff);

                    if (PrevFrame != null)
                    {
                        unsafe
                        {
                            byte *p  = (byte *)frame.Data;
                            byte *pv = (byte *)diff.Data;
                            for (int i = 0; i < width * height; i++)
                            {
                                buf[i] = (double)pv[i] / byte.MaxValue;
                            }
                        }
                    }
                }
                if (PrevFrame == null)
                {
                    PrevFrame     = frame.Clone();
                    PrevDiffFrame = new Mat(PrevFrame.Size(), PrevFrame.Type());
                }
                else
                {
                    double weight = 0.75;
                    Cv2.AddWeighted(PrevFrame, weight, frame, 1 - weight, 0, PrevFrame);
                    PrevDiffFrame = diff.Clone();
                }
            }
        }
Exemple #22
0
    public Mat getHandContour(Mat input, Mat frame)
    {
        Mat detectImage = frame.Clone();

        if (input.Empty())
        {
            return(detectImage);
        }

        // we work only on the 1 channel result, since this function is called inside a loop we are not sure that this is always the case
        if (input.Channels() != 1)
        {
            return(detectImage);
        }

        Point[][]        contours;
        HierarchyIndex[] hierarchy;

        Cv2.FindContours(input,
                         out contours,
                         out hierarchy,
                         RetrievalModes.External,
                         ContourApproximationModes.ApproxSimple);

        if (contours.Length <= 0)
        {
            return(detectImage);
        }


        int    biggest_contour_index = -1;
        double biggest_area          = 0.0;

        for (int i = 0; i < contours.GetLength(0); i++)
        {
            double area = Cv2.ContourArea(contours[i], false);
            if (area > biggest_area)
            {
                biggest_area          = area;
                biggest_contour_index = i;
            }
        }

        if (biggest_contour_index < 0)
        {
            return(detectImage);
        }

        // Debug.Log(" " + biggest_area + " " + biggest_contour_index);
        Point[] hull_points;
        int[]   hull_ints;


        hull_points = Cv2.ConvexHull(contours[biggest_contour_index]);
        hull_ints   = Cv2.ConvexHullIndices(contours[biggest_contour_index]);
        //Debug.Log("hull " + hull_points.Length);
        //Debug.Log("hull " + hull_ints.Length);

        Vec4i[] defects;

        if (hull_ints.Length > 3)
        {
            defects = Cv2.ConvexityDefects(contours[biggest_contour_index], hull_ints);
        }
        else
        {
            return(detectImage);
        }



        ///////////////
        OpenCvSharp.Rect bounding_rectangle = Cv2.BoundingRect(hull_points);

        // we find the center of the bounding rectangle, this should approximately also be the center of the hand
        Point center_bounding_rect = new Point(
            (bounding_rectangle.TopLeft.X + bounding_rectangle.BottomRight.X) / 2,
            (bounding_rectangle.TopLeft.Y + bounding_rectangle.BottomRight.Y) / 2
            );


        // we separate the defects keeping only the ones of intrest
        List <Point> start_points = new List <Point>();
        List <Point> far_points   = new List <Point>();

        // Debug.Log(" " + defects.Length);
        //Debug.Log(" " + contours[biggest_contour_index].Length);
        //Debug.Log(" " + contours.Length);


        for (int i = 0; i < defects.Length; i++)
        {
            start_points.Add(contours[biggest_contour_index][defects[i].Item0]);
            // filtering the far point based on the distance from the center of the bounding rectangle
            if (findPointsDistance(contours[biggest_contour_index][defects[i].Item2], center_bounding_rect) < bounding_rectangle.Height * BOUNDING_RECT_FINGER_SIZE_SCALING)
            {
                far_points.Add(contours[biggest_contour_index][defects[i].Item2]);
            }
        }

        // we compact them on their medians
        List <Point> filtered_start_points = compactOnNeighborhoodMedian(start_points, bounding_rectangle.Height * BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING);
        List <Point> filtered_far_points   = compactOnNeighborhoodMedian(far_points, bounding_rectangle.Height * BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING);

        // now we try to find the fingers
        List <Point> filtered_finger_points = new List <Point>();

        if (filtered_far_points.Count > 1)
        {
            List <Point> finger_points = new List <Point>();

            for (int i = 0; i < filtered_start_points.Count; i++)
            {
                List <Point> closest_points = findClosestOnX(filtered_far_points, filtered_start_points[i]);

                if (isFinger(closest_points[0], filtered_start_points[i], closest_points[1], LIMIT_ANGLE_INF, LIMIT_ANGLE_SUP, center_bounding_rect, bounding_rectangle.Height * BOUNDING_RECT_FINGER_SIZE_SCALING))
                {
                    finger_points.Add(filtered_start_points[i]);
                }
            }

            if (finger_points.Count > 0)
            {
                // we have at most five fingers usually :)
                while (finger_points.Count > 5)
                {
                    finger_points.RemoveAt(0);
                }

                // filter out the points too close to each other
                for (int i = 0; i < finger_points.Count - 1; i++)
                {
                    if (findPointsDistanceOnX(finger_points[i], finger_points[i + 1]) > bounding_rectangle.Height * BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING * 1.5)
                    {
                        filtered_finger_points.Add(finger_points[i]);
                    }
                }

                if (finger_points.Count > 2)
                {
                    if (findPointsDistanceOnX(finger_points[0], finger_points[finger_points.Count - 1]) > bounding_rectangle.Height * BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING * 1.5)
                    {
                        filtered_finger_points.Add(finger_points[finger_points.Count - 1]);
                    }
                }
                else
                {
                    filtered_finger_points.Add(finger_points[finger_points.Count - 1]);
                }
            }
        }

        // we draw what found on the returned image
        Cv2.DrawContours(detectImage, contours, biggest_contour_index, new Scalar(0, 255, 0), 8, LineTypes.Link8, hierarchy);
        //Cv2.Polylines(input, new IEnumerable<IEnumerable<Point>>( hull_points), true, new Scalar(1, 0, 0));
        Cv2.Rectangle(detectImage, bounding_rectangle.TopLeft, bounding_rectangle.BottomRight, new Scalar(0, 0, 255), 8, LineTypes.Link8);
        Cv2.Circle(detectImage, center_bounding_rect.X, center_bounding_rect.Y, 15, new Scalar(255, 0, 255), 3, LineTypes.Link8);
        drawVectorPoints(detectImage, filtered_start_points, new Scalar(255, 0, 0), true);
        drawVectorPoints(detectImage, filtered_far_points, new Scalar(0, 0, 25), true);
        drawVectorPoints(detectImage, filtered_finger_points, new Scalar(0, 255, 255), false);
        Cv2.PutText(detectImage, filtered_finger_points.Count.ToString(), center_bounding_rect, HersheyFonts.HersheyTriplex, 10, new Scalar(255, 0, 25));

        // and on the starting frame
        Cv2.DrawContours(frame, contours, biggest_contour_index, new Scalar(0, 255, 0), 8, LineTypes.Link8, hierarchy);
        Cv2.Circle(frame, center_bounding_rect.X, center_bounding_rect.Y, 15, new Scalar(255, 0, 255), 8, LineTypes.Link8);
        drawVectorPoints(frame, filtered_finger_points, new Scalar(0, 255, 255), false);
        Cv2.PutText(frame, filtered_finger_points.Count.ToString(), center_bounding_rect, HersheyFonts.HersheyTriplex, 10, new Scalar(255, 0, 255));

        fingerCount = filtered_finger_points.Count;
        if (fingerCount <= 1)
        {
            finalPose = "rock";
        }

        if (fingerCount == 2 && fingerCount <= 3)
        {
            finalPose = "scissor";
        }

        if (fingerCount >= 4)
        {
            finalPose = "paper";
        }

        return(detectImage);
    }
        private void OpenImage_Click(object sender, EventArgs e)
        {
            OpenFileDialog Openfile = new OpenFileDialog();

            if (Openfile.ShowDialog() == DialogResult.OK)
            {
                Mat input     = new Mat(Openfile.FileName, ImreadModes.Color);
                Mat grayScale = new Mat();

                Tools.soften(ref input);
                OpenCvSharp.Point[][] contours;
                HierarchyIndex[]      hierarchie_indexes;


                Cv2.CvtColor(input, grayScale, ColorConversionCodes.BGRA2GRAY); //Canny edge detector to remove soft edges. Убираем "мягкие переходы после блюра
                Cv2.Canny(grayScale, grayScale, 50, 150, 3);
                Cv2.FindContours(grayScale, out contours, out hierarchie_indexes, mode: RetrievalModes.External, method: ContourApproximationModes.ApproxSimple);
                Cv2.DrawContours(input, contours, -1, color: Color.blue, 2, lineType: LineTypes.Link8, hierarchy: hierarchie_indexes, maxLevel: int.MaxValue);

                var handContour = Tools.FindBiggestContour(ref contours); // looking for biggest contour in image. Находим наибольший контур на изображении, выбирая максимальный по размеру контейнер с координатами контура
                var hullPoints  = Cv2.ConvexHull(handContour);



                List <List <OpenCvSharp.Point> > all_pts          = new List <List <OpenCvSharp.Point> >();
                List <OpenCvSharp.Point>         exclusive_points = new List <OpenCvSharp.Point>();


                for (int it = 0; it < hullPoints.Length; it++)
                {
                    exclusive_points.Add(hullPoints[it]);
                }

                all_pts.Add(exclusive_points);


                //Cv2.Polylines(input, all_pts, true, color: new Scalar(0, 12, 255)); // looking for outside controu of whole palm. Находим внешний контур ко всей ладони

                List <OpenCvSharp.Point> cnt = new List <OpenCvSharp.Point>();
                for (int it = 0; it < handContour.Length; it++)
                {
                    cnt.Add(handContour[it]);
                }

                // Поиск центра ладони по ближайшей средней точке между min экстремумами контура ладони
                // Looking for center point of palm using minimal extremums mean values

                Rect bounding_rectangle = Cv2.BoundingRect(hullPoints);

                OpenCvSharp.Point center_of_palm = new OpenCvSharp.Point(
                    (bounding_rectangle.TopLeft.X + bounding_rectangle.BottomRight.X) / 2,
                    (bounding_rectangle.TopLeft.Y + bounding_rectangle.BottomRight.Y) / 2
                    );


                //Cv2.Circle(input, center: center_of_palm, radius: 6, color: new Scalar(17, 255, 21), lineType: LineTypes.Link4, thickness: 8);


                //for (int i = 0; i < hullPoints.Length; i++)
                //{

                //    Cv2.Circle(input, center: hullPoints[i], radius: 6, color: Color.unfiltered);
                //}

                Tools.SimplifyNeighbors(ref exclusive_points, ref center_of_palm);
                Tools.RemoveWristPoints(ref exclusive_points, input.Cols, input.Rows); // удаляем точки, сопряженные с краем изображения, в данном случае запястья


                for (int i = 0; i < exclusive_points.Count; i++)
                {
                    Cv2.Circle(input, center: exclusive_points[i], radius: 2, color: Color.red, thickness: 6);
                }

                Cv2.Resize(input, input, dsize: new OpenCvSharp.Size(640, 480));
                Viewport.Image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(input);
            }
        }
Exemple #24
0
        private void CreateObjectMask(ref System.Drawing.Bitmap image, out System.Drawing.Bitmap mask)
        {
            double kThresh = 125;
            double hThresh = 55;
            double canny1  = 25;
            double canny2  = 75;

            mask = null;
            Mat src = BitmapConverter.ToMat(image);

            Mat src_kirsch = BitmapConverter.ToMat(image.KirschFilter());

            Mat kirsch_gray = new Mat();

            Cv2.CvtColor(src_kirsch, kirsch_gray, ColorConversionCodes.RGB2GRAY);

            Cv2.ImWrite(@"C:\temp\kirsch_gray.jpg", kirsch_gray);
            Mat kirsch_threshold = new Mat();

            Cv2.Threshold(kirsch_gray, kirsch_threshold, kThresh, 255, ThresholdTypes.Binary);
            Cv2.ImWrite(@"C:\temp\kirsch_threshold.jpg", kirsch_threshold);

            Mat[] contours;
            List <OpenCvSharp.Point> hierarchy;
            List <Mat> hulls;
            Mat        morph_element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(2, 2), new OpenCvSharp.Point(1, 1));

            #region morphology

            Mat kirsch_threshold_copy = new Mat();
            kirsch_threshold.CopyTo(kirsch_threshold_copy);

            int hullCount = 0, numLoops = 0;
            do
            {
                numLoops++;

                Mat kirsch_morph = kirsch_threshold_copy.MorphologyEx(MorphTypes.Gradient, morph_element);
                Cv2.ImWrite(@"C:\temp\kirsch_morph" + numLoops + ".jpg", kirsch_morph);
                hierarchy = new List <OpenCvSharp.Point>();
                Cv2.FindContours(kirsch_morph, out contours, OutputArray.Create(hierarchy),
                                 RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));

                hulls = new List <Mat>();
                for (int j = 0; j < contours.Length; j++)
                {
                    Mat hull = new Mat();
                    Cv2.ConvexHull(contours[j], hull);
                    hulls.Add(hull);
                }

                Mat drawing = Mat.Zeros(src.Size(), MatType.CV_8UC1);
                Cv2.DrawContours(drawing, hulls, -1, Scalar.White);

                Cv2.ImWrite(@"C:\temp\drawing" + numLoops + ".jpg", drawing);
                if (hulls.Count != hullCount && numLoops < 100)
                {
                    hullCount             = hulls.Count;
                    kirsch_threshold_copy = drawing;
                }
                else
                {
                    break;
                }
            } while (true);

            #endregion

            if (numLoops >= 100)
            {
                throw new Exception("Could not find hull");
            }

            #region bestHull
            //try and filter out dust near to stone
            double largestArea = hulls.Max(m => Cv2.ContourArea(m));
            var    bestHulls   = hulls.Where(m => Cv2.ContourArea(m) == largestArea).ToList();

            Mat hulls_mask = Mat.Zeros(src.Size(), MatType.CV_8UC1);
            Cv2.DrawContours(hulls_mask, bestHulls, -1, Scalar.White, -1);
            Cv2.ImWrite(@"C:\temp\hulls_mask.jpg", hulls_mask);

            //hulls_mask is the convex hull of outline, now look for clefts
            Cv2.Threshold(kirsch_gray, kirsch_threshold, hThresh, 255, ThresholdTypes.Binary);
            Mat kirsch_mask = Mat.Zeros(kirsch_threshold.Size(), kirsch_threshold.Type());
            kirsch_threshold.CopyTo(kirsch_mask, hulls_mask);
            Cv2.ImWrite(@"C:\temp\kirsch_mask.jpg", kirsch_mask);
            Mat kirsch_mask_canny = new Mat();
            Cv2.Canny(kirsch_mask, kirsch_mask_canny, canny1, canny2, 3);
            Cv2.ImWrite(@"C:\temp\kirsch_mask_canny.jpg", kirsch_mask_canny);
            morph_element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(5, 5), new OpenCvSharp.Point(2, 2));
            Mat kirsch_filled = new Mat();
            Cv2.Dilate(kirsch_mask_canny, kirsch_filled, morph_element);
            Cv2.Dilate(kirsch_filled, kirsch_filled, morph_element);
            Cv2.Erode(kirsch_filled, kirsch_filled, morph_element);
            Cv2.Erode(kirsch_filled, kirsch_filled, morph_element);
            Cv2.ImWrite(@"C:\temp\kirsch_filled.jpg", kirsch_filled);
            hierarchy = new List <OpenCvSharp.Point>();;
            Cv2.FindContours(kirsch_filled, out contours, OutputArray.Create(hierarchy),
                             RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));

            #endregion

            hulls_mask = Mat.Zeros(src.Size(), MatType.CV_8UC1);
            Cv2.DrawContours(hulls_mask, contours, -1, Scalar.White, -1);
            Cv2.ImWrite(@"C:\temp\hulls_mask_final.jpg", hulls_mask);
            Cv2.Erode(hulls_mask, hulls_mask, morph_element);
            Cv2.Erode(hulls_mask, hulls_mask, morph_element);

            Mat fImage = new Mat();
            src.CopyTo(fImage, hulls_mask);
            Cv2.ImWrite(@"C:\temp\fImage.png", fImage);
            mask = BitmapConverter.ToBitmap(fImage);

            // contrast calculation
            double contrast, L, a, b, H, C;
            CalculateContrast(ref src, ref hulls_mask, out L, out a, out b, out contrast, out H, out C, ContrastType.RMS);

            Console.WriteLine("contrast: {0}, L: {1}, a: {2}, b: {3}, C: {4}, H: {5}", contrast, L, a, b, C, H);

            //hulls_mask = null;

            CalcHistogram(ref src, ref hulls_mask, out mask);
        }
Exemple #25
0
        private Bitmap CreateObjectMask(Bitmap img, /*out IplImage image_mask,*/
                                        out double mask_length, out double mask_area, out double mask_width, out double mask_height,
                                        out double mask_pvheight, int num_smooth, int contrast, double canny1, double canny2,
                                        out Mat image_mask_spc, out double mask2_area, int filter_size = 3,
                                        int brightAreaThreshold = -1, int darkAreaThreshold = -1)
        {
            Bitmap dst = null;
            //IplImage img_mask = Cv.CreateImage(new CvSize(img.Width, img.Height), BitDepth.U8, 1);
            Mat img_mask = new Mat(new OpenCvSharp.Size(img.Width, img.Height), MatType.CV_8UC1, 0);

            image_mask_spc = null;
            mask_length    = mask_area = mask_width = mask_height = mask_pvheight = mask2_area = 0;

            Mat img_gray;
            Mat img_canny;
            Mat img_mask_copy;

            int    i, x, y, offset;
            IntPtr ptr;
            Byte   pixel;

            //////////////////
            var    distance        = new List <double>();
            double center_x        = 0;
            double center_y        = 0;
            double center_count    = 0;
            double distance_mean   = 0;
            double distance_stddev = 0;
            double sum_m           = 0;
            double sum_v           = 0;
            double temp            = 0;

            //////////////////

            ////////////////////////////////////////////////////////////
            ////////////////////////Mask make///////////////////////////
            ////////////////////////////////////////////////////////////
            img_gray      = new Mat(new OpenCvSharp.Size(img.Width, img.Height), MatType.CV_8UC1, 0);
            img_canny     = new Mat(new OpenCvSharp.Size(img.Width, img.Height), MatType.CV_8UC1, 0);
            img_mask_copy = new Mat(new OpenCvSharp.Size(img.Width, img.Height), MatType.CV_8UC1, 0);

            Mat src = BitmapConverter.ToMat(img);

            Cv2.CvtColor(src, img_gray, ColorConversionCodes.BGR2GRAY);

            //Contrast -> Increase the edge contrast for transparent diamond
            byte[] lut = CalcLut(contrast, 0);
            //img_gray.LUT(img_gray, lut);
            Cv2.LUT(img_gray, lut, img_gray);

            //Median filter -> Eliminate point noise in the image



            //Elimination of big dusts should be coded here
            if (num_smooth > 0)
            {
                //for (i = 0; i < num_smooth; i++) img_gray.Smooth(img_gray, SmoothType.Median, 3, 3, 0, 0);
                //for (i = 0; i < num_smooth; i++) img_gray.Smooth(img_gray, SmoothType.Median, filter_size, filter_size, 0, 0);
                for (i = 0; i < num_smooth; i++)
                {
                    Cv2.MedianBlur(img_gray, img_gray, filter_size);
                }

                img_canny = img_gray.Canny(canny1, canny2);
            }
            else
            {
                img_canny = img_gray.Canny(canny1, canny2);
            }

            /////////////////////////////////////////////////////////////
            //ConvexHull
            /////////////////////////////////////////////////////////////

            //OpenCvSharp.CvMemStorage storage = new CvMemStorage(0);
            //CvSeq points = Cv.CreateSeq(SeqType.EltypePoint, CvSeq.SizeOf, CvPoint.SizeOf, storage);
            //CvSeq<CvPoint> points = new CvSeq<CvPoint>(SeqType.EltypePoint, CvSeq.SizeOf, storage);
            //CvPoint pt;

            List <OpenCvSharp.Point> points = new List <OpenCvSharp.Point>();

            OpenCvSharp.Point pt;

            ptr = img_canny.Data;
            for (y = 0; y < img_canny.Height; y++)
            {
                for (x = 0; x < img_canny.Width; x++)
                {
                    offset = (img_canny.Width * y) + (x);
                    pixel  = Marshal.ReadByte(ptr, offset);
                    if (pixel > 0)
                    {
                        pt.X = x;
                        pt.Y = y;
                        points.Add(pt);
                        //////////////////////
                        center_x = center_x + x;
                        center_y = center_y + y;
                        center_count++;
                        //////////////////////
                    }
                }
            }

            center_x = center_x / center_count;
            center_y = center_y / center_count;

            //CvPoint[] hull;
            //CvMemStorage storage1 = new CvMemStorage(0);
            //CvSeq<CvPoint> contours;
            //List<Mat> hull = new List<Mat>();
            MatOfPoint hull = new MatOfPoint();

            int x_min = 3000, x_max = 0, y_min = 3000, y_max = 0;
            int y_x_min = 3000, y_x_max = 3000;

            if (points.Count > 0)
            {
                //Calcurate Ave and Std of distance from each edge points to the weighed center
                for (i = 0; i < points.Count; i++)
                {
                    pt   = points[i];
                    temp = Math.Sqrt((pt.X - center_x) * (pt.X - center_x) + (pt.Y - center_y) * (pt.Y - center_y));
                    distance.Add(temp);
                    sum_m += temp;
                    sum_v += temp * temp;
                }

                distance_mean   = sum_m / points.Count;
                temp            = (sum_v / points.Count) - distance_mean * distance_mean;
                distance_stddev = Math.Sqrt(temp);

                // Outlier elimination
                for (i = points.Count - 1; i >= 0; i--)
                {
                    if (distance[i] > (distance_mean + 3.0 * distance_stddev))
                    {
                        points.RemoveAt(i);
                    }
                }

                Cv2.ConvexHull(MatOfPoint.FromArray(points), hull, true);


                //2014/4/14 Add calc mask_width, mask_height and mask_pvheight

                foreach (OpenCvSharp.Point item in hull)
                {
                    if (x_min > item.X)
                    {
                        x_min   = item.X;
                        y_x_min = item.Y;
                    }
                    else if (x_min == item.X && y_x_min > item.Y)
                    {
                        y_x_min = item.Y;
                    }

                    if (x_max < item.X)
                    {
                        x_max   = item.X;
                        y_x_max = item.Y;
                    }
                    else if (x_max == item.X && y_x_max > item.Y)
                    {
                        y_x_max = item.Y;
                    }

                    if (y_min > item.Y)
                    {
                        y_min = item.Y;
                    }
                    if (y_max < item.Y)
                    {
                        y_max = item.Y;
                    }
                }
                mask_width    = x_max - x_min;
                mask_height   = y_max - y_min;
                mask_pvheight = ((double)y_x_max + (double)y_x_min) / 2 - (double)y_min;

                /////////////////////////////////////////////////////////////
                // For icecream cone shape diamond, need to use triangle mask
                /////////////////////////////////////////////////////////////

                if (diamond_group == DIAMOND_GROUPING.RBC_HighDepth)
                {
                    for (i = 0; i < hull.Count(); i++)
                    {
                        OpenCvSharp.Point p = hull.At <OpenCvSharp.Point>(i);
                        if (y_x_max >= y_x_min)
                        {
                            if (p.Y > y_x_min)
                            {
                                p.X = x_max;
                                p.Y = y_x_max;
                            }
                        }
                        else
                        {
                            if (p.Y > y_x_max)
                            {
                                p.X = x_min;
                                p.Y = y_x_min;
                            }
                        }
                    }
                }

                //////////////////////////////////////////////////////////////

                Cv2.FillConvexPoly(img_mask, hull, Scalar.White, LineTypes.AntiAlias, 0);

                //2013/11/3 Add erode function
                if (erode > 0)
                {
                    for (i = 0; i < erode; i++)
                    {
                        Cv2.Erode(img_mask, img_mask, null);
                    }
                }

                //Calc length and area of img_mask -> use for fancy shape diamonds
                //Cv.FindContours(img_mask, storage1, out contours, CvContour.SizeOf, ContourRetrieval.External, ContourChain.ApproxSimple);
                //Cv.FIndCOntours overwrites img_mask, need to use copy image
                //IplImage img_mask_copy = Cv.Clone(img_mask);
                //Cv2.Copy(img_mask, img_mask_copy);
                Mat   hierarchy = new Mat();
                Mat[] contours;
                img_mask.CopyTo(img_mask_copy);
                Cv2.FindContours(img_mask_copy, out contours, hierarchy, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
                //Cv.ReleaseImage(img_mask_copy);

                mask_length = Cv2.ArcLength(contours[0], true);
                mask_area   = Math.Abs(Cv2.ContourArea(contours[0]));
                //Cv.ClearSeq(contours);
            }
            else
            {
                mask_length = 0.0;
                mask_area   = 0.0;
            }

            //Memory release
            //Cv.ReleaseImage(img_gray);
            //Cv.ReleaseImage(img_canny);
            //Cv.ReleaseImage(img_mask_copy);
            //Cv.ClearSeq(points);
            //Cv.ReleaseMemStorage(storage);
            //Cv.ReleaseMemStorage(storage1);

            //if the diamond is out of croped image, do not calc color values
            if (x_min == 0 | x_max == (img.Width - 1) | y_min == 0 | y_max == (img.Height - 1))
            {
                return(dst);
            }

            //img_mask.SaveImage(@"P:\Projects\DustDetection\TestSamples\gColorFancyImages\temp\image_mask_hiroshi.jpg");

            if (mask_length > 0)
            {
                dst = BitmapConverter.ToBitmap(img_mask);
            }

            return(dst);
        }
        /// <summary>
        /// 对外函数,用于识别一个图片 detect one frame
        /// </summary>
        /// <param name="frame">一个彩色图片; a RGB picture</param>
        /// <returns>一个ArrayList,包含结果;results of detections</returns>
        public ArrayList detect(Mat frame)
        {
            Mat gray = new Mat();

            Cv2.CvtColor(frame, gray, ColorConversionCodes.RGB2GRAY);
            Mat dst   = new Mat();
            Mat gauss = new Mat();

            Cv2.GaussianBlur(gray, gauss, new Size(3, 3), this.sigma);
            switch (this.threshold)
            {
            case "canny":
                Cv2.Canny(gauss, dst, 150, 400, 3);
                break;

            case "adaptive":
                Cv2.AdaptiveThreshold(gauss, dst, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.BinaryInv, 9, 5);
                break;

            default:
                Cv2.Canny(gauss, dst, 150, 400, 3);
                break;
            }

            Point[][]        contours;
            HierarchyIndex[] hierarchy;
            Cv2.FindContours(dst, out contours, out hierarchy, OpenCvSharp.RetrievalModes.CComp, ContourApproximationModes.ApproxSimple, null);
            if (this.debug == true)
            {
                Mat copyimg = new Mat();
                frame.CopyTo(copyimg);
                copyimg.DrawContours(contours, -1, new Scalar(0, 255, 0));
                using (new Window("contours image", copyimg)) {
                    Cv2.WaitKey();
                }
            }
            ArrayList hulls = new ArrayList();
            ArrayList quads = new ArrayList();

            for (int i = 0; i < contours.Length; i++)
            {
                var contour = contours[i];//取出多边形 get polygon
                if (contour.Length >= 4 && hierarchy[i].Previous < 0)
                {
                    var area = Cv2.ContourArea(contour); //求多边形面积 get contour`s area
                    if (area > this.minarea)
                    {
                        var hull = Cv2.ConvexHull(contour); //求出凸包 get hull
                        if ((area / Cv2.ContourArea(hull)) > 0.8)
                        {
                            hulls.Add(hull);
                            var quad = Cv2.ApproxPolyDP(hull, 9, true); //根据凸包计算出四边形 get quad
                            if (quad.Length == 4)
                            {
                                var areaqued = Cv2.ContourArea(quad);
                                var areahull = Cv2.ContourArea(hull);
                                if (areaqued / areahull > 0.8 && areahull >= areaqued)
                                {
                                    quads.Add(quad);
                                }
                            }
                        }
                    }
                }
            }
            if (this.debug == true)
            {
                Mat copyimg = new Mat();
                frame.CopyTo(copyimg);
                foreach (Point[] item in quads)
                {
                    Point[][] temp = new Point[1][];
                    temp[0] = item;
                    copyimg.DrawContours(temp, -1, new Scalar(0, 255, 0));
                }
                using (new Window("contours image", copyimg)) {
                    Cv2.WaitKey();
                }
                Console.WriteLine("quads count" + quads.Count);
            }

            ArrayList detections  = new ArrayList();
            ArrayList points      = new ArrayList();
            ArrayList whitepoints = new ArrayList();

            //进行点quad点的提取
            foreach (Point[] quad in quads)
            {
                int       dd         = this.tagfamily.getBlackBorder() * 2 + this.tagfamily.getEdge();
                ArrayList blackvalue = new ArrayList();
                ArrayList whitevalue = new ArrayList();

                for (int iy = 0; iy < dd; iy++)
                {
                    for (int ix = 0; ix < dd; ix++)
                    {
                        double x           = (ix + 0.5) / (dd * 1.0);
                        double y           = (iy + 0.5) / (dd * 1.0);
                        var    polatepoint = _interpolate(quad, new Point2d(x, y));
                        points.Add(polatepoint);
                        var value = gray.At <byte> (polatepoint.X, polatepoint.Y);
                        if ((iy == 0 || iy == dd - 1) || (ix == 0 || ix == dd - 1))
                        {
                            blackvalue.Add(value);
                        }
                        else if ((iy == 1 || iy == dd - 2) || (ix == 1 || ix == dd - 2))
                        {
                            whitevalue.Add(value);
                        }
                        else
                        {
                            continue;
                        }
                    }
                }
                long tagcode   = 0;
                var  threshold = 0.5 * (_average(blackvalue) + _average(whitevalue));
                for (int iy = 0; iy < dd; iy++)
                {
                    for (int ix = 0; ix < dd; ix++)
                    {
                        if ((iy == 0 || iy == dd - 1) || (ix == 0 || ix == dd - 1))
                        {
                            continue;
                        }
                        double newx      = (ix + 0.5) / dd * 1.0;
                        double newy      = (iy + 0.5) / dd * 1.0;
                        Point  point     = _interpolate(quad, new Point2d(newx, newy));
                        int    grayvalue = gray.At <byte> (point.X, point.Y);
                        tagcode = tagcode << 1;
                        if (grayvalue > threshold)
                        {
                            tagcode |= 1;
                            whitepoints.Add(point);
                        }
                    }
                }

                TagDetection decoderesult = this.tagfamily._decode(tagcode);
                if (decoderesult.good == true)
                {
                    decoderesult.addPoint(quad);
                    detections.Add(decoderesult);
                }
            }
            if (this.debug == true)
            {
                Mat copyimg = new Mat();
                frame.CopyTo(copyimg);
                foreach (Point item in points)
                {
                    Point tpoint = new Point(item.Y, item.X);
                    copyimg.Circle(tpoint, 1, new Scalar(0, 0, 255));
                }
                using (new Window("quad", copyimg)) {
                    Cv2.WaitKey();
                }

                Mat copyimg2 = new Mat();
                frame.CopyTo(copyimg2);
                foreach (Point item in whitepoints)
                {
                    Point tpoint = new Point(item.Y, item.X);
                    copyimg2.Circle(tpoint, 1, new Scalar(0, 0, 255));
                }
                using (new Window("quad", copyimg2)) {
                    Cv2.WaitKey();
                }
            }
            return(detections);
        }
Exemple #27
0
        private Bitmap CreateObjectMaskNew(Bitmap image, out Mat image_mask,
                                           out double mask_length, out double mask_area, out double mask_width, out double mask_height,
                                           out double mask_pvheight, double kThresh, double hThresh, double canny1, double canny2,
                                           out Mat image_mask_spc, out double mask2_area, int brightAreaThreshold = -1, int darkAreaThreshold = -1)
        {
            Bitmap dst = null;

            image_mask     = null;
            image_mask_spc = null;
            mask_length    = mask_area = mask_width = mask_height = mask_pvheight = mask2_area = 0;

            try
            {
                Mat src = BitmapConverter.ToMat(image);

                Mat src_kirsch = BitmapConverter.ToMat(image.KirschFilter());

                Mat kirsch_gray = new Mat();
                Cv2.CvtColor(src_kirsch, kirsch_gray, ColorConversionCodes.RGB2GRAY);

                Mat kirsch_threshold = new Mat();
                Cv2.Threshold(kirsch_gray, kirsch_threshold, kThresh, 255, ThresholdTypes.Binary);


                Mat[] contours;
                List <OpenCvSharp.Point> hierarchy;
                List <Mat> hulls;
                Mat        morph_element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(2, 2), new OpenCvSharp.Point(1, 1));

                #region morphology

                Mat kirsch_threshold_copy = new Mat();
                kirsch_threshold.CopyTo(kirsch_threshold_copy);

                int hullCount = 0, numLoops = 0;
                do
                {
                    numLoops++;

                    Mat kirsch_morph = kirsch_threshold_copy.MorphologyEx(MorphTypes.Gradient, morph_element);

                    hierarchy = new List <OpenCvSharp.Point>();
                    Cv2.FindContours(kirsch_morph, out contours, OutputArray.Create(hierarchy),
                                     RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));

                    hulls = new List <Mat>();
                    for (int j = 0; j < contours.Length; j++)
                    {
                        Mat hull = new Mat();
                        Cv2.ConvexHull(contours[j], hull);
                        hulls.Add(hull);
                    }

                    Mat drawing = Mat.Zeros(src.Size(), MatType.CV_8UC1);
                    Cv2.DrawContours(drawing, hulls, -1, Scalar.White);

                    if (hulls.Count != hullCount && numLoops < 100)
                    {
                        hullCount             = hulls.Count;
                        kirsch_threshold_copy = drawing;
                    }
                    else
                    {
                        break;
                    }
                } while (true);

                #endregion

                if (numLoops >= 100)
                {
                    throw new Exception("Could not find hull");
                }

                #region bestHull
                //try and filter out dust near to stone

                double largestArea = hulls.Max(m => Cv2.ContourArea(m));
                var    bestHulls   = hulls.Where(m => Cv2.ContourArea(m) == largestArea).ToList();

                Mat hulls_mask = Mat.Zeros(src.Size(), MatType.CV_8UC1);
                Cv2.DrawContours(hulls_mask, bestHulls, -1, Scalar.White, -1);

                //hulls_mask is the convex hull of outline, now look for clefts
                Cv2.Threshold(kirsch_gray, kirsch_threshold, hThresh, 255, ThresholdTypes.Binary);
                Mat kirsch_mask = Mat.Zeros(kirsch_threshold.Size(), kirsch_threshold.Type());
                kirsch_threshold.CopyTo(kirsch_mask, hulls_mask);

                Mat kirsch_mask_canny = new Mat();
                Cv2.Canny(kirsch_mask, kirsch_mask_canny, canny1, canny2, 3);

                morph_element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(5, 5), new OpenCvSharp.Point(2, 2));
                Mat kirsch_filled = new Mat();
                Cv2.Dilate(kirsch_mask_canny, kirsch_filled, morph_element);
                Cv2.Dilate(kirsch_filled, kirsch_filled, morph_element);
                Cv2.Erode(kirsch_filled, kirsch_filled, morph_element);
                Cv2.Erode(kirsch_filled, kirsch_filled, morph_element);

                hierarchy = new List <OpenCvSharp.Point>();;
                Cv2.FindContours(kirsch_filled, out contours, OutputArray.Create(hierarchy),
                                 RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));

                #endregion

                hulls_mask = Mat.Zeros(src.Size(), MatType.CV_8UC1);
                Cv2.DrawContours(hulls_mask, contours, -1, Scalar.White, -1);

                Cv2.Erode(hulls_mask, hulls_mask, morph_element);
                Cv2.Erode(hulls_mask, hulls_mask, morph_element);

                image_mask = hulls_mask;

                //remove bright areas
                if ((brightAreaThreshold > -1) || (darkAreaThreshold > -1))
                {
                    Mat src_mask       = new Mat();
                    Mat hulls_mask_spc = hulls_mask.Clone();
                    src.CopyTo(src_mask, hulls_mask_spc);
                    Mat gray = new Mat();

                    Cv2.CvtColor(src_mask, gray, ColorConversionCodes.BGR2GRAY);
                    if (brightAreaThreshold > -1)
                    {
                        Mat bright = new Mat();
                        Cv2.Threshold(gray, bright, brightAreaThreshold, 255, ThresholdTypes.BinaryInv);
                        Cv2.ImWrite(@"C:\gColorFancy\Image\bright.jpg", bright);
                        Mat t = new Mat();
                        hulls_mask_spc.CopyTo(t, bright);
                        hulls_mask_spc = t.Clone();
                    }
                    if (darkAreaThreshold > -1)
                    {
                        Mat dark = new Mat();
                        Cv2.Threshold(gray, dark, darkAreaThreshold, 255, ThresholdTypes.Binary);
                        Cv2.ImWrite(@"C:\gColorFancy\Image\dark.jpg", dark);
                        Mat t = new Mat();
                        hulls_mask_spc.CopyTo(t, dark);
                        hulls_mask_spc = t.Clone();
                    }

                    image_mask_spc = hulls_mask_spc;

                    var hierarchy2 = new List <OpenCvSharp.Point>();;
                    Cv2.FindContours(hulls_mask_spc, out contours, OutputArray.Create(hierarchy2),
                                     RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));

                    largestArea = contours.Max(m => Cv2.ContourArea(m));
                    Mat finalHullSpc = contours.Where(m => Cv2.ContourArea(m) == largestArea).ToList()[0];

                    if (ConvexHullOnMask)
                    {
                        Mat hull = new Mat();
                        Cv2.ConvexHull(finalHullSpc, hull);
                        Mat polySpc = new Mat();
                        Cv2.ApproxPolyDP(hull, polySpc, 3, true);
                        mask2_area = Cv2.ContourArea(polySpc);
                    }
                    else
                    {
                        mask2_area = largestArea;
                    }
                }
                ///////////////////////////

                hierarchy = new List <OpenCvSharp.Point>();;
                Cv2.FindContours(hulls_mask, out contours, OutputArray.Create(hierarchy),
                                 RetrievalModes.External, ContourApproximationModes.ApproxSimple, new OpenCvSharp.Point(0, 0));

                largestArea = contours.Max(m => Cv2.ContourArea(m));
                Mat finalHull = contours.Where(m => Cv2.ContourArea(m) == largestArea).ToList()[0];

                if (ConvexHullOnMask)
                {
                    var hull = new Mat();
                    Cv2.ConvexHull(finalHull, hull);
                    finalHull = hull;
                }
                List <Mat> finalHulls = new List <Mat>();
                finalHulls.Add(finalHull);
                Cv2.DrawContours(src, finalHulls, -1, new Scalar(128, 0, 128, 255), 3);

                #region bounding

                Mat poly = new Mat();
                Cv2.ApproxPolyDP(finalHull, poly, 3, true);
                Rect boundaryRect = Cv2.BoundingRect(poly);
                mask_width  = boundaryRect.Width;
                mask_height = boundaryRect.Height;
                if (ConvexHullOnMask)
                {
                    mask_area = Cv2.ContourArea(poly);
                }
                else
                {
                    mask_area = largestArea;
                }
                mask_length = Cv2.ArcLength(finalHull, true);

                List <OpenCvSharp.Point> finalPoints = new List <OpenCvSharp.Point>();
                int m1Count            = (finalHull.Rows % 2 > 0) ? finalHull.Rows + 1 : finalHull.Rows;
                OpenCvSharp.Point[] p1 = new OpenCvSharp.Point[m1Count];
                finalHull.GetArray(0, 0, p1);
                Array.Resize(ref p1, finalHull.Rows);
                finalPoints.AddRange(p1.ToList());

                double y_min   = boundaryRect.Bottom;
                double y_x_min = finalPoints.Where(p => p.X == boundaryRect.Left).ToList()[0].Y;
                double y_x_max = finalPoints.Where(p => p.X == boundaryRect.Right).ToList()[0].Y;

                mask_pvheight = ((double)y_x_max + (double)y_x_min) / 2 - (double)y_min;

                #endregion

                //dst = BitmapConverter.ToBitmap(src);
                using (var ms = src.ToMemoryStream())
                {
                    dst = (Bitmap)Image.FromStream(ms);
                }

                try
                {
                    if (saveMaskDataPath.Length > 0)
                    {
                        //StringBuilder sb = new StringBuilder();
                        //sb.AppendLine("mask_length,mask_area,mask_width,mask_height,mask_pvheight");
                        //sb.AppendLine(mask_length + "," + mask_area + "," + mask_width + "," + mask_height + "," + mask_pvheight);
                        image_mask.SaveImage(saveMaskDataPath + @"\image_mask.jpg");
                        if (image_mask_spc != null)
                        {
                            image_mask_spc.SaveImage(saveMaskDataPath + @"\image_mask_spc.jpg");
                        }
                        BitmapConverter.ToMat(image).SaveImage(saveMaskDataPath + @"\src.jpg");
                        //File.WriteAllText(saveMaskDataPath + @"\mask_vals.csv", sb.ToString());
                        //File.AppendAllText(saveMaskDataPath + @"\exception.txt", DateTime.Now + ":" + av.Message);
                        //File.AppendAllText(saveMaskDataPath + @"\exception.txt", DateTime.Now + ":" + av.StackTrace);
                        //File.AppendAllText(saveMaskDataPath + @"\exception.txt", DateTime.Now + ":" + av.Source);
                    }
                }
                catch
                {
                }
            }
            catch (Exception ex)
            {
                dst = null;
            }

            return(dst);
        }
        public ExtractRectangleAction()
        {
            Name   = "Extract rectangle";
            Action = (input) =>
            {
                input.FindContours(out var contours, out var hierarchy, RetrievalModes.List, ContourApproximationModes.ApproxNone);

                var m = input.CvtColor(ColorConversionCodes.GRAY2BGR);

                var imageArea = m.Width * m.Height;

                var allContoursSelect = from contour in contours
                                        let boundingRect = Cv2.MinAreaRect(contour)
                                                           let boundingRectArea = boundingRect.Size.Width * boundingRect.Size.Height
                                                                                  let convexHull = Cv2.ConvexHull(contour)
                                                                                                   let hullArea = Cv2.ContourArea(convexHull)
                                                                                                                  let contourPercentage                                                        = hullArea / boundingRectArea
                                                                                                                                                                let wtoh                       = boundingRect.Size.Width / boundingRect.Size.Height
                                                                                                                                                                                      let htow = boundingRect.Size.Height / boundingRect.Size.Width
                                                                                                                                                                                                 select new
                {
                    boundingRect.Center,
                    Wtoh         = wtoh,
                    Htow         = htow,
                    ImageArea    = hullArea / imageArea,
                    BoundingRect = boundingRect,
                    Pixels       = boundingRect.Size.Width * boundingRect.Size.Height,
                    ContourPerc  = contourPercentage,
                    ConvexHull   = convexHull,
                    HullArea     = hullArea,
                    RectArea     = boundingRect.Size.Width * boundingRect.Size.Height
                };

                if (this.EnableFilters)
                {
                    allContoursSelect = allContoursSelect
                                        .Where(i => i.Pixels >= this.MinRectPixels && i.Pixels <= this.MaxRectPixels &&
                                               i.ContourPerc >= this.MinRectShapeArea &&
                                               (Math.Abs(i.Wtoh - this.WidthToHeightRatio) <= this.WidthToHeightRatioDeviation ||
                                                Math.Abs(i.Htow - this.WidthToHeightRatio) <= this.WidthToHeightRatioDeviation));

                    switch (this.SelectionMode)
                    {
                    case RectangleSelectionMode.MostNorth:
                        allContoursSelect = allContoursSelect.OrderByDescending(c => c.Center.Y);
                        break;

                    case RectangleSelectionMode.MostSouth:
                        allContoursSelect = allContoursSelect.OrderBy(c => c.Center.Y);
                        break;

                    case RectangleSelectionMode.MostEast:
                        allContoursSelect = allContoursSelect.OrderByDescending(c => c.Center.Y);
                        break;

                    case RectangleSelectionMode.MostWest:
                        allContoursSelect = allContoursSelect.OrderBy(c => c.Center.Y);
                        break;

                    case RectangleSelectionMode.BiggestBoundingRectArea:
                        allContoursSelect = allContoursSelect.OrderBy(c => c.RectArea);
                        break;

                    case RectangleSelectionMode.SmallestBoundingRectArea:
                        allContoursSelect = allContoursSelect.OrderByDescending(c => c.RectArea);
                        break;

                    case RectangleSelectionMode.BiggestConvexHullArea:
                        allContoursSelect = allContoursSelect.OrderBy(c => c.HullArea);
                        break;

                    case RectangleSelectionMode.SmallestConvexHullArea:
                        allContoursSelect = allContoursSelect.OrderByDescending(c => c.HullArea);
                        break;

                    default:
                        throw new Exception($"Missing mode handling: {this.SelectionMode}");
                    }
                }

                var allContours = allContoursSelect
                                  .ToArray();

                this.Status       = $"{allContours.Length} found ({contours.Length} unfiltered)";
                this.DetectedRect = string.Empty;

                if (allContours.Length == 0)
                {
                    throw new Exception("No contours found that match the criteria.");
                }

                var contourOfInterest = allContours.Last();
                this.DetectedRect = $"ImageArea: {contourOfInterest.ImageArea}\n" +
                                    $"Pixels: {contourOfInterest.Pixels:F0}\n" +
                                    $"RectShapeArea: {contourOfInterest.ContourPerc:P2}\n" +
                                    $"WidthToHeight: {contourOfInterest.Wtoh}\n" +
                                    $"HeightToWidth: {contourOfInterest.Htow}";

                if (!this.Crop)
                {
                    // Draw contours.
                    foreach (var contour in allContours)
                    {
                        var color = contour == contourOfInterest ? Scalar.Green : Scalar.Red;

                        m.Polylines(new[] { contour.BoundingRect.Points().Select(p => new Point(p.X, p.Y)) }, isClosed: true, color);
                        m.DrawContours(new[] { contour.ConvexHull }, 0, color);
                    }

                    input.Dispose();
                    return(m);
                }

                // Crop!
                var angle = contourOfInterest.BoundingRect.Angle;
                var size  = contourOfInterest.BoundingRect.Size;
                if (angle < -45)
                {
                    angle += 90.0f;
                    size   = new Size2f(size.Height, size.Width);
                }

                var rotMatrix = Cv2.GetRotationMatrix2D(contourOfInterest.BoundingRect.Center, angle, 1.0);
                var warped    = m.WarpAffine(rotMatrix, m.Size(), InterpolationFlags.Cubic);
                input.Dispose();
                m.Dispose();
                return(warped.GetRectSubPix(new Size(size.Width, size.Height), contourOfInterest.BoundingRect.Center));
            };
        }
        private static Vec4i[] GetDefects(OpenCvSharp.Point[] contour)
        {
            var hull = Cv2.ConvexHull(contour);

            return(Cv2.ConvexityDefects(contour, PointsToIndex(contour, hull)));
        }
        private void LoadImage(string filePath)
        {
            //using (Mat mat1 = Mat.Zeros(2048, 1536, MatType.CV_8UC1))
            //using (Mat mat2 = Mat.Zeros(2048, 1536, MatType.CV_8UC1))
            //using (var intersection = new Mat(2048, 1536, MatType.CV_8UC1))
            //using (var union = new Mat(2048, 1536, MatType.CV_8UC1))
            //{
            //    mat1.FillPoly(new[] { new[]
            //    {
            //        new Point(565, 267),
            //        new Point(1210, 207),
            //        new Point(1275, 1720),
            //        new Point(568, 1688)
            //    } }, Scalar.All(255));
            //    AddImage(mat1);
            //    mat2.FillPoly(new[] { new[]
            //    {
            //        new Point(564, 268),
            //        new Point(1208, 208),
            //        new Point(1272, 1716),
            //        new Point(572, 1688)
            //    } }, Scalar.All(255));
            //    AddImage(mat2);
            //    Cv2.BitwiseAnd(mat1, mat2, intersection);
            //    int intersectionPixels = Cv2.CountNonZero(intersection);
            //    AddImage(intersection);
            //    Cv2.BitwiseOr(mat1, mat2, union);
            //    int unionPixels = Cv2.CountNonZero(union);
            //    AddImage(union);
            //    double iou = (double) intersectionPixels / unionPixels;
            //}
            //
            //return;

            try
            {
                using (Mat image = new Mat(filePath))
                    using (Mat resized = image.Resize(GetTargetSize(image.Size()))) //Scale the image, so we are working with something consistent
                    {
                        AddImage(resized);

                        using (Mat gray = resized.CvtColor(ColorConversionCodes.BGRA2GRAY))                            //Convert to gray scale since we don't want the color data
                            using (Mat blur = gray.GaussianBlur(new Size(5, 5), 0, borderType: BorderTypes.Replicate)) //Smooth the image to eliminate noise
                                using (Mat autoCanny = blur.AutoCanny(0.75))                                           //Apply canny edge filter to find edges
                                {
                                    AddImage(blur);
                                    AddImage(autoCanny);

                                    Point[][] contours = autoCanny.FindContoursAsArray(RetrievalModes.List, ContourApproximationModes.ApproxSimple);

                                    //Just get the external hull of the contours
                                    for (int i = 0; i < contours.Length; i++)
                                    {
                                        contours[i] = Cv2.ConvexHull(contours[i]);
                                    }

                                    //Draw all of the found polygons. This is just for reference
                                    using (Mat allFound = resized.Clone())
                                    {
                                        for (int i = 0; i < contours.Length; i++)
                                        {
                                            Cv2.DrawContours(allFound, contours, i, Scalar.RandomColor(), 2);
                                        }
                                        AddImage(allFound);
                                    }

                                    //Find the largest polygons that four corners
                                    var found = (from contour in contours
                                                 let permimiter = Cv2.ArcLength(contour, true)
                                                                  let approx = Cv2.ApproxPolyDP(contour, 0.02 * permimiter, true)
                                                                               where IsValidRectangle(approx, 0.2)
                                                                               let area = Cv2.ContourArea(contour)
                                                                                          orderby area descending            //We are looking for the biggest thing
                                                                                          select contour).Take(3).ToArray(); //Grabbing three just for comparison

                                    //Colors the found polygons Green->Yellow->Red to indicate best matches.
                                    for (int i = found.Length - 1; i >= 0; i--)
                                    {
                                        Scalar color;
                                        switch (i)
                                        {
                                        case 0:
                                            color = Scalar.Green;
                                            break;

                                        case 1:
                                            color = Scalar.Yellow;
                                            break;

                                        case 2:
                                            color = Scalar.Red;
                                            break;

                                        default:
                                            color = Scalar.RandomColor();
                                            break;
                                        }

                                        resized.DrawContours(found, i, color, 3);
                                    }
                                    AddImage(resized);
                                }
                    }
            }
            catch (Exception e)
            {
                Debug.WriteLine(e.ToString());
            }

            bool IsValidRectangle(Point[] contour, double minimum)
            {
                if (contour.Length != 4)
                {
                    return(false);
                }
                double side1 = GetLength(contour[0], contour[1]);
                double side2 = GetLength(contour[1], contour[2]);
                double side3 = GetLength(contour[2], contour[3]);
                double side4 = GetLength(contour[3], contour[0]);

                if (Math.Abs(side1 - side3) / Math.Max(side1, side3) > minimum)
                {
                    return(false);
                }
                if (Math.Abs(side2 - side4) / Math.Max(side2, side4) > minimum)
                {
                    return(false);
                }

                return(true);

                double GetLength(Point p1, Point p2) => Math.Abs(p1.X - p2.X) + Math.Abs(p1.Y - p2.Y);
            }

            Size GetTargetSize(Size size, int longSize = 512)
            {
                if (size.Width > size.Height)
                {
                    return(new Size(longSize, (int)(longSize * (double)size.Height / size.Width)));
                }
                return(new Size((int)(longSize * (double)size.Width / size.Height), longSize));
            }
        }