public FinderPatternFinder(BitMatrix image, ResultPointCallback resultPointCallback)
 {
     this.image = image;
     this.possibleCenters = System.Collections.ArrayList.Synchronized(new System.Collections.ArrayList(10));
     this.crossCheckStateCount = new int[5];
     this.resultPointCallback = resultPointCallback;
 }
예제 #2
0
 /// <param name="bitMatrix">{@link BitMatrix} to parse
 /// </param>
 /// <throws>  ReaderException if dimension is not >= 21 and 1 mod 4 </throws>
 internal BitMatrixParser(BitMatrix bitMatrix)
 {
     int dimension = bitMatrix.Dimension;
     if (dimension < 21 || (dimension & 0x03) != 1)
     {
         throw ReaderException.Instance;
     }
     this.bitMatrix = bitMatrix;
 }
예제 #3
0
 public BinaryBitmap(Binarizer binarizer)
 {
     if (binarizer == null)
     {
         throw new System.ArgumentException("Binarizer must be non-null.");
     }
     this.binarizer = binarizer;
     matrix = null;
 }
예제 #4
0
 /// <summary> <p>Implementations of this method reverse the data masking process applied to a QR Code and
 /// make its bits ready to read.</p>
 /// 
 /// </summary>
 /// <param name="bits">representation of QR Code bits
 /// </param>
 /// <param name="dimension">dimension of QR Code, represented by bits, being unmasked
 /// </param>
 internal void unmaskBitMatrix(BitMatrix bits, int dimension)
 {
     for (int i = 0; i < dimension; i++)
     {
         for (int j = 0; j < dimension; j++)
         {
             if (isMasked(i, j))
             {
                 bits.flip(j, i);
             }
         }
     }
 }
예제 #5
0
        /// <param name="bitMatrix">{@link BitMatrix} to parse
        /// </param>
        /// <throws>  ReaderException if dimension is < 10 or > 144 or not 0 mod 2 </throws>
        internal BitMatrixParser(BitMatrix bitMatrix)
        {
            int dimension = bitMatrix.Dimension;
            if (dimension < 10 || dimension > 144 || (dimension & 0x01) != 0)
            {
                throw ReaderException.Instance;
            }

            version = readVersion(bitMatrix);
            this.mappingBitMatrix = extractDataRegion(bitMatrix);
            // TODO(bbrown): Make this work for rectangular symbols
            this.readMappingMatrix = new BitMatrix(this.mappingBitMatrix.Dimension);
        }
예제 #6
0
 /// <summary> <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>
 /// 
 /// </summary>
 /// <param name="image">booleans representing white/black Data Matrix Code modules
 /// </param>
 /// <returns> text and bytes encoded within the Data Matrix Code
 /// </returns>
 /// <throws>  ReaderException if the Data Matrix Code cannot be decoded </throws>
 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_Renamed(j, i);
             }
         }
     }
     return decode(bits);
 }
예제 #7
0
        /// <summary> <p>Extracts the data region from a {@link BitMatrix} that contains
        /// alignment patterns.</p>
        /// 
        /// </summary>
        /// <param name="bitMatrix">Original {@link BitMatrix} with alignment patterns
        /// </param>
        /// <returns> BitMatrix that has the alignment patterns removed
        /// </returns>
        internal BitMatrix extractDataRegion(BitMatrix bitMatrix)
        {
            int symbolSizeRows = version.SymbolSizeRows;
            int symbolSizeColumns = version.SymbolSizeColumns;

            // TODO(bbrown): Make this work with rectangular codes
            if (bitMatrix.Dimension != symbolSizeRows)
            {
                throw new System.ArgumentException("Dimension of bitMarix must match the version size");
            }

            int dataRegionSizeRows = version.DataRegionSizeRows;
            int dataRegionSizeColumns = version.DataRegionSizeColumns;

            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_Renamed(readColumnOffset, readRowOffset))
                            {
                                int writeColumnOffset = dataRegionColumnOffset + j;
                                bitMatrixWithoutAlignment.set_Renamed(writeColumnOffset, writeRowOffset);
                            }
                        }
                    }
                }
            }
            return bitMatrixWithoutAlignment;
        }
예제 #8
0
        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
        }
예제 #9
0
 public Detector(BitMatrix image)
 {
     this.image = image;
 }
예제 #10
0
        /// <summary> 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.
        /// </summary>
        private static BitMatrix extractPureBits(BitMatrix image)
        {
            // Now need to determine module size in pixels

            int height = image.Height;
            int width = image.Width;
            int minDimension = System.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.get_Renamed(borderWidth, borderWidth))
            {
                borderWidth++;
            }
            if (borderWidth == minDimension)
            {
                throw ReaderException.Instance;
            }

            // And then keep tracking across the top-left black module to determine module size
            int moduleEnd = borderWidth + 1;
            while (moduleEnd < width && image.get_Renamed(moduleEnd, borderWidth))
            {
                moduleEnd++;
            }
            if (moduleEnd == width)
            {
                throw ReaderException.Instance;
            }

            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.get_Renamed(borderWidth, columnEndOfSymbol))
            {
                columnEndOfSymbol--;
            }
            if (columnEndOfSymbol < 0)
            {
                throw ReaderException.Instance;
            }
            columnEndOfSymbol++;

            // Make sure width of barcode is a multiple of module size
            if ((columnEndOfSymbol - borderWidth) % moduleSize != 0)
            {
                throw ReaderException.Instance;
            }
            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 ReaderException.Instance;
            }

            // 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.get_Renamed(borderWidth + j * moduleSize, iOffset))
                    {
                        bits.set_Renamed(j, i);
                    }
                }
            }
            return bits;
        }
예제 #11
0
        /// <summary> This method detects a barcode in a "pure" image -- that is, pure monochrome image
        /// which contains only an unrotated, unskewed, image of a barcode, with some white border
        /// around it. This is a specialized method that works exceptionally fast in this special
        /// case.
        /// </summary>
        private static BitMatrix extractPureBits(BinaryBitmap image)
        {
            // Now need to determine module size in pixels
            BitMatrix matrix = image.BlackMatrix;
            int height = matrix.Height;
            int width = matrix.Width;
            int minDimension = System.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 && !matrix.get_Renamed(borderWidth, borderWidth))
            {
                borderWidth++;
            }
            if (borderWidth == minDimension)
            {
                throw ReaderException.Instance;
            }

            // And then keep tracking across the top-left black module to determine module size
            int moduleEnd = borderWidth;
            while (moduleEnd < minDimension && matrix.get_Renamed(moduleEnd, moduleEnd))
            {
                moduleEnd++;
            }
            if (moduleEnd == minDimension)
            {
                throw ReaderException.Instance;
            }

            int moduleSize = moduleEnd - borderWidth;

            // And now find where the rightmost black module on the first row ends
            int rowEndOfSymbol = width - 1;
            while (rowEndOfSymbol >= 0 && !matrix.get_Renamed(rowEndOfSymbol, borderWidth))
            {
                rowEndOfSymbol--;
            }
            if (rowEndOfSymbol < 0)
            {
                throw ReaderException.Instance;
            }
            rowEndOfSymbol++;

            // Make sure width of barcode is a multiple of module size
            if ((rowEndOfSymbol - borderWidth) % moduleSize != 0)
            {
                throw ReaderException.Instance;
            }
            int dimension = (rowEndOfSymbol - 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 ReaderException.Instance;
            }

            // Now just read off the bits
            BitMatrix bits = new BitMatrix(dimension);
            for (int y = 0; y < dimension; y++)
            {
                int iOffset = borderWidth + y * moduleSize;
                for (int x = 0; x < dimension; x++)
                {
                    if (matrix.get_Renamed(borderWidth + x * moduleSize, iOffset))
                    {
                        bits.set_Renamed(x, y);
                    }
                }
            }
            return bits;
        }
예제 #12
0
 private static BitMatrix sampleGrid(BitMatrix image, PerspectiveTransform transform, int dimension)
 {
     GridSampler sampler = GridSampler.Instance;
     return sampler.sampleGrid(image, dimension, transform);
 }
예제 #13
0
 public Detector(BitMatrix image)
 {
     this.image = image;
     rectangleDetector = new MonochromeRectangleDetector(image);
 }
예제 #14
0
        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);
        }
예제 #15
0
 internal BitMatrixParser(BitMatrix bitMatrix)
 {
     this.bitMatrix = bitMatrix;
 }
 /// <summary> <p>Creates a finder that will search the image for three finder patterns.</p>
 /// 
 /// </summary>
 /// <param name="image">image to search
 /// </param>
 public FinderPatternFinder(BitMatrix image)
     : this(image, null)
 {
 }
예제 #17
0
 public MultiDetector(BitMatrix image)
     : base(image)
 {
 }
예제 #18
0
        /// <summary> <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>
        /// 
        /// </summary>
        /// <param name="bitMatrix">Original {@link BitMatrix} including alignment patterns
        /// </param>
        /// <returns> {@link Version} encapsulating the Data Matrix Code's "version"
        /// </returns>
        /// <throws>  ReaderException if the dimensions of the mapping matrix are not valid </throws>
        /// <summary> Data Matrix dimensions.
        /// </summary>
        internal Version readVersion(BitMatrix bitMatrix)
        {
            if (version != null)
            {
                return version;
            }

            // TODO(bbrown): make this work for rectangular dimensions as well.
            int numRows = bitMatrix.Dimension;
            int numColumns = numRows;

            return Version.getVersionForDimensions(numRows, numColumns);
        }
예제 #19
0
        /// <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;
        }
예제 #20
0
        /// <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>
        /// <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 patternLength = pattern.Length;
            // TODO: Find a way to cache this array, as this method is called hundreds of times
            // per image, and we want to allocate as seldom as possible.
            int[] counters = new int[patternLength];
            bool isWhite = whiteFirst;

            int counterPosition = 0;
            int patternStart = column;
            for (int x = column; x < column + width; x++)
            {
                bool pixel = matrix.get_Renamed(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];
                        for (int y = 2; y < patternLength; y++)
                        {
                            counters[y - 2] = counters[y];
                        }
                        counters[patternLength - 2] = 0;
                        counters[patternLength - 1] = 0;
                        counterPosition--;
                    }
                    else
                    {
                        counterPosition++;
                    }
                    counters[counterPosition] = 1;
                    isWhite = !isWhite;
                }
            }
            return null;
        }
예제 #21
0
        /// <summary> <p>Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken
        /// to mean a black module.</p>
        /// 
        /// </summary>
        /// <param name="bits">booleans representing white/black Data Matrix Code modules
        /// </param>
        /// <returns> text and bytes encoded within the Data Matrix Code
        /// </returns>
        /// <throws>  ReaderException if the Data Matrix Code cannot be decoded </throws>
        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].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
            return DecodedBitStreamParser.decode(resultBytes);
        }
 public MonochromeRectangleDetector(BitMatrix image)
 {
     this.image = image;
 }
 /// <summary> <p>Creates a finder that will look in a portion of the whole image.</p>
 /// 
 /// </summary>
 /// <param name="image">image to search
 /// </param>
 /// <param name="startX">left column from which to start searching
 /// </param>
 /// <param name="startY">top row from which to start searching
 /// </param>
 /// <param name="width">width of region to search
 /// </param>
 /// <param name="height">height of region to search
 /// </param>
 /// <param name="moduleSize">estimated module size so far
 /// </param>
 internal AlignmentPatternFinder(BitMatrix image, int startX, int startY, int width, int height, float moduleSize, ResultPointCallback resultPointCallback)
 {
     this.image = image;
     this.possibleCenters = System.Collections.ArrayList.Synchronized(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];
     this.resultPointCallback = resultPointCallback;
 }