public List <GameObject> FindByWhiteMask(Mat src, Mat preview) { // thresh = cv2.inRange(image, (210, 210, 210), (255, 255, 255)) //var mask_white = new Mat(); //Cv2.InRange(src, new Scalar(150, 150, 150), new Scalar(255, 255, 255), mask_white); Cv2.InRange(src, new Scalar(210, 210, 210), new Scalar(255, 255, 255), mask_white); // cv2.imshow("edges", thresh) //_, cnts, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) //thresh.DrawContours() Mat[] contours = null; Mat dst = new Mat(); //Cv2.FindContours(edged, out contours, new Mat(), RetrievalModes.List, ContourApproximationModes.ApproxSimple); Cv2.FindContours(mask_white, out contours, dst, RetrievalModes.List, ContourApproximationModes.ApproxNone); //Cv2.ImShow("dst", dst); //if (config.Preview == 4) Cv2.ImShow("thresh", mask_white); //dst.Release(); //thresh.Release(); List <GameObject> list_result = new List <GameObject>(); if (contours != null) { Console.WriteLine("contours.size= " + contours.Length); for (int i = 0; i < contours.Length; i++) { Mat contour = contours[i]; double area = Cv2.ContourArea(contour); // if the contour is not sufficiently large, ignore it if (area < 9) { continue; } double peri = Cv2.ArcLength(contour, true); Mat approx = contour.ApproxPolyDP(0.04 * peri, true); // Point p2f= approx.Get<Point>(0, 1); // Console.WriteLine("p2x= " + p2f.X + ", " + p2f.Y); // Console.WriteLine("cols= "+ approx.Cols + ", rows= " + approx.Rows); // // Point[] points_approx = new Point[approx.Rows]; // for (int j = 0; j < approx.Rows; j++) { // points_approx[j] = approx.Get<Point>(0, j); // } if (config.Preview > 0) { Cv2.Polylines(preview, approx, true, new Scalar(0, 255, 0), 1); } //Rect rect = Cv2.BoundingRect(contour); //Cv2.Rectangle(preview, rect, new Scalar(0, 255, 0)); // https://csharp.hotexamples.com/examples/OpenCvSharp/RotatedRect/-/php-rotatedrect-class-examples.html // https://stackoverflow.com/questions/43342199/draw-rotated-rectangle-in-opencv-c RotatedRect rrect = Cv2.MinAreaRect(contour); Point2f[] points2f = rrect.Points(); //points2f = ImUtils.OrderPoints(points2f); if (config.Preview > 0) { ImUtils.PolylinesPoints2f(preview, points2f, Colors.green); } // https://www.pyimagesearch.com/2016/03/21/ordering-coordinates-clockwise-with-python-and-opencv/ // # loop over the original points and draw them //for (int i1 = 0; i1 < points2f.Length; i1++) { // Cv2.Circle(preview, new Point((int)points2f[i1].X, (int)points2f[i1].Y), 5, colors[i1], -1); //} double h = ImUtils.Distance(points2f[0], points2f[1]); double w = ImUtils.Distance(points2f[0], points2f[3]); double ratio = h / w; if (h > w) { ratio = w / h; } // compute the center of the contour Moments m = Cv2.Moments(contour); Point pt_center = new Point((int)(m.M10 / m.M00), (int)(m.M01 / m.M00)); if (this.config.Preview > 0) { Cv2.Circle(preview, pt_center, 2, new Scalar(255, 0, 0), -1); } //Console.Write(", " + Cv2.ContourArea(contour)); // if (Cv2.ContourArea(contour) > max_val && Cv2.ContourArea(contour) < 408) // { // max_val = Cv2.ContourArea(contour); // max_i = i; // //Cv2.DrawContours(image, contours, i, new Scalar(255, 128, 128), 5); // } //Cv2.DrawContours(image, contours, i, new Scalar(255, 128, 128), 5); // https://metanit.com/sharp/tutorial/7.5.php //Console.WriteLine($"object: area={(int)area,5}, pts_count={approx.Rows,3}, ratio= {ratio:f4}, center={pt_center} "); GameObject obj = new GameObject(contour, area, approx, pt_center, ratio, rrect); if (ratio > 0.05) { obj.type = GameObject.ObjectType.unknown; list_result.Add(obj); } else { //obj.type = GameObject.ObjectType.noise; } } dst.Release(); //mask_white.Release(); } //if (configPreview!=0) { // Cv2.DrawContours(preview, contours, -1, new Scalar(0, 255, 0), 2); //} return(list_result); }
//public Mat mask_white = null; // за первый проход наполняю с сортировкой по X // за второй ищу цифры по высоте // https://answers.opencv.org/question/74777/how-to-use-approxpolydp-to-close-contours/ public void PreProcessByWhiteMask(Mat src, Mat preview, Mat mask_white) { // количество гиганских объектов int big_count = 0; int max_y = 0; //Point pt_tmp = new Point(0, 0); Mat[] contours = null; Mat dst = new Mat(); //Cv2.FindContours(edged, out contours, new Mat(), RetrievalModes.List, ContourApproximationModes.ApproxSimple); Cv2.FindContours(mask_white, out contours, dst, RetrievalModes.External, ContourApproximationModes.ApproxNone); if (contours != null) { Console.WriteLine($"contours.size={contours.Length} "); for (int i = 0; i < contours.Length; i++) { Mat contour = contours[i]; double area = Cv2.ContourArea(contour); // if the contour is not sufficiently large, ignore it if (area < 1) { continue; } double peri = Cv2.ArcLength(contour, true); Mat points_approx = contour.ApproxPolyDP(0.04 * peri, true); // Vec2i pt_top= points_approx.Get<Vec2i>(0, 0), pt_bottom = points_approx.Get<Vec2i>(0, 0); // for (int y = 0; y < points_approx.Height; y++) // { // for (int x = 0; x < points_approx.Width; x++) // { // Vec2i pt = points_approx.Get<Vec2i>(y, x); // //if (i==3) { // //Console.WriteLine("" + y + "=" + pt.Item0 + ", "+ pt.Item1+ " "); // if (this.config.Preview > 0) Cv2.Circle(preview, new Point(pt.Item0, pt.Item1), 3, new Scalar(0, 255, 0), -1); // //} // // if (pt.Item1 < pt_top.Item1) { pt_top = pt; } // if (pt.Item1 > pt_bottom.Item1) { pt_bottom = pt; } // } // } // Point[] points_approx = new Point[approx.Rows]; // for (int j = 0; j < approx.Rows; j++) { // points_approx[j] = approx.Get<Point>(0, j); // } // if (config.Preview > 0) Cv2.Polylines(preview, points_approx, true, new Scalar(0, 0, 255), 4); //Rect rect = Cv2.BoundingRect(contour); //Cv2.Rectangle(preview, rect, new Scalar(0, 255, 0)); // https://csharp.hotexamples.com/examples/OpenCvSharp/RotatedRect/-/php-rotatedrect-class-examples.html // https://stackoverflow.com/questions/43342199/draw-rotated-rectangle-in-opencv-c RotatedRect rrect = Cv2.MinAreaRect(contour); // скопировано из ImUtils Point2f[] rrpoints = ImUtils.OrderPoints(rrect.Points()); Point2f tl = rrpoints[0]; Point2f tr = rrpoints[1]; Point2f br = rrpoints[2]; Point2f bl = rrpoints[3]; //if (config.Preview > 0) ImUtils.PolylinesPoints2f(preview, rrpoints); double widthA = ImUtils.Distance(br, bl); double widthB = ImUtils.Distance(tr, tl); double width = (widthA > widthB ? widthA : widthB); double heightA = ImUtils.Distance(tr, br); double heightB = ImUtils.Distance(tl, bl); double height = (heightA > heightB ? heightA : heightB); double ratio = height / width; if (height > width) { ratio = width / height; } int top = (int)tl.Y; if (top > (int)tr.Y) { top = (int)tr.Y; } int bottom = (int)bl.Y; if (bottom < (int)br.Y) { bottom = (int)br.Y; } // compute the center of the contour Moments m = Cv2.Moments(contour); Point pt_center = new Point((int)(m.M10 / m.M00), (int)(m.M01 / m.M00)); //if (this.config.Preview > 0) Cv2.Circle(preview, pt_center, 2, new Scalar(255, 0, 0), -1); // ищу большие буквы - конец игры if (top > 15 && top < 125 && bottom > 300 && bottom < 390 && height > 180 && area > 1000) { // рисую голубым большую цифру rgb(0, 255, 255) new Scalar(51, 0, 153) //if (this.config.Preview > 0) Cv2.Circle(preview, pt_center, 2, new Scalar(255, 255, 0), -1); //if (config.Preview > 0) ImUtils.PolylinesPoints2f(preview, rrpoints, colors[1]); if (config.Preview > 0) { Cv2.DrawContours(preview, contours, i, Colors.red, 2); } //if (config.Preview > 0) Cv2.Polylines(preview, points_approx, true, colors[0], 2); big_count++; } // проверяю цифры if ( //&& obj.center.Y < Program.screenCenter.Y // должен быть в верхней половине экрана bottom < 240 && // должен быть в верхней половине экрана points_approx.Rows >= 2 && // у него должно быть более 2 точек area > 4 && area < 1000 && // должен быть относительно крупный ratio > 0.05 && height > 20 && height < 41 && width > 5 && width < 126 ) { //if (config.Preview > 0) Cv2.Polylines(preview, points_approx, true, colors[1], 2); if (config.Preview > 0) { ImUtils.PolylinesPoints2f(preview, rrpoints, Colors.green2); } if (config.Preview > 0) { Cv2.DrawContours(preview, contours, i, Colors.green2, 2); } GameObject obj = new GameObject(contour, area, points_approx, pt_center, ratio, rrect); list_digits.Add(obj); } // ищу игрока if (player != null && // игнорирую проход до поворота top > screenCenter.Y && pt_center.Y > max_y && // объект должен быть снизу других pt_center.Y > screenCenter.Y && // должен быть в нижней половине экрана points_approx.Rows > 2 && // у него должно быть более 2 точек area > 100 && // должен быть относительно крупный ratio > 0.19 ) { max_y = pt_center.Y; player.contour = contour; player.area = area; player.points_approx = points_approx; // точки контура player.center = pt_center; //player.ratio; // width / height to skip lines //Console.WriteLine("PLAYER" + i); } // https://metanit.com/sharp/tutorial/7.5.php //Console.WriteLine($"object{i}: area={(int)area,5}, pts_count={points_approx.Rows,3}, ratio= {ratio:f4}, top={top}, bottom={bottom}, h={height}, w= {width}, center={pt_center} "); // https://www.pyimagesearch.com/2016/03/21/ordering-coordinates-clockwise-with-python-and-opencv/ // # loop over the original points and draw them //for (int i1 = 0; i1 < points2f.Length; i1++) { // Cv2.Circle(preview, new Point((int)points2f[i1].X, (int)points2f[i1].Y), 2, colors[i1], -1); //} //double h = ImUtils.Distance(points2f[0], points2f[1]); //double w = ImUtils.Distance(points2f[0], points2f[3]); } //mask_white.Release(); } //Cv2.WaitKey(5000); //if (configPreview!=0) { // Cv2.DrawContours(preview, contours, -1, new Scalar(0, 255, 0), 2); //} dst.Release(); if (big_count >= 2) { isGameOver = true; } if (max_y == 0) { player = null; } Console.WriteLine($"big_count={big_count}, isGameOver={isGameOver} "); }