Initial version for node.js

pull/65/head
Christoph Oberhofer 10 years ago
parent 89da5cc4e7
commit a042422515

@ -0,0 +1,15 @@
var Quagga = require('../lib/quagga');
Quagga.decodeSingle({
src: "../test/fixtures/code_128/image-001.jpg",
numOfWorkers: 0,
inputStream: {
size: 640
}
}, function(result) {
if(result.codeResult) {
console.log("result", result.codeResult.code);
} else {
console.log("not detected");
}
});

@ -0,0 +1,75 @@
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define(["cv_utils"], function(CVUtils) {
"use strict";
var FrameGrabber = {};
FrameGrabber.create = function(inputStream) {
var _that = {},
_streamConfig = inputStream.getConfig(),
_video_size = CVUtils.imageRef(inputStream.getRealWidth(), inputStream.getRealHeight()),
_size =_streamConfig.size ? CVUtils.imageRef(inputStream.getWidth(), inputStream.getHeight()) : _video_size,
_sx = 0,
_sy = 0,
_dx = 0,
_dy = 0,
_sWidth,
_dWidth,
_sHeight,
_dHeight,
_canvas = null,
_ctx = null,
_data = null;
_sWidth = _video_size.x;
_dWidth = _size.x;
_sHeight = _video_size.y;
_dHeight = _size.y;
_data = new Uint8Array(_size.x * _size.y);
/**
* Uses the given array as frame-buffer
*/
_that.attachData = function(data) {
_data = data;
};
/**
* Returns the used frame-buffer
*/
_that.getData = function() {
return _data;
};
/**
* Fetches a frame from the input-stream and puts into the frame-buffer.
* The image-data is converted to gray-scale and then half-sampled if configured.
*/
_that.grab = function() {
var doHalfSample = _streamConfig.halfSample,
frame = inputStream.getFrame();
if (frame) {
if(doHalfSample){
CVUtils.grayAndHalfSampleFromCanvasData(frame.data, _size, _data);
} else {
CVUtils.computeGray(frame.data, _data);
}
return true;
} else {
return false;
}
};
_that.getSize = function() {
return _size;
};
return _that;
};
return (FrameGrabber);
});

@ -0,0 +1,138 @@
/* jshint undef: true, unused: true, browser:true, devel: true */
/* global define */
define(function() {
"use strict";
var GetPixels = require("get-pixels");
var InputStream = {};
InputStream.createImageStream = function() {
var that = {};
var _config = null;
var width = 0,
height = 0,
frameIdx = 0,
paused = true,
loaded = false,
frame = null,
baseUrl,
ended = false,
size,
calculatedWidth,
calculatedHeight,
_eventNames = ['canrecord', 'ended'],
_eventHandlers = {};
function loadImages() {
loaded = false;
GetPixels(baseUrl, function(err, pixels) {
if (err) {
console.log(err);
exit(1);
}
loaded = true;
console.log(pixels.shape);
frame = pixels;
width = pixels.shape[0];
height = pixels.shape[1];
calculatedWidth = _config.size ? width/height > 1 ? _config.size : Math.floor((width/height) * _config.size) : width;
calculatedHeight = _config.size ? width/height > 1 ? Math.floor((height/width) * _config.size) : _config.size : height;
setTimeout(function() {
publishEvent("canrecord", []);
}, 0);
});
}
function publishEvent(eventName, args) {
var j,
handlers = _eventHandlers[eventName];
if (handlers && handlers.length > 0) {
for ( j = 0; j < handlers.length; j++) {
handlers[j].apply(that, args);
}
}
}
that.trigger = publishEvent;
that.getWidth = function() {
return calculatedWidth;
};
that.getHeight = function() {
return calculatedHeight;
};
that.setWidth = function(width) {
calculatedWidth = width;
};
that.setHeight = function(height) {
calculatedHeight = height;
};
that.getRealWidth = function() {
return width;
};
that.getRealHeight = function() {
return height;
};
that.setInputStream = function(stream) {
_config = stream;
baseUrl = _config.src;
size = 1;
loadImages();
};
that.ended = function() {
return ended;
};
that.setAttribute = function() {};
that.getConfig = function() {
return _config;
};
that.pause = function() {
paused = true;
};
that.play = function() {
paused = false;
};
that.setCurrentTime = function(time) {
frameIdx = time;
};
that.addEventListener = function(event, f) {
if (_eventNames.indexOf(event) !== -1) {
if (!_eventHandlers[event]) {
_eventHandlers[event] = [];
}
_eventHandlers[event].push(f);
}
};
that.getFrame = function() {
if (!loaded){
return null;
}
return frame;
};
return that;
};
return (InputStream);
});

@ -0,0 +1,12 @@
var requirejs = require('requirejs');
requirejs.config({
"baseUrl" : "../src",
"paths" : {
"typedefs" : "typedefs",
"input_stream": "../lib/input_stream",
"frame_grabber": "../lib/frame_grabber"
}
});
module.exports = requirejs('quagga');

@ -2,7 +2,8 @@
"name": "quagga", "name": "quagga",
"version": "0.6.6", "version": "0.6.6",
"description": "An advanced barcode-scanner written in JavaScript", "description": "An advanced barcode-scanner written in JavaScript",
"main": "dist/quagga.js", "main": "lib/quagga.js",
"browser": "dist/quagga.js",
"devDependencies": { "devDependencies": {
"async": "^0.9.0", "async": "^0.9.0",
"grunt": "~0.4.5", "grunt": "~0.4.5",
@ -46,5 +47,9 @@
"imageprocessing" "imageprocessing"
], ],
"author": "Christoph Oberhofer <ch.oberhofer@gmail.com>", "author": "Christoph Oberhofer <ch.oberhofer@gmail.com>",
"license": "MIT" "license": "MIT",
"dependencies": {
"get-pixels": "^3.2.2",
"gl-matrix": "^2.1.0"
}
} }

@ -1,8 +1,8 @@
/* jshint undef: true, unused: true, browser:true, devel: true */ /* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, mat2, vec2 */ /* global define, mat2, vec2 */
define("barcode_locator", ["image_wrapper", "cv_utils", "rasterizer", "tracer", "skeletonizer", "array_helper", "image_debug"], define("barcode_locator", ["image_wrapper", "cv_utils", "rasterizer", "tracer", "skeletonizer", "array_helper", "image_debug", "gl-matrix"],
function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, ImageDebug) { function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, ImageDebug, glMatrix) {
var _config, var _config,
_currentImageWrapper, _currentImageWrapper,
@ -25,6 +25,8 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
_numPatches = {x: 0, y: 0}, _numPatches = {x: 0, y: 0},
_inputImageWrapper, _inputImageWrapper,
_skeletonizer, _skeletonizer,
vec2 = glMatrix.vec2,
mat2 = glMatrix.mat2,
self = this; self = this;
function initBuffers() { function initBuffers() {
@ -100,15 +102,14 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
overAvg += 180; overAvg += 180;
} }
//console.log(overAvg);
overAvg = (180 - overAvg) * Math.PI / 180; overAvg = (180 - overAvg) * Math.PI / 180;
transMat = mat2.create([Math.cos(overAvg), -Math.sin(overAvg), Math.sin(overAvg), Math.cos(overAvg)]); transMat = mat2.clone([Math.cos(overAvg), Math.sin(overAvg), -Math.sin(overAvg), Math.cos(overAvg)]);
// iterate over patches and rotate by angle // iterate over patches and rotate by angle
for ( i = 0; i < patches.length; i++) { for ( i = 0; i < patches.length; i++) {
patch = patches[i]; patch = patches[i];
for ( j = 0; j < 4; j++) { for ( j = 0; j < 4; j++) {
mat2.xVec2(transMat, patch.box[j]); vec2.transformMat2(patch.box[j], patch.box[j], transMat);
} }
if (_config.boxFromPatches.showTransformed) { if (_config.boxFromPatches.showTransformed) {
@ -143,9 +144,9 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
scale = _config.halfSample ? 2 : 1; scale = _config.halfSample ? 2 : 1;
// reverse rotation; // reverse rotation;
transMat = mat2.inverse(transMat); transMat = mat2.invert(transMat, transMat);
for ( j = 0; j < 4; j++) { for ( j = 0; j < 4; j++) {
mat2.xVec2(transMat, box[j]); vec2.transformMat2(box[j], box[j], transMat);
} }
if (_config.boxFromPatches.showBB) { if (_config.boxFromPatches.showBB) {
@ -153,7 +154,7 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
} }
for ( j = 0; j < 4; j++) { for ( j = 0; j < 4; j++) {
vec2.scale(box[j], scale); vec2.scale(box[j], box[j], scale);
} }
return box; return box;
@ -377,10 +378,10 @@ function(ImageWrapper, CVUtils, Rasterizer, Tracer, skeletonizer, ArrayHelper, I
x : x, x : x,
y : y y : y
}, },
box : [vec2.create([x, y]), vec2.create([x + _subImageWrapper.size.x, y]), vec2.create([x + _subImageWrapper.size.x, y + _subImageWrapper.size.y]), vec2.create([x, y + _subImageWrapper.size.y])], box : [vec2.clone([x, y]), vec2.clone([x + _subImageWrapper.size.x, y]), vec2.clone([x + _subImageWrapper.size.x, y + _subImageWrapper.size.y]), vec2.clone([x, y + _subImageWrapper.size.y])],
moments : matchingMoments, moments : matchingMoments,
rad : avg, rad : avg,
vec : vec2.create([Math.cos(avg), Math.sin(avg)]) vec : vec2.clone([Math.cos(avg), Math.sin(avg)])
}; };
patchesFound.push(patch); patchesFound.push(patch);
} }

@ -1,9 +1,10 @@
/* jshint undef: true, unused: true, browser:true, devel: true */ /* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, vec2 */ /* global define */
define(function() { define(["gl-matrix"], function(glMatrix) {
"use strict"; "use strict";
var vec2 = glMatrix.vec2;
/** /**
* Creates a cluster for grouping similar orientations of datapoints * Creates a cluster for grouping similar orientations of datapoints
*/ */
@ -11,7 +12,7 @@ define(function() {
create : function(point, threshold) { create : function(point, threshold) {
var points = [], center = { var points = [], center = {
rad : 0, rad : 0,
vec : vec2.create([0, 0]) vec : vec2.clone([0, 0])
}, pointMap = {}; }, pointMap = {};
function init() { function init() {
@ -30,7 +31,7 @@ define(function() {
sum += points[i].rad; sum += points[i].rad;
} }
center.rad = sum / points.length; center.rad = sum / points.length;
center.vec = vec2.create([Math.cos(center.rad), Math.sin(center.rad)]); center.vec = vec2.clone([Math.cos(center.rad), Math.sin(center.rad)]);
} }
init(); init();

@ -1,7 +1,7 @@
/* jshint undef: true, unused: true, browser:true, devel: true */ /* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, vec2, vec3 */ /* global define */
define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrixAddon, ArrayHelper) { define(['cluster', "array_helper", "gl-matrix"], function(Cluster2, ArrayHelper, glMatrix) {
"use strict"; "use strict";
/* /*
@ -14,7 +14,9 @@ define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrix
* @class Represents a collection of useful CV algorithms/functions * @class Represents a collection of useful CV algorithms/functions
*/ */
var CVUtils = {}; var CVUtils = {},
vec2 = glMatrix.vec2,
vec3 = glMatrix.vec3;
/** /**
* @param x x-coordinate * @param x x-coordinate
@ -26,10 +28,10 @@ define(['cluster', 'glMatrixAddon', "array_helper"], function(Cluster2, glMatrix
x : x, x : x,
y : y, y : y,
toVec2 : function() { toVec2 : function() {
return vec2.create([this.x, this.y]); return vec2.clone([this.x, this.y]);
}, },
toVec3 : function() { toVec3 : function() {
return vec3.create([this.x, this.y, 1]); return vec3.clone([this.x, this.y, 1]);
}, },
round : function() { round : function() {
this.x = this.x > 0.0 ? Math.floor(this.x + 0.5) : Math.floor(this.x - 0.5); this.x = this.x > 0.0 ? Math.floor(this.x + 0.5) : Math.floor(this.x - 0.5);

@ -224,7 +224,7 @@ mat2.inverse = function(mat){
}; };
var vec2 = {}; var vec2 = {};
vec2.create = function(vec){ vec2.clone = function(vec){
var dest; var dest;
if(vec) { if(vec) {
@ -324,7 +324,7 @@ vec2.length = function(vec){
}; };
vec2.perspectiveProject = function(vec){ vec2.perspectiveProject = function(vec){
var result = vec2.create(vec); var result = vec2.clone(vec);
return vec2.scale(result, 1/vec[2]); return vec2.scale(result, 1/vec[2]);
}; };
@ -333,7 +333,7 @@ vec2.perspectiveProject = function(vec){
* @returns vec2 projected vector * @returns vec2 projected vector
*/ */
vec3.project = function(vec){ vec3.project = function(vec){
return vec2.scale(vec2.create(vec), 1/vec[2]); return vec2.scale(vec2.clone(vec), 1/vec[2]);
}; };
var vec6 = {}; var vec6 = {};

@ -1,14 +1,17 @@
/* jshint undef: true, unused: true, browser:true, devel: true */ /* jshint undef: true, unused: true, browser:true, devel: true */
/* global define, vec2, mat2 */ /* global define */
define([ define([
"subImage", "subImage",
"cv_utils", "cv_utils",
"array_helper" "array_helper",
"gl-matrix"
], ],
function(SubImage, CVUtils, ArrayHelper) { function(SubImage, CVUtils, ArrayHelper, glMatrix) {
'use strict'; 'use strict';
var vec2 = glMatrix.vec2,
mat2 = glMatrix.mat2;
/** /**
* Represents a basic image combining the data and size. * Represents a basic image combining the data and size.
@ -62,11 +65,11 @@ define([
*/ */
ImageWrapper.transform = function(inImg, outImg, M, inOrig, outOrig) { ImageWrapper.transform = function(inImg, outImg, M, inOrig, outOrig) {
var w = outImg.size.x, h = outImg.size.y, iw = inImg.size.x, ih = inImg.size.y; var w = outImg.size.x, h = outImg.size.y, iw = inImg.size.x, ih = inImg.size.y;
var across = vec2.create([M[0], M[2]]); var across = vec2.clone([M[0], M[2]]);
var down = vec2.create([M[1], M[3]]); var down = vec2.clone([M[1], M[3]]);
var defaultValue = 0; var defaultValue = 0;
var p0 = vec2.subtract(inOrig, mat2.xVec2(M, outOrig, vec2.create()), vec2.create()); var p0 = vec2.subtract(inOrig, mat2.xVec2(M, outOrig, vec2.clone()), vec2.clone());
var min_x = p0[0], min_y = p0[1]; var min_x = p0[0], min_y = p0[1];
var max_x = min_x, max_y = min_y; var max_x = min_x, max_y = min_y;
@ -94,7 +97,7 @@ define([
else else
max_y += h * down[1]; max_y += h * down[1];
var carrigeReturn = vec2.subtract(down, vec2.scale(across, w, vec2.create()), vec2.create()); var carrigeReturn = vec2.subtract(down, vec2.scale(across, w, vec2.clone()), vec2.clone());
if (min_x >= 0 && min_y >= 0 && max_x < iw - 1 && max_y < ih - 1) { if (min_x >= 0 && min_y >= 0 && max_x < iw - 1 && max_y < ih - 1) {
p = p0; p = p0;
@ -346,7 +349,7 @@ define([
label.theta += 180; label.theta += 180;
} }
label.rad = tmp > PI ? tmp - PI : tmp; label.rad = tmp > PI ? tmp - PI : tmp;
label.vec = vec2.create([Math.cos(tmp), Math.sin(tmp)]); label.vec = vec2.clone([Math.cos(tmp), Math.sin(tmp)]);
result.push(label); result.push(label);
} }
} }

@ -1,5 +1,5 @@
/* jshint undef: true, unused: true, browser:true, devel: true, evil: true */ /* jshint undef: true, unused: true, browser:true, devel: true, evil: true */
/* global define, vec2 */ /* global define */
define([ define([
@ -15,7 +15,8 @@ define([
"events", "events",
"camera_access", "camera_access",
"image_debug", "image_debug",
"cv_utils"], "cv_utils",
"gl-matrix"],
function(Code128Reader, function(Code128Reader,
EANReader, EANReader,
InputStream, InputStream,
@ -28,7 +29,8 @@ function(Code128Reader,
Events, Events,
CameraAccess, CameraAccess,
ImageDebug, ImageDebug,
CVUtils) { CVUtils,
glMatrix) {
"use strict"; "use strict";
var _inputStream, var _inputStream,
@ -48,7 +50,8 @@ function(Code128Reader,
_boxSize, _boxSize,
_decoder, _decoder,
_workerPool = [], _workerPool = [],
_onUIThread = true; _onUIThread = true,
vec2 = glMatrix.vec2;
function initializeData(imageWrapper) { function initializeData(imageWrapper) {
initBuffers(imageWrapper); initBuffers(imageWrapper);
@ -56,6 +59,7 @@ function(Code128Reader,
} }
function initConfig() { function initConfig() {
if (typeof document !== "undefined") {
var vis = [{ var vis = [{
node: document.querySelector("div[data-controls]"), node: document.querySelector("div[data-controls]"),
prop: _config.controls prop: _config.controls
@ -74,6 +78,7 @@ function(Code128Reader,
} }
} }
} }
}
function initInputStream(cb) { function initInputStream(cb) {
var video; var video;
@ -161,6 +166,7 @@ function(Code128Reader,
} }
function initCanvas() { function initCanvas() {
if (typeof document !== "undefined") {
var $viewport = document.querySelector("#interactive.viewport"); var $viewport = document.querySelector("#interactive.viewport");
_canvasContainer.dom.image = document.querySelector("canvas.imgBuffer"); _canvasContainer.dom.image = document.querySelector("canvas.imgBuffer");
if (!_canvasContainer.dom.image) { if (!_canvasContainer.dom.image) {
@ -191,6 +197,7 @@ function(Code128Reader,
_canvasContainer.dom.overlay.width = _inputStream.getWidth(); _canvasContainer.dom.overlay.width = _inputStream.getWidth();
_canvasContainer.dom.overlay.height = _inputStream.getHeight(); _canvasContainer.dom.overlay.height = _inputStream.getHeight();
} }
}
function initBuffers(imageWrapper) { function initBuffers(imageWrapper) {
if (imageWrapper) { if (imageWrapper) {
@ -204,10 +211,10 @@ function(Code128Reader,
console.log(_inputImageWrapper.size); console.log(_inputImageWrapper.size);
_boxSize = [ _boxSize = [
vec2.create([20, _inputImageWrapper.size.y / 2 - 100]), vec2.clone([20, _inputImageWrapper.size.y / 2 - 100]),
vec2.create([20, _inputImageWrapper.size.y / 2 + 100]), vec2.clone([20, _inputImageWrapper.size.y / 2 + 100]),
vec2.create([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 + 100]), vec2.clone([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 + 100]),
vec2.create([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 - 100]) vec2.clone([_inputImageWrapper.size.x - 20, _inputImageWrapper.size.y / 2 - 100])
]; ];
BarcodeLocator.init(_inputImageWrapper, _config.locator); BarcodeLocator.init(_inputImageWrapper, _config.locator);
} }

@ -4,6 +4,16 @@
define(function() { define(function() {
"use strict"; "use strict";
Math.imul = Math.imul || function(a, b) {
var ah = (a >>> 16) & 0xffff;
var al = a & 0xffff;
var bh = (b >>> 16) & 0xffff;
var bl = b & 0xffff;
// the shift by 0 fixes the sign on the high part
// the final |0 converts the unsigned value into a signed value
return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0);
};
/* @preserve ASM BEGIN */ /* @preserve ASM BEGIN */
function Skeletonizer(stdlib, foreign, buffer) { function Skeletonizer(stdlib, foreign, buffer) {
"use asm"; "use asm";

Loading…
Cancel
Save