Improved code-matching

feature/71
Christoph Oberhofer 9 years ago
parent a9584bae77
commit dadb8dbc9f

@ -254,7 +254,7 @@ export default {
line = getLine(box); line = getLine(box);
lineLength = getLineLength(line); lineLength = getLineLength(line);
lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x); lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
line = getExtendedLine(line, lineAngle, Math.floor(lineLength * 0.2)); line = getExtendedLine(line, lineAngle, Math.floor(lineLength * 0.1));
if (line === null){ if (line === null){
return null; return null;
} }

@ -2,6 +2,7 @@ function BarcodeReader(config, supplements) {
this._row = []; this._row = [];
this.config = config || {}; this.config = config || {};
this.supplements = supplements; this.supplements = supplements;
this.minBarWidth = 1;
return this; return this;
} }
@ -19,15 +20,32 @@ BarcodeReader.prototype._nextUnset = function(line, start) {
return line.length; return line.length;
}; };
BarcodeReader.prototype._matchPattern = function(counter, code) { BarcodeReader.prototype._matchPattern = function(counter, code, maxSingleError) {
var i, var i,
error = 0, error = 0,
singleError = 0, singleError = 0,
modulo = this.MODULO, sum = 0,
maxSingleError = this.SINGLE_CODE_ERROR || 1; modulo = 0,
barWidth,
count,
scaled;
maxSingleError = maxSingleError || this.SINGLE_CODE_ERROR || 1;
for (i = 0; i < counter.length; i++) {
sum += counter[i];
modulo += code[i];
}
if (sum < modulo) {
return Number.MAX_VALUE;
}
barWidth = sum / modulo;
maxSingleError *= barWidth;
for (i = 0; i < counter.length; i++) { for (i = 0; i < counter.length; i++) {
singleError = Math.abs(code[i] - counter[i]); count = counter[i];
scaled = code[i] * barWidth;
singleError = Math.abs(count - scaled) / scaled;
if (singleError > maxSingleError) { if (singleError > maxSingleError) {
return Number.MAX_VALUE; return Number.MAX_VALUE;
} }
@ -58,15 +76,18 @@ BarcodeReader.prototype._normalize = function(counter, correction) {
norm = 0, norm = 0,
modulo = self.MODULO; modulo = self.MODULO;
for (i = 0; i < normalized.length; i++) {
normalized[i] = counter[i] < this.minBarWidth ? counter[i] = this.minBarWidth : counter[i];
}
if (correction) { if (correction) {
self._correct(counter, correction); self._correct(normalized, correction);
} }
for (i = 0; i < counter.length; i++) { for (i = 0; i < normalized.length; i++) {
sum += counter[i]; sum += normalized[i];
} }
ratio = sum / (modulo - numOnes); ratio = sum / (modulo - numOnes);
for (i = 0; i < counter.length; i++) { for (i = 0; i < normalized.length; i++) {
norm = counter[i] === 1 ? counter[i] : counter[i] / ratio; norm = normalized[i] === 1 ? normalized[i] : normalized[i] / ratio;
normalized[i] = norm; normalized[i] = norm;
} }
return normalized; return normalized;

@ -19,13 +19,15 @@ EAN2Reader.prototype.decode = function(row, start) {
offset = start, offset = start,
end = this._row.length, end = this._row.length,
code, code,
result = []; result = [],
decodedCodes = [];
for (i = 0; i < 2 && offset < end; i++) { for (i = 0; i < 2 && offset < end; i++) {
code = this._decodeCode(offset); code = this._decodeCode(offset);
if (!code) { if (!code) {
return null; return null;
} }
decodedCodes.push(code);
result.push(code.code % 10); result.push(code.code % 10);
if (code.code >= this.CODE_G_START) { if (code.code >= this.CODE_G_START) {
codeFrequency |= 1 << (1 - i); codeFrequency |= 1 << (1 - i);
@ -39,8 +41,11 @@ EAN2Reader.prototype.decode = function(row, start) {
if (result.length != 2 || (parseInt(result.join("")) % 4) !== codeFrequency) { if (result.length != 2 || (parseInt(result.join("")) % 4) !== codeFrequency) {
return null; return null;
} }
console.log(result); return {
return offset; code: result.join(""),
decodedCodes,
end: code.end
};
}; };
export default EAN2Reader; export default EAN2Reader;

@ -21,13 +21,15 @@ EAN5Reader.prototype.decode = function(row, start) {
offset = start, offset = start,
end = this._row.length, end = this._row.length,
code, code,
result = []; result = [],
decodedCodes = [];
for (i = 0; i < 5 && offset < end; i++) { for (i = 0; i < 5 && offset < end; i++) {
code = this._decodeCode(offset); code = this._decodeCode(offset);
if (!code) { if (!code) {
return null; return null;
} }
decodedCodes.push(code);
result.push(code.code % 10); result.push(code.code % 10);
if (code.code >= this.CODE_G_START) { if (code.code >= this.CODE_G_START) {
codeFrequency |= 1 << (4 - i); codeFrequency |= 1 << (4 - i);
@ -45,8 +47,11 @@ EAN5Reader.prototype.decode = function(row, start) {
if (extensionChecksum(result) !== determineCheckDigit(codeFrequency)) { if (extensionChecksum(result) !== determineCheckDigit(codeFrequency)) {
return null; return null;
} }
console.log(result); return {
return offset; code: result.join(""),
decodedCodes,
end: code.end
};
}; };
function determineCheckDigit(codeFrequency) { function determineCheckDigit(codeFrequency) {

@ -19,10 +19,10 @@ var properties = {
CODE_L_START: {value: 0}, CODE_L_START: {value: 0},
MODULO: {value: 7}, MODULO: {value: 7},
CODE_G_START: {value: 10}, CODE_G_START: {value: 10},
START_PATTERN: {value: [1 / 3 * 7, 1 / 3 * 7, 1 / 3 * 7]}, START_PATTERN: {value: [1, 1, 1]},
STOP_PATTERN: {value: [1 / 3 * 7, 1 / 3 * 7, 1 / 3 * 7]}, STOP_PATTERN: {value: [1, 1, 1]},
MIDDLE_PATTERN: {value: [1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7]}, MIDDLE_PATTERN: {value: [1, 1, 1, 1, 1]},
EXTENSION_START_PATTERN: {value: [1 / 4 * 7, 1 / 4 * 7, 2 / 4 * 7]}, EXTENSION_START_PATTERN: {value: [1, 1, 2]},
CODE_PATTERN: {value: [ CODE_PATTERN: {value: [
[3, 2, 1, 1], [3, 2, 1, 1],
[2, 2, 2, 1], [2, 2, 2, 1],
@ -46,8 +46,8 @@ var properties = {
[2, 1, 1, 3] [2, 1, 1, 3]
]}, ]},
CODE_FREQUENCY: {value: [0, 11, 13, 14, 19, 25, 28, 21, 22, 26]}, CODE_FREQUENCY: {value: [0, 11, 13, 14, 19, 25, 28, 21, 22, 26]},
SINGLE_CODE_ERROR: {value: 0.67}, SINGLE_CODE_ERROR: {value: 0.70},
AVG_CODE_ERROR: {value: 0.27}, AVG_CODE_ERROR: {value: 0.48},
FORMAT: {value: "ean_13", writeable: false} FORMAT: {value: "ean_13", writeable: false}
}; };
@ -68,8 +68,7 @@ EANReader.prototype._decodeCode = function(start, coderange) {
end: start end: start
}, },
code, code,
error, error;
normalized;
if (!coderange) { if (!coderange) {
coderange = self.CODE_PATTERN.length; coderange = self.CODE_PATTERN.length;
@ -80,10 +79,8 @@ EANReader.prototype._decodeCode = function(start, coderange) {
counter[counterPos]++; counter[counterPos]++;
} else { } else {
if (counterPos === counter.length - 1) { if (counterPos === counter.length - 1) {
normalized = self._normalize(counter);
if (normalized) {
for (code = 0; code < coderange; code++) { for (code = 0; code < coderange; code++) {
error = self._matchPattern(normalized, self.CODE_PATTERN[code]); error = self._matchPattern(counter, self.CODE_PATTERN[code]);
if (error < bestMatch.error) { if (error < bestMatch.error) {
bestMatch.code = code; bestMatch.code = code;
bestMatch.error = error; bestMatch.error = error;
@ -94,7 +91,6 @@ EANReader.prototype._decodeCode = function(start, coderange) {
return null; return null;
} }
return bestMatch; return bestMatch;
}
} else { } else {
counterPos++; counterPos++;
} }
@ -118,8 +114,7 @@ EANReader.prototype._findPattern = function(pattern, offset, isWhite, tryHarder,
}, },
error, error,
j, j,
sum, sum;
normalized;
if (!offset) { if (!offset) {
offset = self._nextSet(self._row); offset = self._nextSet(self._row);
@ -150,9 +145,7 @@ EANReader.prototype._findPattern = function(pattern, offset, isWhite, tryHarder,
for ( j = 0; j < counter.length; j++) { for ( j = 0; j < counter.length; j++) {
sum += counter[j]; sum += counter[j];
} }
normalized = self._normalize(counter); error = self._matchPattern(counter, pattern);
if (normalized) {
error = self._matchPattern(normalized, pattern);
if (error < epsilon) { if (error < epsilon) {
bestMatch.error = error; bestMatch.error = error;
@ -160,7 +153,6 @@ EANReader.prototype._findPattern = function(pattern, offset, isWhite, tryHarder,
bestMatch.end = i; bestMatch.end = i;
return bestMatch; return bestMatch;
} }
}
if (tryHarder) { if (tryHarder) {
for ( j = 0; j < counter.length - 2; j++) { for ( j = 0; j < counter.length - 2; j++) {
counter[j] = counter[j + 2]; counter[j] = counter[j + 2];
@ -285,12 +277,15 @@ EANReader.prototype._decode = function() {
self = this, self = this,
code, code,
result = [], result = [],
decodedCodes = []; decodedCodes = [],
resultInfo = {};
this.minBarWidth = 1;
startInfo = self._findStart(); startInfo = self._findStart();
if (!startInfo) { if (!startInfo) {
return null; return null;
} }
this.minBarWidth = (startInfo.end - startInfo.start) / 3;
code = { code = {
code: startInfo.code, code: startInfo.code,
start: startInfo.start, start: startInfo.start,
@ -318,6 +313,18 @@ EANReader.prototype._decode = function() {
if (!ext) { if (!ext) {
return null; return null;
} }
let lastCode = ext.decodedCodes[ext.decodedCodes.length-1],
endInfo = {
start: lastCode.start + (((lastCode.end - lastCode.start) / 2) | 0),
end: lastCode.end
};
if(!self._verifyTrailingWhitespace(endInfo)) {
return null;
}
resultInfo = {
supplement: ext,
code: result.join("") + ext.code
}
} }
return { return {
@ -326,24 +333,32 @@ EANReader.prototype._decode = function() {
end: code.end, end: code.end,
codeset: "", codeset: "",
startInfo: startInfo, startInfo: startInfo,
decodedCodes: decodedCodes decodedCodes: decodedCodes,
...resultInfo
}; };
}; };
EANReader.prototype._decodeExtensions = function(offset) { EANReader.prototype._decodeExtensions = function(offset) {
var i, var i,
start = this._nextSet(this._row, offset), start = this._nextSet(this._row, offset),
code = this._findPattern(this.EXTENSION_START_PATTERN, start, false, false), startInfo = this._findPattern(this.EXTENSION_START_PATTERN, start, false, false),
result; result;
if (code === null) { if (startInfo === null) {
return null; return null;
} }
for (i = 0; i < this.supplements.length; i++) { for (i = 0; i < this.supplements.length; i++) {
result = this.supplements[i].decode(this._row, code.end); result = this.supplements[i].decode(this._row, startInfo.end);
if (result !== null) { if (result !== null) {
return result; return {
code: result.code,
start,
startInfo,
end: result.end,
codeset: "",
decodedCodes: result.decodedCodes
}
} }
} }
return null; return null;

Loading…
Cancel
Save