Moved files into meaningful folders

This commit is contained in:
Christoph Oberhofer
2016-02-24 21:37:46 +01:00
parent 6343a235f8
commit b7ffeec6db
34 changed files with 841 additions and 632 deletions
+299
View File
@@ -0,0 +1,299 @@
import Bresenham from './bresenham';
import ImageDebug from '../common/image_debug';
import Code128Reader from '../reader/code_128_reader';
import EANReader from '../reader/ean_reader';
import Code39Reader from '../reader/code_39_reader';
import Code39VINReader from '../reader/code_39_vin_reader';
import CodabarReader from '../reader/codabar_reader';
import UPCReader from '../reader/upc_reader';
import EAN8Reader from '../reader/ean_8_reader';
import UPCEReader from '../reader/upc_e_reader';
import I2of5Reader from '../reader/i2of5_reader';
const READERS = {
code_128_reader: Code128Reader,
ean_reader: EANReader,
ean_8_reader: EAN8Reader,
code_39_reader: Code39Reader,
code_39_vin_reader: Code39VINReader,
codabar_reader: CodabarReader,
upc_reader: UPCReader,
upc_e_reader: UPCEReader,
i2of5_reader: I2of5Reader
};
export default {
create: function(config, inputImageWrapper) {
var _canvas = {
ctx: {
frequency: null,
pattern: null,
overlay: null
},
dom: {
frequency: null,
pattern: null,
overlay: null
}
},
_barcodeReaders = [];
initCanvas();
initReaders();
initConfig();
function initCanvas() {
if (typeof document !== 'undefined') {
var $debug = document.querySelector("#debug.detection");
_canvas.dom.frequency = document.querySelector("canvas.frequency");
if (!_canvas.dom.frequency) {
_canvas.dom.frequency = document.createElement("canvas");
_canvas.dom.frequency.className = "frequency";
if ($debug) {
$debug.appendChild(_canvas.dom.frequency);
}
}
_canvas.ctx.frequency = _canvas.dom.frequency.getContext("2d");
_canvas.dom.pattern = document.querySelector("canvas.patternBuffer");
if (!_canvas.dom.pattern) {
_canvas.dom.pattern = document.createElement("canvas");
_canvas.dom.pattern.className = "patternBuffer";
if ($debug) {
$debug.appendChild(_canvas.dom.pattern);
}
}
_canvas.ctx.pattern = _canvas.dom.pattern.getContext("2d");
_canvas.dom.overlay = document.querySelector("canvas.drawingBuffer");
if (_canvas.dom.overlay) {
_canvas.ctx.overlay = _canvas.dom.overlay.getContext("2d");
}
}
}
function initReaders() {
config.readers.forEach(function(readerConfig) {
var reader,
configuration = {};
if (typeof readerConfig === 'object') {
reader = readerConfig.format;
configuration = readerConfig.config;
} else if (typeof readerConfig === 'string') {
reader = readerConfig;
}
console.log("Before registering reader: ", reader);
_barcodeReaders.push(new READERS[reader](configuration));
});
console.log("Registered Readers: " + _barcodeReaders
.map((reader) => JSON.stringify({format: reader.FORMAT, config: reader.config}))
.join(', '));
}
function initConfig() {
if (typeof document !== 'undefined') {
var i,
vis = [{
node: _canvas.dom.frequency,
prop: config.showFrequency
}, {
node: _canvas.dom.pattern,
prop: config.showPattern
}];
for (i = 0; i < vis.length; i++) {
if (vis[i].prop === true) {
vis[i].node.style.display = "block";
} else {
vis[i].node.style.display = "none";
}
}
}
}
/**
* extend the line on both ends
* @param {Array} line
* @param {Number} angle
*/
function getExtendedLine(line, angle, ext) {
function extendLine(amount) {
var extension = {
y: amount * Math.sin(angle),
x: amount * Math.cos(angle)
};
line[0].y -= extension.y;
line[0].x -= extension.x;
line[1].y += extension.y;
line[1].x += extension.x;
}
// check if inside image
extendLine(ext);
while (ext > 1 && (!inputImageWrapper.inImageWithBorder(line[0], 0)
|| !inputImageWrapper.inImageWithBorder(line[1], 0))) {
ext -= Math.ceil(ext / 2);
extendLine(-ext);
}
return line;
}
function getLine(box) {
return [{
x: (box[1][0] - box[0][0]) / 2 + box[0][0],
y: (box[1][1] - box[0][1]) / 2 + box[0][1]
}, {
x: (box[3][0] - box[2][0]) / 2 + box[2][0],
y: (box[3][1] - box[2][1]) / 2 + box[2][1]
}];
}
function tryDecode(line) {
var result = null,
i,
barcodeLine = Bresenham.getBarcodeLine(inputImageWrapper, line[0], line[1]);
if (config.showFrequency) {
ImageDebug.drawPath(line, {x: 'x', y: 'y'}, _canvas.ctx.overlay, {color: 'red', lineWidth: 3});
Bresenham.debug.printFrequency(barcodeLine.line, _canvas.dom.frequency);
}
Bresenham.toBinaryLine(barcodeLine);
if (config.showPattern) {
Bresenham.debug.printPattern(barcodeLine.line, _canvas.dom.pattern);
}
for ( i = 0; i < _barcodeReaders.length && result === null; i++) {
result = _barcodeReaders[i].decodePattern(barcodeLine.line);
}
if (result === null){
return null;
}
return {
codeResult: result,
barcodeLine: barcodeLine
};
}
/**
* This method slices the given area apart and tries to detect a barcode-pattern
* for each slice. It returns the decoded barcode, or null if nothing was found
* @param {Array} box
* @param {Array} line
* @param {Number} lineAngle
*/
function tryDecodeBruteForce(box, line, lineAngle) {
var sideLength = Math.sqrt(Math.pow(box[1][0] - box[0][0], 2) + Math.pow((box[1][1] - box[0][1]), 2)),
i,
slices = 16,
result = null,
dir,
extension,
xdir = Math.sin(lineAngle),
ydir = Math.cos(lineAngle);
for ( i = 1; i < slices && result === null; i++) {
// move line perpendicular to angle
dir = sideLength / slices * i * (i % 2 === 0 ? -1 : 1);
extension = {
y: dir * xdir,
x: dir * ydir
};
line[0].y += extension.x;
line[0].x -= extension.y;
line[1].y += extension.x;
line[1].x -= extension.y;
result = tryDecode(line);
}
return result;
}
function getLineLength(line) {
return Math.sqrt(
Math.pow(Math.abs(line[1].y - line[0].y), 2) +
Math.pow(Math.abs(line[1].x - line[0].x), 2));
}
/**
* With the help of the configured readers (Code128 or EAN) this function tries to detect a
* valid barcode pattern within the given area.
* @param {Object} box The area to search in
* @returns {Object} the result {codeResult, line, angle, pattern, threshold}
*/
function decodeFromBoundingBox(box) {
var line,
lineAngle,
ctx = _canvas.ctx.overlay,
result,
lineLength;
if (config.drawBoundingBox && ctx) {
ImageDebug.drawPath(box, {x: 0, y: 1}, ctx, {color: "blue", lineWidth: 2});
}
line = getLine(box);
lineLength = getLineLength(line);
lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x);
line = getExtendedLine(line, lineAngle, Math.floor(lineLength * 0.1));
if (line === null){
return null;
}
result = tryDecode(line);
if (result === null) {
result = tryDecodeBruteForce(box, line, lineAngle);
}
if (result === null) {
return null;
}
if (result && config.drawScanline && ctx) {
ImageDebug.drawPath(line, {x: 'x', y: 'y'}, ctx, {color: 'red', lineWidth: 3});
}
return {
codeResult: result.codeResult,
line: line,
angle: lineAngle,
pattern: result.barcodeLine.line,
threshold: result.barcodeLine.threshold
};
}
return {
decodeFromBoundingBox: function(box) {
return decodeFromBoundingBox(box);
},
decodeFromBoundingBoxes: function(boxes) {
var i, result,
barcodes = [],
multiple = config.multiple;
for ( i = 0; i < boxes.length; i++) {
const box = boxes[i];
result = decodeFromBoundingBox(box) || {};
result.box = box;
if (multiple) {
barcodes.push(result);
} else if (result.codeResult) {
return result;
}
}
if (multiple) {
return {
barcodes
};
}
},
setReaders: function(readers) {
config.readers = readers;
_barcodeReaders.length = 0;
initReaders();
}
};
}
};
+213
View File
@@ -0,0 +1,213 @@
import CVUtils from '../common/cv_utils';
import ImageWrapper from '../common/image_wrapper';
var Bresenham = {};
var Slope = {
DIR: {
UP: 1,
DOWN: -1
}
};
/**
* Scans a line of the given image from point p1 to p2 and returns a result object containing
* gray-scale values (0-255) of the underlying pixels in addition to the min
* and max values.
* @param {Object} imageWrapper
* @param {Object} p1 The start point {x,y}
* @param {Object} p2 The end point {x,y}
* @returns {line, min, max}
*/
Bresenham.getBarcodeLine = function(imageWrapper, p1, p2) {
var x0 = p1.x | 0,
y0 = p1.y | 0,
x1 = p2.x | 0,
y1 = p2.y | 0,
steep = Math.abs(y1 - y0) > Math.abs(x1 - x0),
deltax,
deltay,
error,
ystep,
y,
tmp,
x,
line = [],
imageData = imageWrapper.data,
width = imageWrapper.size.x,
sum = 0,
val,
min = 255,
max = 0;
function read(a, b) {
val = imageData[b * width + a];
sum += val;
min = val < min ? val : min;
max = val > max ? val : max;
line.push(val);
}
if (steep) {
tmp = x0;
x0 = y0;
y0 = tmp;
tmp = x1;
x1 = y1;
y1 = tmp;
}
if (x0 > x1) {
tmp = x0;
x0 = x1;
x1 = tmp;
tmp = y0;
y0 = y1;
y1 = tmp;
}
deltax = x1 - x0;
deltay = Math.abs(y1 - y0);
error = (deltax / 2) | 0;
y = y0;
ystep = y0 < y1 ? 1 : -1;
for ( x = x0; x < x1; x++) {
if (steep){
read(y, x);
} else {
read(x, y);
}
error = error - deltay;
if (error < 0) {
y = y + ystep;
error = error + deltax;
}
}
return {
line: line,
min: min,
max: max
};
};
Bresenham.toOtsuBinaryLine = function(result) {
var line = result.line,
image = new ImageWrapper({x: line.length - 1, y: 1}, line),
threshold = CVUtils.determineOtsuThreshold(image, 5);
line = CVUtils.sharpenLine(line);
CVUtils.thresholdImage(image, threshold);
return {
line: line,
threshold: threshold
};
};
/**
* Converts the result from getBarcodeLine into a binary representation
* also considering the frequency and slope of the signal for more robust results
* @param {Object} result {line, min, max}
*/
Bresenham.toBinaryLine = function(result) {
var min = result.min,
max = result.max,
line = result.line,
slope,
slope2,
center = min + (max - min) / 2,
extrema = [],
currentDir,
dir,
threshold = (max - min) / 12,
rThreshold = -threshold,
i,
j;
// 1. find extrema
currentDir = line[0] > center ? Slope.DIR.UP : Slope.DIR.DOWN;
extrema.push({
pos: 0,
val: line[0]
});
for ( i = 0; i < line.length - 2; i++) {
slope = (line[i + 1] - line[i]);
slope2 = (line[i + 2] - line[i + 1]);
if ((slope + slope2) < rThreshold && line[i + 1] < (center * 1.5)) {
dir = Slope.DIR.DOWN;
} else if ((slope + slope2) > threshold && line[i + 1] > (center * 0.5)) {
dir = Slope.DIR.UP;
} else {
dir = currentDir;
}
if (currentDir !== dir) {
extrema.push({
pos: i,
val: line[i]
});
currentDir = dir;
}
}
extrema.push({
pos: line.length,
val: line[line.length - 1]
});
for ( j = extrema[0].pos; j < extrema[1].pos; j++) {
line[j] = line[j] > center ? 0 : 1;
}
// iterate over extrema and convert to binary based on avg between minmax
for ( i = 1; i < extrema.length - 1; i++) {
if (extrema[i + 1].val > extrema[i].val) {
threshold = (extrema[i].val + ((extrema[i + 1].val - extrema[i].val) / 3) * 2) | 0;
} else {
threshold = (extrema[i + 1].val + ((extrema[i].val - extrema[i + 1].val) / 3)) | 0;
}
for ( j = extrema[i].pos; j < extrema[i + 1].pos; j++) {
line[j] = line[j] > threshold ? 0 : 1;
}
}
return {
line: line,
threshold: threshold
};
};
/**
* Used for development only
*/
Bresenham.debug = {
printFrequency: function(line, canvas) {
var i,
ctx = canvas.getContext("2d");
canvas.width = line.length;
canvas.height = 256;
ctx.beginPath();
ctx.strokeStyle = "blue";
for ( i = 0; i < line.length; i++) {
ctx.moveTo(i, 255);
ctx.lineTo(i, 255 - line[i]);
}
ctx.stroke();
ctx.closePath();
},
printPattern: function(line, canvas) {
var ctx = canvas.getContext("2d"), i;
canvas.width = line.length;
ctx.fillColor = "black";
for ( i = 0; i < line.length; i++) {
if (line[i] === 1) {
ctx.fillRect(i, 0, 1, 100);
}
}
}
};
export default Bresenham;