mirror of
https://github.com/zxing/zxing.git
synced 2025-03-05 20:48:51 -08:00
Update black box tests to reflect much better decoding with EC. Add support for correcting erasures plus tests.
git-svn-id: https://zxing.googlecode.com/svn/trunk@2280 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
a107d0c0a4
commit
0b005747ff
|
@ -78,7 +78,7 @@ public final class Decoder {
|
|||
int numECCodewords = 1 << (ecLevel + 1);
|
||||
int[] erasures = parser.getErasures();
|
||||
|
||||
correctErrors(codewords, erasures.length, numECCodewords);
|
||||
correctErrors(codewords, erasures, numECCodewords);
|
||||
verifyCodewordCount(codewords, numECCodewords);
|
||||
|
||||
// Decode the codewords
|
||||
|
@ -119,17 +119,19 @@ public final class Decoder {
|
|||
* correct the errors in-place.</p>
|
||||
*
|
||||
* @param codewords data and error correction codewords
|
||||
* @param erasures positions of any known erasures
|
||||
* @param numECCodewords number of error correction codewards that were available in codewords
|
||||
* @throws ChecksumException if error correction fails
|
||||
*/
|
||||
private void correctErrors(int[] codewords,
|
||||
int numErasures,
|
||||
int[] erasures,
|
||||
int numECCodewords) throws ChecksumException {
|
||||
if (numErasures > numECCodewords / 2 + MAX_ERRORS ||
|
||||
if (erasures.length > numECCodewords / 2 + MAX_ERRORS ||
|
||||
numECCodewords < 0 || numECCodewords > MAX_EC_CODEWORDS) {
|
||||
// Too many errors or EC Codewords is corrupted
|
||||
throw ChecksumException.getChecksumInstance();
|
||||
}
|
||||
errorCorrection.decode(codewords, numECCodewords);
|
||||
errorCorrection.decode(codewords, numECCodewords, erasures);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,7 +35,10 @@ public final class ErrorCorrection {
|
|||
this.field = ModulusGF.PDF417_GF;
|
||||
}
|
||||
|
||||
public void decode(int[] received, int numECCodewords) throws ChecksumException {
|
||||
public void decode(int[] received,
|
||||
int numECCodewords,
|
||||
int[] erasures) throws ChecksumException {
|
||||
|
||||
ModulusPoly poly = new ModulusPoly(field, received);
|
||||
int[] S = new int[numECCodewords];
|
||||
boolean error = false;
|
||||
|
@ -46,15 +49,30 @@ public final class ErrorCorrection {
|
|||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
|
||||
ModulusPoly knownErrors = field.getOne();
|
||||
for (int erasure : erasures) {
|
||||
int b = field.exp(received.length - 1 - erasure);
|
||||
// Add (1 - bx) term:
|
||||
ModulusPoly term = new ModulusPoly(field, new int[] { field.subtract(0, b), 1 });
|
||||
knownErrors = knownErrors.multiply(term);
|
||||
}
|
||||
|
||||
ModulusPoly syndrome = new ModulusPoly(field, S);
|
||||
ErrorCorrection ec = new ErrorCorrection();
|
||||
syndrome = syndrome.multiply(knownErrors);
|
||||
|
||||
ModulusPoly[] sigmaOmega =
|
||||
ec.runEuclideanAlgorithm(field.buildMonomial(numECCodewords, 1), syndrome, numECCodewords);
|
||||
runEuclideanAlgorithm(field.buildMonomial(numECCodewords, 1), syndrome, numECCodewords);
|
||||
ModulusPoly sigma = sigmaOmega[0];
|
||||
ModulusPoly omega = sigmaOmega[1];
|
||||
int[] errorLocations = ec.findErrorLocations(sigma);
|
||||
int[] errorMagnitudes = ec.findErrorMagnitudes(omega, sigma, errorLocations);
|
||||
|
||||
sigma = sigma.multiply(knownErrors);
|
||||
|
||||
int[] errorLocations = findErrorLocations(sigma);
|
||||
int[] errorMagnitudes = findErrorMagnitudes(omega, sigma, errorLocations);
|
||||
|
||||
for (int i = 0; i < errorLocations.length; i++) {
|
||||
int position = received.length - 1 - field.log(errorLocations[i]);
|
||||
if (position < 0) {
|
||||
|
|
|
@ -29,8 +29,8 @@ public final class PDF417BlackBox2TestCase extends AbstractBlackBoxTestCase {
|
|||
|
||||
public PDF417BlackBox2TestCase() {
|
||||
super("test/data/blackbox/pdf417-2", new MultiFormatReader(), BarcodeFormat.PDF_417);
|
||||
addTest(12, 12, 0, 0, 0.0f);
|
||||
addTest(16, 16, 0, 0, 180.0f);
|
||||
addTest(19, 19, 0, 0, 0.0f);
|
||||
addTest(17, 17, 0, 0, 180.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,6 +40,23 @@ abstract class AbstractErrorCorrectionTestCase extends Assert {
|
|||
}
|
||||
}
|
||||
|
||||
static int[] erase(int[] received, int howMany, Random random) {
|
||||
BitSet erased = new BitSet(received.length);
|
||||
int[] erasures = new int[howMany];
|
||||
int erasureOffset = 0;
|
||||
for (int j = 0; j < howMany; j++) {
|
||||
int location = random.nextInt(received.length);
|
||||
if (erased.get(location)) {
|
||||
j--;
|
||||
} else {
|
||||
erased.set(location);
|
||||
received[location] = 0;
|
||||
erasures[erasureOffset++] = location;
|
||||
}
|
||||
}
|
||||
return erasures;
|
||||
}
|
||||
|
||||
static Random getRandom() {
|
||||
return new SecureRandom(new byte[] {(byte) 0xDE, (byte) 0xAD, (byte) 0xBE, (byte) 0xEF});
|
||||
}
|
||||
|
|
|
@ -32,7 +32,12 @@ public final class ErrorCorrectionTestCase extends AbstractErrorCorrectionTestCa
|
|||
private static final int[] PDF417_TEST_WITH_EC =
|
||||
{ 5, 453, 178, 121, 239, 452, 327, 657, 619 };
|
||||
private static final int ECC_BYTES = PDF417_TEST_WITH_EC.length - PDF417_TEST.length;
|
||||
private static final int CORRECTABLE = ECC_BYTES / 2;
|
||||
// Example is EC level 1 (s=1). The number of erasures (l) and substitutions (f) must obey:
|
||||
// l + 2f <= 2^(s+1) - 3
|
||||
private static final int EC_LEVEL = 1;
|
||||
private static final int ERROR_LIMIT = (1 << (EC_LEVEL + 1)) - 3;
|
||||
private static final int MAX_ERRORS = ERROR_LIMIT / 2;
|
||||
private static final int MAX_ERASURES = ERROR_LIMIT;
|
||||
|
||||
private final ErrorCorrection ec = new ErrorCorrection();
|
||||
|
||||
|
@ -58,7 +63,7 @@ public final class ErrorCorrectionTestCase extends AbstractErrorCorrectionTestCa
|
|||
Random random = getRandom();
|
||||
for (int test : PDF417_TEST) { // # iterations is kind of arbitrary
|
||||
int[] received = PDF417_TEST_WITH_EC.clone();
|
||||
corrupt(received, CORRECTABLE, random);
|
||||
corrupt(received, MAX_ERRORS, random);
|
||||
checkDecode(received);
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +72,7 @@ public final class ErrorCorrectionTestCase extends AbstractErrorCorrectionTestCa
|
|||
public void testTooManyErrors() {
|
||||
int[] received = PDF417_TEST_WITH_EC.clone();
|
||||
Random random = getRandom();
|
||||
corrupt(received, CORRECTABLE + 1, random);
|
||||
corrupt(received, MAX_ERRORS + 3, random); // +3 since the algo can actually correct 2 more than it should here
|
||||
try {
|
||||
checkDecode(received);
|
||||
fail("Should not have decoded");
|
||||
|
@ -76,8 +81,53 @@ public final class ErrorCorrectionTestCase extends AbstractErrorCorrectionTestCa
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxErasures() throws ChecksumException {
|
||||
Random random = getRandom();
|
||||
for (int test : PDF417_TEST) { // # iterations is kind of arbitrary
|
||||
int[] received = PDF417_TEST_WITH_EC.clone();
|
||||
int[] erasures = erase(received, MAX_ERASURES, random);
|
||||
checkDecode(received, erasures);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTooManyErasures() {
|
||||
Random random = getRandom();
|
||||
int[] received = PDF417_TEST_WITH_EC.clone();
|
||||
int[] erasures = erase(received, MAX_ERASURES + 1, random);
|
||||
try {
|
||||
checkDecode(received, erasures);
|
||||
fail("Should not have decoded");
|
||||
} catch (ChecksumException ce) {
|
||||
// good
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErasureAndError() throws ChecksumException {
|
||||
// Not sure this is valid according to the spec but it's correctable
|
||||
Random random = getRandom();
|
||||
for (int i = 0; i < PDF417_TEST_WITH_EC.length; i++) {
|
||||
int[] received = PDF417_TEST_WITH_EC.clone();
|
||||
received[i] = random.nextInt(256);
|
||||
for (int j = 0; j < PDF417_TEST_WITH_EC.length; j++) {
|
||||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
received[j] = 0;
|
||||
int[] erasures = {j};
|
||||
checkDecode(received, erasures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDecode(int[] received) throws ChecksumException {
|
||||
ec.decode(received, ECC_BYTES);
|
||||
checkDecode(received, new int[0]);
|
||||
}
|
||||
|
||||
private void checkDecode(int[] received, int[] erasures) throws ChecksumException {
|
||||
ec.decode(received, ECC_BYTES, erasures);
|
||||
for (int i = 0; i < PDF417_TEST.length; i++) {
|
||||
assertEquals(received[i], PDF417_TEST[i]);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue