-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
79 lines (77 loc) · 2.53 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// import pico from 'picojs'
const pico = require('picojs');
const fs = require('fs');
const path = require('path');
const { createCanvas, loadImage } = require('canvas');
/*
1. load the face-detection cascade
*/
const getFaceClassifier = async () => {
const filePath = path.join(__dirname, './bin/facefinder')
let buffer = fs.readFileSync(filePath);
var bytes = new Int8Array(buffer);
console.log('cascade loaded');
return pico.unpack_cascade(bytes);
}
/*
2. prepare the image and canvas context
*/
const getImage = async (source) => {
const image = await loadImage(source);
const { width, height } = image;
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
return { image, ctx };
}
/*
3. transform an RGBA image to grayscale
*/
const rgba_to_grayscale = (rgba, nrows, ncols) => {
var gray = new Uint8Array(nrows*ncols);
for(var r=0; r<nrows; ++r)
for(var c=0; c<ncols; ++c)
// gray = 0.2*red + 0.7*green + 0.1*blue
gray[r*ncols + c] = (2*rgba[r*4*ncols+4*c+0]+7*rgba[r*4*ncols+4*c+1]+1*rgba[r*4*ncols+4*c+2])/10;
return gray;
}
/*
4. main function
*/
const getDefaultParams = (width, height) => {
const factor = {
shiftfactor: 0.1,
scalefactor: 1.1
};
const size = {
minsize: Math.min(width, height) * 0.07 >> 0, // minimum size of a face
maxsize: Math.max(width, height) * 3 >> 0 // maximum size of a face
};
return Object.assign(factor, size);
}
const face_detection = async (img, option, qThreshold = 5.0, IoU = 0.2) => {
const facefinder_classify_region = await getFaceClassifier();
let { image, ctx} = await getImage(img);
let { width, height } = image;
// re-draw the image to clear previous results and get its RGBA pixel data
var rgba = ctx.getImageData(0, 0, width, height).data;
// prepare input to `run_cascade`
const imageParams = {
"pixels": rgba_to_grayscale(rgba, height, width),
"nrows": height,
"ncols": width,
"ldim": width
};
const params = Object.assign(getDefaultParams(width, height), option);
// run the cascade over the image
// dets is an array that contains (r, c, s, q) quadruplets
// (representing row, column, scale and detection score)
dets = pico.run_cascade(imageParams, facefinder_classify_region, params);
// cluster the obtained detections
dets = pico.cluster_detections(dets, IoU); // set IoU threshold to 0.2
// return results
return dets.filter(e => e[3] > qThreshold);
}
const pico_node = {};
pico_node.face_detection = face_detection;
module.exports = pico_node;