public virtual PerspectiveTransform createTransform(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint alignmentPattern, int dimension) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float dimMinusThree = (float) dimension - 3.5f; float bottomRightX; float bottomRightY; float sourceBottomRightX; float sourceBottomRightY; if (alignmentPattern != null) { bottomRightX = alignmentPattern.X; bottomRightY = alignmentPattern.Y; sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; } else { // Don't have an alignment pattern, just make up the bottom-right point bottomRightX = (topRight.X - topLeft.X) + bottomLeft.X; bottomRightY = (topRight.Y - topLeft.Y) + bottomLeft.Y; sourceBottomRightX = sourceBottomRightY = dimMinusThree; } PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, sourceBottomRightY, 3.5f, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y); return transform; }
/// <summary> /// Initializes a new instance of the <see cref="AztecDetectorResult"/> class. /// </summary> /// <param name="bits">The bits.</param> /// <param name="points">The points.</param> /// <param name="compact">if set to <c>true</c> [compact].</param> /// <param name="nbDatablocks">The nb datablocks.</param> /// <param name="nbLayers">The nb layers.</param> public AztecDetectorResult(BitMatrix bits, ResultPoint[] points, bool compact, int nbDatablocks, int nbLayers) : base(bits, points) { Compact = compact; NbDatablocks = nbDatablocks; NbLayers = nbLayers; }
/// <summary> /// Apply the result points' order correction due to mirroring. /// </summary> /// <param name="points">Array of points to apply mirror correction to.</param> internal void applyMirroredCorrection(ResultPoint[] points) { if (!mirrored || points == null || points.Length < 3) { return; } ResultPoint bottomLeft = points[0]; points[0] = points[2]; points[2] = bottomLeft; // No need to 'fix' top-left and alignment pattern. }
public Result(String text, sbyte[] rawBytes, ResultPoint[] resultPoints, BarcodeFormat format) { if (text == null && rawBytes == null) { throw new ArgumentException("Text and bytes are null"); } this.text = text; this.rawBytes = rawBytes; this.resultPoints = resultPoints; this.format = format; resultMetadata = null; }
/// <summary> /// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.BoundingBox"/> class. /// returns null if the corner points don't match up correctly /// </summary> /// <param name="image">The image.</param> /// <param name="topLeft">The top left.</param> /// <param name="bottomLeft">The bottom left.</param> /// <param name="topRight">The top right.</param> /// <param name="bottomRight">The bottom right.</param> /// <returns></returns> public static BoundingBox Create(BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight) { if ((topLeft == null && topRight == null) || (bottomLeft == null && bottomRight == null) || (topLeft != null && bottomLeft == null) || (topRight != null && bottomRight == null)) { return null; } return new BoundingBox(image, topLeft, bottomLeft, topRight, bottomRight); }
/** * <p>Orders an array of three ResultPoints in an order [A,B,C] such that AB < AC and * BC < AC and the angle between BC and BA is less than 180 degrees. */ public static void orderBestPatterns(ResultPoint[] patterns) { // Find distances between pattern centers float zeroOneDistance = distance(patterns[0], patterns[1]); float oneTwoDistance = distance(patterns[1], patterns[2]); float zeroTwoDistance = distance(patterns[0], patterns[2]); ResultPoint pointA, pointB, pointC; // Assume one closest to other two is B; A and C will just be guesses at first if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) { pointB = patterns[0]; pointA = patterns[1]; pointC = patterns[2]; } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) { pointB = patterns[1]; pointA = patterns[0]; pointC = patterns[2]; } else { pointB = patterns[2]; pointA = patterns[0]; pointC = patterns[1]; } // Use cross product to figure out whether A and C are correct or flipped. // This asks whether BC x BA has a positive z component, which is the arrangement // we want for A, B, C. If it's negative, then we've got it flipped around and // should swap A and C. if (crossProductZ(pointA, pointB, pointC) < 0.0f) { ResultPoint temp = pointA; pointA = pointC; pointC = temp; } patterns[0] = pointA; patterns[1] = pointB; patterns[2] = pointC; }
/** * Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. */ private ResultPointsAndTransitions transitionsBetween(ResultPoint from, ResultPoint to) { // See QR Code Detector, sizeOfBlackWhiteBlackRun() int fromX = (int)from.getX(); int fromY = (int)from.getY(); int toX = (int)to.getX(); int toY = (int)to.getY(); bool steep = Math.Abs(toY - fromY) > Math.Abs(toX - fromX); if (steep) { int temp = fromX; fromX = fromY; fromY = temp; temp = toX; toX = toY; toY = temp; } int dx = Math.Abs(toX - fromX); int dy = Math.Abs(toY - fromY); int error = -dx >> 1; int ystep = fromY < toY ? 1 : -1; int xstep = fromX < toX ? 1 : -1; int transitions = 0; bool inBlack = image.isBlack(steep ? fromY : fromX, steep ? fromX : fromY); for (int x = fromX, y = fromY; x != toX; x += xstep) { bool isBlack = image.isBlack(steep ? y : x, steep ? x : y); if (isBlack == !inBlack) { transitions++; inBlack = isBlack; } error += dy; if (error > 0) { y += ystep; error -= dx; } } return(new ResultPointsAndTransitions(from, to, transitions)); }
public static Individual ToIndividual(ResultPoint resultPoint) { var individual = new Individual(); individual.Evaluations.Add(new Evaluation { Type = ObjectiveType.Cost, Score = resultPoint.Cost, Direction = Direction.Minimize }); individual.Evaluations.Add(new Evaluation { Type = ObjectiveType.Macro, Score = resultPoint.Macro, Direction = Direction.Minimize }); individual.Evaluations.Add(new Evaluation { Type = ObjectiveType.Preferences, Score = resultPoint.Preferences, Direction = Direction.Minimize }); individual.Evaluations.Add(new Evaluation { Type = ObjectiveType.PreparationTime, Score = resultPoint.PreparationTime, Direction = Direction.Minimize }); return(individual); }
/// <summary> <p>Estimates module size based on two finder patterns -- it uses /// {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the /// width of each, measuring along the axis between their centers.</p> /// </summary> private float calculateModuleSizeOneWay(ResultPoint pattern, ResultPoint otherPattern) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern.X, (int)pattern.Y, (int)otherPattern.X, (int)otherPattern.Y); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern.X, (int)otherPattern.Y, (int)pattern.X, (int)pattern.Y); if (System.Single.IsNaN(moduleSizeEst1)) { return(moduleSizeEst2 / 7.0f); } if (System.Single.IsNaN(moduleSizeEst2)) { return(moduleSizeEst1 / 7.0f); } // Average them, and divide by 7 since we've counted the width of 3 black modules, // and 1 white and 1 black module on either side. Ergo, divide sum by 14. return((moduleSizeEst1 + moduleSizeEst2) / 14.0f); }
/// <summary> /// Calculates the minimum and maximum X & Y values based on the corner points. /// </summary> private void calculateMinMaxValues() { // Constructor ensures that either Left or Right is not null if (TopLeft == null) { TopLeft = new ResultPoint(0, TopRight.Y); BottomLeft = new ResultPoint(0, BottomRight.Y); } else if (TopRight == null) { TopRight = new ResultPoint(image.Width - 1, TopLeft.Y); BottomRight = new ResultPoint(image.Width - 1, TopLeft.Y); } MinX = (int)Math.Min(TopLeft.X, BottomLeft.X); MaxX = (int)Math.Max(TopRight.X, BottomRight.X); MinY = (int)Math.Min(TopLeft.Y, TopRight.Y); MaxY = (int)Math.Max(BottomLeft.Y, BottomRight.Y); }
// Note that we don't try rotation without the try harder flag, even if rotation was supported. //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public com.google.zxing.Result decode(com.google.zxing.BinaryBitmap image, java.util.Map<com.google.zxing.DecodeHintType,?> hints) throws com.google.zxing.NotFoundException, com.google.zxing.FormatException public virtual Result decode(BinaryBitmap image, IDictionary <DecodeHintType, object> hints) { try { return(doDecode(image, hints)); } catch (NotFoundException nfe) { bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); if (tryHarder && image.RotateSupported) { BinaryBitmap rotatedImage = image.rotateCounterClockwise(); Result result = doDecode(rotatedImage, hints); // Record that we found it rotated 90 degrees CCW / 270 degrees CW //JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET: //ORIGINAL LINE: java.util.Map<com.google.zxing.ResultMetadataType,?> metadata = result.getResultMetadata(); IDictionary <ResultMetadataType, object> metadata = result.ResultMetadata; int orientation = 270; if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION)) { // But if we found it reversed in doDecode(), add in that result here: orientation = (orientation + (int)metadata[ResultMetadataType.ORIENTATION]) % 360; } result.putMetadata(ResultMetadataType.ORIENTATION, orientation); // Update result points ResultPoint[] points = result.ResultPoints; if (points != null) { int height = rotatedImage.Height; for (int i = 0; i < points.Length; i++) { points[i] = new ResultPoint(height - points[i].Y - 1, points[i].X); } } return(result); } else { throw nfe; } } }
public static double HyperVolume(List <Individual> individuals, ResultPoint resultPoint = null) { var scores = new List <double>(); var scoreS = new StringBuilder(); foreach (var individual in individuals) { var currentIndividualScores = individual.Evaluations.Select(e => e.Score).ToList(); scores.AddRange(currentIndividualScores); foreach (var currentIndividualScore in currentIndividualScores) { scoreS.Append(currentIndividualScore.ToString(CultureInfo.InvariantCulture) + ", "); } } if (resultPoint != null) { //todo finish } var engine = REngine.GetInstance(); var data = engine.CreateNumericVector(scores.ToArray()); engine.SetSymbol("data", data); engine.SetSymbol("individuals", engine.CreateNumericVector(new double[] { individuals.Count })); engine.SetSymbol("criterions", engine.CreateNumericVector(new double[] { individuals.First().Evaluations.Count })); RunScript("hv", engine); var hv = engine.GetSymbol("dhv").AsNumeric(); var hvValue = hv.ToArray().First(); if (Math.Abs(hvValue) < 0.0001) { var letsTakeABreak = true; } return(hvValue); }
/// <summary> /// Samples a line /// </summary> /// <param name="p1">start point (inclusive)</param> /// <param name="p2">end point (exclusive)</param> /// <param name="size">number of bits</param> /// <returns> the array of bits as an int (first bit is high-order bit of result)</returns> private int sampleLine(ResultPoint p1, ResultPoint p2, int size) { int result = 0; float d = distance(p1, p2); float moduleSize = d / size; float px = p1.X; float py = p1.Y; float dx = moduleSize * (p2.X - p1.X) / d; float dy = moduleSize * (p2.Y - p1.Y) / d; for (int i = 0; i < size; i++) { if (image[MathUtils.round(px + i * dx), MathUtils.round(py + i * dy)]) { result |= 1 << (size - i - 1); } } return(result); }
/// <summary> /// Expand the square represented by the corner points by pushing out equally in all directions /// </summary> /// <param name="cornerPoints">the corners of the square, which has the bull's eye at its center</param> /// <param name="oldSide">the original length of the side of the square in the target bit matrix</param> /// <param name="newSide">the new length of the size of the square in the target bit matrix</param> /// <returns>the corners of the expanded square</returns> private static ResultPoint[] expandSquare(ResultPoint[] cornerPoints, float oldSide, float newSide) { float ratio = newSide / (2 * oldSide); float dx = cornerPoints[0].X - cornerPoints[2].X; float dy = cornerPoints[0].Y - cornerPoints[2].Y; float centerx = (cornerPoints[0].X + cornerPoints[2].X) / 2.0f; float centery = (cornerPoints[0].Y + cornerPoints[2].Y) / 2.0f; var result0 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy); var result2 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy); dx = cornerPoints[1].X - cornerPoints[3].X; dy = cornerPoints[1].Y - cornerPoints[3].Y; centerx = (cornerPoints[1].X + cornerPoints[3].X) / 2.0f; centery = (cornerPoints[1].Y + cornerPoints[3].Y) / 2.0f; var result1 = new ResultPoint(centerx + ratio * dx, centery + ratio * dy); var result3 = new ResultPoint(centerx - ratio * dx, centery - ratio * dy); return(new ResultPoint[] { result0, result1, result2, result3 }); }
private static PerspectiveTransform createTransform(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint alignmentPattern, int dimension) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float dimMinusThree = (float)dimension - 3.5f; float bottomRightX; float bottomRightY; float sourceBottomRightX; float sourceBottomRightY; if (alignmentPattern != null) { bottomRightX = alignmentPattern.X; bottomRightY = alignmentPattern.Y; sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; } else { // Don't have an alignment pattern, just make up the bottom-right point bottomRightX = (topRight.X - topLeft.X) + bottomLeft.X; bottomRightY = (topRight.Y - topLeft.Y) + bottomLeft.Y; sourceBottomRightX = sourceBottomRightY = dimMinusThree; } return(PerspectiveTransform.quadrilateralToQuadrilateral( 3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, sourceBottomRightY, 3.5f, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y)); }
/// <summary> /// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.BoundingBox"/> class. /// Will throw an exception if the corner points don't match up correctly /// </summary> /// <param name="image">Image.</param> /// <param name="topLeft">Top left.</param> /// <param name="topRight">Top right.</param> /// <param name="bottomLeft">Bottom left.</param> /// <param name="bottomRight">Bottom right.</param> public BoundingBox(BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight) { if ((topLeft == null && topRight == null) || (bottomLeft == null && bottomRight == null) || (topLeft != null && bottomLeft == null) || (topRight != null && bottomRight == null)) { throw ReaderException.Instance; } this.Image = image; this.TopLeft = topLeft; this.TopRight = topRight; this.BottomLeft = bottomLeft; this.BottomRight = bottomRight; CalculateMinMaxValues(); }
private static Point GetScanLineVector(Point[] scanLine) { ResultPoint vScan = new ResultPoint(scanLine[1].X - scanLine[0].X, scanLine[1].Y - scanLine[0].Y); int dx = Math.Sign(vScan.X); int dy = Math.Sign(vScan.Y); if (dx != 0 && dy != 0) { // Линия диагональная, такого быть не должно, но так как координаты float всё может быть, // тогда чья линия длиннее тот и прав if (Math.Abs(vScan.X) < Math.Abs(vScan.Y)) { dx = 0; } else { dy = 0; } } return(new Point(dx, dy)); }
/// <summary> /// Calculates the position of the white top right module using the output of the rectangle detector /// for a square matrix /// </summary> private ResultPoint correctTopRight(ResultPoint bottomLeft, ResultPoint bottomRight, ResultPoint topLeft, ResultPoint topRight, int dimension) { float corr = distance(bottomLeft, bottomRight) / (float)dimension; int norm = distance(topLeft, topRight); float cos = (topRight.X - topLeft.X) / norm; float sin = (topRight.Y - topLeft.Y) / norm; ResultPoint c1 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin); corr = distance(bottomLeft, topLeft) / (float)dimension; norm = distance(bottomRight, topRight); cos = (topRight.X - bottomRight.X) / norm; sin = (topRight.Y - bottomRight.Y) / norm; ResultPoint c2 = new ResultPoint(topRight.X + corr * cos, topRight.Y + corr * sin); if (!isValid(c1)) { if (isValid(c2)) { return(c2); } return(null); } if (!isValid(c2)) { return(c1); } int l1 = Math.Abs(transitionsBetween(topLeft, c1).Transitions - transitionsBetween(bottomRight, c1).Transitions); int l2 = Math.Abs(transitionsBetween(topLeft, c2).Transitions - transitionsBetween(bottomRight, c2).Transitions); return(l1 <= l2 ? c1 : c2); }
/// <summary> /// Locates and decodes a barcode in some format within an image. This method also accepts /// hints, each possibly associated to some data, which may help the implementation decode. /// Note that we don't try rotation without the try harder flag, even if rotation was supported. /// </summary> /// <param name="image">image of barcode to decode</param> /// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}"/> from <see cref="DecodeHintType"/> /// to arbitrary data. The /// meaning of the data depends upon the hint type. The implementation may or may not do /// anything with these hints.</param> /// <returns> /// String which the barcode encodes /// </returns> virtual public Result decode(BinaryBitmap image, IDictionary <DecodeHintType, object> hints) { var result = doDecode(image, hints); if (result == null) { bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); bool tryHarderWithoutRotation = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER_WITHOUT_ROTATION); if (tryHarder && !tryHarderWithoutRotation && image.RotateSupported) { BinaryBitmap rotatedImage = image.rotateCounterClockwise(); result = doDecode(rotatedImage, hints); if (result == null) { return(null); } // Record that we found it rotated 90 degrees CCW / 270 degrees CW IDictionary <ResultMetadataType, object> metadata = result.ResultMetadata; int orientation = 270; if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION)) { // But if we found it reversed in doDecode(), add in that result here: orientation = (orientation + (int)metadata[ResultMetadataType.ORIENTATION]) % 360; } result.putMetadata(ResultMetadataType.ORIENTATION, orientation); // Update result points ResultPoint[] points = result.ResultPoints; if (points != null) { int height = rotatedImage.Height; for (int i = 0; i < points.Length; i++) { points[i] = new ResultPoint(height - points[i].Y - 1, points[i].X); } } } } return(result); }
/// <summary> /// Detect a second solid side next to first solid side. /// </summary> /// <param name="points"></param> /// <returns></returns> private ResultPoint[] detectSolid2(ResultPoint[] points) { // A..D // : : // B--C ResultPoint pointA = points[0]; ResultPoint pointB = points[1]; ResultPoint pointC = points[2]; ResultPoint pointD = points[3]; // Transition detection on the edge is not stable. // To safely detect, shift the points to the module center. int tr = transitionsBetween(pointA, pointD); ResultPoint pointBs = shiftPoint(pointB, pointC, (tr + 1) * 4); ResultPoint pointCs = shiftPoint(pointC, pointB, (tr + 1) * 4); int trBA = transitionsBetween(pointBs, pointA); int trCD = transitionsBetween(pointCs, pointD); // 0..3 // | : // 1--2 if (trBA < trCD) { // solid sides: A-B-C points[0] = pointA; points[1] = pointB; points[2] = pointC; points[3] = pointD; } else { // solid sides: B-C-D points[0] = pointB; points[1] = pointC; points[2] = pointD; points[3] = pointA; } return(points); }
/// <summary> /// recenters the points of a constant distance towards the center /// </summary> /// <param name="y">bottom most point</param> /// <param name="z">left most point</param> /// <param name="x">right most point</param> /// <param name="t">top most point</param> /// <returns><see cref="ResultPoint"/>[] describing the corners of the rectangular /// region. The first and last points are opposed on the diagonal, as /// are the second and third. The first point will be the topmost /// point and the last, the bottommost. The second point will be /// leftmost and the third, the rightmost</returns> private ResultPoint[] centerEdges(ResultPoint y, ResultPoint z, ResultPoint x, ResultPoint t) { // // t t // z x // x OR z // y y // float yi = y.X; float yj = y.Y; float zi = z.X; float zj = z.Y; float xi = x.X; float xj = x.Y; float ti = t.X; float tj = t.Y; if (yi < width / 2.0f) { return(new[] { new ResultPoint(ti - CORR, tj + CORR), new ResultPoint(zi + CORR, zj + CORR), new ResultPoint(xi - CORR, xj - CORR), new ResultPoint(yi + CORR, yj - CORR) }); } else { return(new[] { new ResultPoint(ti + CORR, tj + CORR), new ResultPoint(zi + CORR, zj - CORR), new ResultPoint(xi - CORR, xj + CORR), new ResultPoint(yi - CORR, yj - CORR) }); } }
/// <summary> /// <p>Computes the dimension (number of modules on a size) of the QR Code based on the position /// of the finder patterns and estimated module size.</p> /// </summary> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: private static int computeDimension(com.google.zxing.ResultPoint topLeft, com.google.zxing.ResultPoint topRight, com.google.zxing.ResultPoint bottomLeft, float moduleSize) throws com.google.zxing.NotFoundException private static int computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, float moduleSize) { int tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize); int tlblCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; switch (dimension & 0x03) // mod 4 { case 0: dimension++; break; // 1? do nothing case 2: dimension--; break; case 3: throw NotFoundException.NotFoundInstance; } return(dimension); }
public static double HyperVolume(List <ResultPoint> resultPoints, ResultPoint referencePoint = null) { var scores = new List <double>(); var engine = REngine.GetInstance(); engine.ClearGlobalEnvironment(); foreach (var point in resultPoints) { scores.Add(point.Macro); scores.Add(point.PreparationTime); scores.Add(point.Cost); scores.Add(point.Preferences); } if (referencePoint != null) { engine.SetSymbol("useReferecnePoint", engine.CreateLogical(true)); engine.SetSymbol("referencePoint", engine.CreateNumericVector(new [] { referencePoint.Macro, referencePoint.PreparationTime, referencePoint.Cost, referencePoint.Preferences })); } else { engine.SetSymbol("useReferecnePoint", engine.CreateLogical(false)); } engine.SetSymbol("data", engine.CreateNumericVector(scores.ToArray())); engine.SetSymbol("individuals", engine.CreateNumericVector(new double[] { resultPoints.Count })); engine.SetSymbol("criterions", engine.CreateNumericVector(new double[] { 4 })); RunScript("hv", engine); var hv = engine.GetSymbol("dhv").AsNumeric().ToArray().First(); return(hv); }
private static ResultPoint[] GetBarCodeRect(Point[] scanLine, ResultPoint[] whiterect, float dx) { ResultPoint pt0 = new ResultPoint(scanLine[0].X, scanLine[0].Y); // Начало линии сканирования (заканчивается за 3 штрихполоски до начала штрихкода) ResultPoint pt1 = new ResultPoint(scanLine[1].X, scanLine[1].Y); // Конец линии сканирования (заканчивается за 3 штрихполоски до конца штрихкода) // whiterect п/у ограничивающий одну или несколько полосок штрих кода, // сделаем его направленным, повернем вдоль скан линии, чтобы можно было ширину расширить whiterect = RotateRect(whiterect, scanLine); // Проекция точки x,y на найденную полоску штрихкода. ResultPoint proj = Projection(pt1, whiterect[1], whiterect[0]); float vLen = ResultPoint.distance(pt1, proj); ResultPoint v = new ResultPoint(pt1.X - proj.X, pt1.Y - proj.Y); // Вектор b перпендикулярный вектору a против часовой стрелки равен b = (-ay, ax). // Найдем правую нормаль к вертикальной полоске float height = ResultPoint.distance(whiterect[1], whiterect[0]); ResultPoint vOrto = new ResultPoint(-(whiterect[1].Y - whiterect[0].Y) / height, (whiterect[1].X - whiterect[0].X) / height); var lastBarCodeLine = new ResultPoint[2] { new ResultPoint(whiterect[0].X + v.X - vOrto.X * dx, whiterect[0].Y + v.Y - vOrto.Y * dx), new ResultPoint(whiterect[1].X + v.X - vOrto.X * dx, whiterect[1].Y + v.Y - vOrto.Y * dx) }; ResultPoint proj0 = Projection(pt0, whiterect[1], whiterect[0]); ResultPoint v0 = new ResultPoint(pt0.X - proj0.X, pt0.Y - proj0.Y); var firstBarCodeLine = new ResultPoint[2] { new ResultPoint(whiterect[0].X + v0.X + vOrto.X * dx, whiterect[0].Y + v0.Y + vOrto.Y * dx), new ResultPoint(whiterect[1].X + v0.X + vOrto.X * dx, whiterect[1].Y + v0.Y + vOrto.Y * dx) }; return(new ResultPoint[] { firstBarCodeLine[0], firstBarCodeLine[1], lastBarCodeLine[0], lastBarCodeLine[1] }); }
/** * <p>Estimates module size based on two finder patterns -- it uses * {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the * width of each, measuring along the axis between their centers.</p> */ private float calculateModuleSizeOneWay(ResultPoint pattern, ResultPoint otherPattern) { float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern.getX(), (int)pattern.getY(), (int)otherPattern.getX(), (int)otherPattern.getY()); float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern.getX(), (int)otherPattern.getY(), (int)pattern.getX(), (int)pattern.getY()); if (Single.IsNaN(moduleSizeEst1)) { return(moduleSizeEst2); } if (Single.IsNaN(moduleSizeEst2)) { return(moduleSizeEst1); } // Average them, and divide by 7 since we've counted the width of 3 black modules, // and 1 white and 1 black module on either side. Ergo, divide sum by 14. return((moduleSizeEst1 + moduleSizeEst2) / 14.0f); }
/// <summary> <p>Computes the dimension (number of modules on a size) of the QR Code based on the position /// of the finder patterns and estimated module size.</p> /// </summary> protected internal static int computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, float moduleSize) { int tltrCentersDimension = round(ResultPoint.distance(topLeft, topRight) / moduleSize); int tlblCentersDimension = round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); int dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; switch (dimension & 0x03) { // mod 4 case 0: dimension++; break; // 1? do nothing case 2: dimension--; break; case 3: throw ReaderException.Instance; } return(dimension); }
/// <summary> <p>Computes the dimension (number of modules on a size) of the QR Code based on the position /// of the finder patterns and estimated module size.</p> /// </summary> private static bool computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, float moduleSize, out int dimension) { int tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize); int tlblCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; switch (dimension & 0x03) { // mod 4 case 0: dimension++; break; // 1? do nothing case 2: dimension--; break; case 3: return(true); } return(true); }
// Note that we don't try rotation without the try harder flag, even if rotation was supported. public virtual Result Decode(BinaryBitmap image, System.Collections.Hashtable hints) { try { return(doDecode(image, hints)); } catch (ReaderException re) { bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); if (tryHarder && image.RotateSupported) { BinaryBitmap rotatedImage = image.rotateCounterClockwise(); Result result = doDecode(rotatedImage, hints); // Record that we found it rotated 90 degrees CCW / 270 degrees CW System.Collections.Hashtable metadata = result.ResultMetadata; int orientation = 270; if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION)) { // But if we found it reversed in doDecode(), add in that result here: orientation = (orientation + ((System.Int32)metadata[ResultMetadataType.ORIENTATION])) % 360; } result.putMetadata(ResultMetadataType.ORIENTATION, (System.Object)orientation); // Update result points ResultPoint[] points = result.ResultPoints; int height = rotatedImage.Height; for (int i = 0; i < points.Length; i++) { points[i] = new ResultPoint(height - points[i].Y - 1, points[i].X); } return(result); } else { throw re; } } }
// Note that we don't try rotation without the try harder flag, even if rotation was supported. public virtual Result decode(BinaryBitmap image, System.Collections.Generic.Dictionary <Object,Object> hints) { try { return doDecode(image, hints); } catch (ReaderException re) { bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); if (tryHarder && image.RotateSupported) { BinaryBitmap rotatedImage = image.rotateCounterClockwise(); Result result = doDecode(rotatedImage, hints); // Record that we found it rotated 90 degrees CCW / 270 degrees CW System.Collections.Generic.Dictionary <Object,Object> metadata = result.ResultMetadata; int orientation = 270; if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION)) { // But if we found it reversed in doDecode(), add in that result here: orientation = (orientation + ((System.Int32) metadata[ResultMetadataType.ORIENTATION])) % 360; } result.putMetadata(ResultMetadataType.ORIENTATION, (System.Object) orientation); // Update result points ResultPoint[] points = result.ResultPoints; int height = rotatedImage.Height; for (int i = 0; i < points.Length; i++) { points[i] = new ResultPoint(height - points[i].Y - 1, points[i].X); } return result; } else { throw re; } } }
private static BitMatrix sampleGrid(MonochromeBitmapSource image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint bottomRight, int dimension) { // We make up the top right point for now, based on the others. // TODO: we actually found a fourth corner above and figured out which of two modules // it was the corner of. We could use that here and adjust for perspective distortion. float topRightX = (bottomRight.getX() - bottomLeft.getX()) + topLeft.getX(); float topRightY = (bottomRight.getY() - bottomLeft.getY()) + topLeft.getY(); // Note that unlike in the QR Code sampler, we didn't find the center of modules, but the // very corners. So there is no 0.5f here; 0.0f is right. GridSampler sampler = GridSampler.Instance; return(sampler.sampleGrid( image, dimension, 0.0f, 0.0f, dimension, 0.0f, dimension, dimension, 0.0f, dimension, topLeft.getX(), topLeft.getY(), topRightX, topRightY, bottomRight.getX(), bottomRight.getY(), bottomLeft.getX(), bottomLeft.getY())); }
/// <summary> /// Creates a BitMatrix by sampling the provided image. /// topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the /// diagonal just outside the bull's eye. /// </summary> /// <param name="image">The image.</param> /// <param name="topLeft">The top left.</param> /// <param name="bottomLeft">The bottom left.</param> /// <param name="bottomRight">The bottom right.</param> /// <param name="topRight">The top right.</param> /// <returns></returns> private BitMatrix sampleGrid(BitMatrix image, ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomRight, ResultPoint bottomLeft) { GridSampler sampler = GridSampler.Instance; int dimension = getDimension(); float low = dimension / 2.0f - nbCenterLayers; float high = dimension / 2.0f + nbCenterLayers; return(sampler.sampleGrid(image, dimension, dimension, low, low, // topleft high, low, // topright high, high, // bottomright low, high, // bottomleft topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y)); }
/// <summary> Increments the Integer associated with a key by one.</summary> private static void increment(System.Collections.Hashtable table, ResultPoint key) { //System.Int32 value_Renamed = (System.Int32) table[key]; ////UPGRADE_TODO: The 'System.Int32' structure does not have an equivalent to NULL. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1291'" //table[key] = value_Renamed == null?INTEGERS[1]:INTEGERS[value_Renamed + 1]; // Redivivus.in Java to c# Porting update // 30/01/2010 // Added // START System.Int32 value_Renamed = 0; try { if (table.Count > 0) { value_Renamed = (System.Int32)table[key]; } } catch { value_Renamed = 0; } table[key] = value_Renamed == 0 ? INTEGERS[1] : INTEGERS[value_Renamed + 1]; //END }
protected internal virtual DetectorResult processFinderPatternInfo(FinderPatternInfo info) { FinderPattern topLeft = info.TopLeft; FinderPattern topRight = info.TopRight; FinderPattern bottomLeft = info.BottomLeft; float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1.0f) { throw ReaderException.Instance; } int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); int modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7; PerspectiveTransform transform = createTransform(topLeft, topRight, bottomLeft, dimension); BitMatrix bits = sampleGrid(image, transform, dimension); ResultPoint[] points; points = new ResultPoint[] { bottomLeft, topLeft, topRight }; return(new DetectorResult(bits, points)); }
/// <summary> /// Samples an Aztec matrix from an image /// </summary> /// <param name="image">The image.</param> /// <param name="topLeft">The top left.</param> /// <param name="bottomLeft">The bottom left.</param> /// <param name="bottomRight">The bottom right.</param> /// <param name="topRight">The top right.</param> /// <returns></returns> private BitMatrix sampleGrid(BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint bottomRight, ResultPoint topRight) { int dimension; if (compact) { dimension = 4 * nbLayers + 11; } else { if (nbLayers <= 4) { dimension = 4 * nbLayers + 15; } else { dimension = 4 * nbLayers + 2 * ((nbLayers - 4) / 8 + 1) + 15; } } GridSampler sampler = GridSampler.Instance; return sampler.sampleGrid(image, dimension, dimension, 0.5f, 0.5f, dimension - 0.5f, 0.5f, dimension - 0.5f, dimension - 0.5f, 0.5f, dimension - 0.5f, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); }
/// <summary> /// recenters the points of a constant distance towards the center /// </summary> /// <param name="y">bottom most point</param> /// <param name="z">left most point</param> /// <param name="x">right most point</param> /// <param name="t">top most point</param> /// <returns><see cref="ResultPoint"/>[] describing the corners of the rectangular /// region. The first and last points are opposed on the diagonal, as /// are the second and third. The first point will be the topmost /// point and the last, the bottommost. The second point will be /// leftmost and the third, the rightmost</returns> private ResultPoint[] centerEdges(ResultPoint y, ResultPoint z, ResultPoint x, ResultPoint t) { // // t t // z x // x OR z // y y // float yi = y.X; float yj = y.Y; float zi = z.X; float zj = z.Y; float xi = x.X; float xj = x.Y; float ti = t.X; float tj = t.Y; if (yi < width / 2.0f) { return new[] { new ResultPoint(ti - CORR, tj + CORR), new ResultPoint(zi + CORR, zj + CORR), new ResultPoint(xi - CORR, xj - CORR), new ResultPoint(yi + CORR, yj - CORR) }; } else { return new[] { new ResultPoint(ti + CORR, tj + CORR), new ResultPoint(zi + CORR, zj - CORR), new ResultPoint(xi - CORR, xj + CORR), new ResultPoint(yi - CORR, yj - CORR) }; } }
/// <summary> /// If we adjust the width, set a new right corner coordinate and recalculate /// </summary> /// <param name="bottomRight">Bottom right.</param> internal void SetBottomRight(ResultPoint bottomRight) { this.BottomRight = bottomRight; calculateMinMaxValues(); }
/// <summary> /// Adds the missing rows. /// </summary> /// <returns>The missing rows.</returns> /// <param name="missingStartRows">Missing start rows.</param> /// <param name="missingEndRows">Missing end rows.</param> /// <param name="isLeft">If set to <c>true</c> is left.</param> public BoundingBox addMissingRows(int missingStartRows, int missingEndRows, bool isLeft) { ResultPoint newTopLeft = TopLeft; ResultPoint newBottomLeft = BottomLeft; ResultPoint newTopRight = TopRight; ResultPoint newBottomRight = BottomRight; if (missingStartRows > 0) { ResultPoint top = isLeft ? TopLeft : TopRight; int newMinY = (int)top.Y - missingStartRows; if (newMinY < 0) { newMinY = 0; } // TODO use existing points to better interpolate the new x positions ResultPoint newTop = new ResultPoint(top.X, newMinY); if (isLeft) { newTopLeft = newTop; } else { newTopRight = newTop; } } if (missingEndRows > 0) { ResultPoint bottom = isLeft ? BottomLeft : BottomRight; int newMaxY = (int)bottom.Y + missingEndRows; if (newMaxY >= image.Height) { newMaxY = image.Height - 1; } // TODO use existing points to better interpolate the new x positions ResultPoint newBottom = new ResultPoint(bottom.X, newMaxY); if (isLeft) { newBottomLeft = newBottom; } else { newBottomRight = newBottom; } } calculateMinMaxValues(); return new BoundingBox(image, newTopLeft, newBottomLeft, newTopRight, newBottomRight); }
/// <summary> /// Initializes a new instance of the <see cref="ZXing.PDF417.Internal.BoundingBox"/> class. /// Will throw an exception if the corner points don't match up correctly /// </summary> /// <param name="image">Image.</param> /// <param name="topLeft">Top left.</param> /// <param name="topRight">Top right.</param> /// <param name="bottomLeft">Bottom left.</param> /// <param name="bottomRight">Bottom right.</param> private BoundingBox(BitMatrix image, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight) { this.image = image; this.TopLeft = topLeft; this.TopRight = topRight; this.BottomLeft = bottomLeft; this.BottomRight = bottomRight; calculateMinMaxValues(); }
/// <summary> <p>Computes the dimension (number of modules on a size) of the QR Code based on the position /// of the finder patterns and estimated module size.</p> /// </summary> private static bool computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, float moduleSize, out int dimension) { int tltrCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, topRight) / moduleSize); int tlblCentersDimension = MathUtils.round(ResultPoint.distance(topLeft, bottomLeft) / moduleSize); dimension = ((tltrCentersDimension + tlblCentersDimension) >> 1) + 7; switch (dimension & 0x03) { // mod 4 case 0: dimension++; break; // 1? do nothing case 2: dimension--; break; case 3: return true; } return true; }
/// <summary> /// Gets the minimum width of the codeword. /// </summary> /// <returns>The minimum codeword width.</returns> /// <param name="p">P.</param> private static int GetMinCodewordWidth(ResultPoint[] p) { return Math.Min( Math.Min(GetMinWidth(p[0], p[4]), GetMinWidth(p[6], p[2]) * PDF417Common.MODULES_IN_CODEWORD / PDF417Common.MODULES_IN_STOP_PATTERN), Math.Min(GetMinWidth(p[1], p[5]), GetMinWidth(p[7], p[3]) * PDF417Common.MODULES_IN_CODEWORD / PDF417Common.MODULES_IN_STOP_PATTERN)); }
/// <summary> /// Gets the row indicator column. /// </summary> /// <returns>The row indicator column.</returns> /// <param name="image">Image.</param> /// <param name="boundingBox">Bounding box.</param> /// <param name="startPoint">Start point.</param> /// <param name="leftToRight">If set to <c>true</c> left to right.</param> /// <param name="minCodewordWidth">Minimum codeword width.</param> /// <param name="maxCodewordWidth">Max codeword width.</param> private static DetectionResultRowIndicatorColumn getRowIndicatorColumn(BitMatrix image, BoundingBox boundingBox, ResultPoint startPoint, bool leftToRight, int minCodewordWidth, int maxCodewordWidth) { DetectionResultRowIndicatorColumn rowIndicatorColumn = new DetectionResultRowIndicatorColumn(boundingBox, leftToRight); for (int i = 0; i < 2; i++) { int increment = i == 0 ? 1 : -1; int startColumn = (int) startPoint.X; for (int imageRow = (int) startPoint.Y; imageRow <= boundingBox.MaxY && imageRow >= boundingBox.MinY; imageRow += increment) { Codeword codeword = detectCodeword(image, 0, image.Width, leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth); if (codeword != null) { rowIndicatorColumn.setCodeword(imageRow, codeword); if (leftToRight) { startColumn = codeword.StartX; } else { startColumn = codeword.EndX; } } } } return rowIndicatorColumn; }
/// <summary> /// Gets the minimum width of the barcode /// </summary> /// <returns>The minimum width.</returns> /// <param name="p1">P1.</param> /// <param name="p2">P2.</param> private static int GetMinWidth(ResultPoint p1, ResultPoint p2) { if (p1 == null || p2 == null) { return int.MaxValue; } return (int)Math.Abs(p1.X - p2.X); }
/// <summary> <p>Estimates module size based on two finder patterns -- it uses /// {@link #sizeOfBlackWhiteBlackRunBothWays(int, int, int, int)} to figure the /// width of each, measuring along the axis between their centers.</p> /// </summary> private float calculateModuleSizeOneWay(ResultPoint pattern, ResultPoint otherPattern) { //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float moduleSizeEst1 = sizeOfBlackWhiteBlackRunBothWays((int)pattern.X, (int)pattern.Y, (int)otherPattern.X, (int)otherPattern.Y); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float moduleSizeEst2 = sizeOfBlackWhiteBlackRunBothWays((int)otherPattern.X, (int)otherPattern.Y, (int)pattern.X, (int)pattern.Y); if (Single.IsNaN(moduleSizeEst1)) { return moduleSizeEst2 / 7.0f; } if (Single.IsNaN(moduleSizeEst2)) { return moduleSizeEst1 / 7.0f; } // Average them, and divide by 7 since we've counted the width of 3 black modules, // and 1 white and 1 black module on either side. Ergo, divide sum by 14. return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; }
/// <summary> <p>Computes an average estimated module size based on estimated derived from the positions /// of the three finder patterns.</p> /// </summary> protected internal virtual float calculateModuleSize(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft) { // Take the average return (calculateModuleSizeOneWay(topLeft, topRight) + calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2.0f; }
private void drawLine(Canvas canvas, Paint paint, ResultPoint a, ResultPoint b) { canvas.DrawLine(a.X, a.Y, b.X, b.Y, paint); }
/// <summary> /// Locate the vertices and the codewords area of a black blob using the Start and Stop patterns as locators. /// </summary> /// <param name="matrix">Matrix.</param> /// <param name="startRow">Start row.</param> /// <param name="startColumn">Start column.</param> /// <returns> an array containing the vertices: /// vertices[0] x, y top left barcode /// vertices[1] x, y bottom left barcode /// vertices[2] x, y top right barcode /// vertices[3] x, y bottom right barcode /// vertices[4] x, y top left codeword area /// vertices[5] x, y bottom left codeword area /// vertices[6] x, y top right codeword area /// vertices[7] x, y bottom right codeword area /// </returns> private static ResultPoint[] FindVertices(BitMatrix matrix, int startRow, int startColumn) { int height = matrix.Height; int width = matrix.Width; ResultPoint[] result = new ResultPoint[8]; CopyToResult(result, FindRowsWithPattern(matrix, height, width, startRow, startColumn, START_PATTERN), INDEXES_START_PATTERN); if (result[4] != null) { startColumn = (int) result[4].X; startRow = (int) result[4].Y; } CopyToResult(result, FindRowsWithPattern(matrix, height, width, startRow, startColumn, STOP_PATTERN), INDEXES_STOP_PATTERN); return result; }
private static Result translateResultPoints(Result result, int xOffset, int yOffset) { ResultPoint[] oldResultPoints = result.ResultPoints; ResultPoint[] newResultPoints = new ResultPoint[oldResultPoints.Length]; for (int i = 0; i < oldResultPoints.Length; i++) { ResultPoint oldPoint = oldResultPoints[i]; newResultPoints[i] = new ResultPoint(oldPoint.X + xOffset, oldPoint.Y + yOffset); } return new Result(result.Text, result.RawBytes, newResultPoints, result.BarcodeFormat); }
/// <summary> /// Finds the rows with the given pattern. /// </summary> /// <returns>The rows with pattern.</returns> /// <param name="matrix">Matrix.</param> /// <param name="height">Height.</param> /// <param name="width">Width.</param> /// <param name="startRow">Start row.</param> /// <param name="startColumn">Start column.</param> /// <param name="pattern">Pattern.</param> private static ResultPoint[] FindRowsWithPattern( BitMatrix matrix, int height, int width, int startRow, int startColumn, int[] pattern) { ResultPoint[] result = new ResultPoint[4]; bool found = false; int[] counters = new int[pattern.Length]; for (; startRow < height; startRow += ROW_STEP) { int[] loc = FindGuardPattern(matrix, startColumn, startRow, width, false, pattern, counters); if (loc != null) { while (startRow > 0) { int[] previousRowLoc = FindGuardPattern(matrix, startColumn, --startRow, width, false, pattern, counters); if (previousRowLoc != null) { loc = previousRowLoc; } else { startRow++; break; } } result[0] = new ResultPoint(loc[0], startRow); result[1] = new ResultPoint(loc[1], startRow); found = true; break; } } int stopRow = startRow + 1; // Last row of the current symbol that contains pattern if (found) { int skippedRowCount = 0; int[] previousRowLoc = {(int) result[0].X, (int) result[1].X}; for (; stopRow < height; stopRow++) { int[] loc = FindGuardPattern(matrix, previousRowLoc[0], stopRow, width, false, pattern, counters); // a found pattern is only considered to belong to the same barcode if the start and end positions // don't differ too much. Pattern drift should be not bigger than two for consecutive rows. With // a higher number of skipped rows drift could be larger. To keep it simple for now, we allow a slightly // larger drift and don't check for skipped rows. if (loc != null && Math.Abs(previousRowLoc[0] - loc[0]) < MAX_PATTERN_DRIFT && Math.Abs(previousRowLoc[1] - loc[1]) < MAX_PATTERN_DRIFT) { previousRowLoc = loc; skippedRowCount = 0; } else { if (skippedRowCount > SKIPPED_ROW_COUNT_MAX) { break; } else { skippedRowCount++; } } } stopRow -= skippedRowCount + 1; result[2] = new ResultPoint(previousRowLoc[0], stopRow); result[3] = new ResultPoint(previousRowLoc[1], stopRow); } if (stopRow - startRow < BARCODE_MIN_HEIGHT) { for (int i = 0; i < result.Length; i++) { result[i] = null; } } return result; }
public ResultPointsAndTransitions(ResultPoint from, ResultPoint to, int transitions) { this.from = from; this.to = to; this.transitions = transitions; }
/// <summary> /// Processes the finder pattern info. /// </summary> /// <param name="info">The info.</param> /// <returns></returns> protected internal virtual DetectorResult processFinderPatternInfo(FinderPatternInfo info) { FinderPattern topLeft = info.TopLeft; FinderPattern topRight = info.TopRight; FinderPattern bottomLeft = info.BottomLeft; float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1.0f) { return null; } int dimension; if (!computeDimension(topLeft, topRight, bottomLeft, moduleSize, out dimension)) return null; Internal.Version provisionalVersion = Internal.Version.getProvisionalVersionForDimension(dimension); if (provisionalVersion == null) return null; int modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7; AlignmentPattern alignmentPattern = null; // Anything above version 1 has an alignment pattern if (provisionalVersion.AlignmentPatternCenters.Length > 0) { // Guess where a "bottom right" finder pattern would have been float bottomRightX = topRight.X - topLeft.X + bottomLeft.X; float bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y; // Estimate that alignment pattern is closer by 3 modules // from "bottom right" to known top left location //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" int estAlignmentX = (int)(topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X)); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1042'" int estAlignmentY = (int)(topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y)); // Kind of arbitrary -- expand search radius before giving up for (int i = 4; i <= 16; i <<= 1) { alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); if (alignmentPattern == null) continue; break; } // If we didn't find alignment pattern... well try anyway without it } PerspectiveTransform transform = createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension); BitMatrix bits = sampleGrid(image, transform, dimension); if (bits == null) return null; ResultPoint[] points; if (alignmentPattern == null) { points = new ResultPoint[] { bottomLeft, topLeft, topRight }; } else { points = new ResultPoint[] { bottomLeft, topLeft, topRight, alignmentPattern }; } return new DetectorResult(bits, points); }
/// <summary> /// Decode the specified image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, minCodewordWidth /// and maxCodewordWidth. /// TODO: don't pass in minCodewordWidth and maxCodewordWidth, pass in barcode columns for start and stop pattern /// columns. That way width can be deducted from the pattern column. /// This approach also allows to detect more details about the barcode, e.g. if a bar type (white or black) is wider /// than it should be. This can happen if the scanner used a bad blackpoint. /// </summary> /// <param name="image">Image.</param> /// <param name="imageTopLeft">Image top left.</param> /// <param name="imageBottomLeft">Image bottom left.</param> /// <param name="imageTopRight">Image top right.</param> /// <param name="imageBottomRight">Image bottom right.</param> /// <param name="minCodewordWidth">Minimum codeword width.</param> /// <param name="maxCodewordWidth">Max codeword width.</param> public static DecoderResult decode(BitMatrix image, ResultPoint imageTopLeft, ResultPoint imageBottomLeft, ResultPoint imageTopRight, ResultPoint imageBottomRight, int minCodewordWidth, int maxCodewordWidth) { BoundingBox boundingBox = BoundingBox.Create(image, imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight); if (boundingBox == null) return null; DetectionResultRowIndicatorColumn leftRowIndicatorColumn = null; DetectionResultRowIndicatorColumn rightRowIndicatorColumn = null; DetectionResult detectionResult = null; for (int i = 0; i < 2; i++) { if (imageTopLeft != null) { leftRowIndicatorColumn = getRowIndicatorColumn(image, boundingBox, imageTopLeft, true, minCodewordWidth, maxCodewordWidth); } if (imageTopRight != null) { rightRowIndicatorColumn = getRowIndicatorColumn(image, boundingBox, imageTopRight, false, minCodewordWidth, maxCodewordWidth); } detectionResult = merge(leftRowIndicatorColumn, rightRowIndicatorColumn); if (detectionResult == null) { // TODO Based on Owen's Comments in <see cref="ZXing.ReaderException"/>, this method has been modified to continue silently // if a barcode was not decoded where it was detected instead of throwing a new exception object. return null; } if (i == 0 && detectionResult.Box != null && (detectionResult.Box.MinY < boundingBox.MinY || detectionResult.Box.MaxY > boundingBox.MaxY)) { boundingBox = detectionResult.Box; } else { detectionResult.Box = boundingBox; break; } } int maxBarcodeColumn = detectionResult.ColumnCount + 1; detectionResult.DetectionResultColumns[0] = leftRowIndicatorColumn; detectionResult.DetectionResultColumns[maxBarcodeColumn] = rightRowIndicatorColumn; bool leftToRight = leftRowIndicatorColumn != null; for (int barcodeColumnCount = 1; barcodeColumnCount <= maxBarcodeColumn; barcodeColumnCount++) { int barcodeColumn = leftToRight ? barcodeColumnCount : maxBarcodeColumn - barcodeColumnCount; if (detectionResult.DetectionResultColumns[barcodeColumn] != null) { // This will be the case for the opposite row indicator column, which doesn't need to be decoded again. continue; } DetectionResultColumn detectionResultColumn; if (barcodeColumn == 0 || barcodeColumn == maxBarcodeColumn) { detectionResultColumn = new DetectionResultRowIndicatorColumn(boundingBox, barcodeColumn == 0); } else { detectionResultColumn = new DetectionResultColumn(boundingBox); } detectionResult.DetectionResultColumns[barcodeColumn] = detectionResultColumn; int startColumn = -1; int previousStartColumn = startColumn; // TODO start at a row for which we know the start position, then detect upwards and downwards from there. for (int imageRow = boundingBox.MinY; imageRow <= boundingBox.MaxY; imageRow++) { startColumn = getStartColumn(detectionResult, barcodeColumn, imageRow, leftToRight); if (startColumn < 0 || startColumn > boundingBox.MaxX) { if (previousStartColumn == -1) { continue; } startColumn = previousStartColumn; } Codeword codeword = detectCodeword(image, boundingBox.MinX, boundingBox.MaxX, leftToRight, startColumn, imageRow, minCodewordWidth, maxCodewordWidth); if (codeword != null) { detectionResultColumn.setCodeword(imageRow, codeword); previousStartColumn = startColumn; minCodewordWidth = Math.Min(minCodewordWidth, codeword.Width); maxCodewordWidth = Math.Max(maxCodewordWidth, codeword.Width); } } } return createDecoderResult(detectionResult); }
/// <summary> /// If we adjust the width, set a new right corner coordinate and recalculate /// </summary> /// <param name="topRight">Top right.</param> internal void SetTopRight(ResultPoint topRight) { this.TopRight = topRight; CalculateMinMaxValues(); }
/// <summary> /// We're going to examine rows from the middle outward, searching alternately above and below the /// middle, and farther out each time. rowStep is the number of rows between each successive /// attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then /// middle + rowStep, then middle - (2 * rowStep), etc. /// rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily /// decided that moving up and down by about 1/16 of the image is pretty good; we try more of the /// image if "trying harder". /// </summary> /// <param name="image">The image to decode</param> /// <param name="hints">Any hints that were requested</param> /// <returns>The contents of the decoded barcode</returns> virtual protected Result doDecode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints) { int width = image.Width; int height = image.Height; BitArray row = new BitArray(width); int middle = height >> 1; bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); int rowStep = Math.Max(1, height >> (tryHarder ? 8 : 5)); int maxLines; if (tryHarder) { maxLines = height; // Look at the whole image, not just the center } else { maxLines = 15; // 15 rows spaced 1/32 apart is roughly the middle half of the image } for (int x = 0; x < maxLines; x++) { // Scanning from the middle out. Determine which row we're looking at next: int rowStepsAboveOrBelow = (x + 1) >> 1; bool isAbove = (x & 0x01) == 0; // i.e. is x even? int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); if (rowNumber < 0 || rowNumber >= height) { // Oops, if we run off the top or bottom, stop break; } // Estimate black point for this row and load it: row = image.getBlackRow(rowNumber, row); if (row == null) continue; // While we have the image data in a BitArray, it's fairly cheap to reverse it in place to // handle decoding upside down barcodes. for (int attempt = 0; attempt < 2; attempt++) { if (attempt == 1) { // trying again? row.reverse(); // reverse the row and continue // This means we will only ever draw result points *once* in the life of this method // since we want to avoid drawing the wrong points after flipping the row, and, // don't want to clutter with noise from every single row scan -- just the scans // that start on the center line. if (hints != null && hints.ContainsKey(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) { IDictionary<DecodeHintType, Object> newHints = new Dictionary<DecodeHintType, Object>(); foreach (var hint in hints) { if (hint.Key != DecodeHintType.NEED_RESULT_POINT_CALLBACK) newHints.Add(hint.Key, hint.Value); } hints = newHints; } } // Look for a barcode Result result = decodeRow(rowNumber, row, hints); if (result == null) continue; // We found our barcode if (attempt == 1) { // But it was upside down, so note that result.putMetadata(ResultMetadataType.ORIENTATION, 180); // And remember to flip the result points horizontally. ResultPoint[] points = result.ResultPoints; if (points != null) { points[0] = new ResultPoint(width - points[0].X - 1, points[0].Y); points[1] = new ResultPoint(width - points[1].X - 1, points[1].Y); } } return result; } } return null; }
/// <summary> /// Copies the temp data to the final result /// </summary> /// <param name="result">Result.</param> /// <param name="tmpResult">Temp result.</param> /// <param name="destinationIndexes">Destination indexes.</param> private static void CopyToResult(ResultPoint[] result, ResultPoint[] tmpResult, int[] destinationIndexes) { for (int i = 0; i < destinationIndexes.Length; i++) { result[destinationIndexes[i]] = tmpResult[i]; } }
/** * <p>Detects a Data Matrix Code in an image.</p> * * @return {@link DetectorResult} encapsulating results of detecting a QR Code * @throws ReaderException if no Data Matrix Code can be found */ public DetectorResult detect() { if (!BlackPointEstimationMethod.TWO_D_SAMPLING.Equals(image.getLastEstimationMethod())) { image.estimateBlackPoint(BlackPointEstimationMethod.TWO_D_SAMPLING, 0); } int height = image.getHeight(); int width = image.getWidth(); int halfHeight = height >> 1; int halfWidth = width >> 1; int iSkip = Math.Max(1, height / (MAX_MODULES << 3)); int jSkip = Math.Max(1, width / (MAX_MODULES << 3)); int minI = 0; int maxI = height; int minJ = 0; int maxJ = width; ResultPoint pointA = findCornerFromCenter(halfHeight, -iSkip, minI, maxI, halfWidth, 0, minJ, maxJ, halfWidth >> 1); minI = (int)pointA.getY() - 1; ResultPoint pointB = findCornerFromCenter(halfHeight, 0, minI, maxI, halfWidth, -jSkip, minJ, maxJ, halfHeight >> 1); minJ = (int)pointB.getX() - 1; ResultPoint pointC = findCornerFromCenter(halfHeight, 0, minI, maxI, halfWidth, jSkip, minJ, maxJ, halfHeight >> 1); maxJ = (int)pointC.getX() + 1; ResultPoint pointD = findCornerFromCenter(halfHeight, iSkip, minI, maxI, halfWidth, 0, minJ, maxJ, halfWidth >> 1); maxI = (int)pointD.getY() + 1; // Go try to find point A again with better information -- might have been off at first. pointA = findCornerFromCenter(halfHeight, -iSkip, minI, maxI, halfWidth, 0, minJ, maxJ, halfWidth >> 2); // Point A and D are across the diagonal from one another, // as are B and C. Figure out which are the solid black lines // by counting transitions System.Collections.ArrayList transitions = new System.Collections.ArrayList(4); transitions.Add(transitionsBetween(pointA, pointB)); transitions.Add(transitionsBetween(pointA, pointC)); transitions.Add(transitionsBetween(pointB, pointD)); transitions.Add(transitionsBetween(pointC, pointD)); Collections.insertionSort(transitions, new ResultPointsAndTransitionsComparator()); // Sort by number of transitions. First two will be the two solid sides; last two // will be the two alternating black/white sides ResultPointsAndTransitions lSideOne = (ResultPointsAndTransitions)transitions[0]; ResultPointsAndTransitions lSideTwo = (ResultPointsAndTransitions)transitions[1]; // Figure out which point is their intersection by tallying up the number of times we see the // endpoints in the four endpoints. One will show up twice. System.Collections.Hashtable pointCount = new System.Collections.Hashtable(); increment(pointCount, lSideOne.getFrom()); increment(pointCount, lSideOne.getTo()); increment(pointCount, lSideTwo.getFrom()); increment(pointCount, lSideTwo.getTo()); ResultPoint maybeTopLeft = null; ResultPoint bottomLeft = null; ResultPoint maybeBottomRight = null; System.Collections.IEnumerator points = pointCount.GetEnumerator(); while (points.MoveNext()) { ResultPoint point = (ResultPoint)points.Current; int value = (int)pointCount[point]; if (value == 2) { bottomLeft = point; // this is definitely the bottom left, then -- end of two L sides } else { // Otherwise it's either top left or bottom right -- just assign the two arbitrarily now if (maybeTopLeft == null) { maybeTopLeft = point; } else { maybeBottomRight = point; } } } if (maybeTopLeft == null || bottomLeft == null || maybeBottomRight == null) { throw new ReaderException(); } // Bottom left is correct but top left and bottom right might be switched ResultPoint[] corners = { maybeTopLeft, bottomLeft, maybeBottomRight }; // Use the dot product trick to sort them out GenericResultPoint.orderBestPatterns(corners); // Now we know which is which: ResultPoint bottomRight = corners[0]; bottomLeft = corners[1]; ResultPoint topLeft = corners[2]; // Which point didn't we find in relation to the "L" sides? that's the top right corner ResultPoint topRight; if (!pointCount.ContainsKey(pointA)) { topRight = pointA; } else if (!pointCount.ContainsKey(pointB)) { topRight = pointB; } else if (!pointCount.ContainsKey(pointC)) { topRight = pointC; } else { topRight = pointD; } // Next determine the dimension by tracing along the top or right side and counting black/white // transitions. Since we start inside a black module, we should see a number of transitions // equal to 1 less than the code dimension. Well, actually 2 less, because we are going to // end on a black module: // The top right point is actually the corner of a module, which is one of the two black modules // adjacent to the white module at the top right. Tracing to that corner from either the top left // or bottom right should work here, but, one will be more reliable since it's traced straight // up or across, rather than at a slight angle. We use dot products to figure out which is // better to use: int dimension; if (GenericResultPoint.crossProductZ(bottomLeft, bottomRight, topRight) < GenericResultPoint.crossProductZ(topRight, topLeft, bottomLeft)) { dimension = transitionsBetween(topLeft, topRight).getTransitions(); } else { dimension = transitionsBetween(bottomRight, topRight).getTransitions(); } dimension += 2; BitMatrix bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, dimension); return(new DetectorResult(bits, new ResultPoint[] { pointA, pointB, pointC, pointD })); }
/// <summary> /// Locates and decodes a barcode in some format within an image. This method also accepts /// hints, each possibly associated to some data, which may help the implementation decode. /// Note that we don't try rotation without the try harder flag, even if rotation was supported. /// </summary> /// <param name="image">image of barcode to decode</param> /// <param name="hints">passed as a <see cref="IDictionary{TKey, TValue}"/> from <see cref="DecodeHintType"/> /// to arbitrary data. The /// meaning of the data depends upon the hint type. The implementation may or may not do /// anything with these hints.</param> /// <returns> /// String which the barcode encodes /// </returns> virtual public Result decode(BinaryBitmap image, IDictionary<DecodeHintType, object> hints) { var result = doDecode(image, hints); if (result == null) { bool tryHarder = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER); bool tryHarderWithoutRotation = hints != null && hints.ContainsKey(DecodeHintType.TRY_HARDER_WITHOUT_ROTATION); if (tryHarder && !tryHarderWithoutRotation && image.RotateSupported) { BinaryBitmap rotatedImage = image.rotateCounterClockwise(); result = doDecode(rotatedImage, hints); if (result == null) return null; // Record that we found it rotated 90 degrees CCW / 270 degrees CW IDictionary<ResultMetadataType, object> metadata = result.ResultMetadata; int orientation = 270; if (metadata != null && metadata.ContainsKey(ResultMetadataType.ORIENTATION)) { // But if we found it reversed in doDecode(), add in that result here: orientation = (orientation + (int) metadata[ResultMetadataType.ORIENTATION])%360; } result.putMetadata(ResultMetadataType.ORIENTATION, orientation); // Update result points ResultPoint[] points = result.ResultPoints; if (points != null) { int height = rotatedImage.Height; for (int i = 0; i < points.Length; i++) { points[i] = new ResultPoint(height - points[i].Y - 1, points[i].X); } } } } return result; }