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

boofcv.alg.fiducial.aztec.AztecMessageModeCodec 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.aztec;

import boofcv.alg.fiducial.qrcode.PackedBits8;
import boofcv.alg.fiducial.qrcode.ReedSolomonCodes_U8;
import boofcv.misc.BoofMiscOps;
import org.ddogleg.struct.DogArray_I8;

/**
 * Encodes and decodes binary data for mode message
 *
 * @author Peter Abeles
 */
public class AztecMessageModeCodec {
	// Error correction for encoding the message mode
	ReedSolomonCodes_U8 rscodes = new ReedSolomonCodes_U8(4, 19, 1);

	// Storage for input and output when computing ECC bits
	DogArray_I8 eccInput = new DogArray_I8();
	DogArray_I8 eccOutput = new DogArray_I8();

	/**
	 * Encodes the binary data for the mode message for the provided marker. ECC is computed using Reed-Solomon
	 * encoding with 4-bit Galois Fields.
	 *
	 * @param marker (Input) Marker which is to be encoded
	 * @param bits (Output) Encoded binary data
	 */
	public void encodeMode( AztecCode marker, PackedBits8 bits ) {
		bits.resize(0);

		switch (marker.structure) {
			case COMPACT -> {
				bits.append(marker.dataLayers - 1, 2, false);
				bits.append(marker.messageWordCount - 1, 6, false);
				eccInput.resize(2);
				rscodes.generator(5);
			}
			case FULL -> {
				bits.append(marker.dataLayers - 1, 5, false);
				bits.append(marker.messageWordCount - 1, 11, false);
				eccInput.resize(4);
				rscodes.generator(6);
			}
		}

		// Convert into 4-bit words for ECC
		for (int word = 0; word < eccInput.size; word++) {
			eccInput.data[word] = (byte)bits.read(word*4, 4, true);
		}
		rscodes.computeECC(eccInput, eccOutput);

		// Append resulting check words from ECC to bits data
		for (int word = 0; word < eccOutput.size; word++) {
			bits.append(eccOutput.get(word), 4, false);
		}
	}

	/**
	 * Applies error correction to bits then decodes the values. Save results into marker. Returns true if successful
	 */
	public boolean decodeMode( PackedBits8 bits, AztecCode marker ) {
		if (!correctDataBits(bits, marker.structure))
			return false;

		switch (marker.structure) {
			case COMPACT -> {
				marker.dataLayers = bits.read(0, 2, true) + 1;
				marker.messageWordCount = bits.read(2, 6, true) + 1;
			}
			case FULL -> {
				marker.dataLayers = bits.read(0, 5, true) + 1;
				marker.messageWordCount = bits.read(5, 11, true) + 1;
			}
		}

		return true;
	}

	/**
	 * Corrects the data portion of the packet and re-write the input 'bits' array with just the corrected data.
	 *
	 * @param bits (Input) all bits, data and ECC. (Output) corrected data
	 * @param structure Which type of marker was encoded
	 * @return true if successful or false if it failed
	 */
	boolean correctDataBits( PackedBits8 bits, AztecCode.Structure structure ) {
		switch (structure) {
			case COMPACT -> {
				BoofMiscOps.checkEq(28, bits.size, "Invalid number of bits");
				eccInput.resize(2);
				eccOutput.resize(5);
			}
			case FULL -> {
				BoofMiscOps.checkEq(40, bits.size, "Invalid number of bits");
				eccInput.resize(4);
				eccOutput.resize(6);
			}
		}
		rscodes.generator(eccOutput.size);

		// Convert into 4-bit words for ECC
		int bitLocation = 0;
		for (int word = 0; word < eccInput.size; word++, bitLocation += 4) {
			eccInput.data[word] = (byte)bits.read(bitLocation, 4, true);
		}

		// Convert into 4-bit words for ECC
		for (int word = 0; word < eccOutput.size; word++, bitLocation += 4) {
			eccOutput.data[word] = (byte)bits.read(bitLocation, 4, true);
		}

		if (!rscodes.correct(eccInput, eccOutput))
			return false;

		// Copy results into bits. Just the data and no ECC
		bits.resize(0);
		for (int word = 0; word < eccInput.size; word++) {
			bits.append(eccInput.get(word), 4, false);
		}
		return true;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy