/// <summary> /// Gets the closest decoded value. /// </summary> /// <returns>The closest decoded value.</returns> /// <param name="moduleBitCount">Module bit count.</param> private static int GetClosestDecodedValue(int[] moduleBitCount) { int bitCountSum = PDF417Common.GetBitCountSum(moduleBitCount); float[] bitCountRatios = new float[PDF417Common.BARS_IN_MODULE]; for (int i = 0; i < bitCountRatios.Length; i++) { bitCountRatios[i] = moduleBitCount[i] / (float)bitCountSum; } float bestMatchError = float.MaxValue; int bestMatch = PDF417Common.INVALID_CODEWORD; for (int j = 0; j < RATIOS_TABLE.Length; j++) { float error = 0.0f; for (int k = 0; k < PDF417Common.BARS_IN_MODULE; k++) { float diff = RATIOS_TABLE[j][k] - bitCountRatios[k]; error += diff * diff; } if (error < bestMatchError) { bestMatchError = error; bestMatch = PDF417Common.SYMBOL_TABLE[j]; } } return(bestMatch); }
/// <summary> /// Samples the bit counts. /// </summary> /// <returns>The bit counts.</returns> /// <param name="moduleBitCount">Module bit count.</param> private static int[] SampleBitCounts(int[] moduleBitCount) { float bitCountSum = PDF417Common.GetBitCountSum(moduleBitCount); int[] result = new int[PDF417Common.BARS_IN_MODULE]; int bitCountIndex = 0; int sumPreviousBits = 0; for (int i = 0; i < PDF417Common.MODULES_IN_CODEWORD; i++) { float sampleIndex = bitCountSum / (2 * PDF417Common.MODULES_IN_CODEWORD) + (i * bitCountSum) / PDF417Common.MODULES_IN_CODEWORD; if (sumPreviousBits + moduleBitCount[bitCountIndex] <= sampleIndex) { sumPreviousBits += moduleBitCount[bitCountIndex]; bitCountIndex++; } result[bitCountIndex]++; } return(result); }
/// <summary> /// Detects the codeword. /// </summary> /// <returns>The codeword.</returns> /// <param name="image">Image.</param> /// <param name="minColumn">Minimum column.</param> /// <param name="maxColumn">Max column.</param> /// <param name="leftToRight">If set to <c>true</c> left to right.</param> /// <param name="startColumn">Start column.</param> /// <param name="imageRow">Image row.</param> /// <param name="minCodewordWidth">Minimum codeword width.</param> /// <param name="maxCodewordWidth">Max codeword width.</param> private static Codeword DetectCodeword(BitMatrix image, int minColumn, int maxColumn, bool leftToRight, int startColumn, int imageRow, int minCodewordWidth, int maxCodewordWidth) { startColumn = AdjustCodewordStartColumn(image, minColumn, maxColumn, leftToRight, startColumn, imageRow); // we usually know fairly exact now how long a codeword is. We should provide minimum and maximum expected Length // and try to adjust the read pixels, e.g. remove single pixel errors or try to cut off exceeding pixels. // min and maxCodewordWidth should not be used as they are calculated for the whole barcode an can be inaccurate // for the current position int[] moduleBitCount = GetModuleBitCount(image, minColumn, maxColumn, leftToRight, startColumn, imageRow); if (moduleBitCount == null) { return(null); } int endColumn; int codewordBitCount = PDF417Common.GetBitCountSum(moduleBitCount); if (leftToRight) { endColumn = startColumn + codewordBitCount; } else { for (int i = 0; i < moduleBitCount.Length >> 1; i++) { int tmpCount = moduleBitCount[i]; moduleBitCount[i] = moduleBitCount[moduleBitCount.Length - 1 - i]; moduleBitCount[moduleBitCount.Length - 1 - i] = tmpCount; } endColumn = startColumn; startColumn = endColumn - codewordBitCount; } // TODO implement check for width and correction of black and white bars // use start (and maybe stop pattern) to determine if blackbars are wider than white bars. If so, adjust. // should probably done only for codewords with a lot more than 17 bits. // The following fixes 10-1.png, which has wide black bars and small white bars // for (int i = 0; i < moduleBitCount.Length; i++) { // if (i % 2 == 0) { // moduleBitCount[i]--; // } else { // moduleBitCount[i]++; // } // } // We could also use the width of surrounding codewords for more accurate results, but this seems // sufficient for now if (!CheckCodewordSkew(codewordBitCount, minCodewordWidth, maxCodewordWidth)) { // We could try to use the startX and endX position of the codeword in the same column in the previous row, // create the bit count from it and normalize it to 8. This would help with single pixel errors. return(null); } int decodedValue = PDF417CodewordDecoder.GetDecodedValue(moduleBitCount); int codeword = PDF417Common.GetCodeword(decodedValue); if (codeword == -1) { return(null); } return(new Codeword(startColumn, endColumn, GetCodewordBucketNumber(decodedValue), codeword)); }