Exemple #1
0
        private static List <PointF> Crop(Test test, ref byte[,] image, ref byte[,] imgBarCode, int searchSize)
        {
            List <PointF> calPoints = CalibrationPoints(test, image, searchSize);

            if (calPoints.Count > 0)
            {
                PointF leftDown = new PointF(calPoints[0].X, calPoints[0].Y);
                PointF rightUp  = new PointF(calPoints[calPoints.Count - 1].X, calPoints[calPoints.Count - 1].Y);

                RectangleF cropRectangle = new RectangleF(leftDown.X, rightUp.Y, rightUp.X - leftDown.X, leftDown.Y - rightUp.Y);



                float pixelsPerBlockWidth  = cropRectangle.Width / (test.Paper.Blocks.X + .5f);
                float pixelsPerBlockHeight = cropRectangle.Height / (test.Paper.Blocks.Y + 1);

                cropRectangle.X      -= pixelsPerBlockWidth / 2;
                cropRectangle.Y      -= pixelsPerBlockHeight / 2;
                cropRectangle.Width  -= pixelsPerBlockWidth / 2;
                cropRectangle.Height -= pixelsPerBlockHeight;

                imgBarCode = Processing.Crop(image, new RectangleF(
                                                 calPoints[0].X + (float)(.6 * pixelsPerBlockWidth),
                                                 cropRectangle.Bottom + (float)(.15 * pixelsPerBlockWidth),
                                                 calPoints[1].X - calPoints[0].X - (float)(1.2 * pixelsPerBlockWidth),
                                                 pixelsPerBlockHeight + (float)(.6 * pixelsPerBlockWidth)
                                                 ));
                image = Processing.Crop(image, cropRectangle);
                for (int i = 0; i < calPoints.Count; i++)
                {
                    calPoints[i] = new PointF(calPoints[i].X - leftDown.X + (pixelsPerBlockWidth / 2), calPoints[i].Y - rightUp.Y + (pixelsPerBlockHeight / 2));
                }
            }
            return(calPoints);
        }
Exemple #2
0
        private static List <PointF> Rotate(Test test, ref byte[,] image, int searchSize)
        {
            List <PointF> calPoints = CalibrationPoints(test, image, searchSize);

            if (calPoints.Count == test.Paper.CalibrationCircles.X + test.Paper.CalibrationCircles.Y - 1)
            {
                var corner    = CornerPoints(test, calPoints);
                var leftDown  = corner[0];
                var rightUp   = corner[1];
                var rightDown = corner[2];

                double rotLong = Math.Atan((rightDown.X - rightUp.X) / (rightUp.Y - rightDown.Y));
                if (rightUp.Y > rightDown.Y)
                {
                    rotLong += Math.PI;
                }
                if (rotLong < 0)
                {
                    rotLong += 2 * Math.PI;
                }
                else if (rotLong > 2 * Math.PI)
                {
                    rotLong -= 2 * Math.PI;
                }

                double rotShort = Math.Atan((leftDown.Y - rightDown.Y) / (leftDown.X - rightDown.X));
                if (leftDown.X > rightDown.X)
                {
                    rotShort += Math.PI;
                }
                if (rotShort < 0)
                {
                    rotShort += 2 * Math.PI;
                }
                else if (rotShort > 2 * Math.PI)
                {
                    rotShort -= 2 * Math.PI;
                }
                double rotation = AverageAngle(rotLong, rotShort);

                Size oldSize = new Size(image.GetLength(0), image.GetLength(1));
                image = Processing.Rotate(image, -rotation);

                // Crop after rotation is not necessary but makes following fase of exact cropping slightly faster (easier to find calPoints). However, might be wrong when rotation is too high.
                if (Math.Abs(rotation) < 1)
                {
                    image = Processing.Crop(image, new Rectangle((image.GetLength(0) - oldSize.Width) / 2, (image.GetLength(1) - oldSize.Height) / 2, oldSize.Width, oldSize.Height));
                }
            }
            return(calPoints);
        }
Exemple #3
0
        // Persumed to be rotated correctly (but not yet cropped)
        public static byte[] Read(byte[,] imageData)
        {
            byte[,] array = new byte[19, 4];

            if (imageData != null)
            {
                if (imageData.GetLength(0) > 0 && imageData.GetLength(1) > 0)
                {
                    imageData = Processing.FloatToByte(Processing.Gaussian(imageData));
                    imageData = Processing.Binarize(imageData, 200);

                    int minBlack = Math.Min(4, Math.Min(imageData.GetLength(0) / 19, imageData.GetLength(1) / 4));

                    Point p1 = new Point(-1, -1);
                    Point p2 = new Point(-1, -1);

                    for (int i = 0; i < (imageData.GetLength(0) / 2); i++)
                    {
                        int sum1 = 0;
                        int sum2 = 0;
                        for (int j = 0; j < imageData.GetLength(1); j++)
                        {
                            sum1 += imageData[i, j] > 0 ? 0 : 1;
                            sum2 += imageData[imageData.GetLength(0) - i - 1, j] > 0 ? 0 : 1;
                        }
                        if (p1.X == -1 && sum1 >= minBlack)
                        {
                            p1.X = i;
                        }
                        if (p2.X == -1 && sum2 >= minBlack)
                        {
                            p2.X = imageData.GetLength(0) - i - 1;
                        }
                        if (p1.X != -1 && p2.X != -1)
                        {
                            break;
                        }
                    }

                    for (int j = 0; j < (imageData.GetLength(1) / 2); j++)
                    {
                        int sum1 = 0;
                        int sum2 = 0;
                        for (int i = 0; i < imageData.GetLength(0); i++)
                        {
                            sum1 += imageData[i, j] > 0 ? 0 : 1;
                            sum2 += imageData[i, imageData.GetLength(1) - j - 1] > 0 ? 0 : 1;
                        }
                        if (p1.Y == -1 && sum1 >= minBlack)
                        {
                            p1.Y = j;
                        }
                        if (p2.Y == -1 && sum2 >= minBlack)
                        {
                            p2.Y = imageData.GetLength(1) - j - 1;
                        }
                        if (p1.Y != -1 && p2.Y != -1)
                        {
                            break;
                        }
                    }

                    if (p1.X != -1 && p1.Y != -1 && p2.X != -1 && p2.Y != -1)
                    {
                        imageData = Processing.Crop(imageData, new Rectangle(p1.X, p1.Y, p2.X - p1.X + 1, p2.Y - p1.Y + 1));

                        int blockWidth  = (int)Math.Floor((double)imageData.GetLength(0) / 19);
                        int blockHeight = (int)Math.Floor((double)imageData.GetLength(1) / 4);

                        int newWidth  = blockWidth * 19;
                        int newHeight = blockHeight * 4;

                        imageData = Processing.Resize(imageData, newWidth, newHeight);
                        int threshold = (blockWidth * blockHeight) / 2;

                        for (int j = 0; j < 4; j++)
                        {
                            for (int i = 0; i < 19; i++)
                            {
                                double sum = 0;
                                for (int k = 0; k < blockHeight; k++)
                                {
                                    for (int l = 0; l < blockWidth; l++)
                                    {
                                        sum += (int)imageData[(i * blockWidth) + l, (j * blockHeight) + k] > 1 ? 1 : 0;
                                    }
                                }
                                array[i, j] = sum < threshold ? (byte)0 : (byte)1;
                            }
                        }
                    }
                    else
                    {
                        Logger.LogLow("Could not crop barcode.");
                    }
                }
            }
            return(ReadFrom2DArray(array));
        }
Exemple #4
0
        public void CalculateInitialItemAltsCheckedState(int pageNumber, float sure, float doubt)
        {
            if (ItemAltsCheckedState == null)
            {
                ItemAltsCheckedState = new ItemCheckedState[Program.Test.Paper.Blocks.X, Program.Test.Paper.Blocks.Y];
            }
            var itemAlternativeOnLocation = Program.Test.Pages[pageNumber].ItemAlternativeOnLocation();

            for (int i = 0; i < Program.Test.Paper.Blocks.X; i++)
            {
                for (int j = 0; j < Program.Test.Paper.Blocks.Y; j++)
                {
                    if (itemAlternativeOnLocation[i, j])
                    {
                        var crop = Processing.Crop(ScannedImage, ItemAltRectangle(i, j));
                        int w    = crop.GetLength(0);
                        int h    = crop.GetLength(1);

                        double val = 0;
                        Single w2  = (Single)(w - 1) / 2;
                        Single h2  = (Single)(h - 1) / 2;
                        Single max = w2 * w2 * h2 * h2;
                        double old = 0;
                        double nw  = 0;
                        for (int x = 0; x < w; x++)
                        {
                            for (int y = 0; y < h; y++)
                            {
                                val += crop[x, y] * (max - ((x - w2) * (x - w2) * (y - h2) * (y - h2)));;
                                old += crop[x, y];
                                nw  += crop[x, y] * (max - ((x - w2) * (x - w2) * (y - h2) * (y - h2)));
                            }
                        }
                        val /= 2.55f * ((w * h * max) - (
                                            (w * (w - 1) * (w + 1) / 12) *
                                            (h * (h - 1) * (h + 1) / 12)
                                            ));
                        ColorDistribution.Add(val);
                        ItemCheckedState state = ItemCheckedState.Unknown;

                        if (val < sure)
                        {
                            state = ItemCheckedState.Checked;
                        }
                        else if (val < doubt)
                        {
                            state = ItemCheckedState.Doubt;
                        }
                        else
                        {
                            state = ItemCheckedState.Unchecked;
                        }
                        ItemAltsCheckedState[i, j] = state;
                    }
                    else
                    {
                        ItemAltsCheckedState[i, j] = ItemCheckedState.Unavailable;
                    }
                }
            }
        }
Exemple #5
0
        private static List <EllipticalFit> FindPointsByCanny(int numberToFind,
                                                              int currentCross, byte[,] cannyData, int searchSize, ref int searchShift, ref int attempt, ref bool ellipsesValid)
        {
            searchSize = (int)(Math.Round((double)searchSize / 2) * 2); // has to be even
            int shiftX     = searchShift == 1 || searchShift == 3 ? (int)(searchSize / 4) : 0;
            int shiftY     = searchShift == 2 || searchShift == 3 ? (int)(searchSize / 4) : 0;
            int searchJump = searchSize / 2;
            int w          = cannyData.GetLength(0);
            int h          = cannyData.GetLength(1);

            // Create a list with areas to look => cannot be reused due to (even very small) differences in size of scans
            List <Point> searchPoints = new List <Point>();

            for (int x = shiftX; x < w; x += searchJump)
            {
                int searchX = x;
                if (x + searchSize >= w)
                {
                    searchX = w - searchSize;
                    x       = w;
                }
                for (int y = shiftY; y < h; y += searchJump)
                {
                    int searchY = y;
                    if (y + searchSize >= h)
                    {
                        searchY = h - searchSize;
                        y       = h;
                    }
                    searchPoints.Add(new Point(searchX, searchY));
                }
            }

            // Assumed that the paper is oriented right => faster
            searchPoints.Sort(delegate(Point p1, Point p2) { return(Math.Min(w - p1.X, h - p1.Y).CompareTo(Math.Min(w - p2.X, h - p2.Y))); });

            /*
             *
             *
             *
             *
             ********
             */

#if DEBUG
            var img = Processing.ByteToImage(cannyData);
#endif

            // Crop small rectangles from canny
            List <EllipticalFit> ellipseList = new List <EllipticalFit>();
            for (int i = 0; i < searchPoints.Count; i++)
            {
                // Fit an ellipse
                EllipticalFit fit = null;
                RectangleF    boundingRectangle = new RectangleF();
                try
                {
                    var searchRectangle = new Rectangle(searchPoints[i].X, searchPoints[i].Y, searchSize, searchSize);
                    fit = new EllipticalFit(cannyData, 255, searchRectangle);

#if DEBUG
                    using (Graphics g = Graphics.FromImage(img))
                    {
                        g.DrawRectangle(new Pen(Color.Yellow), searchRectangle);
                    }
#endif

                    // Empty search areas are already ignored in fit
                    boundingRectangle = fit.BoundingRectangle();

                    // If a valid ellipse is found
                    if (!double.IsNaN(boundingRectangle.X) && boundingRectangle.X > 0 &&
                        !double.IsNaN(boundingRectangle.Y) && boundingRectangle.Y > 0 &&
                        boundingRectangle.Width < searchSize && boundingRectangle.Height < searchSize &&
                        boundingRectangle.Width > .25 * searchSize && boundingRectangle.Height > .25 * searchSize &&
                        boundingRectangle.Width > 15 && boundingRectangle.Height > 15)
                    {
                        var    observed   = Processing.Crop(cannyData, searchRectangle);
                        var    moments    = Processing.Moments(observed);
                        double squareness = Math.Min((double)boundingRectangle.Width, (double)boundingRectangle.Height) / Math.Max((double)boundingRectangle.Width, (double)boundingRectangle.Height);

                        // Ellipse has to be more or less round, based on enough points and have some variance in each direction
                        if (squareness > .9 && moments[0] >= 8 && moments[3] > 0 && moments[4] > 0)
                        {
                            // Fill the ellipse with floodfill
                            var observedFilled = Processing.FloodFill(observed, 1, new PointF(
                                                                          boundingRectangle.X - searchRectangle.X + (boundingRectangle.Width / 2),
                                                                          boundingRectangle.Y - searchRectangle.Y + (boundingRectangle.Height / 2)));

                            var momentsFilled = Processing.Moments(observedFilled);

                            if (momentsFilled[1] > (boundingRectangle.Width / 2) && momentsFilled[1] < searchRectangle.Width - (boundingRectangle.Width / 2) &&
                                momentsFilled[2] > (boundingRectangle.Height / 2) && momentsFilled[2] < searchRectangle.Height - (boundingRectangle.Height / 2))
                            {
                                // Create a white circle of similar size
                                var expectedFilled = Processing.WhiteCircle(observedFilled.GetLength(0), observedFilled.GetLength(1), new RectangleF(
                                                                                boundingRectangle.X - searchRectangle.X, boundingRectangle.Y - searchRectangle.Y, boundingRectangle.Width, boundingRectangle.Height));

                                // Compare the result of the floodfill with the white circle
                                fit.DifferenceFromCircle = Processing.AverageDifference(observedFilled, expectedFilled);

                                // Only if ellipse was closed they will be similar
                                if (fit.DifferenceFromCircle < .1)
                                {
                                    ellipseList = AddWithoutOverlap(ellipseList, fit);
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogLow(ex.Message);
                }
                if (ellipseList.Count == numberToFind)
                {
                    break;
                }
            }

            ellipsesValid = EllipsePointsAreValid(Program.Test, ellipseList); // Count and colinearity have to be correct

            /*
             * using (Graphics g = Graphics.FromImage(img))
             * {
             *  for (int i = 0; i < ellipseList.Count; i++)
             *  {
             *      g.DrawLine(new Pen(Color.Blue, 2), ellipseList[i].MidPoint().X - 15, ellipseList[i].MidPoint().Y, ellipseList[i].MidPoint().X + 15, ellipseList[i].MidPoint().Y);
             *      g.DrawLine(new Pen(Color.Blue, 2), ellipseList[i].MidPoint().X, ellipseList[i].MidPoint().Y - 15, ellipseList[i].MidPoint().X, ellipseList[i].MidPoint().Y + 15);
             *  }
             * }
             * img.Save(Program.UserSettings.defaultDirectory + "\\img\\"
             + Convert.ToString(DateTime.Now.Minute)
             + " - " + Convert.ToString(DateTime.Now.Second)
             + " - " + Convert.ToString(DateTime.Now.Millisecond)
             + " - " + currentCross
             + " - " + searchSize
             + " - " + searchShift
             + " - " + attempt
             + " - " + ellipseList.Count
             + " - " + ellipsesValid
             + ".bmp");
             */

            Logger.LogHigh(
                "Attempt:\t" + attempt +
                "\tCanny:\t" + currentCross +
                "\tSearch size:\t" + searchSize +
                "\tSearch shift:\t" + searchShift +
                "\tEllipses found:\t" + ellipseList.Count +
                "\tEllipses valid:\t" + ellipsesValid);

            // If not all ellipses are found, retry with shifted searcharea
            if (ellipseList.Count != numberToFind && searchShift < 3)
            {
                searchShift++;
                attempt++;
                ellipseList = FindPointsByCanny(numberToFind, currentCross, cannyData, searchSize, ref searchShift, ref attempt, ref ellipsesValid);
            }

            return(ellipseList);
        }