public DataMatrixExtraction(Bitmap sourceImage, FinderPatternPair fpp) { this.fpp = fpp; PointF p1 = fpp.p1.X < fpp.p2.X ? fpp.p1.ToF() : fpp.p2.ToF(); PointF p2 = fpp.p1.X < fpp.p2.X ? fpp.p2.ToF() : fpp.p1.ToF(); PointF vect = PointOps.Mult(PointOps.Sub(p2, p1), 0.1f); float unit = (float)PointOps.Distance(vect); PointF normX = PointOps.Normalize(vect); angX = Math.Atan2(normX.Y, normX.X); double angY = angX - Math.PI / 2; PointF normY = new PointF((float)Math.Cos(angY), (float)Math.Sin(angY)); topLeft = PointOps.Add(p1, PointOps.Add(PointOps.Mult(normX, unit), PointOps.Mult(normY, unit))); bottomLeft = PointOps.Add(p1, PointOps.Sub(PointOps.Mult(normX, unit), PointOps.Mult(normY, unit))); topRight = PointOps.Add(p1, PointOps.Add(PointOps.Mult(normX, unit * 9), PointOps.Mult(normY, unit))); bottomRight = PointOps.Add(p1, PointOps.Sub(PointOps.Mult(normX, unit * 9), PointOps.Mult(normY, unit))); rotatedMatrix = new Bitmap((int)Math.Ceiling(unit * 8), (int)Math.Ceiling(unit * 2), PixelFormat.Format32bppArgb); Graphics rotG = Graphics.FromImage(rotatedMatrix); rotG.RotateTransform((float)(-angX * 180 / Math.PI)); float diagonal = (float)PointOps.Distance(p1, p2); rotG.DrawImage( sourceImage, new RectangleF(-diagonal, -diagonal, diagonal * 2, diagonal * 2), new RectangleF(topLeft.X - diagonal, topLeft.Y - diagonal, diagonal * 2, diagonal * 2), GraphicsUnit.Pixel); rotG.Dispose(); int[] cellSum = new int[DataMatrixDrawer.rowCount * DataMatrixDrawer.columnCount]; unsafe { BitmapData bd = rotatedMatrix.LockBits(ImageLockMode.ReadOnly); byte * ptr = (byte *)bd.Scan0.ToPointer(); for (int y = 0; y < rotatedMatrix.Height; y++) { for (int x = 0; x < rotatedMatrix.Width; x++) { int cx = (int)Math.Floor((float)x * DataMatrixDrawer.columnCount / rotatedMatrix.Width); int cy = (int)Math.Floor((float)y * DataMatrixDrawer.rowCount / rotatedMatrix.Height); cellSum[cy * DataMatrixDrawer.columnCount + cx] += *ptr; ptr += 4; } } rotatedMatrix.UnlockBits(bd); } double threshold = ValueClustering.DivThreshold(cellSum); extractedData = new bool[DataMatrixDrawer.rowCount * DataMatrixDrawer.columnCount]; for (int q = 0; q < DataMatrixDrawer.rowCount * DataMatrixDrawer.columnCount; q++) { extractedData[q] = cellSum[q] < threshold; } }
private static List <Point3> LocatePeaks(int[,,] hough, int patternCount, List <Point3> foundPeaks, int minPatternSize) { int max = int.MinValue; int maxX = 0; int maxY = 0; int maxZ = 0; for (int z = 0; z < hough.GetLength(0); z++) { for (int y = 0; y < hough.GetLength(1); y++) { for (int x = 0; x < hough.GetLength(2); x++) { Point3 neighbourPeak = foundPeaks.Find(p => PointOps.Distance(x, y, p.X, p.Y) < minPatternSize); if (neighbourPeak == null && hough[z, y, x] > max) { max = hough[z, y, x]; maxX = x; maxY = y; maxZ = z; } } } } foundPeaks.Add(new Point3(maxX, maxY, maxZ)); if (patternCount == 1) { return(foundPeaks); } else { return(LocatePeaks(hough, patternCount - 1, foundPeaks, minPatternSize)); } }
static void StressTest() { int patternRadius = 60; int minPatternRadius = 50; int maxPatternRadius = 70; int imgSize = 3000; int N = 100; int success = 0; int failure = 0; Random r = new Random(); double time = 0; for (int q = 0; q < N; q++) { uint codeValue = (uint)r.Next(); Bitmap codeImage = ARCodeUtil.BuildCode(codeValue, patternRadius); int diag = (int)PointOps.Distance(0, 0, codeImage.Width, codeImage.Height); Point codeLocation = new Point( r.Next(imgSize - diag) + diag / 2, r.Next(imgSize - diag) + diag / 2); Bitmap sourceImage = new Bitmap(imgSize, imgSize, PixelFormat.Format32bppArgb); Graphics g = Graphics.FromImage(sourceImage); g.FillRectangle(Brushes.White, new Rectangle(0, 0, sourceImage.Width, sourceImage.Height)); g.TranslateTransform(codeLocation.X, codeLocation.Y); g.RotateTransform((float)((r.NextDouble() - 0.5) * 2)); g.TranslateTransform(-codeLocation.X, -codeLocation.Y); Point codeDrawLocation = new Point( codeLocation.X - codeImage.Width / 2, codeLocation.Y - codeImage.Height / 2); g.DrawImage(codeImage, codeDrawLocation); g.Dispose(); Bitmap noisedImage = GetTestNoiseFilter().Apply(sourceImage); DateTime stt = DateTime.Now; Option <uint> extractedValue = ARCodeUtil.ExtractCode(noisedImage, minPatternRadius, maxPatternRadius); DateTime end = DateTime.Now; time += (end - stt).TotalMilliseconds; if (extractedValue.NonEmpty() && extractedValue.Get() == codeValue) { success++; Console.WriteLine("({0}/{1}) Success.", q + 1, N); } else { failure++; Console.WriteLine("({0}/{1}) Failure.", q + 1, N); } } Console.WriteLine("successes/failures: {0}/{1}", success, failure); Console.WriteLine("average recognition time: {0:F3} ms", time / N); }
private static List <Point> CaclulateOffsetTable(int patternRadius, Func <int, int, bool> testPixel) { List <Point> pts = new List <Point>(); PointF center = new PointF(0, 0); for (int cy = -patternRadius; cy <= patternRadius; cy++) { for (int cx = -patternRadius; cx <= patternRadius; cx++) { PointF p = new PointF(cx, cy); float r = (float)PointOps.Distance(p, center) / patternRadius; PointF prevP = new PointF(cx - 1, cy); float prevR = (float)PointOps.Distance(prevP, center) / patternRadius; if (testPixel(FinderCircleDrawer.GetPixelAtRadius(prevR), FinderCircleDrawer.GetPixelAtRadius(r))) { pts.Add(new Point(cx, cy)); } } } return(pts); }
public static Bitmap GetFinderCircleImage(int radius) { Bitmap img = new Bitmap(radius * 2 + 1, radius * 2 + 1, PixelFormat.Format32bppArgb); unsafe { BitmapData bd = img.LockBits(ImageLockMode.WriteOnly); uint * ptr = (uint *)bd.Scan0.ToPointer(); PointF center = new PointF(radius, radius); for (int y = 0; y < img.Height; y++) { for (int x = 0; x < img.Width; x++) { PointF p = new PointF(x, y); float r = (float)PointOps.Distance(p, center) / radius; int px = GetPixelAtRadius(r); if (px == 1) { *ptr = 0xff000000; } else if (px == -1) { *ptr = 0xffffffff; } ptr++; } } img.UnlockBits(bd); } return(img); }