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> <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; }
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); }
private static BitMatrix sampleGrid(BitMatrix matrix, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight, int dimension) { // Note that unlike 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(matrix, dimension, 0.0f, 0.0f, dimension, 0.0f, dimension, dimension, 0.0f, dimension, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); // p4FromY }
/// <summary> Locate the vertices and the codewords area of a black blob using the Start /// and Stop patterns as locators. This assumes that the image is rotated 180 /// degrees and if it locates the start and stop patterns at it will re-map /// the vertices for a 0 degree rotation. /// TODO: Change assumption about barcode location. /// TODO: Scanning every row is very expensive. We should only do this for TRY_HARDER. /// /// </summary> /// <param name="matrix">the scanned barcode image. /// </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[] findVertices180(BitMatrix matrix) { int height = matrix.Height; int width = matrix.Width; int halfWidth = width >> 1; ResultPoint[] result = new ResultPoint[8]; bool found = false; // Top Left for (int i = height - 1; i > 0; i--) { int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE); if (loc != null) { result[0] = new ResultPoint(loc[1], i); result[4] = new ResultPoint(loc[0], i); found = true; break; } } // Bottom Left if (found) { // Found the Top Left vertex found = false; for (int i = 0; i < height; i++) { int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE); if (loc != null) { result[1] = new ResultPoint(loc[1], i); result[5] = new ResultPoint(loc[0], i); found = true; break; } } } // Top Right if (found) { // Found the Bottom Left vertex found = false; for (int i = height - 1; i > 0; i--) { int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE); if (loc != null) { result[2] = new ResultPoint(loc[0], i); result[6] = new ResultPoint(loc[1], i); found = true; break; } } } // Bottom Right if (found) { // Found the Top Right vertex found = false; for (int i = 0; i < height; i++) { int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE); if (loc != null) { result[3] = new ResultPoint(loc[0], i); result[7] = new ResultPoint(loc[1], i); found = true; break; } } } return found?result:null; }
/// <summary> Because we scan horizontally to detect the start and stop patterns, the vertical component of /// the codeword coordinates will be slightly wrong if there is any skew or rotation in the image. /// This method moves those points back onto the edges of the theoretically perfect bounding /// quadrilateral if needed. /// /// </summary> /// <param name="vertices">The eight vertices located by findVertices(). /// </param> private static void correctCodeWordVertices(ResultPoint[] vertices, bool upsideDown) { float skew = vertices[4].Y - vertices[6].Y; if (upsideDown) { skew = - skew; } if (skew > SKEW_THRESHOLD) { // Fix v4 float length = vertices[4].X - vertices[0].X; float deltax = vertices[6].X - vertices[0].X; float deltay = vertices[6].Y - vertices[0].Y; float correction = length * deltay / deltax; vertices[4] = new ResultPoint(vertices[4].X, vertices[4].Y + correction); } else if (- skew > SKEW_THRESHOLD) { // Fix v6 float length = vertices[2].X - vertices[6].X; float deltax = vertices[2].X - vertices[4].X; float deltay = vertices[2].Y - vertices[4].Y; float correction = length * deltay / deltax; vertices[6] = new ResultPoint(vertices[6].X, vertices[6].Y - correction); } skew = vertices[7].Y - vertices[5].Y; if (upsideDown) { skew = - skew; } if (skew > SKEW_THRESHOLD) { // Fix v5 float length = vertices[5].X - vertices[1].X; float deltax = vertices[7].X - vertices[1].X; float deltay = vertices[7].Y - vertices[1].Y; float correction = length * deltay / deltax; vertices[5] = new ResultPoint(vertices[5].X, vertices[5].Y + correction); } else if (- skew > SKEW_THRESHOLD) { // Fix v7 float length = vertices[3].X - vertices[7].X; float deltax = vertices[3].X - vertices[5].X; float deltay = vertices[3].Y - vertices[5].Y; float correction = length * deltay / deltax; vertices[7] = new ResultPoint(vertices[7].X, vertices[7].Y - correction); } }
private static BitMatrix sampleGrid(BitMatrix 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.X - bottomLeft.X) + topLeft.X; float topRightY = (bottomRight.Y - bottomLeft.Y) + topLeft.Y; // 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.X, topLeft.Y, topRightX, topRightY, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); }
/// <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; }
// 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; } } }
/// <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> /// <throws> ReaderException Any spontaneous errors which occur </throws> private Result doDecode(BinaryBitmap image, System.Collections.Hashtable 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 = System.Math.Max(1, height >> (tryHarder?7:4)); int maxLines; if (tryHarder) { maxLines = height; // Look at the whole image, not just the center } else { maxLines = 9; // Nine rows spaced 1/16 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: try { row = image.getBlackRow(rowNumber, row); } catch (ReaderException) { 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)) { System.Collections.Hashtable newHints = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable()); // Can't use clone() in J2ME System.Collections.IEnumerator hintEnum = hints.Keys.GetEnumerator(); //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'" while (hintEnum.MoveNext()) { //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'" System.Object key = hintEnum.Current; if (!key.Equals(DecodeHintType.NEED_RESULT_POINT_CALLBACK)) { newHints[key] = hints[key]; } } hints = newHints; } } try { // Look for a barcode Result result = decodeRow(rowNumber, row, hints); // We found our barcode if (attempt == 1) { // But it was upside down, so note that result.putMetadata(ResultMetadataType.ORIENTATION, (System.Object) 180); // And remember to flip the result points horizontally. ResultPoint[] points = result.ResultPoints; 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; } catch (ReaderException) { // continue -- just couldn't decode this row } } } throw ReaderException.Instance; }
public DetectorResult(BitMatrix bits, ResultPoint[] points) { this.bits = bits; this.points = points; }
/// <summary> <p>Detects a Data Matrix Code in an image.</p> /// /// </summary> /// <returns> {@link DetectorResult} encapsulating results of detecting a QR Code /// </returns> /// <throws> ReaderException if no Data Matrix Code can be found </throws> public DetectorResult detect() { ResultPoint[] cornerPoints = rectangleDetector.detect(); ResultPoint pointA = cornerPoints[0]; ResultPoint pointB = cornerPoints[1]; ResultPoint pointC = cornerPoints[2]; ResultPoint pointD = cornerPoints[3]; // 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 = System.Collections.ArrayList.Synchronized(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 = System.Collections.Hashtable.Synchronized(new System.Collections.Hashtable()); increment(pointCount, lSideOne.From); increment(pointCount, lSideOne.To); increment(pointCount, lSideTwo.From); increment(pointCount, lSideTwo.To); ResultPoint maybeTopLeft = null; ResultPoint bottomLeft = null; ResultPoint maybeBottomRight = null; System.Collections.IEnumerator points = pointCount.Keys.GetEnumerator(); //UPGRADE_TODO: Method 'java.util.Enumeration.hasMoreElements' was converted to 'System.Collections.IEnumerator.MoveNext' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationhasMoreElements'" while (points.MoveNext()) { //UPGRADE_TODO: Method 'java.util.Enumeration.nextElement' was converted to 'System.Collections.IEnumerator.Current' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javautilEnumerationnextElement'" ResultPoint point = (ResultPoint) points.Current; System.Int32 value_Renamed = (System.Int32) pointCount[point]; if (value_Renamed == 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 ReaderException.Instance; } // Bottom left is correct but top left and bottom right might be switched ResultPoint[] corners = new ResultPoint[]{maybeTopLeft, bottomLeft, maybeBottomRight}; // Use the dot product trick to sort them out ResultPoint.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. The number of transitions could be higher than it should be // due to noise. So we try both and take the min. int dimension = System.Math.Min(transitionsBetween(topLeft, topRight).Transitions, transitionsBetween(bottomRight, topRight).Transitions); if ((dimension & 0x01) == 1) { // it can't be odd, so, round... up? dimension++; } dimension += 2; BitMatrix bits = sampleGrid(image, topLeft, bottomLeft, bottomRight, dimension); return new DetectorResult(bits, new ResultPoint[]{pointA, pointB, pointC, pointD}); }
internal ResultPointsAndTransitions(ResultPoint from, ResultPoint to, int transitions) { this.from = from; this.to = to; this.transitions = transitions; }
/// <summary> Counts the number of black/white transitions between two points, using something like Bresenham's algorithm.</summary> private ResultPointsAndTransitions transitionsBetween(ResultPoint from, ResultPoint to) { // See QR Code Detector, sizeOfBlackWhiteBlackRun() //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 fromX = (int) from.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 fromY = (int) from.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'" int toX = (int) to.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 toY = (int) to.Y; bool steep = System.Math.Abs(toY - fromY) > System.Math.Abs(toX - fromX); if (steep) { int temp = fromX; fromX = fromY; fromY = temp; temp = toX; toX = toY; toY = temp; } int dx = System.Math.Abs(toX - fromX); int dy = System.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.get_Renamed(steep?fromY:fromX, steep?fromX:fromY); for (int x = fromX, y = fromY; x != toX; x += xstep) { bool isBlack = image.get_Renamed(steep?y:x, steep?x:y); if (isBlack != inBlack) { transitions++; inBlack = isBlack; } error += dy; if (error > 0) { if (y == toY) { break; } y += ystep; error -= dx; } } return new ResultPointsAndTransitions(from, to, transitions); }
/// <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; }
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; 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) { try { //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'" alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float) i); break; } catch (ReaderException) { // try next round } } // 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); 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> Computes the dimension (number of modules in a row) of the PDF417 Code /// based on vertices of the codeword area and estimated module size. /// /// </summary> /// <param name="topLeft"> of codeword area /// </param> /// <param name="topRight"> of codeword area /// </param> /// <param name="bottomLeft"> of codeword area /// </param> /// <param name="bottomRight">of codeword are /// </param> /// <param name="moduleWidth">estimated module size /// </param> /// <returns> the number of modules in a row. /// </returns> private static int computeDimension(ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint bottomRight, float moduleWidth) { int topRowDimension = round(ResultPoint.distance(topLeft, topRight) / moduleWidth); int bottomRowDimension = round(ResultPoint.distance(bottomLeft, bottomRight) / moduleWidth); return ((((topRowDimension + bottomRowDimension) >> 1) + 8) / 17) * 17; /* * int topRowDimension = round(ResultPoint.distance(topLeft, * topRight)); //moduleWidth); int bottomRowDimension = * round(ResultPoint.distance(bottomLeft, bottomRight)); // * moduleWidth); int dimension = ((topRowDimension + bottomRowDimension) * >> 1); // Round up to nearest 17 modules i.e. there are 17 modules per * codeword //int dimension = ((((topRowDimension + bottomRowDimension) >> * 1) + 8) / 17) * 17; return dimension; */ }
/// <summary> <p>Estimates module size (pixels in a module) based on the Start and End /// finder patterns.</p> /// /// </summary> /// <param name="vertices">an array of 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 /// </param> /// <returns> the module size. /// </returns> private static float computeModuleWidth(ResultPoint[] vertices) { float pixels1 = ResultPoint.distance(vertices[0], vertices[4]); float pixels2 = ResultPoint.distance(vertices[1], vertices[5]); float moduleWidth1 = (pixels1 + pixels2) / (17 * 2.0f); float pixels3 = ResultPoint.distance(vertices[6], vertices[2]); float pixels4 = ResultPoint.distance(vertices[7], vertices[3]); float moduleWidth2 = (pixels3 + pixels4) / (18 * 2.0f); return (moduleWidth1 + moduleWidth2) / 2.0f; }
/// <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 }