Skip to content

Commit

Permalink
Merge pull request #273 from ericblade/dev
Browse files Browse the repository at this point in the history
WIP #269 restructure frame_grabber
  • Loading branch information
ericblade authored Nov 12, 2020
2 parents 0fb48f9 + dafa022 commit 3351029
Show file tree
Hide file tree
Showing 10 changed files with 186 additions and 190 deletions.
3 changes: 2 additions & 1 deletion configs/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ module.exports = {
new webpack.DefinePlugin({
ENV: require(path.join(__dirname, './env/', process.env.BUILD_ENV)),
}),
new webpack.NormalModuleReplacementPlugin(/input_stream_node/, './input_stream/input_stream_browser'),
new webpack.NormalModuleReplacementPlugin(/..\/input\/frame_grabber/, '../input/frame_grabber_browser.js'),
new webpack.NormalModuleReplacementPlugin(/^..\/input\/input_stream\/input_stream/, '../input/input_stream/input_stream_browser'),
],
optimization: {
minimize: false,
Expand Down
1 change: 0 additions & 1 deletion configs/webpack.node.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ module.exports.plugins = [
new webpack.DefinePlugin({
ENV: require(path.join(__dirname, './env/', process.env.BUILD_ENV)),
}),
new webpack.NormalModuleReplacementPlugin(/input_stream_browser/, './input_stream/input_stream_node'),
];
module.exports.output.path = __dirname + '/../lib';
module.exports.output.filename = 'quagga.js';
2 changes: 1 addition & 1 deletion src/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ interface QuaggaBuildEnvironment {
}

// injected by the build system
declare const ENV: QuaggaBuildEnvironment;
declare const ENV: QuaggaBuildEnvironment;
130 changes: 53 additions & 77 deletions src/input/frame_grabber.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,37 @@
import NodeFrameGrabber from './frame_grabber_node';
// NOTE FOR ANYONE IN HERE IN THE FUTURE: This module is used when the module is built for use in Node.
// Webpack.config.js explicitly REPLACES this module with the file called frame_grabber_browser when it is packing the Browser distribution.

import {
imageRef,
grayAndHalfSampleFromCanvasData,
computeGray,
} from '../common/cv_utils';

const TO_RADIANS = Math.PI / 180;

function adjustCanvasSize(canvas, targetSize) {
if (canvas.width !== targetSize.x) {
if (ENV.development) {
console.log('WARNING: canvas-size needs to be adjusted');
}
canvas.width = targetSize.x;
}
if (canvas.height !== targetSize.y) {
if (ENV.development) {
console.log('WARNING: canvas-size needs to be adjusted');
}
canvas.height = targetSize.y;
}
}
const CVUtils = require('../common/cv_utils');
const Ndarray = require('ndarray');
const Interp2D = require('ndarray-linear-interpolate').d2;

const FrameGrabber = {};

FrameGrabber.create = function (inputStream, canvas) {
const _that = {};
const _streamConfig = inputStream.getConfig();
const _videoSize = imageRef(inputStream.getRealWidth(), inputStream.getRealHeight());
const _videoSize = CVUtils.imageRef(inputStream.getRealWidth(), inputStream.getRealHeight());
const _canvasSize = inputStream.getCanvasSize();
const _size = imageRef(inputStream.getWidth(), inputStream.getHeight());
const topRight = inputStream.getTopRight();
const _sx = topRight.x;
const _sy = topRight.y;
let _canvas;
let _ctx = null;
let _data = null;
const _size = CVUtils.imageRef(inputStream.getWidth(), inputStream.getHeight());
const _topRight = inputStream.getTopRight();
let _data = new Uint8Array(_size.x * _size.y);
const _grayData = new Uint8Array(_videoSize.x * _videoSize.y);
const _canvasData = new Uint8Array(_canvasSize.x * _canvasSize.y);
/* eslint-disable new-cap */
const _grayImageArray = Ndarray(_grayData, [_videoSize.y, _videoSize.x]).transpose(1, 0);
const _canvasImageArray = Ndarray(_canvasData, [_canvasSize.y, _canvasSize.x]).transpose(1, 0);
const _targetImageArray = _canvasImageArray
.hi(_topRight.x + _size.x, _topRight.y + _size.y)
.lo(_topRight.x, _topRight.y);
const _stepSizeX = _videoSize.x / _canvasSize.x;
const _stepSizeY = _videoSize.y / _canvasSize.y;

_canvas = canvas || document.createElement('canvas');
_canvas.width = _canvasSize.x;
_canvas.height = _canvasSize.y;
_ctx = _canvas.getContext('2d');
_data = new Uint8Array(_size.x * _size.y);
if (ENV.development) {
console.log('FrameGrabber', JSON.stringify({
size: _size,
topRight,
videoSize: _videoSize,
canvasSize: _canvasSize,
videoSize: _grayImageArray.shape,
canvasSize: _canvasImageArray.shape,
stepSize: [_stepSizeX, _stepSizeY],
size: _targetImageArray.shape,
topRight: _topRight,
}));
}

Expand All @@ -71,46 +54,40 @@ FrameGrabber.create = function (inputStream, canvas) {
* The image-data is converted to gray-scale and then half-sampled if configured.
*/
_that.grab = function () {
const doHalfSample = _streamConfig.halfSample;
const frame = inputStream.getFrame();
let drawable = frame;
let drawAngle = 0;
let ctxData;
if (drawable) {
adjustCanvasSize(_canvas, _canvasSize);
if (_streamConfig.type === 'ImageStream') {
drawable = frame.img;
if (frame.tags && frame.tags.orientation) {
switch (frame.tags.orientation) {
case 6:
drawAngle = 90 * TO_RADIANS;
break;
case 8:
drawAngle = -90 * TO_RADIANS;
break;
}
}
}

if (drawAngle !== 0) {
_ctx.translate(_canvasSize.x / 2, _canvasSize.y / 2);
_ctx.rotate(drawAngle);
_ctx.drawImage(drawable, -_canvasSize.y / 2, -_canvasSize.x / 2, _canvasSize.y, _canvasSize.x);
_ctx.rotate(-drawAngle);
_ctx.translate(-_canvasSize.x / 2, -_canvasSize.y / 2);
} else {
_ctx.drawImage(drawable, 0, 0, _canvasSize.x, _canvasSize.y);
if (frame) {
this.scaleAndCrop(frame);
return true;
}
return false;
};

// eslint-disable-next-line
_that.scaleAndCrop = function(frame) {
// 1. compute full-sized gray image
CVUtils.computeGray(frame.data, _grayData);

// 2. interpolate
for (let y = 0; y < _canvasSize.y; y++) {
for (let x = 0; x < _canvasSize.x; x++) {
// eslint-disable-next-line no-bitwise
_canvasImageArray.set(x, y, (Interp2D(_grayImageArray, x * _stepSizeX, y * _stepSizeY)) | 0);
}
}

ctxData = _ctx.getImageData(_sx, _sy, _size.x, _size.y).data;
if (doHalfSample) {
grayAndHalfSampleFromCanvasData(ctxData, _size, _data);
} else {
computeGray(ctxData, _data, _streamConfig);
// targetImageArray must be equal to targetSize
if (_targetImageArray.shape[0] !== _size.x
|| _targetImageArray.shape[1] !== _size.y) {
throw new Error('Shapes do not match!');
}

// 3. crop
for (let y = 0; y < _size.y; y++) {
for (let x = 0; x < _size.x; x++) {
_data[y * _size.x + x] = _targetImageArray.get(x, y);
}
return true;
}
return false;
};

_that.getSize = function () {
Expand All @@ -120,5 +97,4 @@ FrameGrabber.create = function (inputStream, canvas) {
return _that;
};

export default FrameGrabber;
export { NodeFrameGrabber };
module.exports = FrameGrabber;
124 changes: 124 additions & 0 deletions src/input/frame_grabber_browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// NOTE FOR ANYONE IN HERE IN THE FUTURE:
// webpack.config.js replaces the frame_grabber module with THIS module when it is building for a Browser environment.

import {
imageRef,
grayAndHalfSampleFromCanvasData,
computeGray,
} from '../common/cv_utils';

const TO_RADIANS = Math.PI / 180;

function adjustCanvasSize(canvas, targetSize) {
if (canvas.width !== targetSize.x) {
if (ENV.development) {
console.log('WARNING: canvas-size needs to be adjusted');
}
canvas.width = targetSize.x;
}
if (canvas.height !== targetSize.y) {
if (ENV.development) {
console.log('WARNING: canvas-size needs to be adjusted');
}
canvas.height = targetSize.y;
}
}

const FrameGrabber = {};

FrameGrabber.create = function (inputStream, canvas) {
const _that = {};
const _streamConfig = inputStream.getConfig();
const _videoSize = imageRef(inputStream.getRealWidth(), inputStream.getRealHeight());
const _canvasSize = inputStream.getCanvasSize();
const _size = imageRef(inputStream.getWidth(), inputStream.getHeight());
const topRight = inputStream.getTopRight();
const _sx = topRight.x;
const _sy = topRight.y;
let _canvas;
let _ctx = null;
let _data = null;

_canvas = canvas || document.createElement('canvas');
_canvas.width = _canvasSize.x;
_canvas.height = _canvasSize.y;
_ctx = _canvas.getContext('2d');
_data = new Uint8Array(_size.x * _size.y);
if (ENV.development) {
console.log('FrameGrabber', JSON.stringify({
size: _size,
topRight,
videoSize: _videoSize,
canvasSize: _canvasSize,
}));
}

/**
* 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 () {
const doHalfSample = _streamConfig.halfSample;
const frame = inputStream.getFrame();
let drawable = frame;
let drawAngle = 0;
let ctxData;
if (drawable) {
adjustCanvasSize(_canvas, _canvasSize);
if (_streamConfig.type === 'ImageStream') {
drawable = frame.img;
if (frame.tags && frame.tags.orientation) {
switch (frame.tags.orientation) {
case 6:
drawAngle = 90 * TO_RADIANS;
break;
case 8:
drawAngle = -90 * TO_RADIANS;
break;
}
}
}

if (drawAngle !== 0) {
_ctx.translate(_canvasSize.x / 2, _canvasSize.y / 2);
_ctx.rotate(drawAngle);
_ctx.drawImage(drawable, -_canvasSize.y / 2, -_canvasSize.x / 2, _canvasSize.y, _canvasSize.x);
_ctx.rotate(-drawAngle);
_ctx.translate(-_canvasSize.x / 2, -_canvasSize.y / 2);
} else {
_ctx.drawImage(drawable, 0, 0, _canvasSize.x, _canvasSize.y);
}

ctxData = _ctx.getImageData(_sx, _sy, _size.x, _size.y).data;
if (doHalfSample) {
grayAndHalfSampleFromCanvasData(ctxData, _size, _data);
} else {
computeGray(ctxData, _data, _streamConfig);
}
return true;
}
return false;
};

_that.getSize = function () {
return _size;
};

return _that;
};

export default FrameGrabber;
Loading

0 comments on commit 3351029

Please sign in to comment.