Ejemplo n.º 1
0
 /// <summary>
 ///  Find total squared error between quads
 /// </summary>
 private float QuadTotalSquaredError(GridQuad x, GridQuad y)
 {
     return
             Math.Abs(x.p[0].X - y.p[0].X) + Math.Abs(x.p[0].Y - y.p[0].Y) +
             Math.Abs(x.p[1].X - y.p[1].X) + Math.Abs(x.p[1].Y - y.p[1].Y) +
             Math.Abs(x.p[2].X - y.p[2].X) + Math.Abs(x.p[2].Y - y.p[2].Y) +
             Math.Abs(x.p[3].X - y.p[3].X) + Math.Abs(x.p[3].Y - y.p[3].Y);
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Find the quad most similar to quad, or null if no similar quads are found
        /// </summary>
        private GridQuad GetMostSimilarQuad(GridQuad quad, GridQuad[] quadsToChase)
        {
            GridQuad mostSimilarQuad = null;
            float mostSimilarityValue = 20f;

            foreach(GridQuad testQuad in quadsToChase)
            {
                if (QuadTotalSquaredError(testQuad, quad) < mostSimilarityValue)
                {
                    mostSimilarQuad = testQuad;
                    mostSimilarityValue = QuadTotalSquaredError(testQuad, quad);
                }
            }

            return mostSimilarQuad;
        }
Ejemplo n.º 3
0
        private GridQuad[] FilterOutBadQuads(List<GridQuad> quads)
        {
            const float MAXAREA = 400f * 300f / 64f;
            const float MINAREA = (400f * 300f / 64f) / 5f;

            const float MAXWIDTH = 400f / 8f;
            const float MINWIDTH = (400f / 8f) / 1.7f;

            const float MAXHEIGHT = 300f / 8f;
            const float MINHEIGHT = (300f / 8f) / 3f;

            var bs1 = quads.Where(x => x.Area < MAXAREA && x.Area > MINAREA);
            var bs2 = bs1.Where(x => x.Width < MAXWIDTH && x.Width > MINWIDTH);
            var bs3 = bs2.Where(x => x.Height < MAXHEIGHT && x.Height > MINHEIGHT);
            var bs4 = bs3.Where(x => x.Height < x.Width * 1.7f && x.Width < x.Height * 3f);
            var bs5 = bs4.OrderBy(x => x.Area).ToArray();

            float minDiffToBox64Ago = 99999f;
            int indexAtMinDiff = 999;

            if(bs5.Length <= 64) throw new ApplicationException(
                string.Format("Found {0} quads, of which only {1} are plausible.", bs1.Count(), bs5.Length));

            for (int i = 64; i < bs5.Length; i++)
            {
                float diffToBox64Ago = bs5[i].Area - bs5[i - 64].Area;
                if (diffToBox64Ago < minDiffToBox64Ago)
                {
                    indexAtMinDiff = i;
                    minDiffToBox64Ago = diffToBox64Ago;
                }
            }

            float widthMaxError = 6f;
            float heightMaxError = 5f;

            medianBox = bs5[indexAtMinDiff - 32];
            var bsfinal = bs5.Where(x => x.Width > medianBox.Width - widthMaxError && x.Width < medianBox.Width + widthMaxError &&
                                         x.Height > medianBox.Height - heightMaxError && x.Height < medianBox.Height + heightMaxError)
                .OrderBy(b => b.Area)
                .ToArray();

            return bsfinal;
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Returns a quad the same as quad but proportionally in direction dir.
        /// </summary>
        private GridQuad EstimateQuadPosition(GridQuad quad, Dir dir)
        {
            PointF p0 = new PointF(quad.p[0].X, quad.p[0].Y);
            PointF p1 = new PointF(quad.p[1].X, quad.p[1].Y);
            PointF p2 = new PointF(quad.p[2].X, quad.p[2].Y);
            PointF p3 = new PointF(quad.p[3].X, quad.p[3].Y);

            if (dir == Dir.S)
            {
                p0.Y += quad.Height;
                p1.Y += quad.Height;
                p2.Y += quad.Height;
                p3.Y += quad.Height;
            }
            else if (dir == Dir.N)
            {
                p0.Y -= quad.Height;
                p1.Y -= quad.Height;
                p2.Y -= quad.Height;
                p3.Y -= quad.Height;
            }
            else if (dir == Dir.E)
            {
                p0.X += quad.Width;
                p1.X += quad.Width;
                p2.X += quad.Width;
                p3.X += quad.Width;
            }
            else if (dir == Dir.W)
            {
                p0.X -= quad.Width;
                p1.X -= quad.Width;
                p2.X -= quad.Width;
                p3.X -= quad.Width;
            }

            return new GridQuad(new PointF[] {p0, p1, p2, p3});
        }
Ejemplo n.º 5
0
        private GridQuad[,] ChaseThe64Quads(GridQuad[] quadsToChase)
        {
            List<GridQuad> quadTrain = new List<GridQuad>();
            GridQuad nextQuad = medianBox;

            // Go to the top right through the quads

            while (true)
            {
                GridQuad guessBox = EstimateQuadPosition(nextQuad, Dir.W);
                GridQuad guessQuad = GetMostSimilarQuad(guessBox, quadsToChase);

                if (guessQuad == null) break;
                nextQuad = guessQuad;
            }
            while (true)
            {
                GridQuad guessBox = EstimateQuadPosition(nextQuad, Dir.N);
                GridQuad guessQuad = GetMostSimilarQuad(guessBox, quadsToChase);

                if (guessQuad == null) break;
                nextQuad = guessQuad;
            }

            // We're now at the top right.  We can now iterate across the 8x8 grid to find all the 64 quads

            GridQuad[,] grid = new GridQuad[8, 8];

            grid[0, 0] = nextQuad;

            for (int row = 0; row < 8; row++)
            {
                if (row > 0)
                {
                    GridQuad guessBox = EstimateQuadPosition(grid[row - 1, 0], Dir.S);
                    nextQuad = GetMostSimilarQuad(guessBox, quadsToChase);
                    if (nextQuad == null) break;

                    grid[row, 0] = nextQuad;
                }

                for (int column = 1; column < 8; column++)
                {
                    if (nextQuad == null) break;
                    GridQuad guessBox = EstimateQuadPosition(nextQuad, Dir.E);
                    nextQuad = GetMostSimilarQuad(guessBox, quadsToChase);
                    grid[row, column] = nextQuad;
                }
            }

            return grid;
        }
Ejemplo n.º 6
0
        public void FindBoard()
        {
            // Convert the image to grayscale and filter out the noise
            GrayImage = BoardImage.Convert<Gray, Byte>().PyrDown().PyrUp();

            // Do canny filter
            CannyImage = GrayImage.Canny(170.0, 50.0);

            // Do Edge finder
            Lines = CannyImage.HoughLinesBinary(
                1, //Distance resolution in pixel-related units
                Math.PI / 360.0, //Angle resolution measured in radians.
                50, //threshold
                30, //min Line width
                20 //gap between lines
                )[0]; //Get the lines from the first channel

            // Find board
            BoardFinder boardLineFinder1 = new BoardFinder();
            boardLineFinder1.BuildLineSets(Lines, Lines, Math.PI / 10.0, Math.PI / 40.0);

            // Make lines image
            Image<Bgr, Byte> linesImage = BoardImage.CopyBlank();
            foreach (LineSegment2D line in Lines)
                linesImage.Draw(line, new Bgr(System.Drawing.Color.Gray), 1);
            foreach (LineSegment2D line in boardLineFinder1.HorizLines)
                linesImage.Draw(line, new Bgr(System.Drawing.Color.Red), 1);
            foreach (LineSegment2D line in boardLineFinder1.VertLines)
                linesImage.Draw(line, new Bgr(System.Drawing.Color.Green), 1);
            LinesImage = linesImage;

            // Remove perspective from image
            RemovePerspective(boardLineFinder1.GetBoardRegression());

            // Convert the warped image to grayscale and filter out the noise
            WarpedGrayImage = WarpedImage.Convert<Gray, Byte>().PyrDown().PyrUp();

            // Do canny filter on warped image
            WarpedCannyImage = WarpedGrayImage.Canny(160, 90);

            // Do Edge finder on warped image
            WarpedVertLines = WarpedCannyImage.HoughLinesBinary(
                1, //Distance resolution in pixel-related units
                Math.PI / 360, //Angle resolution measured in radians.
                30, //threshold
                40, //min Line width
                20 //gap between lines
                )[0]; //Get the lines from the first channel
            WarpedHorizLines = WarpedCannyImage.HoughLinesBinary(
                1, //Distance resolution in pixel-related units
                Math.PI / 360, //Angle resolution measured in radians.
                60, //threshold
                70, //min Line width
                40 //gap between lines
                )[0]; //Get the lines from the first channel

            // Find board
            BoardFinder boardLineFinder2 = new BoardFinder();
            boardLineFinder2.BuildLineSets(WarpedVertLines, WarpedHorizLines, Math.PI / 60.0, Math.PI / 60.0);

            // Make lines image
            Image<Bgr, Byte> warpedLinesImage = WarpedImage.CopyBlank();
            Image<Gray, Byte> warpedGridLinesImage = WarpedGrayImage.CopyBlank();

            //foreach (LineSegment2D line in WarpedVertLines.Union(WarpedHorizLines))
            //    warpedLinesImage.Draw(line, new Bgr(System.Drawing.Color.Gray), 1);
            foreach (LineSegment2D line in boardLineFinder2.HorizLines)
            {
                warpedGridLinesImage.Draw(line, new Gray(100), 1);
                warpedLinesImage.Draw(line, new Bgr(System.Drawing.Color.Red), 1);
            }
            foreach (LineSegment2D line in boardLineFinder2.VertLines)
            {
                warpedGridLinesImage.Draw(line, new Gray(100), 1);
                warpedLinesImage.Draw(line, new Bgr(System.Drawing.Color.Green), 1);
            }
            WarpedLinesImage = warpedLinesImage;

            GridQuadsImage = WarpedImage.Copy();
            BoardImageWithBoxes = BoardImage.Copy();

            try
            {
                // Find grid quads

                List<GridQuad> quads = FindBoardQuads(boardLineFinder2);
                GridQuad[] quadsToChase = FilterOutBadQuads(quads);
                GridQuad[,] quadsToDraw = ChaseThe64Quads(quadsToChase);

                for (int i = 0; i < 8; i++)
                    for (int j = 0; j < 8; j++)
                    {
                        if (quadsToDraw[i, j] != null)
                            DrawRectangle(GridQuadsImage, quadsToDraw[i, j].p, new Bgr(120, 190, 20), 2);
                    }

                DrawRectangle(GridQuadsImage, medianBox.p, new Bgr(220, 250, 20), 2);

                // Set up return array

                Quads = new GridQuad[8, 8];

                for (int i = 0; i < 8; i++)
                    for (int j = 0; j < 8; j++)
                    {
                        if (quadsToDraw[i, j] != null)
                        {
                            Quads[i, j] = new GridQuad(quadsToDraw[i, j].p);
                            m_InverseWarpMatrix.ProjectPoints(Quads[i, j].p);
                            DrawRectangle(BoardImageWithBoxes, Quads[i, j].p, new Bgr(120, 190, 20), 2);
                        }
                    }

            }
            catch { }
        }