All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.alg.fiducial.qrcode.QrCodePolynomialMath Maven / Gradle / Ivy

/*
 * Copyright (c) 2022, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.alg.fiducial.qrcode;

import boofcv.alg.descriptor.DescriptorDistance;

/**
 * Contains all the formulas for encoding and decoding BCH and Reed-Solomon codes. For a more accessible
 * introduction to this material see [1] and [2].
 *
 * 
 * [1] S. A. Tretter "Introduction to Bose Chaudhuri Hocquenghem codes" Goddard Space Flight Center, September 1967
 * [2] https://en.wikiversity.org/wiki/Reed–Solomon_codes_for_coders
 * 
* * @author Peter Abeles */ // TODO replaced correctDCH() with a non-brute force method. public class QrCodePolynomialMath { public static final int FORMAT_GENERATOR = 0b10100110111; public static final int VERSION_GENERATOR = 0b1111100100101; /** * Encodes the version bits. BCH(18,6) * * @param version QR code version. 7 to 40 * @return encoded bit field */ public static int encodeVersionBits( int version ) { int message = version << 12; return message ^ bitPolyModulus(message, VERSION_GENERATOR, 18, 6); } /** * Encodes the version bits. BCH(18,6) * * @param bits Read in bits. Should encode 18-bits * @return encoded bit field */ public static boolean checkVersionBits( int bits ) { return bitPolyModulus(bits, VERSION_GENERATOR, 18, 6) == 0; } /** * Attempts to correct version bit sequence. * * @param bits Read in bits after removing the mask * @return If the message could be corrected, th 5-bit format message. -1 if it couldn't */ public static int correctVersionBits( int bits ) { return correctDCH(64, bits, VERSION_GENERATOR, 18, 6); } /** * Encodes the format bits. BCH(15,5) * * @param level Error correction level * @param mask The type of mask that is applied to the qr code * @return encoded bit field */ public static int encodeFormatBits( QrCode.ErrorLevel level, int mask ) { return encodeFormatBits((level.value << 3) | (mask & 0xFFFFFFF7)); } /** * Encodes the 5-bit format bits for QR and Micro QR. BCH(15,5) * * @param message5bits 5-bit message * @return encoded bit field */ public static int encodeFormatBits( int message5bits ) { int message = message5bits << 10; return message ^ bitPolyModulus(message, FORMAT_GENERATOR, 15, 5); } /** * Check the format bits. BCH(15,5) code. */ public static boolean checkFormatBits( int bitsNoMask ) { return bitPolyModulus(bitsNoMask, FORMAT_GENERATOR, 15, 5) == 0; } /** * Assumes that the format message has no errors in it and decodes its data and saves it into the qr code * * @param message format data bits after the mask has been remove and shifted over 10 bits * @param qr Where the results are written to */ public static void decodeFormatMessage( int message, QrCode qr ) { int error = message >> 3; qr.error = QrCode.ErrorLevel.lookup(error); qr.mask = QrCodeMaskPattern.lookupMask(message & 0x07); } /** * Attempts to correct format bit sequence. * * @param bitsNoMask Read in bits after removing the mask * @return If the message could be corrected, th 5-bit format message. -1 if it couldn't */ public static int correctFormatBits( int bitsNoMask ) { return correctDCH(32, bitsNoMask, FORMAT_GENERATOR, 15, 5); } /** * Applies a brute force algorithm to find the message which has the smallest hamming distance. if two * messages have the same distance -1 is returned. * * @param N Number of possible messages. 32 or 64 * @param messageNoMask The observed message with mask removed * @param generator Generator polynomial * @param totalBits Total number of bits in the message. * @param dataBits Total number of data bits in the message * @return The error corrected message or -1 if it can't be determined. */ public static int correctDCH( int N, int messageNoMask, int generator, int totalBits, int dataBits ) { int bestHamming = 255; int bestMessage = -1; int errorBits = totalBits - dataBits; // exhaustively check all possibilities for (int i = 0; i < N; i++) { int test = i << errorBits; test = test ^ bitPolyModulus(test, generator, totalBits, dataBits); int distance = DescriptorDistance.hamming(test ^ messageNoMask); // see if it found a better match if (distance < bestHamming) { bestHamming = distance; bestMessage = i; } else if (distance == bestHamming) { // ambiguous so reject bestMessage = -1; } } return bestMessage; } /** * Performs division using xcr operators on the encoded polynomials. used in BCH encoding/decoding * * @param data Data being checked * @param generator Generator polynomial * @param totalBits Total number of bits in data * @param dataBits Number of data bits. Rest are error correction bits * @return Remainder after polynomial division */ public static int bitPolyModulus( int data, int generator, int totalBits, int dataBits ) { int errorBits = totalBits - dataBits; for (int i = dataBits - 1; i >= 0; i--) { if ((data & (1 << (i + errorBits))) != 0) { data ^= generator << i; } } return data; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy