public override BitMatrix sampleGrid(BitMatrix image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) { PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); return sampleGrid(image, dimension, transform); }
/** * <p>Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken * to mean a black module.</p> * * @param bits booleans representing white/black Data Matrix Code modules * @return text and bytes encoded within the Data Matrix Code * @throws ReaderException if the Data Matrix Code cannot be decoded */ public DecoderResult decode(BitMatrix bits) { // Construct a parser and read version, error-correction level BitMatrixParser parser = new BitMatrixParser(bits); Version version = parser.readVersion(bits); // Read codewords sbyte[] codewords = parser.readCodewords(); // Separate into data blocks DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version); // Count total number of data bytes int totalBytes = 0; for (int i = 0; i < dataBlocks.Length; i++) { totalBytes += dataBlocks[i].getNumDataCodewords(); } sbyte[] resultBytes = new sbyte[totalBytes]; int resultOffset = 0; // Error-correct and copy data blocks together into a stream of bytes for (int j = 0; j < dataBlocks.Length; j++) { DataBlock dataBlock = dataBlocks[j]; sbyte[] codewordBytes = dataBlock.getCodewords(); int numDataCodewords = dataBlock.getNumDataCodewords(); correctErrors(codewordBytes, numDataCodewords); for (int i = 0; i < numDataCodewords; i++) { resultBytes[resultOffset++] = codewordBytes[i]; } } // Decode the contents of that stream of bytes return DecodedBitStreamParser.decode(resultBytes); }
/** * @param bitMatrix {@link BitMatrix} to parse * @throws ReaderException if dimension is not >= 21 and 1 mod 4 */ public BitMatrixParser(BitMatrix bitMatrix){ int dimension = bitMatrix.getDimension(); if (dimension < 21 || (dimension & 0x03) != 1) { throw new ReaderException(); } this.bitMatrix = bitMatrix; }
/** * @param bitMatrix {@link BitMatrix} to parse * @throws ReaderException if dimension is < 10 or > 144 or not 0 mod 2 */ public BitMatrixParser(BitMatrix bitMatrix) { int dimension = bitMatrix.getDimension(); if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0) { throw new ReaderException(); } version = readVersion(bitMatrix); this.mappingBitMatrix = extractDataRegion(bitMatrix); // TODO(bbrown): Make this work for rectangular symbols this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.getDimension()); }
/** * <p>Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans. * "true" is taken to mean a black module.</p> * * @param image booleans representing white/black Data Matrix Code modules * @return text and bytes encoded within the Data Matrix Code * @throws ReaderException if the Data Matrix Code cannot be decoded */ public DecoderResult decode(bool[][] image) { int dimension = image.Length; BitMatrix bits = new BitMatrix(dimension); for (int i = 0; i < dimension; i++) { for (int j = 0; j < dimension; j++) { if (image[i][j]) { bits.set(i, j); } } } return decode(bits); }
/** * <p>Convenience method that can decode a QR Code represented as a 2D array of booleans. * "true" is taken to mean a black module.</p> * * @param image booleans representing white/black QR Code modules * @return text and bytes encoded within the QR Code * @throws ReaderException if the QR Code cannot be decoded */ public DecoderResult decode(bool[][] image) { try{ int dimension = image.Length; BitMatrix bits = new BitMatrix(dimension); for (int i = 0; i < dimension; i++) { for (int j = 0; j < dimension; j++) { if (image[i][j]) { bits.set(i, j); } } } return decode(bits); }catch (Exception e){ throw new ReaderException(e.Message); } }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform) throws com.google.zxing.NotFoundException public override BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform) { if (dimensionX <= 0 || dimensionY <= 0) { throw NotFoundException.NotFoundInstance; } BitMatrix bits = new BitMatrix(dimensionX, dimensionY); float[] points = new float[dimensionX << 1]; for (int y = 0; y < dimensionY; y++) { int max = points.Length; float iValue = (float) y + 0.5f; for (int x = 0; x < max; x += 2) { points[x] = (float)(x >> 1) + 0.5f; points[x + 1] = iValue; } transform.transformPoints(points); // Quick check to see if points transformed to something inside the image; // sufficient to check the endpoints checkAndNudgePoints(image, points); try { for (int x = 0; x < max; x += 2) { if (image.get((int) points[x], (int) points[x + 1])) { // Black(-ish) pixel bits.set(x >> 1, y); } } } catch (System.IndexOutOfRangeException aioobe) { // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting // transform gets "twisted" such that it maps a straight line of points to a set of points // whose endpoints are in bounds, but others are not. There is probably some mathematical // way to detect this about the transformation that I don't know yet. // This results in an ugly runtime exception despite our clever checks above -- can't have // that. We could check each point's coordinates but that feels duplicative. We settle for // catching and wrapping ArrayIndexOutOfBoundsException. throw NotFoundException.NotFoundInstance; } } return bits; }
public override BitMatrix sampleGrid(MonochromeBitmapSource image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) { PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); BitMatrix bits = new BitMatrix(dimension); float[] points = new float[dimension << 1]; for (int i = 0; i < dimension; i++) { int max = points.Length; float iValue = (float)i + 0.5f; for (int j = 0; j < max; j += 2) { points[j] = (float)(j >> 1) + 0.5f; points[j + 1] = iValue; } transform.transformPoints(points); // Quick check to see if points transformed to something inside the image; // sufficent to check the endpoints checkAndNudgePoints(image, points); try { for (int j = 0; j < max; j += 2) { //UPGRADE_WARNING: Narrowing conversions may produce unexpected results in C#. 'ms-help://MS.VSCC.2003/commoner/redir/redirect.htm?keyword="jlca1042"' if (image.isBlack((int)points[j], (int)points[j + 1])) { // Black(-ish) pixel bits.set(i, j >> 1); } } } catch (System.IndexOutOfRangeException aioobe) { // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting // transform gets "twisted" such that it maps a straight line of points to a set of points // whose endpoints are in bounds, but others are not. There is probably some mathematical // way to detect this about the transformation that I don't know yet. // This results in an ugly runtime exception despite our clever checks above -- can't have that. // We could check each point's coordinates but that feels duplicative. We settle for // catching and wrapping ArrayIndexOutOfBoundsException. throw new ReaderException(aioobe.Message); } } return bits; }
public override BitMatrix sampleGrid(BitMatrix image, int dimension, PerspectiveTransform transform) { BitMatrix bits = new BitMatrix(dimension); float[] points = new float[dimension << 1]; for (int y = 0; y < dimension; y++) { int max = points.Length; //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 iValue = (float) y + 0.5f; for (int x = 0; x < max; x += 2) { //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'" points[x] = (float) (x >> 1) + 0.5f; points[x + 1] = iValue; } transform.transformPoints(points); // Quick check to see if points transformed to something inside the image; // sufficient to check the endpoints checkAndNudgePoints(image, points); try { for (int x = 0; x < max; x += 2) { //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'" if (image.get_Renamed((int) points[x], (int) points[x + 1])) { // Black(-ish) pixel bits.set_Renamed(x >> 1, y); } } } catch (System.IndexOutOfRangeException) { // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting // transform gets "twisted" such that it maps a straight line of points to a set of points // whose endpoints are in bounds, but others are not. There is probably some mathematical // way to detect this about the transformation that I don't know yet. // This results in an ugly runtime exception despite our clever checks above -- can't have // that. We could check each point's coordinates but that feels duplicative. We settle for // catching and wrapping ArrayIndexOutOfBoundsException. throw ReaderException.Instance; } } return bits; }
/** * <p>Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module.</p> * * @param bits booleans representing white/black QR Code modules * @return text and bytes encoded within the QR Code * @throws ReaderException if the QR Code cannot be decoded */ public DecoderResult decode(BitMatrix bits) { try{ // Construct a parser and read version, error-correction level BitMatrixParser parser = new BitMatrixParser(bits); Version version = parser.readVersion(); ErrorCorrectionLevel ecLevel = parser.readFormatInformation().getErrorCorrectionLevel(); // Read codewords sbyte[] codewords = parser.readCodewords(); // Separate into data blocks DataBlock[] dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel); // Count total number of data bytes int totalBytes = 0; for (int i = 0; i < dataBlocks.Length; i++) { totalBytes += dataBlocks[i].NumDataCodewords; } sbyte[] resultBytes = new sbyte[totalBytes]; int resultOffset = 0; // Error-correct and copy data blocks together into a stream of bytes for (int j = 0; j < dataBlocks.Length; j++) { DataBlock dataBlock = dataBlocks[j]; sbyte[] codewordBytes = dataBlock.Codewords; int numDataCodewords = dataBlock.NumDataCodewords; correctErrors(codewordBytes, numDataCodewords); for (int i = 0; i < numDataCodewords; i++) { resultBytes[resultOffset++] = codewordBytes[i]; } } // Decode the contents of that stream of bytes string sResult = DecodedBitStreamParser.decode(resultBytes, version); return new DecoderResult(resultBytes, sResult, null); }catch(Exception e){ throw new ReaderException(e.Message); } }
// Calculates the final BitMatrix once for all requests. This could be called once from the // constructor instead, but there are some advantages to doing it lazily, such as making // profiling easier, and not doing heavy lifting when callers don't expect it. private void binarizeEntireImage() { if (matrix == null) { LuminanceSource source = LuminanceSource; if (source.Width >= MINIMUM_DIMENSION && source.Height >= MINIMUM_DIMENSION) { sbyte[] luminances = source.Matrix; int width = source.Width; int height = source.Height; int subWidth = width >> 3; int subHeight = height >> 3; int[][] blackPoints = calculateBlackPoints(luminances, subWidth, subHeight, width); matrix = new BitMatrix(width, height); calculateThresholdForBlock(luminances, subWidth, subHeight, width, blackPoints, matrix); } else { // If the image is too small, fall back to the global histogram approach. matrix = base.BlackMatrix; } } }
// For each 8x8 block in the image, calculate the average black point using a 5x5 grid // of the blocks around it. Also handles the corner cases, but will ignore up to 7 pixels // on the right edge and 7 pixels at the bottom of the image if the overall dimensions are not // multiples of eight. In practice, leaving those pixels white does not seem to be a problem. private static void calculateThresholdForBlock(sbyte[] luminances, int subWidth, int subHeight, int stride, int[][] blackPoints, BitMatrix matrix) { for (int y = 0; y < subHeight; y++) { for (int x = 0; x < subWidth; x++) { int left = (x > 1)?x:2; left = (left < subWidth - 2)?left:subWidth - 3; int top = (y > 1)?y:2; top = (top < subHeight - 2)?top:subHeight - 3; int sum = 0; for (int z = - 2; z <= 2; z++) { int[] blackRow = blackPoints[top + z]; sum += blackRow[left - 2]; sum += blackRow[left - 1]; sum += blackRow[left]; sum += blackRow[left + 1]; sum += blackRow[left + 2]; } int average = sum / 25; threshold8x8Block(luminances, x << 3, y << 3, average, stride, matrix); } } }
/** * <p>Creates the version object based on the dimension of the original bit matrix from * the datamatrix code.</p> * * <p>See ISO 16022:2006 Table 7 - ECC 200 symbol attributes</p> * * @param bitMatrix Original {@link BitMatrix} including alignment patterns * @return {@link Version} encapsulating the Data Matrix Code's "version" * @throws ReaderException if the dimensions of the mapping matrix are not valid * Data Matrix dimensions. */ public Version readVersion(BitMatrix bitMatrix) { if (version != null) { return version; } // TODO(bbrown): make this work for rectangular dimensions as well. int numRows = bitMatrix.getDimension(); int numColumns = numRows; return Version.getVersionForDimensions(numRows, numColumns); }
/** * <p>Extracts the data region from a {@link BitMatrix} that contains * alignment patterns.</p> * * @param bitMatrix Original {@link BitMatrix} with alignment patterns * @return BitMatrix that has the alignment patterns removed */ BitMatrix extractDataRegion(BitMatrix bitMatrix) { int symbolSizeRows = version.getSymbolSizeRows(); int symbolSizeColumns = version.getSymbolSizeColumns(); // TODO(bbrown): Make this work with rectangular codes if (bitMatrix.getDimension() != symbolSizeRows) { throw new ArgumentException("Dimension of bitMarix must match the version size"); } int dataRegionSizeRows = version.getDataRegionSizeRows(); int dataRegionSizeColumns = version.getDataRegionSizeColumns(); int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows; int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns; int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows; //int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns; // TODO(bbrown): Make this work with rectangular codes BitMatrix bitMatrixWithoutAlignment = new BitMatrix(sizeDataRegionRow); for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) { int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows; for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) { int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns; for (int i = 0; i < dataRegionSizeRows; ++i) { int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i; int writeRowOffset = dataRegionRowOffset + i; for (int j = 0; j < dataRegionSizeColumns; ++j) { int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j; if (bitMatrix.get(readRowOffset, readColumnOffset)) { int writeColumnOffset = dataRegionColumnOffset + j; bitMatrixWithoutAlignment.set(writeRowOffset, writeColumnOffset); } } } } } return bitMatrixWithoutAlignment; }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: private static com.google.zxing.common.BitMatrix sampleGrid(com.google.zxing.common.BitMatrix matrix, com.google.zxing.ResultPoint topLeft, com.google.zxing.ResultPoint bottomLeft, com.google.zxing.ResultPoint topRight, com.google.zxing.ResultPoint bottomRight, int xdimension, int ydimension) throws com.google.zxing.NotFoundException private static BitMatrix sampleGrid(BitMatrix matrix, ResultPoint topLeft, ResultPoint bottomLeft, ResultPoint topRight, ResultPoint bottomRight, int xdimension, int ydimension) { // 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, xdimension, ydimension, 0.0f, 0.0f, xdimension, 0.0f, xdimension, ydimension, 0.0f, ydimension, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRight.X, bottomRight.Y, bottomLeft.X, bottomLeft.Y); // p4FromY - p4FromX - p3FromY - p3FromX - p2FromY - p2FromX - p1FromY - p1FromX - p4ToY - p4ToX - p3ToY - p3ToX - p2ToY - p2ToX - p1ToY - p1ToX }
/** * This method detects a Data Matrix code in a "pure" image -- that is, pure monochrome image * which contains only an unrotated, unskewed, image of a Data Matrix code, with some white border * around it. This is a specialized method that works exceptionally fast in this special * case. */ private static BitMatrix extractPureBits(MonochromeBitmapSource image) { // Now need to determine module size in pixels int height = image.getHeight(); int width = image.getWidth(); int minDimension = Math.Min(height, width); // First, skip white border by tracking diagonally from the top left down and to the right: int borderWidth = 0; while (borderWidth < minDimension && !image.isBlack(borderWidth, borderWidth)) { borderWidth++; } if (borderWidth == minDimension) { throw new ReaderException(); } // And then keep tracking across the top-left black module to determine module size int moduleEnd = borderWidth + 1; while (moduleEnd < width && image.isBlack(moduleEnd, borderWidth)) { moduleEnd++; } if (moduleEnd == width) { throw new ReaderException(); } int moduleSize = moduleEnd - borderWidth; // And now find where the bottommost black module on the first column ends int columnEndOfSymbol = height - 1; while (columnEndOfSymbol >= 0 && !image.isBlack(borderWidth, columnEndOfSymbol)) { columnEndOfSymbol--; } if (columnEndOfSymbol < 0) { throw new ReaderException(); } columnEndOfSymbol++; // Make sure width of barcode is a multiple of module size if ((columnEndOfSymbol - borderWidth) % moduleSize != 0) { throw new ReaderException(); } int dimension = (columnEndOfSymbol - borderWidth) / moduleSize; // Push in the "border" by half the module width so that we start // sampling in the middle of the module. Just in case the image is a // little off, this will help recover. borderWidth += moduleSize >> 1; int sampleDimension = borderWidth + (dimension - 1) * moduleSize; if (sampleDimension >= width || sampleDimension >= height) { throw new ReaderException(); } // Now just read off the bits BitMatrix bits = new BitMatrix(dimension); for (int i = 0; i < dimension; i++) { int iOffset = borderWidth + i * moduleSize; for (int j = 0; j < dimension; j++) { if (image.isBlack(borderWidth + j * moduleSize, iOffset)) { bits.set(i, j); } } } return bits; }
public DetectorResult(BitMatrix bits, ResultPoint[] points) { this.bits = bits; this.points = points; }
/** * See ISO 18004:2006 Annex E */ public BitMatrix buildFunctionPattern() { int dimension = getDimensionForVersion(); BitMatrix bitMatrix = new BitMatrix(dimension); // Top left finder pattern + separator + format bitMatrix.setRegion(0, 0, 9, 9); // Top right finder pattern + separator + format bitMatrix.setRegion(0, dimension - 8, 9, 8); // Bottom left finder pattern + separator + format bitMatrix.setRegion(dimension - 8, 0, 8, 9); // Alignment patterns int max = alignmentPatternCenters.Length; for (int x = 0; x < max; x++) { int i = alignmentPatternCenters[x] - 2; for (int y = 0; y < max; y++) { if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { // No alignment patterns near the three finder paterns continue; } bitMatrix.setRegion(i, alignmentPatternCenters[y] - 2, 5, 5); } } // Vertical timing pattern bitMatrix.setRegion(9, 6, dimension - 17, 1); // Horizontal timing pattern bitMatrix.setRegion(6, 9, 1, dimension - 17); if (versionNumber > 6) { // Version info, top right bitMatrix.setRegion(0, dimension - 11, 6, 3); // Version info, bottom left bitMatrix.setRegion(dimension - 11, 0, 3, 6); } return bitMatrix; }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) throws com.google.zxing.NotFoundException public override BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY) { PerspectiveTransform transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); return(sampleGrid(image, dimensionX, dimensionY, transform)); }
/// <summary> /// <p>Checks a set of points that have been transformed to sample points on an image against /// the image's dimensions to see if the point are even within the image.</p> /// /// <p>This method will actually "nudge" the endpoints back onto the image if they are found to be /// barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder /// patterns in an image where the QR Code runs all the way to the image border.</p> /// /// <p>For efficiency, the method will check points from either end of the line until one is found /// to be within the image. Because the set of points are assumed to be linear, this is valid.</p> /// </summary> /// <param name="image"> image into which the points should map </param> /// <param name="points"> actual points in x1,y1,...,xn,yn form </param> /// <exception cref="NotFoundException"> if an endpoint is lies outside the image boundaries </exception> //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: protected static void checkAndNudgePoints(BitMatrix image, float[] points) throws com.google.zxing.NotFoundException protected internal static void checkAndNudgePoints(BitMatrix image, float[] points) { int width = image.Width; int height = image.Height; // Check and nudge points from start until we see some that are OK: bool nudged = true; for (int offset = 0; offset < points.Length && nudged; offset += 2) { int x = (int) points[offset]; int y = (int) points[offset + 1]; if (x < -1 || x > width || y < -1 || y > height) { throw NotFoundException.NotFoundInstance; } nudged = false; if (x == -1) { points[offset] = 0.0f; nudged = true; } else if (x == width) { points[offset] = width - 1; nudged = true; } if (y == -1) { points[offset + 1] = 0.0f; nudged = true; } else if (y == height) { points[offset + 1] = height - 1; nudged = true; } } // Check and nudge points from end: nudged = true; for (int offset = points.Length - 2; offset >= 0 && nudged; offset -= 2) { int x = (int) points[offset]; int y = (int) points[offset + 1]; if (x < -1 || x > width || y < -1 || y > height) { throw NotFoundException.NotFoundInstance; } nudged = false; if (x == -1) { points[offset] = 0.0f; nudged = true; } else if (x == width) { points[offset] = width - 1; nudged = true; } if (y == -1) { points[offset + 1] = 0.0f; nudged = true; } else if (y == height) { points[offset + 1] = height - 1; nudged = true; } } }
public virtual BitMatrix sampleGrid(BitMatrix image, int dimension, PerspectiveTransform transform) { throw new System.NotSupportedException(); }
/// <summary> <p>Samples an image for a square matrix of bits of the given dimension. This is used to extract /// the black/white modules of a 2D barcode like a QR Code found in an image. Because this barcode /// may be rotated or perspective-distorted, the caller supplies four points in the source image /// that define known points in the barcode, so that the image may be sampled appropriately.</p> /// /// <p>The last eight "from" parameters are four X/Y coordinate pairs of locations of points in /// the image that define some significant points in the image to be sample. For example, /// these may be the location of finder pattern in a QR Code.</p> /// /// <p>The first eight "to" parameters are four X/Y coordinate pairs measured in the destination /// {@link BitMatrix}, from the top left, where the known points in the image given by the "from" /// parameters map to.</p> /// /// <p>These 16 parameters define the transformation needed to sample the image.</p> /// /// </summary> /// <param name="image">image to sample /// </param> /// <param name="dimension">width/height of {@link BitMatrix} to sample from image /// </param> /// <returns> {@link BitMatrix} representing a grid of points sampled from the image within a region /// defined by the "from" parameters /// </returns> /// <throws> ReaderException if image can't be sampled, for example, if the transformation defined </throws> /// <summary> by the given points is invalid or results in sampling outside the image boundaries /// </summary> public abstract BitMatrix sampleGrid(BitMatrix image, int dimension, float p1ToX, float p1ToY, float p2ToX, float p2ToY, float p3ToX, float p3ToY, float p4ToX, float p4ToY, float p1FromX, float p1FromY, float p2FromX, float p2FromY, float p3FromX, float p3FromY, float p4FromX, float p4FromY);
/// <summary> <p>Checks a set of points that have been transformed to sample points on an image against /// the image's dimensions to see if the point are even within the image.</p> /// /// <p>This method will actually "nudge" the endpoints back onto the image if they are found to be /// barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder /// patterns in an image where the QR Code runs all the way to the image border.</p> /// /// <p>For efficiency, the method will check points from either end of the line until one is found /// to be within the image. Because the set of points are assumed to be linear, this is valid.</p> /// /// </summary> /// <param name="image">image into which the points should map /// </param> /// <param name="points">actual points in x1,y1,...,xn,yn form /// </param> /// <throws> ReaderException if an endpoint is lies outside the image boundaries </throws> protected internal static void checkAndNudgePoints(BitMatrix image, float[] points) { int width = image.Width; int height = image.Height; // Check and nudge points from start until we see some that are OK: bool nudged = true; for (int offset = 0; offset < points.Length && nudged; offset += 2) { //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 x = (int) points[offset]; //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 y = (int) points[offset + 1]; if (x < - 1 || x > width || y < - 1 || y > height) { throw ReaderException.Instance; } nudged = false; if (x == - 1) { points[offset] = 0.0f; nudged = true; } else if (x == width) { points[offset] = width - 1; nudged = true; } if (y == - 1) { points[offset + 1] = 0.0f; nudged = true; } else if (y == height) { points[offset + 1] = height - 1; nudged = true; } } // Check and nudge points from end: nudged = true; for (int offset = points.Length - 2; offset >= 0 && nudged; offset -= 2) { //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 x = (int) points[offset]; //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 y = (int) points[offset + 1]; if (x < - 1 || x > width || y < - 1 || y > height) { throw ReaderException.Instance; } nudged = false; if (x == - 1) { points[offset] = 0.0f; nudged = true; } else if (x == width) { points[offset] = width - 1; nudged = true; } if (y == - 1) { points[offset + 1] = 0.0f; nudged = true; } else if (y == height) { points[offset + 1] = height - 1; nudged = true; } } }
// Applies a single threshold to an 8x8 block of pixels. private static void threshold8x8Block(sbyte[] luminances, int xoffset, int yoffset, int threshold, int stride, BitMatrix matrix) { for (int y = 0; y < 8; y++) { int offset = (yoffset + y) * stride + xoffset; for (int x = 0; x < 8; x++) { int pixel = luminances[offset + x] & 0xff; if (pixel < threshold) { matrix.set_Renamed(xoffset + x, yoffset + y); } } } }
/// <param name="matrix"> row of black/white values to search </param> /// <param name="column"> x position to start search </param> /// <param name="row"> y position to start search </param> /// <param name="width"> the number of pixels to search on this row </param> /// <param name="pattern"> pattern of counts of number of black and white pixels that are /// being searched for as a pattern </param> /// <param name="counters"> array of counters, as long as pattern, to re-use </param> /// <returns> start/end horizontal offset of guard pattern, as an array of two ints. </returns> private static int[] findGuardPattern(BitMatrix matrix, int column, int row, int width, bool whiteFirst, int[] pattern, int[] counters) { //Arrays.fill(counters, 0, counters.Length, 0); counters.Fill(0); int patternLength = pattern.Length; bool isWhite = whiteFirst; int counterPosition = 0; int patternStart = column; for (int x = column; x < column + width; x++) { bool pixel = matrix.get(x, row); if (pixel ^ isWhite) { counters[counterPosition]++; } else { if (counterPosition == patternLength - 1) { if (patternMatchVariance(counters, pattern, MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) { return new int[]{patternStart, x}; } patternStart += counters[0] + counters[1]; Array.Copy(counters, 2, counters, 0, patternLength - 2); counters[patternLength - 2] = 0; counters[patternLength - 1] = 0; counterPosition--; } else { counterPosition++; } counters[counterPosition] = 1; isWhite = !isWhite; } } return null; }
/// <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. /// </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, bool tryHarder) { int height = matrix.Height; int width = matrix.Width; int halfWidth = width >> 1; ResultPoint[] result = new ResultPoint[8]; bool found = false; int[] counters = new int[START_PATTERN_REVERSE.Length]; int rowStep = Math.Max(1, height >> (tryHarder ? 9 : 7)); // Top Left for (int i = height - 1; i > 0; i -= rowStep) { int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE, counters); 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 += rowStep) { int[] loc = findGuardPattern(matrix, halfWidth, i, halfWidth, true, START_PATTERN_REVERSE, counters); if (loc != null) { result[1] = new ResultPoint(loc[1], i); result[5] = new ResultPoint(loc[0], i); found = true; break; } } } counters = new int[STOP_PATTERN_REVERSE.Length]; // Top Right if (found) // Found the Bottom Left vertex { found = false; for (int i = height - 1; i > 0; i -= rowStep) { int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE, counters); 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 += rowStep) { int[] loc = findGuardPattern(matrix, 0, i, halfWidth, false, STOP_PATTERN_REVERSE, counters); 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> /// For each block in the image, calculate the average black point using a 5x5 grid /// of the blocks around it. Also handles the corner cases (fractional blocks are computed based /// on the last pixels in the row/column which are also used in the previous block). /// </summary> private static void calculateThresholdForBlock(sbyte[] luminances, int subWidth, int subHeight, int width, int height, int[][] blackPoints, BitMatrix matrix) { for (int y = 0; y < subHeight; y++) { int yoffset = y << BLOCK_SIZE_POWER; int maxYOffset = height - BLOCK_SIZE; if (yoffset > maxYOffset) { yoffset = maxYOffset; } for (int x = 0; x < subWidth; x++) { int xoffset = x << BLOCK_SIZE_POWER; int maxXOffset = width - BLOCK_SIZE; if (xoffset > maxXOffset) { xoffset = maxXOffset; } int left = cap(x, 2, subWidth - 3); int top = cap(y, 2, subHeight - 3); int sum = 0; for (int z = -2; z <= 2; z++) { int[] blackRow = blackPoints[top + z]; sum += blackRow[left - 2] + blackRow[left - 1] + blackRow[left] + blackRow[left + 1] + blackRow[left + 2]; } int average = sum / 25; thresholdBlock(luminances, xoffset, yoffset, average, width, matrix); } } }
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET: //ORIGINAL LINE: public abstract BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform) throws com.google.zxing.NotFoundException; public abstract BitMatrix sampleGrid(BitMatrix image, int dimensionX, int dimensionY, PerspectiveTransform transform);
/// <summary> /// Applies a single threshold to a block of pixels. /// </summary> private static void thresholdBlock(sbyte[] luminances, int xoffset, int yoffset, int threshold, int stride, BitMatrix matrix) { for (int y = 0, offset = yoffset * stride + xoffset; y < BLOCK_SIZE; y++, offset += stride) { for (int x = 0; x < BLOCK_SIZE; x++) { // Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0. if ((luminances[offset + x] & 0xFF) <= threshold) { matrix.set(xoffset + x, yoffset + y); } } } }