Ejemplo n.º 1
0
        public void ProcessOCR(Mat thresh, GameObject obj)
        {
            if (charMat == null)
            {
                return;                 // "";
            }
            // Apply a Perspective Transform & Threshold
            // apply the four point transform to obtain a top-down
            // view of the original image
            //Mat warped = ImUtils.FourPointTransformFast(thresh, obj.orderedPts, obj.rrect_w, obj.rrect_h);
            Mat warped = ImUtils.FourPointTransformFast(thresh, obj.orderedPts, 18, 36);

            // https://docs.opencv.org/3.0-beta/doc/py_tutorials/py_imgproc/py_template_matching/py_template_matching.html
            // All the 6 methods for comparison in a list
            // methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
            // 'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
            //Cv2.ImShow("warped", warped);
            //Cv2.WaitKey(250);

            //Console.Write("RES: ");
            double score      = -1;
            double score_prev = -1;
            int    imax       = -1;

            for (int i = 0; i < charMat.Length; i++)
            {
                Mat result = new Mat();
                Cv2.MatchTemplate(warped, charMat[i], result, TemplateMatchModes.CCoeff);
                double minVal, maxVal;
                Cv2.MinMaxLoc(result, out minVal, out maxVal);
                //Console.Write($", {(int)maxVal}");
                if (maxVal > score)
                {
                    score_prev = score;
                    score      = maxVal;
                    imax       = i;
                }
            }
            //Console.WriteLine("       ");
            if (imax != -1)
            //Console.WriteLine($"MAX_SCORE = {score}, MAX_SCORE_PREV = {score_prev}, INDEX = {charValues[imax]}   ");

            //if (score > 3000000)
            {
                //Cv2.ImShow("ocr111", warped);
                //Cv2.WaitKey(500);
            }

            warped.Release();
            if (score > 3000000)
            {
                ocrTimerN     = ocrTimerN * 10 + imax;
                ocrTimerText += charValues[imax];
                //return charValues[imax];
            }
            //else return "";
        }
Ejemplo n.º 2
0
        // возвращает ближайшую к ptB точку
        public static Point NearestPoint(Mat points, Point ptB)
        {
            double[] dists = new double[points.Rows];
            int      i_min = 0;

            for (int i = 0; i < points.Rows; i++)
            {
                dists[i] = ImUtils.Distance(points.Get <Point>(0, i), ptB);
                if (dists[i] < dists[i_min])
                {
                    i_min = i;
                }
            }

            return(points.Get <Point>(0, i_min));
        }
Ejemplo n.º 3
0
        // необходимо, чтобы в списке были только цифры и они уже были отсортированы
        public void FindTimer2(Mat thresh, List <GameObject> list_digits)
        {
            ocrTimerText = "";
            ocrTimerN    = 0;

            // FAST алгоритм проверяю только по размеру
            if (list_digits.Count > 0 && list_digits.Count < 8)
            {
                // OCR
                for (int i = 0; i < list_digits.Count; i++)
                {
                    GameObject obj  = list_digits[i];
                    Point2f[]  rect = ImUtils.OrderPoints(obj.rrect.Points());
                    obj.orderedPts = rect;
                    ProcessOCR(thresh, obj);
                }
            }
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        //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}   ");
        }
Ejemplo n.º 6
0
        public void FindTimer(Mat thresh, List <GameObject> list_obj)
        {
            ocrTimerText = "";
            List <int> list_index = new List <int>(); // список индексов потенциальных цифр
            GameObject obj;

            for (int i = 0; i < list_obj.Count; i++)
            {
                obj = list_obj[i];
                if (obj.type != GameObject.ObjectType.unknown)
                {
                    continue;
                }
                //Console.WriteLine($"CENTER={obj.center}, AREA={obj.area}");

                if (obj.type == GameObject.ObjectType.unknown
                    //&& obj.center.Y < Program.screenCenter.Y // должен быть в верхней половине экрана
                    && obj.center.Y < 240 && // должен быть в верхней половине экрана
                    obj.points_approx.Rows > 2 &&  // у него должно быть более 2 точек
                    obj.area > 4                   // должен быть относительно крупный
                    )
                {
                    // скопировано из ImUtils
                    Point2f[] rect = ImUtils.OrderPoints(obj.rrect.Points());
                    Point2f   tl   = rect[0];
                    Point2f   tr   = rect[1];
                    Point2f   br   = rect[2];
                    Point2f   bl   = rect[3];

                    double widthA = ImUtils.Distance(br, bl);
                    double widthB = ImUtils.Distance(tr, tl);
                    int    width  = (int)(widthA > widthB ? widthA : widthB);

                    double heightA = ImUtils.Distance(tr, br);
                    double heightB = ImUtils.Distance(tl, bl);
                    int    height  = (int)(heightA > heightB ? heightA : heightB);

                    obj.orderedPts = rect;
                    obj.rrect_w    = width;
                    obj.rrect_h    = height;

                    //Console.WriteLine($"CENTER={obj.center}, W={width}, H={height}");
                    //if (height > 20 && height < 40 && width > 5 && width < 20)
                    {
                        list_index.Add(i);
                    }
                }
            }

            // FAST алгоритм проверяю только по размеру
            if (list_index.Count > 0 && list_index.Count < 36)
            {
                // сортировка
                int xmin = list_obj[list_index[0]].center.X;
                int imin = 0;
                for (int i1 = 0; i1 < list_index.Count - 1; i1++)
                {
                    imin = i1;
                    xmin = list_obj[list_index[i1]].center.X;
                    for (int i2 = i1 + 1; i2 < list_index.Count; i2++)
                    {
                        if (xmin > list_obj[list_index[i2]].center.X)
                        {
                            imin = i2;
                            xmin = list_obj[list_index[i2]].center.X;
                        }
                    }
                    if (imin != i1)
                    {
                        xmin             = list_index[i1];
                        list_index[i1]   = list_index[imin];
                        list_index[imin] = xmin;
                    }
                }

                // OCR
                for (int i = 0; i < list_index.Count; i++)
                {
                    //string txt= ProcessOCR(thresh, list_obj[list_index[i]]);
                    //if (txt.Length > 0) {
                    //    ocrTimerText += txt;
                    //    list_obj[list_index[i]].type = GameObject.ObjectType.timer;
                    //}
                }
            }
        }