Ejemplo n.º 1
0
        /**
         * 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);
        }
        /**
           * 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;
        }
Ejemplo n.º 3
0
        /**
         * <p>This method traces a line from a point in the image, in the direction towards another point.
         * It begins in a black region, and keeps going until it finds white, then black, then white again.
         * It reports the distance from the start to this point.</p>
         *
         * <p>This is used when figuring out how wide a finder pattern is, when the finder pattern
         * may be skewed or rotated.</p>
         */
        private float sizeOfBlackWhiteBlackRun(int fromX, int fromY, int toX, int toY)
        {
            // Mild variant of Bresenham's algorithm;
            // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
            bool steep = Math.Abs(toY - fromY) > Math.Abs(toX - fromX);

            if (steep)
            {
                int temp = fromX;
                fromX = fromY;
                fromY = temp;
                temp  = toX;
                toX   = toY;
                toY   = temp;
            }

            int dx    = Math.Abs(toX - fromX);
            int dy    = Math.Abs(toY - fromY);
            int error = -dx >> 1;
            int ystep = fromY < toY ? 1 : -1;
            int xstep = fromX < toX ? 1 : -1;
            int state = 0; // In black pixels, looking for white, first or second time
            int diffX = 0;
            int diffY = 0;

            for (int x = fromX, y = fromY; x != toX; x += xstep)
            {
                int realX = steep ? y : x;
                int realY = steep ? x : y;
                if (state == 1) // In white pixels, looking for black
                {
                    if (image.isBlack(realX, realY))
                    {
                        state++;
                    }
                }
                else
                {
                    if (!image.isBlack(realX, realY))
                    {
                        state++;
                    }
                }

                if (state == 3) // Found black, white, black, and stumbled back onto white; done
                {
                    diffX = x - fromX;
                    diffY = y - fromY;
                    return((float)Math.Sqrt((double)(diffX * diffX + diffY * diffY)));
                }
                error += dy;
                if (error > 0)
                {
                    y     += ystep;
                    error -= dx;
                }
            }

            diffX = toX - fromX;
            diffY = toY - fromY;
            return((float)Math.Sqrt((double)(diffX * diffX + diffY * diffY)));
        }
Ejemplo n.º 4
0
        /**
         * <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);
        }
Ejemplo n.º 5
0
        /**
         * <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);
        }
Ejemplo n.º 6
0
        /**
         * <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);
        }