public Result decode(MonochromeBitmapSource image, System.Collections.Hashtable hints) { DecoderResult decoderResult; ResultPoint[] points; if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) { BitMatrix bits = extractPureBits(image); decoderResult = decoder.decode(bits); points = NO_POINTS; } else { DetectorResult detectorResult = new Detector(image).detect(); decoderResult = decoder.decode(detectorResult.getBits()); points = detectorResult.getPoints(); } Result result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.DATAMATRIX); if (decoderResult.getByteSegments() != null) { result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult.getByteSegments()); } return(result); }
public Result decode(MonochromeBitmapSource 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.isRotateSupported()) { MonochromeBitmapSource 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.getResultMetadata(); 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); return(result); } else { throw re; } } }
/** * Decode an image using the hints provided. Does not honor existing state. * * @param image The pixel data to decode * @param hints The hints to use, clearing the previous state. * @return The contents of the image * @throws ReaderException Any errors which occurred */ public Result decode(MonochromeBitmapSource image, Hashtable hints){ try{ setHints(hints); return decodeInternal(image); }catch(Exception e){ throw new ReaderException (e.Message); } }
/** * Locates and decodes a QR code in an image. * * @return a String representing the content encoded by the QR code * @throws ReaderException if a QR code cannot be found, or cannot be decoded */ public Result decode(MonochromeBitmapSource image) { try{ return(decode(image, null)); } catch (Exception e) { throw new ReaderException(e.Message); } }
/** * Locates and decodes a QR code in an image. * * @return a String representing the content encoded by the QR code * @throws ReaderException if a QR code cannot be found, or cannot be decoded */ public Result decode(MonochromeBitmapSource image) { try{ return decode(image, null); } catch(Exception e){ throw new ReaderException(e.Message); } }
/** * Decode an image using the hints provided. Does not honor existing state. * * @param image The pixel data to decode * @param hints The hints to use, clearing the previous state. * @return The contents of the image * @throws ReaderException Any errors which occurred */ public Result decode(MonochromeBitmapSource image, Hashtable hints) { try{ setHints(hints); return(decodeInternal(image)); }catch (Exception e) { throw new ReaderException(e.Message); } }
/** * Decode an image using the state set up by calling setHints() previously. Continuous scan * clients will get a <b>large</b> speed increase by using this instead of decode(). * * @param image The pixel data to decode * @return The contents of the image * @throws ReaderException Any errors which occurred */ public Result decodeWithState(MonochromeBitmapSource image){ try{ // Make sure to set up the default state so we don't crash if (readers == null) { setHints(null); } return decodeInternal(image); }catch(Exception e){ throw new ReaderException(e.Message); } }
/** * Decode an image using the state set up by calling setHints() previously. Continuous scan * clients will get a <b>large</b> speed increase by using this instead of decode(). * * @param image The pixel data to decode * @return The contents of the image * @throws ReaderException Any errors which occurred */ public Result decodeWithState(MonochromeBitmapSource image) { try{ // Make sure to set up the default state so we don't crash if (readers == null) { setHints(null); } return(decodeInternal(image)); }catch (Exception e) { throw new ReaderException(e.Message); } }
private static BitMatrix sampleGrid(MonochromeBitmapSource image, ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint alignmentPattern, int dimension) { float dimMinusThree = (float)dimension - 3.5f; float bottomRightX; float bottomRightY; float sourceBottomRightX; float sourceBottomRightY; if (alignmentPattern != null) { bottomRightX = alignmentPattern.getX(); bottomRightY = alignmentPattern.getY(); sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; } else { // Don't have an alignment pattern, just make up the bottom-right point bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX(); bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY(); sourceBottomRightX = sourceBottomRightY = dimMinusThree; } GridSampler sampler = GridSampler.Instance; return(sampler.sampleGrid( image, dimension, 3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, sourceBottomRightY, 3.5f, dimMinusThree, topLeft.getX(), topLeft.getY(), topRight.getX(), topRight.getY(), bottomRightX, bottomRightY, bottomLeft.getX(), bottomLeft.getY())); }
/** * <p>Creates a finder that will look in a portion of the whole image.</p> * * @param image image to search * @param startX left column from which to start searching * @param startY top row from which to start searching * @param width width of region to search * @param height height of region to search * @param moduleSize estimated module size so far */ public AlignmentPatternFinder(MonochromeBitmapSource image, int startX, int startY, int width, int height, float moduleSize) { this.image = image; this.possibleCenters = new System.Collections.ArrayList(5); this.startX = startX; this.startY = startY; this.width = width; this.height = height; this.moduleSize = moduleSize; this.crossCheckStateCount = new int[3]; }
/** * <p>Creates a finder that will look in a portion of the whole image.</p> * * @param image image to search * @param startX left column from which to start searching * @param startY top row from which to start searching * @param width width of region to search * @param height height of region to search * @param moduleSize estimated module size so far */ public AlignmentPatternFinder(MonochromeBitmapSource image, int startX, int startY, int width, int height, float moduleSize) { this.image = image; this.possibleCenters = new System.Collections.ArrayList(5); this.startX = startX; this.startY = startY; this.width = width; this.height = height; this.moduleSize = moduleSize; this.crossCheckStateCount = new int[3]; }
public Result decode(MonochromeBitmapSource image, System.Collections.Hashtable hints) { DecoderResult decoderResult; ResultPoint[] points; if (hints != null && hints.ContainsKey(DecodeHintType.PURE_BARCODE)) { BitMatrix bits = extractPureBits(image); decoderResult = decoder.decode(bits); points = NO_POINTS; } else { DetectorResult detectorResult = new Detector(image).detect(); decoderResult = decoder.decode(detectorResult.getBits()); points = detectorResult.getPoints(); } Result result = new Result(decoderResult.getText(), decoderResult.getRawBytes(), points, BarcodeFormat.DATAMATRIX); if (decoderResult.getByteSegments() != null) { result.putMetadata(ResultMetadataType.BYTE_SEGMENTS, decoderResult.getByteSegments()); } return result; }
private Result decodeInternal(MonochromeBitmapSource image) { try { int size = readers.Count; for (int i = 0; i < size; i++) { Reader reader = (Reader)readers[i]; try { return(reader.decode(image, hints)); } catch (ReaderException re) { // continue } } throw new ReaderException(""); } catch (Exception e) { throw new ReaderException(e.Message); } }
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())); }
public Result decode(MonochromeBitmapSource image, System.Collections.Hashtable hints) { return maybeReturnResult(ean13Reader.decode(image, hints)); }
public Result decode(MonochromeBitmapSource image) { return maybeReturnResult(ean13Reader.decode(image)); }
/** * 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". * * @param image The image to decode * @param hints Any hints that were requested * @return The contents of the decoded barcode * @throws ReaderException Any spontaneous errors which occur */ private Result doDecode(MonochromeBitmapSource image, System.Collections.Hashtable hints) { int width = image.getWidth(); int height = image.getHeight(); 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 ? 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 { image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber); } catch (ReaderException re) { continue; } image.getBlackRow(rowNumber, row, 0, width); // 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 } 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, 180); // And remember to flip the result points horizontally. ResultPoint[] points = result.getResultPoints(); points[0] = (ResultPoint) new GenericResultPoint(width - points[0].getX() - 1, points[0].getY()); points[1] = (ResultPoint) new GenericResultPoint(width - points[1].getX() - 1, points[1].getY()); } return(result); } catch (ReaderException re) { // continue -- just couldn't decode this row } } } throw new ReaderException(); }
/** * <p>Creates a finder that will search the image for three finder patterns.</p> * * @param image image to search */ public FinderPatternFinder(MonochromeBitmapSource image) { this.image = image; this.possibleCenters = new System.Collections.ArrayList(); this.crossCheckStateCount = new int[5]; }
public Result decode(MonochromeBitmapSource image) { return(decode(image, null)); }
/** * 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); }
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()); }
/** * 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". * * @param image The image to decode * @param hints Any hints that were requested * @return The contents of the decoded barcode * @throws ReaderException Any spontaneous errors which occur */ private Result doDecode(MonochromeBitmapSource image, System.Collections.Hashtable hints) { int width = image.getWidth(); int height = image.getHeight(); 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 ? 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 { image.estimateBlackPoint(BlackPointEstimationMethod.ROW_SAMPLING, rowNumber); } catch (ReaderException re) { continue; } image.getBlackRow(rowNumber, row,0, width); // 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 } 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, 180); // And remember to flip the result points horizontally. ResultPoint[] points = result.getResultPoints(); points[0] = (ResultPoint) new GenericResultPoint(width - points[0].getX() - 1, points[0].getY()); points[1] = (ResultPoint)new GenericResultPoint(width - points[1].getX() - 1, points[1].getY()); } return result; } catch (ReaderException re) { // continue -- just couldn't decode this row } } } throw new ReaderException(); }
public Result decode(MonochromeBitmapSource 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.isRotateSupported()) { MonochromeBitmapSource 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.getResultMetadata(); 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); return result; } else { throw re; } } }
/** * <p>Like {@link #crossCheckVertical(int, int, int, int)}, and in fact is basically identical, * except it reads horizontally instead of vertically. This is used to cross-cross * check a vertical cross check and locate the real center of the alignment pattern.</p> */ private float crossCheckHorizontal(int startJ, int centerI, int maxCount, int originalStateCountTotal) { MonochromeBitmapSource image = this.image; int maxJ = image.getWidth(); int[] stateCount = getCrossCheckStateCount(); int j = startJ; while (j >= 0 && image.isBlack(j, centerI)) { stateCount[2]++; j--; } if (j < 0) { return(float.NaN); } while (j >= 0 && !image.isBlack(j, centerI) && stateCount[1] <= maxCount) { stateCount[1]++; j--; } if (j < 0 || stateCount[1] > maxCount) { return(float.NaN); } while (j >= 0 && image.isBlack(j, centerI) && stateCount[0] <= maxCount) { stateCount[0]++; j--; } if (stateCount[0] > maxCount) { return(float.NaN); } j = startJ + 1; while (j < maxJ && image.isBlack(j, centerI)) { stateCount[2]++; j++; } if (j == maxJ) { return(float.NaN); } while (j < maxJ && !image.isBlack(j, centerI) && stateCount[3] < maxCount) { stateCount[3]++; j++; } if (j == maxJ || stateCount[3] >= maxCount) { return(float.NaN); } while (j < maxJ && image.isBlack(j, centerI) && stateCount[4] < maxCount) { stateCount[4]++; j++; } if (stateCount[4] >= maxCount) { return(float.NaN); } // If we found a finder-pattern-like section, but its size is significantly different than // the original, assume it's a false positive int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; if (5 * Math.Abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { return(float.NaN); } return(foundPatternCross(stateCount) ? centerFromEnd(stateCount, j) : float.NaN); }
public Detector(MonochromeBitmapSource image) { this.image = image; }
public Result decode(MonochromeBitmapSource image, System.Collections.Hashtable hints) { return(maybeReturnResult(ean13Reader.decode(image, hints))); }
private Result decodeInternal(MonochromeBitmapSource image) { try { int size = readers.Count; for (int i = 0; i < size; i++) { Reader reader = (Reader)readers[i]; try { return reader.decode(image, hints); } catch (ReaderException re) { // continue } } throw new ReaderException(""); } catch (Exception e) { throw new ReaderException(e.Message); } }
public Result decode(MonochromeBitmapSource image) { return(maybeReturnResult(ean13Reader.decode(image))); }
/** * 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; }
/** * <p>After a horizontal scan finds a potential alignment pattern, this method * "cross-checks" by scanning down vertically through the center of the possible * alignment pattern to see if the same proportion is detected.</p> * * @param startI row where an alignment pattern was detected * @param centerJ center of the section that appears to cross an alignment pattern * @param maxCount maximum reasonable number of modules that should be * observed in any reading state, based on the results of the horizontal scan * @return vertical center of alignment pattern, or {@link Float#NaN} if not found */ private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) { MonochromeBitmapSource image = this.image; int maxI = image.getHeight(); int[] stateCount = crossCheckStateCount; stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; // Start counting up from center int i = startI; while (i >= 0 && image.isBlack(centerJ, i) && stateCount[1] <= maxCount) { stateCount[1]++; i--; } // If already too many modules in this state or ran off the edge: if (i < 0 || stateCount[1] > maxCount) { return(float.NaN); } while (i >= 0 && !image.isBlack(centerJ, i) && stateCount[0] <= maxCount) { stateCount[0]++; i--; } if (stateCount[0] > maxCount) { return(float.NaN); } // Now also count down from center i = startI + 1; while (i < maxI && image.isBlack(centerJ, i) && stateCount[1] <= maxCount) { stateCount[1]++; i++; } if (i == maxI || stateCount[1] > maxCount) { return(float.NaN); } while (i < maxI && !image.isBlack(centerJ, i) && stateCount[2] <= maxCount) { stateCount[2]++; i++; } if (stateCount[2] > maxCount) { return(float.NaN); } int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; if (5 * Math.Abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { return(float.NaN); } return(foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : float.NaN); }
private static BitMatrix sampleGrid(MonochromeBitmapSource image, ResultPoint topLeft, ResultPoint topRight, ResultPoint bottomLeft, ResultPoint alignmentPattern, int dimension) { float dimMinusThree = (float) dimension - 3.5f; float bottomRightX; float bottomRightY; float sourceBottomRightX; float sourceBottomRightY; if (alignmentPattern != null) { bottomRightX = alignmentPattern.getX(); bottomRightY = alignmentPattern.getY(); sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3.0f; } else { // Don't have an alignment pattern, just make up the bottom-right point bottomRightX = (topRight.getX() - topLeft.getX()) + bottomLeft.getX(); bottomRightY = (topRight.getY() - topLeft.getY()) + bottomLeft.getY(); sourceBottomRightX = sourceBottomRightY = dimMinusThree; } GridSampler sampler = GridSampler.Instance; return sampler.sampleGrid( image, dimension, 3.5f, 3.5f, dimMinusThree, 3.5f, sourceBottomRightX, sourceBottomRightY, 3.5f, dimMinusThree, topLeft.getX(), topLeft.getY(), topRight.getX(), topRight.getY(), bottomRightX, bottomRightY, bottomLeft.getX(), bottomLeft.getY()); }
/** * <p>Detects a QR Code in an image, simply.</p> * * @param hints optional hints to detector * @return {@link DetectorResult} encapsulating results of detecting a QR Code * @throws ReaderException if no QR Code can be found */ public DetectorResult detect(System.Collections.Hashtable hints) { MonochromeBitmapSource image = this.image; if (!BlackPointEstimationMethod.TWO_D_SAMPLING.Equals(image.getLastEstimationMethod())) { image.estimateBlackPoint(BlackPointEstimationMethod.TWO_D_SAMPLING, 0); } FinderPatternFinder finder = new FinderPatternFinder(image); FinderPatternInfo info = finder.find(hints); FinderPattern topLeft = info.getTopLeft(); FinderPattern topRight = info.getTopRight(); FinderPattern bottomLeft = info.getBottomLeft(); float moduleSize = calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1.0f) { throw new ReaderException(); } int dimension = computeDimension(topLeft, topRight, bottomLeft, moduleSize); Version provisionalVersion = Version.getProvisionalVersionForDimension(dimension); int modulesBetweenFPCenters = provisionalVersion.getDimensionForVersion() - 7; AlignmentPattern alignmentPattern = null; // Anything above version 1 has an alignment pattern if (provisionalVersion.getAlignmentPatternCenters().Length > 0) { // Guess where a "bottom right" finder pattern would have been float bottomRightX = topRight.getX() - topLeft.getX() + bottomLeft.getX(); float bottomRightY = topRight.getY() - topLeft.getY() + bottomLeft.getY(); // Estimate that alignment pattern is closer by 3 modules // from "bottom right" to known top left location float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; int estAlignmentX = (int)(topLeft.getX() + correctionToTopLeft * (bottomRightX - topLeft.getX())); int estAlignmentY = (int)(topLeft.getY() + correctionToTopLeft * (bottomRightY - topLeft.getY())); // Kind of arbitrary -- expand search radius before giving up for (int i = 4; i <= 16; i <<= 1) { try { alignmentPattern = findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, (float)i); break; } catch (ReaderException re) { // try next round } } if (alignmentPattern == null) { throw new ReaderException(); } } BitMatrix bits = sampleGrid(image, topLeft, topRight, bottomLeft, alignmentPattern, 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)); }
/** * <p>Creates a finder that will search the image for three finder patterns.</p> * * @param image image to search */ public FinderPatternFinder(MonochromeBitmapSource image) { this.image = image; this.possibleCenters = new System.Collections.ArrayList(); this.crossCheckStateCount = new int[5]; }
/** * Locates and decodes a Data Matrix code in an image. * * @return a String representing the content encoded by the Data Matrix code * @throws ReaderException if a Data Matrix code cannot be found, or cannot be decoded */ public Result decode(MonochromeBitmapSource image) { return decode(image, null); }
public Detector(MonochromeBitmapSource image) { this.image = image; }
/** * <p>After a horizontal scan finds a potential finder pattern, this method * "cross-checks" by scanning down vertically through the center of the possible * finder pattern to see if the same proportion is detected.</p> * * @param startI row where a finder pattern was detected * @param centerJ center of the section that appears to cross a finder pattern * @param maxCount maximum reasonable number of modules that should be * observed in any reading state, based on the results of the horizontal scan * @return vertical center of finder pattern, or {@link Float#NaN} if not found */ private float crossCheckVertical(int startI, int centerJ, int maxCount, int originalStateCountTotal) { MonochromeBitmapSource image = this.image; int maxI = image.getHeight(); int[] stateCount = getCrossCheckStateCount(); // Start counting up from center int i = startI; while (i >= 0 && image.isBlack(centerJ, i)) { stateCount[2]++; i--; } if (i < 0) { return(float.NaN); } while (i >= 0 && !image.isBlack(centerJ, i) && stateCount[1] <= maxCount) { stateCount[1]++; i--; } // If already too many modules in this state or ran off the edge: if (i < 0 || stateCount[1] > maxCount) { return(float.NaN); } while (i >= 0 && image.isBlack(centerJ, i) && stateCount[0] <= maxCount) { stateCount[0]++; i--; } if (stateCount[0] > maxCount) { return(float.NaN); } // Now also count down from center i = startI + 1; while (i < maxI && image.isBlack(centerJ, i)) { stateCount[2]++; i++; } if (i == maxI) { return(float.NaN); } while (i < maxI && !image.isBlack(centerJ, i) && stateCount[3] < maxCount) { stateCount[3]++; i++; } if (i == maxI || stateCount[3] >= maxCount) { return(float.NaN); } while (i < maxI && image.isBlack(centerJ, i) && stateCount[4] < maxCount) { stateCount[4]++; i++; } if (stateCount[4] >= maxCount) { return(float.NaN); } // If we found a finder-pattern-like section, but its size is more than 20% different than // the original, assume it's a false positive int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; if (5 * Math.Abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { return(float.NaN); } return(foundPatternCross(stateCount) ? centerFromEnd(stateCount, i) : float.NaN); }