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

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

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

There is a newer version: 1.1.7
Show newest version
/*
 * Copyright (c) 2011-2017, 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 org.ddogleg.struct.GrowQueue_I32;
import org.ddogleg.struct.GrowQueue_I8;

import java.util.Arrays;

/**
 * TODO Summarize
 *
 * 

Code and code comments based on the tutorial at [1].

* *

[1] Reed-Solomon Codes for Coders * Viewed on September 28, 2017

* * @author Peter Abeles */ public class ReidSolomonCodes { GaliosFieldTableOps math; GrowQueue_I8 generator = new GrowQueue_I8(); GrowQueue_I8 tmp0 = new GrowQueue_I8(); GrowQueue_I8 tmp1 = new GrowQueue_I8(); GrowQueue_I32 errorLocations = new GrowQueue_I32(); GrowQueue_I8 errorLocatorPoly = new GrowQueue_I8(); GrowQueue_I8 syndromes = new GrowQueue_I8(); public ReidSolomonCodes( int numBits , int primitive) { math = new GaliosFieldTableOps(numBits,primitive); } public void setDegree( int degree ) { generator(degree); } /** * Given the input message compute the error correction code for it * @param input Input message. Modified internally then returned to its initial state * @param output error correction code */ public void computeECC( GrowQueue_I8 input , GrowQueue_I8 output ) { int N = generator.size-1; input.extend(input.size+N); Arrays.fill(input.data,input.size-N,input.size,(byte)0); math.polyDivide(input,generator,tmp0,output); input.size -= N; } /** * Decodes the message and performs any necessary error correction * @param input (Input) Corrupted Message (Output) corrected message * @param ecc (Input) error correction code for the message * @return true if it was successful or false if it failed */ public boolean correct(GrowQueue_I8 input , GrowQueue_I8 ecc ) { computeSyndromes(input,ecc,syndromes); findErrorLocatorPolynomialBM(syndromes,errorLocatorPoly); if( !findErrorLocations_BruteForce(errorLocatorPoly,input.size+ecc.size,errorLocations)) return false; correctErrors(input,input.size+ecc.size,syndromes,errorLocatorPoly,errorLocations); return true; } /** * Computes the syndromes for the message (input + ecc). If there's no error then the output will be zero. * @param input Data portion of the message * @param ecc ECC portion of the message * @param syndromes (Output) results of the syndromes computations */ void computeSyndromes( GrowQueue_I8 input , GrowQueue_I8 ecc , GrowQueue_I8 syndromes) { syndromes.resize(syndromeLength()); for (int i = 0; i < syndromes.size; i++) { int val = math.power(2,i); syndromes.data[i] = (byte)math.polyEval(input,val); syndromes.data[i] = (byte)math.polyEvalContinue(syndromes.data[i]&0xFF,ecc,val); } } /** * Computes the error locator polynomial using Berlekamp-Massey algorithm [1] * *

[1] Massey, J. L. (1969), "Shift-register synthesis and BCH decoding" (PDF), IEEE Trans. * Information Theory, IT-15 (1): 122–127

* * @param syndromes (Input) The syndromes * @param errorLocator (Output) Error locator polynomial. Coefficients are large to small. */ void findErrorLocatorPolynomialBM(GrowQueue_I8 syndromes , GrowQueue_I8 errorLocator ) { GrowQueue_I8 C = errorLocator; // error polynomial GrowQueue_I8 B = new GrowQueue_I8(); // previous error polynomial // TODO remove new from this function initToOne(C,syndromes.size+1); initToOne(B,syndromes.size+1); GrowQueue_I8 tmp = new GrowQueue_I8(syndromes.size); // int L = 0; // int m = 1; // stores how much B is 'shifted' by int b = 1; for (int n = 0; n < syndromes.size; n++) { // Compute discrepancy delta int delta = syndromes.data[n]&0xFF; for (int j = 1; j < C.size; j++) { delta ^= math.multiply(C.data[C.size-j-1]&0xFF, syndromes.data[n-j]&0xFF); } // B = D^m * B B.data[B.size++] = 0; // Step 3 is implicitly handled // m = m + 1 if( delta != 0 ) { int scale = math.multiply(delta, math.inverse(b)); math.polyAddScaleB(C, B, scale, tmp); if (B.size <= C.size) { // if 2*L > N ---- Step 4 // m += 1; } else { // if 2*L <= N --- Step 5 B.setTo(C); // L = n+1-L; b = delta; // m = 1; } C.setTo(tmp); } } removeLeadingZeros(C); } private void removeLeadingZeros(GrowQueue_I8 poly ) { int count = 0; for (; count < poly.size; count++) { if( poly.data[count] != 0 ) break; } for (int i = count; i < poly.size; i++) { poly.data[i-count] = poly.data[i]; } poly.size -= count; } /** * Compute the error locator polynomial when given the error locations in the message. * * @param messageLength (Input) Length of the message * @param errorLocations (Input) List of error locations in the byte * @param errorLocator (Output) Error locator polynomial. Coefficients are large to small. */ void findErrorLocatorPolynomial( int messageLength , GrowQueue_I32 errorLocations , GrowQueue_I8 errorLocator ) { tmp1.resize(2); tmp1.data[1] = 1; errorLocator.resize(1); errorLocator.data[0] = 1; for (int i = 0; i < errorLocations.size; i++) { // Convert from positions in the message to coefficient degrees int where = messageLength - errorLocations.get(i) - 1; // tmp1 = [2**w,1] tmp1.data[0] = (byte)math.power(2,where); // tmp1.data[1] = 1; tmp0.setTo(errorLocator); math.polyMult(tmp0,tmp1,errorLocator); } } /** * Creates a list of bytes that have errors in them * * @param errorLocator (Input) Error locator polynomial. Coefficients from small to large. * @param messageLength (Input) Length of the message + ecc. * @param locations (Output) locations of bytes in message with errors. */ public boolean findErrorLocations_BruteForce(GrowQueue_I8 errorLocator , int messageLength , GrowQueue_I32 locations ) { locations.resize(0); for (int i = 0; i < messageLength; i++) { if( math.polyEval_S(errorLocator,math.power(2,i)) == 0 ) { locations.add(messageLength-i-1); } } // see if the expected number of errors were found return locations.size == errorLocator.size - 1; } /** * Use Forney algorithm to compute correction values. * * @param message (Input/Output) The message which is to be corrected. Just the message. ECC not required. * @param length_msg_ecc (Input) length of message and ecc code * @param errorLocations (Input) locations of bytes in message with errors. */ void correctErrors( GrowQueue_I8 message , int length_msg_ecc, GrowQueue_I8 syndromes, GrowQueue_I8 errorLocator , GrowQueue_I32 errorLocations) { GrowQueue_I8 err_eval = new GrowQueue_I8(); // TODO avoid new findErrorEvaluator(syndromes,errorLocator,err_eval); // Compute error positions GrowQueue_I8 X = GrowQueue_I8.zeros(errorLocations.size); // TODO avoid new for (int i = 0; i < errorLocations.size; i++) { int coef_pos = (length_msg_ecc-errorLocations.data[i]-1); X.data[i] = (byte)math.power(2,coef_pos); // The commented out code below replicates exactly how the reference code works. This code above // seems to work just as well and passes all the unit tests // int coef_pos = math.max_value-(length_msg_ecc-errorLocations.data[i]-1); // X.data[i] = (byte)math.power_n(2,-coef_pos); } GrowQueue_I8 err_loc_prime_tmp = new GrowQueue_I8(X.size); // storage for error magnitude polynomial for (int i = 0; i < X.size; i++) { int Xi = X.data[i]&0xFF; int Xi_inv = math.inverse(Xi); // Compute the polynomial derivative err_loc_prime_tmp.size = 0; for (int j = 0; j < X.size; j++) { if( i == j ) continue; err_loc_prime_tmp.data[err_loc_prime_tmp.size++] = (byte)GaliosFieldOps.subtract(1,math.multiply(Xi_inv,X.data[j]&0xFF)); } // compute the product, which is the denominator of Forney algorithm (errata locator derivative) int err_loc_prime = 1; for (int j = 0; j < err_loc_prime_tmp.size; j++) { err_loc_prime = math.multiply(err_loc_prime,err_loc_prime_tmp.data[j]&0xFF); } int y = math.polyEval_S(err_eval,Xi_inv); y = math.multiply(math.power(Xi,1),y); // Compute the magnitude int magnitude = math.divide(y,err_loc_prime); // only apply a correction if it's part of the message and not the ECC int loc = errorLocations.get(i); if( loc < message.size ) message.data[loc] = (byte)((message.data[loc]&0xFF) ^ magnitude); } } /** * Compute the error evaluator polynomial Omega. * * @param syndromes (Input) syndromes * @param errorLocator (Input) error locator polynomial. * @param evaluator (Output) error evaluator polynomial. large to small coef */ void findErrorEvaluator( GrowQueue_I8 syndromes , GrowQueue_I8 errorLocator , GrowQueue_I8 evaluator ) { math.polyMult_flipA(syndromes,errorLocator,evaluator); int N = errorLocator.size-1; int offset = evaluator.size-N; for (int i = 0; i < N; i++) { evaluator.data[i] = evaluator.data[i+offset]; } evaluator.data[N]=0; evaluator.size = errorLocator.size; // flip evaluator around // TODO remove this flip and do it in place for (int i = 0; i < evaluator.size / 2; i++) { int j = evaluator.size-i-1; int tmp = evaluator.data[i]; evaluator.data[i] = evaluator.data[j]; evaluator.data[j] = (byte)tmp; } } /** * Creates the generator function with the specified polynomial degree. The generator function is composed * of factors of (x-a_n) where a_n is a power of 2.
* * g4(x) = (x - α0) (x - α1) (x - α2) (x - α3) = 01 x4 + 0f x3 + 36 x2 + 78 x + 40 */ void generator( int degree ) { // initialize to a polynomial = 1 initToOne(generator,degree+1); // (1*x - a[i]) tmp1.resize(2); tmp1.data[0] = 1; for (int i = 0; i < degree; i++) { tmp1.data[1] = (byte)math.power(2,i); math.polyMult(generator,tmp1,tmp0); generator.setTo(tmp0); } } void initToOne( GrowQueue_I8 poly , int length ) { poly.setMaxSize(length); poly.size = 1; poly.data[0] = 1; } private int syndromeLength() { return generator.size-1; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy