2016-11-02 18:15:20 +00:00
/ * *
* Photography _with _detected _features . js
* /
'use strict' ;
var Width _used _for _displaying _canvas = ( function ( ) {
return function ( ) {
return 200 ;
} ;
} ) ( ) ;
var Height _used _for _displaying _canvas = ( function ( ) {
return function ( ) {
return 200 ;
} ;
} ) ( ) ;
var Photography _with _detected _features = function ( image /* Image */ , image _name /* String */ ) {
chai . assert . isTrue ( image !== undefined && image !== null && image instanceof Image && image . complete , 'Photography_with_detected_features._image' ) ;
2016-11-03 14:01:51 +00:00
// 'image_name instanceof String === false' when 'var image_name = "Not constructed through constructor!";'
2016-11-02 18:15:20 +00:00
chai . assert . isTrue ( image _name !== undefined && image _name !== null /* && image_name instanceof String */ , 'Photography_with_detected_features._image_name' ) ;
/** Check image resizing here that has to occur in calling context */
/** Not sure 'image' has to be recorded since it is immediately transformed into canvas: */
this . _image = image ;
this . _image _name = image _name ;
/** JSFeat: */
2016-11-03 14:01:51 +00:00
// jsfeat.matrix_t(columns, rows, data_type, data_buffer = undefined);
// jsfeat.U8_t | jsfeat.C1_t; // 1 channel with unsigned char:
2016-11-02 18:15:20 +00:00
this . _matrix _char8 _C1 = new jsfeat . matrix _t ( this . _image . width , this . _image . height , /*jsfeat.U8_t | jsfeat.C1_t*/ jsfeat . U8C1 _t ) ;
/** Canvases */
this . $ _image _canvas = $ ( '<canvas>' ) . attr ( { // Canvas as jQuery object
id : "image-canvas-" + this . _image _name
} ) ;
// Configuring canvas' size with jQuery is not reliable using 'innerWidth(this._image.width)' or 'outerWidth(this._image.width)':
this . $ _image _canvas . get ( 0 ) . width = this . _image . width ;
this . $ _image _canvas . get ( 0 ) . height = this . _image . height ;
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . drawImage ( this . _image , 0 , 0 , this . _image . width , this . _image . height ) ;
// Display:
this . $ _image _canvas . css ( "width" , Width _used _for _displaying _canvas ( ) + "px" ) ;
this . $ _image _canvas . css ( "height" , Width _used _for _displaying _canvas ( ) + "px" ) ;
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . font = "italic 10px Arial" ;
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . strokeText ( "Original: " + this . _image _name , 10 , 10 ) ;
$ ( "body" ) . prepend ( this . $ _image _canvas ) ;
this . _image _data = this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . getImageData ( 0 , 0 , this . _image . width , this . _image . height ) ;
this . _image _data _buffer = new Uint32Array ( this . _image _data . data . buffer ) ;
this . $ _grayscale _canvas = $ ( '<canvas>' ) . attr ( { // Canvas as jQuery object
id : "grayscale-canvas-" + this . _image _name
} ) ;
this . $ _grayscale _canvas . get ( 0 ) . width = this . _image . width ;
this . $ _grayscale _canvas . get ( 0 ) . height = this . _image . height ;
this . _grayscale _image _data = this . $ _grayscale _canvas . get ( 0 ) . getContext ( '2d' ) . getImageData ( 0 , 0 , this . _image . width , this . _image . height ) ;
this . _grayscale _image _data _buffer = new Uint32Array ( this . _grayscale _image _data . data . buffer ) ;
this . $ _gaussian _blur _canvas = $ ( '<canvas>' ) . attr ( { // Canvas as jQuery object
id : "gaussian_blur-canvas-" + this . _image _name
} ) ;
this . $ _gaussian _blur _canvas . get ( 0 ) . width = this . _image . width ;
this . $ _gaussian _blur _canvas . get ( 0 ) . height = this . _image . height ;
this . $ _gaussian _blur _canvas . get ( 0 ) . getContext ( '2d' ) . drawImage ( this . _image , 0 , 0 , this . _image . width , this . _image . height ) ;
this . _gaussian _blur _image _data = this . $ _gaussian _blur _canvas . get ( 0 ) . getContext ( '2d' ) . getImageData ( 0 , 0 , this . _image . width , this . _image . height ) ;
this . _gaussian _blur _image _data _buffer = new Uint32Array ( this . _gaussian _blur _image _data . data . buffer ) ;
/** Canny: */
this . $ _canny _canvas = $ ( '<canvas>' ) . attr ( { // Canvas as jQuery object
id : "canny-canvas-" + this . _image _name
} ) ;
this . $ _canny _canvas . get ( 0 ) . width = this . _image . width ;
this . $ _canny _canvas . get ( 0 ) . height = this . _image . height ;
this . $ _canny _canvas . get ( 0 ) . getContext ( '2d' ) . drawImage ( this . _image , 0 , 0 , this . _image . width , this . _image . height ) ;
this . _canny _image _data = this . $ _canny _canvas . get ( 0 ) . getContext ( '2d' ) . getImageData ( 0 , 0 , this . _image . width , this . _image . height ) ;
this . _canny _image _data _buffer = new Uint32Array ( this . _canny _image _data . data . buffer ) ;
/** Sobel: */
this . $ _sobel _canvas = $ ( '<canvas>' ) . attr ( {
id : "sobel-canvas-" + this . _image _name
} ) ;
this . $ _sobel _canvas . get ( 0 ) . width = this . _image . width ;
this . $ _sobel _canvas . get ( 0 ) . height = this . _image . height ;
this . $ _sobel _canvas . get ( 0 ) . getContext ( '2d' ) . drawImage ( this . _image , 0 , 0 , this . _image . width , this . _image . height ) ;
this . _sobel _image _data = this . $ _sobel _canvas . get ( 0 ) . getContext ( '2d' ) . getImageData ( 0 , 0 , this . _image . width , this . _image . height ) ;
this . _sobel _image _data _buffer = new Uint32Array ( this . _sobel _image _data . data . buffer ) ;
/** Detection: */
this . _gaussian _blur ( ) ;
this . _canny _processing ( ) ;
this . _canny _postprocessing ( ) ;
this . _sobel _processing ( ) ;
this . _sobel _postprocessing ( ) ;
/** BBF: */
this . _brightness _binary _face = null // Sample: '[{"x":44.86460414486096,"y":40.36860185248175,"width":51.39751761778363,"height":51.39751761778363,"neighbors":14,"confidence":8.938965569999997}]'
this . _brightness _binary _face _detecting ( chroma ( 'blue' ) . hex ( ) ) ;
/** Haar: */
this . _haar _feature = null ;
// Classifiers: 'jsfeat.haar.eye', 'jsfeat.haar.frontalface' and 'jsfeat.haar.mouth'
this . _haar _feature _detecting ( chroma ( 'green' ) . hex ( ) , jsfeat . haar . frontalface , 1 ) ;
this . _haar _feature _detecting ( chroma ( 'yellow' ) . hex ( ) , jsfeat . haar . mouth , 1 ) ;
this . _haar _feature _detecting ( chroma ( 'magenta' ) . hex ( ) , jsfeat . haar . eye , 2 ) ; // Bad result
/** tracking.js */
this . _tracking _face ( ) ;
} ;
Photography _with _detected _features . prototype . _gaussian _blur = function ( ) {
var source = new jsfeat . matrix _t ( this . _image . width , this . _image . height , /*jsfeat.U8_t | jsfeat.C1_t*/ jsfeat . U8C1 _t ) ;
var pixel _number = this . _image . width * this . _image . height ;
while ( -- pixel _number >= 0 ) {
var pixel = this . _image _data _buffer [ pixel _number ] ;
source . data [ pixel _number ] = ( pixel << 24 ) | ( pixel << 16 ) | ( pixel << 8 ) | pixel ;
}
var target = new jsfeat . matrix _t ( this . _image . width , this . _image . height , /*jsfeat.U8_t | jsfeat.C1_t*/ jsfeat . U8C1 _t ) ;
var sigma = 2 ; // gui.add(options, 'sigma', 0, 10).step(0.5); // It increases bluring
var radius = 3 ; // [1 - 11]
var kernel _size = ( radius + 1 ) << 1 ;
jsfeat . imgproc . gaussian _blur ( source , target , kernel _size , sigma ) ;
var pixel _number = target . cols * target . rows ;
while ( -- pixel _number >= 0 ) {
var pixel = target . data [ pixel _number ] ;
this . _gaussian _blur _image _data _buffer [ pixel _number ] = ( pixel << 24 ) | ( pixel << 16 ) | ( pixel << 8 ) | pixel ;
}
this . $ _gaussian _blur _canvas . get ( 0 ) . getContext ( '2d' ) . putImageData ( this . _gaussian _blur _image _data , 0 , 0 ) ;
// Display:
this . $ _gaussian _blur _canvas . css ( "width" , Width _used _for _displaying _canvas ( ) + "px" ) ;
this . $ _gaussian _blur _canvas . css ( "height" , Width _used _for _displaying _canvas ( ) + "px" ) ;
this . $ _gaussian _blur _canvas . get ( 0 ) . getContext ( '2d' ) . font = "italic 10px Arial" ;
this . $ _gaussian _blur _canvas . get ( 0 ) . getContext ( '2d' ) . strokeText ( "Gaussian blur: " + this . _image _name , 10 , 10 ) ;
$ ( "body" ) . prepend ( this . $ _gaussian _blur _canvas ) ;
} ;
Photography _with _detected _features . prototype . _canny _processing = function ( ) {
chai . assert . isNotNull ( this . _canny _image _data , 'Photography_with_detected_features._canny_image_data' ) ;
chai . assert . isNotNull ( this . _canny _image _data _buffer , 'Photography_with_detected_features._canny_image_data_buffer' ) ;
jsfeat . imgproc . grayscale ( this . _canny _image _data . data , this . _image . width , this . _image . height , this . _matrix _char8 _C1 ) ;
var blur _radius = 3 ;
var low _threshold = 40 ;
var high _threshold = 40 ;
2016-11-03 14:01:51 +00:00
// Bitwise OR with '0' is equivalent to 'Math.floor()':
2016-11-02 18:15:20 +00:00
var r = blur _radius | 0 ;
var kernel _size = ( r + 1 ) << 1 ;
jsfeat . imgproc . gaussian _blur ( this . _matrix _char8 _C1 , this . _matrix _char8 _C1 , kernel _size , 0 ) ;
2016-11-03 14:01:51 +00:00
// Bitwise OR with '0' is equivalent to 'Math.floor()':
2016-11-02 18:15:20 +00:00
jsfeat . imgproc . canny ( this . _matrix _char8 _C1 , this . _matrix _char8 _C1 , low _threshold | 0 , high _threshold | 0 ) ;
2016-11-03 14:01:51 +00:00
// Render result back to canvas:
2016-11-02 18:15:20 +00:00
var alpha = ( 0x000000FF << 24 ) ; // 'alpha' is set to max., i.e., '255'
var pixel _number = this . _matrix _char8 _C1 . cols * this . _matrix _char8 _C1 . rows ;
while ( -- pixel _number >= 0 ) {
var pixel = this . _matrix _char8 _C1 . data [ pixel _number ] ;
this . _canny _image _data _buffer [ pixel _number ] = alpha | ( pixel << 16 ) | ( pixel << 8 ) | pixel ;
}
} ;
Photography _with _detected _features . prototype . _canny _postprocessing = function ( ) {
chai . assert . isNotNull ( this . _canny _image _data , 'Photography_with_detected_features._canny_image_data' ) ;
chai . assert . isNotNull ( this . _canny _image _data _buffer , 'Photography_with_detected_features._canny_image_data_buffer' ) ;
for ( var pixel _number = 0 ; pixel _number < this . _canny _image _data _buffer . length ; pixel _number ++ ) {
2016-11-03 14:01:51 +00:00
// Décalage sur la droite SANS préservation du signe (i.e., remplissage à gauche par des '0'):
2016-11-02 18:15:20 +00:00
var alpha = this . _canny _image _data _buffer [ pixel _number ] >>> 24 ; // Most left byte
var blue = ( this . _canny _image _data _buffer [ pixel _number ] & 0x00FF0000 ) >> 16 ;
var green = ( this . _canny _image _data _buffer [ pixel _number ] & 0x0000FF00 ) >> 8 ;
var red = this . _canny _image _data _buffer [ pixel _number ] & 0x000000FF ; // Most right byte
if ( red === 255 && green === 255 && blue === 255 ) { // white
green = 0 ;
blue = 0 ;
alpha = ( 0x000000FF << 24 ) ; // 'alpha' is set to max., i.e., '255'
} else
alpha = ( 0x00000000 << 24 ) ; // 'alpha' is set to min., i.e., '0'
this . _canny _image _data _buffer [ pixel _number ] = alpha | ( blue << 16 ) | ( green << 8 ) | red ;
}
this . $ _canny _canvas . get ( 0 ) . getContext ( '2d' ) . putImageData ( this . _canny _image _data , 0 , 0 ) ;
// Display:
this . $ _canny _canvas . css ( "width" , Width _used _for _displaying _canvas ( ) + "px" ) ;
this . $ _canny _canvas . css ( "height" , Height _used _for _displaying _canvas ( ) + "px" ) ;
this . $ _canny _canvas . get ( 0 ) . getContext ( '2d' ) . font = "italic 10px Arial" ;
this . $ _canny _canvas . get ( 0 ) . getContext ( '2d' ) . strokeText ( "Canny: " + this . _image _name , 10 , 10 ) ;
$ ( "body" ) . prepend ( this . $ _canny _canvas ) ;
} ;
Photography _with _detected _features . prototype . _sobel _processing = function ( ) {
chai . assert . isNotNull ( this . _sobel _image _data , 'Photography_with_detected_features._sobel_image_data' ) ;
chai . assert . isNotNull ( this . _sobel _image _data _buffer , 'Photography_with_detected_features._sobel_image_data_buffer' ) ;
2016-11-03 14:01:51 +00:00
// 2 channels with 32 bit integer:
2016-11-02 18:15:20 +00:00
var matrix _integer32 _C2 = new jsfeat . matrix _t ( this . _image . width , this . _image . height , jsfeat . S32C2 _t ) ;
// Passe l'image en nuances de gris au lieu des couleurs:
jsfeat . imgproc . grayscale ( this . _sobel _image _data . data , this . _image . width , this . _image . height , this . _matrix _char8 _C1 , jsfeat . COLOR _RGBA2GRAY ) ;
// Image source in 'this._matrix_char8_C1', result in 'matrix_integer32_C2'
jsfeat . imgproc . sobel _derivatives ( this . _matrix _char8 _C1 , matrix _integer32 _C2 ) ;
2016-11-03 14:01:51 +00:00
// Render result back to canvas:
2016-11-02 18:15:20 +00:00
// RGBA pixel's features are packed into 32 bits (https://hacks.mozilla.org/2011/12/faster-canvas-pixel-manipulation-with-typed-arrays/):
var i = this . _sobel _image _data _buffer . length , pixel = 0 , gx = 0 , gy = 0 ;
while ( -- i >= 0 ) { // 'i' = this._image.width * this._image.height, matrix_integer32_C2.data.length = this._image.width * this._image.height
2016-11-03 14:01:51 +00:00
// First iteration:
// 'i << 1' === matrix_integer32_C2.data.length - 2
// '(i << 1) + 1' === matrix_integer32_C2.data.length - 1
// Gradient de l'intensité sur l'axe x:
2016-11-02 18:15:20 +00:00
gx = Math . abs ( matrix _integer32 _C2 . data [ i << 1 ] >> 2 ) & 0x000000FF ;
// Gradient de l'intensité sur l'axe y:
gy = Math . abs ( matrix _integer32 _C2 . data [ ( i << 1 ) + 1 ] >> 2 ) & 0x000000FF ;
pixel = ( ( gx + gy ) >> 1 ) & 0x000000FF ;
this . _sobel _image _data _buffer [ i ] = ( pixel << 24 ) | ( gx << 16 ) | ( 0 << 8 ) | gy ;
}
} ;
Photography _with _detected _features . prototype . _sobel _postprocessing = function ( ) {
chai . assert . isNotNull ( this . _sobel _image _data , 'Photography_with_detected_features._sobel_image_data' ) ;
chai . assert . isNotNull ( this . _sobel _image _data _buffer , 'Photography_with_detected_features._sobel_image_data_buffer' ) ;
chai . assert . isNotNull ( this . _image _data , 'Photography_with_detected_features._image_data' ) ;
chai . assert . isNotNull ( this . _image _data _buffer , 'Photography_with_detected_features._image_data_buffer' ) ;
for ( var pixel _number = 0 ; pixel _number < this . _sobel _image _data _buffer . length ; pixel _number ++ ) {
var alpha = this . _sobel _image _data _buffer [ pixel _number ] >>> 24 ; // Most left byte
var blue = ( this . _sobel _image _data _buffer [ pixel _number ] & 0x00FF0000 ) >> 16 ;
var green = ( this . _sobel _image _data _buffer [ pixel _number ] & 0x0000FF00 ) >> 8 ;
var red = this . _sobel _image _data _buffer [ pixel _number ] & 0x000000FF ; // Most right byte
/** Gray scale: red-channel == green-channel == blue-channel */
if ( alpha > 10 ) { // Lower: useless details are kept (outside faces especially) while higher: faces lose quality
red = alpha ;
blue = alpha ;
green = alpha ;
// Change 'alpha'?
} else {
alpha = 0 ;
}
// Pixel reload:
this . _sobel _image _data _buffer [ pixel _number ] = ( alpha << 24 ) | ( blue << 16 ) | ( green << 8 ) | red ;
/** Original image is setup according to Sobel: */
var sobel _alpha = alpha ;
alpha = this . _image _data _buffer [ pixel _number ] >>> 24 ; // Most left byte
blue = ( this . _image _data _buffer [ pixel _number ] & 0x00FF0000 ) >> 16 ;
green = ( this . _image _data _buffer [ pixel _number ] & 0x0000FF00 ) >> 8 ;
red = this . _image _data _buffer [ pixel _number ] & 0x000000FF ; // Most right byte
if ( sobel _alpha === 0 ) {
// Pixel reload:
//this._image_data_buffer[pixel_number] = (alpha << 24) | (blue << 16) | (green << 8) | red; // Colors are kept
}
}
/** Update pixels into canvas: */
this . $ _sobel _canvas . get ( 0 ) . getContext ( '2d' ) . putImageData ( this . _sobel _image _data , 0 , 0 ) ;
// Display for test only:
this . $ _sobel _canvas . css ( "width" , Width _used _for _displaying _canvas ( ) + "px" ) ;
this . $ _sobel _canvas . css ( "height" , Height _used _for _displaying _canvas ( ) + "px" ) ;
this . $ _sobel _canvas . get ( 0 ) . getContext ( '2d' ) . font = "italic 10px Arial" ;
this . $ _sobel _canvas . get ( 0 ) . getContext ( '2d' ) . strokeText ( "Sobel: " + this . _image _name , 10 , 10 ) ;
$ ( "body" ) . prepend ( this . $ _sobel _canvas ) ;
} ;
Photography _with _detected _features . prototype . _brightness _binary _face _detecting = function ( color ) {
var canvas = $ ( '<canvas>' ) . attr ( {
id : "bbf-canvas-" + this . _image _name
} ) ;
canvas . get ( 0 ) . width = this . _image . width ;
canvas . get ( 0 ) . height = this . _image . height ;
canvas . get ( 0 ) . getContext ( '2d' ) . drawImage ( this . _image , 0 , 0 , this . _image . width , this . _image . height ) ;
jsfeat . imgproc . grayscale ( canvas . get ( 0 ) . getContext ( '2d' ) . getImageData ( 0 , 0 , this . _image . width , this . _image . height ) . data , this . _image . width , this . _image . height , this . _matrix _char8 _C1 ) ;
2016-11-03 14:01:51 +00:00
// Possible option:
2016-11-02 18:15:20 +00:00
// jsfeat.imgproc.equalize_histogram(img_u8, img_u8);
/ *
Build image pyramid using canvas drawImage
src - source grayscale matrix _t ( U8 _t | C1 _t )
min _width - minimum width to scale pyramid to
min _height - minimum height to scale pyramid to
interval - number of original scale levels in pyramid
* /
var pyramid = jsfeat . bbf . build _pyramid ( this . _matrix _char8 _C1 , 24 * 2 , 24 * 2 , 5 ) ; // Oscar passe à '5'
/ *
This step needed only once to create local copy of features to prevent multiple Array relocation during detection
* /
jsfeat . bbf . prepare _cascade ( jsfeat . bbf . face _cascade ) ; // 'bbf_face.js'
/ *
Run detection
pyramid - 'pyramid_t' object from 'build_pyramid' method
cascade - cascade data
* /
this . _brightness _binary _face = jsfeat . bbf . detect ( pyramid , jsfeat . bbf . face _cascade ) ; // 'bbf_face.js'
/ *
Groups the object candidate rectangles
this . _brightness _binary _face - input candidate objects sequence
min _neighbors - Minimum possible number of rectangles minus 1 , the threshold is used in a group of rectangles to retain it
* /
// En augmentant 'min_neighbors', on augmente la qualité de la détection pour ensuite choisir le rectangle:
this . _brightness _binary _face = jsfeat . bbf . group _rectangles ( this . _brightness _binary _face , 1 ) ; // '1' par défaut pour 'min_neighbors'
/** JS conventions: */
2016-11-03 14:01:51 +00:00
// All objects are considered to be 'true'
// Strings are considered to be 'false' if they are empty
// 'null' and 'undefined' are considered to be 'false'
// A Number is 'false' if it is zero
2016-11-02 18:15:20 +00:00
if ( this . _brightness _binary _face . length > 0 ) {
jsfeat . math . qsort ( this . _brightness _binary _face , 0 , this . _brightness _binary _face . length - 1 , function ( a , b ) {
return ( b . confidence < a . confidence ) ;
} ) ; // Les rectangles sont triés par ordre de confiance
// Display:
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . strokeStyle = color ;
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . lineWidth = 3 ;
var scale = this . _image . width / this . _matrix _char8 _C1 . cols ;
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . strokeRect ( ( this . _brightness _binary _face [ 0 ] . x * scale ) | 0 , ( this . _brightness _binary _face [ 0 ] . y * scale ) | 0 , ( this . _brightness _binary _face [ 0 ] . width * scale ) | 0 , ( this . _brightness _binary _face [ 0 ] . height * scale ) | 0 ) ;
}
} ;
Photography _with _detected _features . prototype . _haar _feature _detecting = function ( color , classifier , feature _number ) {
var canvas = $ ( '<canvas>' ) . attr ( {
id : "frontalface-canvas-" + this . _image _name
} ) ;
canvas . get ( 0 ) . width = this . _image . width ;
canvas . get ( 0 ) . height = this . _image . height ;
canvas . get ( 0 ) . getContext ( '2d' ) . drawImage ( this . _image , 0 , 0 , this . _image . width , this . _image . height ) ;
var edges = new jsfeat . matrix _t ( this . _image . width , this . _image . height , jsfeat . U8 _t | jsfeat . C1 _t ) ;
var ii _sum = new Int32Array ( ( this . _image . width + 1 ) * ( this . _image . height + 1 ) ) ;
var ii _sqsum = new Int32Array ( ( this . _image . width + 1 ) * ( this . _image . height + 1 ) ) ;
var ii _tilted = new Int32Array ( ( this . _image . width + 1 ) * ( this . _image . height + 1 ) ) ;
var ii _canny = new Int32Array ( ( this . _image . width + 1 ) * ( this . _image . height + 1 ) ) ;
jsfeat . imgproc . grayscale ( canvas . get ( 0 ) . getContext ( '2d' ) . getImageData ( 0 , 0 , this . _image . width , this . _image . height ) . data , this . _image . width , this . _image . height , this . _matrix _char8 _C1 ) ;
/** option */ jsfeat . imgproc . equalize _histogram ( this . _matrix _char8 _C1 , this . _matrix _char8 _C1 ) ;
// jsfeat.imgproc.gaussian_blur(this._matrix_char8_C1, this._matrix_char8_C1, 3);
jsfeat . imgproc . compute _integral _image ( this . _matrix _char8 _C1 , ii _sum , ii _sqsum , classifier . tilted ? ii _tilted : null ) ;
/** option */ jsfeat . imgproc . canny ( this . _matrix _char8 _C1 , edges , 10 , 50 ) ;
jsfeat . imgproc . compute _integral _image ( edges , ii _canny , null , null ) ;
var min _scale = 1. ; // '1.' to '4.' step '0.1'
var scale _factor = 1.15 ; // '1.1' to '2.' step '0.025'
jsfeat . haar . edges _density = 0.13 ; // '0.01' to '1.' step '0.005'
this . _haar _feature = jsfeat . haar . detect _multi _scale ( ii _sum , ii _sqsum , ii _tilted , ii _canny /* 'null' if canny is not used */ , this . _matrix _char8 _C1 . cols , this . _matrix _char8 _C1 . rows , classifier , scale _factor , min _scale ) ;
this . _haar _feature = jsfeat . haar . group _rectangles ( this . _haar _feature , 1 ) ;
if ( this . _haar _feature . length > 1 ) {
jsfeat . math . qsort ( this . _haar _feature , 0 , this . _haar _feature . length - 1 , function ( a , b ) {
return ( b . confidence < a . confidence ) ;
} ) ; // Les rectangles sont triés par ordre de confiance
}
// Display:
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . strokeStyle = color ;
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . lineWidth = 3 ;
var scale = this . _image . width / this . _matrix _char8 _C1 . cols ;
for ( var i = 0 ; i < Math . min ( this . _haar _feature . length , feature _number ) ; ++ i ) {
this . $ _image _canvas . get ( 0 ) . getContext ( '2d' ) . strokeRect ( ( this . _haar _feature [ i ] . x * scale ) | 0 , ( this . _haar _feature [ i ] . y * scale ) | 0 , ( this . _haar _feature [ i ] . width * scale ) | 0 , ( this . _haar _feature [ i ] . height * scale ) | 0 ) ;
}
} ;
/** tracking.js */
Photography _with _detected _features . prototype . _tracking _face = function ( ) {
var tracker = new tracking . ObjectTracker ( [ 'face' ] ) ;
tracker . setInitialScale ( 1. ) ; // gui.add(tracker, 'initialScale', 1.0, 10.0).step(0.1);
tracker . setStepSize ( 1. ) ; // gui.add(tracker, 'stepSize', 1, 5).step(0.1);
tracker . setEdgesDensity ( 0.1 ) ; // gui.add(tracker, 'edgesDensity', 0.1, 0.5).step(0.01);
var display _face = function ( event ) {
// Display:
this . $ _sobel _canvas . get ( 0 ) . getContext ( '2d' ) . strokeStyle = chroma ( 'red' ) . hex ( ) ;
this . $ _sobel _canvas . get ( 0 ) . getContext ( '2d' ) . lineWidth = 3 ;
for ( var i = 0 ; i < event . data . length ; ++ i ) {
this . $ _sobel _canvas . get ( 0 ) . getContext ( '2d' ) . strokeRect ( Math . round ( event . data [ i ] . x ) , Math . round ( event . data [ i ] . y ) , Math . round ( event . data [ i ] . width ) , Math . round ( event . data [ i ] . height ) ) ;
}
} ;
tracker . on ( 'track' , display _face . bind ( this ) ) ;
tracking . track ( this . _image , tracker ) ;
} ;