mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-13 05:31:37 +08:00
fromCamera working; experimenting with zoom
This commit is contained in:
@@ -77,7 +77,7 @@
|
|||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<span>Half-Sample</span>
|
<span>Half-Sample</span>
|
||||||
<input type="checkbox" name="locator_half-sample" />
|
<input checked="checked" type="checkbox" name="locator_half-sample" />
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<span>Single Channel</span>
|
<span>Single Channel</span>
|
||||||
|
|||||||
+25
-20
@@ -3,24 +3,29 @@ $(function() {
|
|||||||
init : function() {
|
init : function() {
|
||||||
this.overlay = document.querySelector('#interactive canvas.drawing');
|
this.overlay = document.querySelector('#interactive canvas.drawing');
|
||||||
|
|
||||||
this.scanner = Quagga
|
this.state.inputStream.constraints.zoom = {exact: 2};
|
||||||
.fromConfig(this.state);
|
Quagga.fromCamera({
|
||||||
|
constraints: this.state.inputStream.constraints,
|
||||||
|
locator: this.state.locator,
|
||||||
|
decoder: this.state.decoder,
|
||||||
|
}).then(function(scanner) {
|
||||||
|
this.scanner = scanner;
|
||||||
|
this.scanner
|
||||||
|
.addEventListener("processed", drawResult.bind(this, this.scanner))
|
||||||
|
.addEventListener("detected", addToResults.bind(this, this.scanner));
|
||||||
|
|
||||||
this.scanner
|
this.scanner.start()
|
||||||
.addEventListener("processed", drawResult.bind(this, this.scanner))
|
.then(function (){
|
||||||
.addEventListener("detected", addToResults.bind(this, this.scanner));
|
console.log("started");
|
||||||
|
this.attachListeners();
|
||||||
this.scanner.start()
|
}.bind(this))
|
||||||
.then(function (){
|
.catch(function(err) {
|
||||||
console.log("started");
|
console.error(err);
|
||||||
this.attachListeners();
|
});
|
||||||
}.bind(this))
|
}.bind(this));
|
||||||
.catch(function(err) {
|
|
||||||
console.log("Error: " + err);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
initCameraSelection: function(){
|
initCameraSelection: function() {
|
||||||
var streamLabel = Quagga.CameraAccess.getActiveStreamLabel();
|
var streamLabel = this.scanner.getSource().getLabel();
|
||||||
|
|
||||||
return Quagga.CameraAccess.enumerateVideoDevices()
|
return Quagga.CameraAccess.enumerateVideoDevices()
|
||||||
.then(function(devices) {
|
.then(function(devices) {
|
||||||
@@ -106,8 +111,8 @@ $(function() {
|
|||||||
if (/^(\d+)x(\d+)$/.test(value)) {
|
if (/^(\d+)x(\d+)$/.test(value)) {
|
||||||
var values = value.split('x');
|
var values = value.split('x');
|
||||||
return {
|
return {
|
||||||
width: {min: parseInt(values[0])},
|
width: {ideal: parseInt(values[0])},
|
||||||
height: {min: parseInt(values[1])}
|
height: {ideal: parseInt(values[1])}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -141,8 +146,8 @@ $(function() {
|
|||||||
inputStream: {
|
inputStream: {
|
||||||
type : "LiveStream",
|
type : "LiveStream",
|
||||||
constraints: {
|
constraints: {
|
||||||
width: {min: 640},
|
width: {ideal: 640},
|
||||||
height: {min: 480},
|
height: {ideal: 480},
|
||||||
facingMode: "environment",
|
facingMode: "environment",
|
||||||
aspectRatio: {min: 1, max: 2}
|
aspectRatio: {min: 1, max: 2}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,3 +4,13 @@ export function sleep(millis) {
|
|||||||
window.setTimeout(resolve, millis);
|
window.setTimeout(resolve, millis);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getViewport(target) {
|
||||||
|
if (target && target.nodeName && target.nodeType === 1) {
|
||||||
|
return target;
|
||||||
|
} else {
|
||||||
|
// Use '#interactive.viewport' as a fallback selector (backwards compatibility)
|
||||||
|
var selector = typeof target === 'string' ? target : '#interactive.viewport';
|
||||||
|
return document.querySelector(selector);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
locator: {
|
locator: {
|
||||||
halfSample: false,
|
halfSample: true,
|
||||||
patchSize: "medium", // x-small, small, medium, large, x-large
|
patchSize: "medium", // x-small, small, medium, large, x-large
|
||||||
debug: {
|
debug: {
|
||||||
showCanvas: false,
|
showCanvas: false,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import {
|
|||||||
computeGray
|
computeGray
|
||||||
} from '../common/cv_utils';
|
} from '../common/cv_utils';
|
||||||
import {sleep} from '../common/utils';
|
import {sleep} from '../common/utils';
|
||||||
|
import {getViewport} from '../common/utils';
|
||||||
|
|
||||||
function adjustCanvasSize(input, canvas) {
|
function adjustCanvasSize(input, canvas) {
|
||||||
if (input instanceof HTMLVideoElement) {
|
if (input instanceof HTMLVideoElement) {
|
||||||
@@ -25,18 +26,8 @@ function adjustCanvasSize(input, canvas) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getViewPort(target) {
|
|
||||||
if (target && target.nodeName && target.nodeType === 1) {
|
|
||||||
return target;
|
|
||||||
} else {
|
|
||||||
// Use '#interactive.viewport' as a fallback selector (backwards compatibility)
|
|
||||||
var selector = typeof target === 'string' ? target : '#interactive.viewport';
|
|
||||||
return document.querySelector(selector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOrCreateCanvas(source, target) {
|
function getOrCreateCanvas(source, target) {
|
||||||
const $viewport = getViewPort(target);
|
const $viewport = getViewport(target);
|
||||||
let $canvas = $viewport.querySelector("canvas.imgBuffer");
|
let $canvas = $viewport.querySelector("canvas.imgBuffer");
|
||||||
if (!$canvas) {
|
if (!$canvas) {
|
||||||
$canvas = document.createElement("canvas");
|
$canvas = document.createElement("canvas");
|
||||||
|
|||||||
+31
-12
@@ -1,21 +1,40 @@
|
|||||||
|
import {clone} from 'lodash';
|
||||||
import {determineOrientation, PORTRAIT} from '../common/device';
|
import {determineOrientation, PORTRAIT} from '../common/device';
|
||||||
import CameraAccess from './camera_access';
|
import CameraAccess from './camera_access';
|
||||||
|
import {getViewport} from '../common/utils';
|
||||||
|
|
||||||
|
function getOrCreateVideo(source, target) {
|
||||||
|
const $viewport = getViewport(target);
|
||||||
|
if ($viewport) {
|
||||||
|
let $video = $viewport.querySelector("video");
|
||||||
|
if (!$video) {
|
||||||
|
$video = document.createElement("video");
|
||||||
|
$viewport.appendChild($video);
|
||||||
|
}
|
||||||
|
return $video;
|
||||||
|
}
|
||||||
|
return document.createElement("video");
|
||||||
|
}
|
||||||
|
|
||||||
export function fromCamera(constraints) {
|
export function fromCamera(constraints) {
|
||||||
if (!constraints) {
|
|
||||||
constraints = {width: {ideal: 540}, height: {ideal: 540}, aspectRatio: {ideal: 1}, facingMode: 'environment'};
|
|
||||||
}
|
|
||||||
var orientation = determineOrientation();
|
var orientation = determineOrientation();
|
||||||
var videoConstraints = constraints;
|
var videoConstraints = clone(constraints);
|
||||||
if (orientation === PORTRAIT) {
|
if (orientation === PORTRAIT) {
|
||||||
constraints = Object.assign({}, constraints, {
|
videoConstraints = Object.assign({}, videoConstraints, {
|
||||||
width: constraints.height,
|
width: videoConstraints.height,
|
||||||
height: constraints.width,
|
height: videoConstraints.width,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const video = document.querySelector('video');
|
if (videoConstraints.zoom && videoConstraints.zoom.exact > 1) {
|
||||||
CameraAccess.request(videoConstraints, video)
|
videoConstraints.width.ideal = Math.floor(videoConstraints.width.ideal * videoConstraints.zoom.exact);
|
||||||
|
videoConstraints.height.ideal = Math.floor(videoConstraints.height.ideal * videoConstraints.zoom.exact);
|
||||||
|
delete videoConstraints.zoom;
|
||||||
|
}
|
||||||
|
console.log(videoConstraints);
|
||||||
|
|
||||||
|
const video = getOrCreateVideo();
|
||||||
|
return CameraAccess.request(video, videoConstraints)
|
||||||
.then(function(mediastream) {
|
.then(function(mediastream) {
|
||||||
const track = mediastream.getVideoTracks()[0];
|
const track = mediastream.getVideoTracks()[0];
|
||||||
return {
|
return {
|
||||||
@@ -39,8 +58,8 @@ export function fromCamera(constraints) {
|
|||||||
return {
|
return {
|
||||||
viewport,
|
viewport,
|
||||||
canvas: {
|
canvas: {
|
||||||
width: constraints.width, // AR
|
width: viewport.width, // AR
|
||||||
height: constraints.height, // AR
|
height: viewport.height, // AR
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -65,7 +84,7 @@ export function fromCamera(constraints) {
|
|||||||
constraints.height.ideal = Math.floor(constraints.height.ideal * constraints.zoom.exact);
|
constraints.height.ideal = Math.floor(constraints.height.ideal * constraints.zoom.exact);
|
||||||
delete constraints.zoom;
|
delete constraints.zoom;
|
||||||
}
|
}
|
||||||
return CameraAccess.request(videoConstraints, video);
|
return CameraAccess.request(video, videoConstraints);
|
||||||
},
|
},
|
||||||
getLabel: function() {
|
getLabel: function() {
|
||||||
return track.label;
|
return track.label;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ var streamRef;
|
|||||||
|
|
||||||
function waitForVideo(video, stream) {
|
function waitForVideo(video, stream) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let attempts = 10;
|
let attempts = 20;
|
||||||
|
|
||||||
function checkVideo() {
|
function checkVideo() {
|
||||||
if (attempts > 0) {
|
if (attempts > 0) {
|
||||||
@@ -20,7 +20,7 @@ function waitForVideo(video, stream) {
|
|||||||
}
|
}
|
||||||
resolve(stream);
|
resolve(stream);
|
||||||
} else {
|
} else {
|
||||||
window.setTimeout(checkVideo, 500);
|
window.setTimeout(checkVideo, 200);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
reject('Unable to play video stream. Is webcam working?');
|
reject('Unable to play video stream. Is webcam working?');
|
||||||
|
|||||||
+26
-3
@@ -5,13 +5,14 @@ import ImageDebug from './common/image_debug';
|
|||||||
import ResultCollector from './analytics/result_collector';
|
import ResultCollector from './analytics/result_collector';
|
||||||
import Config from './config/config';
|
import Config from './config/config';
|
||||||
import {merge} from 'lodash';
|
import {merge} from 'lodash';
|
||||||
import {createConfigForImage} from './input/config_factory';
|
import CameraAccess from './input/camera_access';
|
||||||
import * as PixelCapture from './input/PixelCapture';
|
import * as PixelCapture from './input/PixelCapture';
|
||||||
import * as Source from './input/Source';
|
import * as Source from './input/Source';
|
||||||
|
|
||||||
function fromConfig(pixelCapturer, config) {
|
function fromConfig(pixelCapturer, config) {
|
||||||
const scanner = createScanner(pixelCapturer);
|
const scanner = createScanner(pixelCapturer);
|
||||||
const source = pixelCapturer.getSource();
|
const source = pixelCapturer.getSource();
|
||||||
|
let currentConfig = config;
|
||||||
let pendingStart = null;
|
let pendingStart = null;
|
||||||
let initialized = false;
|
let initialized = false;
|
||||||
return {
|
return {
|
||||||
@@ -35,7 +36,7 @@ function fromConfig(pixelCapturer, config) {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
pendingStart = new Promise((resolve, reject) => {
|
pendingStart = new Promise((resolve, reject) => {
|
||||||
scanner.init(config, (error) => {
|
scanner.init(currentConfig, (error) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
reject(error);
|
reject(error);
|
||||||
@@ -80,7 +81,7 @@ function fromConfig(pixelCapturer, config) {
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
scanner.decodeSingle(config, (result) => {
|
scanner.decodeSingle(currentConfig, (result) => {
|
||||||
if (result && result.codeResult && result.codeResult.code) {
|
if (result && result.codeResult && result.codeResult.code) {
|
||||||
return resolve(result);
|
return resolve(result);
|
||||||
}
|
}
|
||||||
@@ -95,6 +96,21 @@ function fromConfig(pixelCapturer, config) {
|
|||||||
getCanvas() {
|
getCanvas() {
|
||||||
return pixelCapturer.getCanvas();
|
return pixelCapturer.getCanvas();
|
||||||
},
|
},
|
||||||
|
applyConfig(newConfig) {
|
||||||
|
// during runtime?
|
||||||
|
// running scanners must know that!
|
||||||
|
// apply constraints to source, only if changed
|
||||||
|
|
||||||
|
const normalizedConfig = merge({}, Config, newConfig);
|
||||||
|
this.stop();
|
||||||
|
currentConfig = normalizedConfig;
|
||||||
|
|
||||||
|
return source.applyConstraints(currentConfig.constraints)
|
||||||
|
.then(() => this.start());
|
||||||
|
},
|
||||||
|
getSource() {
|
||||||
|
return pixelCapturer.getSource();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +132,12 @@ function createApi() {
|
|||||||
.fromImage(image, config.constraints)
|
.fromImage(image, config.constraints)
|
||||||
.then(fromSource.bind(null, config));
|
.then(fromSource.bind(null, config));
|
||||||
},
|
},
|
||||||
|
fromCamera(options) {
|
||||||
|
const config = merge({}, Config, options);
|
||||||
|
return Source
|
||||||
|
.fromCamera(config.constraints)
|
||||||
|
.then(fromSource.bind(null, config));
|
||||||
|
},
|
||||||
fromSource(src, inputConfig) {
|
fromSource(src, inputConfig) {
|
||||||
return fromSource(configuration, src, inputConfig);
|
return fromSource(configuration, src, inputConfig);
|
||||||
},
|
},
|
||||||
@@ -134,6 +156,7 @@ function createApi() {
|
|||||||
config(conf) {
|
config(conf) {
|
||||||
return createApi(merge({}, configuration, conf));
|
return createApi(merge({}, configuration, conf));
|
||||||
},
|
},
|
||||||
|
CameraAccess,
|
||||||
ImageWrapper,
|
ImageWrapper,
|
||||||
ImageDebug,
|
ImageDebug,
|
||||||
ResultCollector,
|
ResultCollector,
|
||||||
|
|||||||
+12
-8
@@ -209,10 +209,11 @@ function createScanner(pixelCapturer) {
|
|||||||
} else {
|
} else {
|
||||||
//_framegrabber.attachData(_inputImageWrapper.data);
|
//_framegrabber.attachData(_inputImageWrapper.data);
|
||||||
}
|
}
|
||||||
pixelCapturer.grabFrameData()
|
|
||||||
|
return pixelCapturer.grabFrameData()
|
||||||
.then((bitmap) => {
|
.then((bitmap) => {
|
||||||
_inputImageWrapper.data = bitmap.data;
|
|
||||||
if (bitmap) {
|
if (bitmap) {
|
||||||
|
_inputImageWrapper.data = bitmap.data;
|
||||||
if (availableWorker) {
|
if (availableWorker) {
|
||||||
availableWorker.busy = true;
|
availableWorker.busy = true;
|
||||||
availableWorker.worker.postMessage({
|
availableWorker.worker.postMessage({
|
||||||
@@ -226,15 +227,15 @@ function createScanner(pixelCapturer) {
|
|||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
})
|
});
|
||||||
} else {
|
|
||||||
locateAndDecode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return locateAndDecode();
|
||||||
}
|
}
|
||||||
|
|
||||||
function startContinuousUpdate() {
|
function startContinuousUpdate() {
|
||||||
var next = null,
|
var next = null,
|
||||||
delay = 1000 / (_config.frequency === 0 ? 60 : (_config.frequency || 60));
|
delay = 1000 / (_config.frequency === 0 ? 10 : (_config.frequency || 10));
|
||||||
|
|
||||||
_stopped = false;
|
_stopped = false;
|
||||||
(function frame(timestamp) {
|
(function frame(timestamp) {
|
||||||
@@ -242,9 +243,12 @@ function createScanner(pixelCapturer) {
|
|||||||
if (!_stopped) {
|
if (!_stopped) {
|
||||||
if (timestamp >= next) {
|
if (timestamp >= next) {
|
||||||
next += delay;
|
next += delay;
|
||||||
update();
|
update().then(() => {
|
||||||
|
window.requestAnimFrame(frame);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.requestAnimFrame(frame);
|
||||||
}
|
}
|
||||||
window.requestAnimFrame(frame);
|
|
||||||
}
|
}
|
||||||
}(performance.now()));
|
}(performance.now()));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user