PHP face detection class
Face detection is a computer technology that determines the locations and sizes of human faces in arbitrary (digital) images.
It detects facial features and ignores anything else, such as buildings, trees and bodies.
(source: Wikipedia)
There is so much to say about face detection and all its algorithms… I am planning a step by step tutorial about every branch of object detection in digital images, but first I want to publish Maurice Svay‘s PHP class.
Maurice, in his blog svay.com, explains he was looking for a face detection script for PHP, but wasn’t able to find one working without OpenCV (Open Source Computer Vision), an opensource lib that was originally developed by Intel.
OpenCV seems to perform well but you need to be able to install it on your server.
So he coded his own pure PHP solution, that does not require any library to be installed on the server.
And, obviously, that can be easily ported into any language. His class itself has been translated from a javascript code that actually is no longer available online
So this is the class:
|
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
<?php // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // @Author Karthik Tharavaad // karthik_tharavaad@yahoo.com // @Contributor Maurice Svay // maurice@svay.Com class Face_Detector { protected $detection_data; protected $canvas; protected $face; private $reduced_canvas; public function __construct($detection_file = 'detection.dat') { if (is_file($detection_file)) { $this->detection_data = unserialize(file_get_contents($detection_file)); } else { throw new Exception("Couldn't load detection data"); } //$this->detection_data = json_decode(file_get_contents('data.js')); } public function face_detect($file) { if (!is_file($file)) { throw new Exception("Can not load $file"); } $this->canvas = imagecreatefromjpeg($file); $im_width = imagesx($this->canvas); $im_height = imagesy($this->canvas); //Resample before detection? $ratio = 0; $diff_width = 320 - $im_width; $diff_height = 240 - $im_height; if ($diff_width > $diff_height) { $ratio = $im_width / 320; } else { $ratio = $im_height / 240; } if ($ratio != 0) { $this->reduced_canvas = imagecreatetruecolor($im_width / $ratio, $im_height / $ratio); imagecopyresampled($this->reduced_canvas, $this->canvas, 0, 0, 0, 0, $im_width / $ratio, $im_height / $ratio, $im_width, $im_height); $stats = $this->get_img_stats($this->reduced_canvas); $this->face = $this->do_detect_greedy_big_to_small($stats['ii'], $stats['ii2'], $stats['width'], $stats['height']); $this->face['x'] *= $ratio; $this->face['y'] *= $ratio; $this->face['w'] *= $ratio; } else { $stats = $this->get_img_stats($this->canvas); $this->face = $this->do_detect_greedy_big_to_small($stats['ii'], $stats['ii2'], $stats['width'], $stats['height']); } return ($this->face['w'] > 0); } public function toJpeg() { $color = imagecolorallocate($this->canvas, 255, 0, 0); //red imagerectangle($this->canvas, $this->face['x'], $this->face['y'], $this->face['x']+$this->face['w'], $this->face['y']+ $this->face['w'], $color); header('Content-type: image/jpeg'); imagejpeg($this->canvas); } public function toJson() { return "{'x':" . $this->face['x'] . ", 'y':" . $this->face['y'] . ", 'w':" . $this->face['w'] . "}"; } public function getFace() { return $this->face; } protected function get_img_stats($canvas){ $image_width = imagesx($canvas); $image_height = imagesy($canvas); $iis = $this->compute_ii($canvas, $image_width, $image_height); return array( 'width' => $image_width, 'height' => $image_height, 'ii' => $iis['ii'], 'ii2' => $iis['ii2'] ); } protected function compute_ii($canvas, $image_width, $image_height ){ $ii_w = $image_width+1; $ii_h = $image_height+1; $ii = array(); $ii2 = array(); for($i=0; $i<$ii_w; $i++ ){ $ii[$i] = 0; $ii2[$i] = 0; } for($i=1; $i<$ii_w; $i++ ){ $ii[$i*$ii_w] = 0; $ii2[$i*$ii_w] = 0; $rowsum = 0; $rowsum2 = 0; for($j=1; $j<$ii_h; $j++ ){ $rgb = ImageColorAt($canvas, $j, $i); $red = ($rgb >> 16) & 0xFF; $green = ($rgb >> 8) & 0xFF; $blue = $rgb & 0xFF; $grey = ( 0.2989*$red + 0.587*$green + 0.114*$blue )>>0; // this is what matlab uses $rowsum += $grey; $rowsum2 += $grey*$grey; $ii_above = ($i-1)*$ii_w + $j; $ii_this = $i*$ii_w + $j; $ii[$ii_this] = $ii[$ii_above] + $rowsum; $ii2[$ii_this] = $ii2[$ii_above] + $rowsum2; } } return array('ii'=>$ii, 'ii2' => $ii2); } protected function do_detect_greedy_big_to_small( $ii, $ii2, $width, $height ){ $s_w = $width/20.0; $s_h = $height/20.0; $start_scale = $s_h < $s_w ? $s_h : $s_w; $scale_update = 1 / 1.2; for($scale = $start_scale; $scale > 1; $scale *= $scale_update ){ $w = (20*$scale) >> 0; $endx = $width - $w - 1; $endy = $height - $w - 1; $step = max( $scale, 2 ) >> 0; $inv_area = 1 / ($w*$w); for($y = 0; $y < $endy ; $y += $step ){ for($x = 0; $x < $endx ; $x += $step ){ $passed = $this->detect_on_sub_image( $x, $y, $scale, $ii, $ii2, $w, $width+1, $inv_area); if( $passed ) { return array('x'=>$x, 'y'=>$y, 'w'=>$w); } } // end x } // end y } // end scale return null; } protected function detect_on_sub_image( $x, $y, $scale, $ii, $ii2, $w, $iiw, $inv_area){ $mean = ( $ii[($y+$w)*$iiw + $x + $w] + $ii[$y*$iiw+$x] - $ii[($y+$w)*$iiw+$x] - $ii[$y*$iiw+$x+$w] )*$inv_area; $vnorm = ( $ii2[($y+$w)*$iiw + $x + $w] + $ii2[$y*$iiw+$x] - $ii2[($y+$w)*$iiw+$x] - $ii2[$y*$iiw+$x+$w] )*$inv_area - ($mean*$mean); $vnorm = $vnorm > 1 ? sqrt($vnorm) : 1; $passed = true; for($i_stage = 0; $i_stage < count($this->detection_data); $i_stage++ ){ $stage = $this->detection_data[$i_stage]; $trees = $stage[0]; $stage_thresh = $stage[1]; $stage_sum = 0; for($i_tree = 0; $i_tree < count($trees); $i_tree++ ){ $tree = $trees[$i_tree]; $current_node = $tree[0]; $tree_sum = 0; while( $current_node != null ){ $vals = $current_node[0]; $node_thresh = $vals[0]; $leftval = $vals[1]; $rightval = $vals[2]; $leftidx = $vals[3]; $rightidx = $vals[4]; $rects = $current_node[1]; $rect_sum = 0; for( $i_rect = 0; $i_rect < count($rects); $i_rect++ ){ $s = $scale; $rect = $rects[$i_rect]; $rx = ($rect[0]*$s+$x)>>0; $ry = ($rect[1]*$s+$y)>>0; $rw = ($rect[2]*$s)>>0; $rh = ($rect[3]*$s)>>0; $wt = $rect[4]; $r_sum = ( $ii[($ry+$rh)*$iiw + $rx + $rw] + $ii[$ry*$iiw+$rx] - $ii[($ry+$rh)*$iiw+$rx] - $ii[$ry*$iiw+$rx+$rw] )*$wt; $rect_sum += $r_sum; } $rect_sum *= $inv_area; $current_node = null; if( $rect_sum >= $node_thresh*$vnorm ){ if( $rightidx == -1 ) $tree_sum = $rightval; else $current_node = $tree[$rightidx]; } else { if( $leftidx == -1 ) $tree_sum = $leftval; else $current_node = $tree[$leftidx]; } } $stage_sum += $tree_sum; } if( $stage_sum < $stage_thresh ){ return false; } } return true; } } |
Using it is very easy, just write
|
1 2 3 |
$detector = new Face_Detector('detection.dat'); $detector->face_detect('your_file.jpg'); $detector->toJpeg(); |
once you unpacked and included detection.dat and the image in the same path as your class.
Do you want to see a result?

This was generated by the script, just changing the frame color from red to green, to make it more visible.
The class does not work that well on every photo, but it’s a good start for a journey into face detection





(36 votes, average: 4.75 out of 5)








This post has 32 comments
Martti Laine
Holy sh*t. Never even thought about detecting faces in php. Thumbs up!
Martti Laine
Sorry for my bad language.
This article proves it, we’re on 21st century.
Thomas
So, what are the logics that make it work?
mario
face.com had release a API for face detection, you can even use the code to detect the location of eye, nose and mouth
Mal kurz rundgeschaut… #24 | Braekling.de
[...] PHP face detection class – gut erkannt mit Emanuele Feronato. [...]
bossoi
I have a question… why are .dat file for?
ammii*
Absolutely yes!! I’ve never ever thought about PHP for detecting faces!!!
Thank you very much :))
Marcius
Very good, congratuloations and tks for your contribe
prince
Amazing might use it in my next project :)
Zeeshan Lalani
very nice.. thanks..
Face Detection Using PHP | blogfreakz.com
[...] Source: http://www.emanueleferonato.com/2010/07/06/php-face-detection-class/ [...]
Shashi
Thanks a lot for this great post… i have been wondering whether it would be possible to do these kind of things with php… hats off php !
datshay
Amazing….. No words to say ….
Thumbs up !
Karl Roos
This is amazing! Never thought you’d be able to do this with PHP!
vcrack
how long your execution time to do this?
Vincent
I’ve never tought that PHP could do this thing too. It’s awesome
harika
thank you:D
Proger
Thanks, cool script.
However, it is not always working correctly, here’s an example:
http://programming.su/sites/programming.su/files/demo/face-detector/putin.jpg
Detectar una cara en una foto usando PHP | Blog personal de Brian Urban
[...] Via Emanuele Feronato [...]
Face detection using PHP
[...] Without Open CV you can apply face detection using the PHP class mentioned at this blog [...]
long.vu
I saw that happend error in function imagecolorat and can not work
PHP and Jquery face detection scripts « Webania.net
[...] Download page [...]
Dmitry
Doesn`t detect multiple and small faces. How’d you tweak the code to do that?
tumaji
Thank you, I looking for this script.
tejas tank
Here detection.dat is which kind of file. is a jpg or movie or other things…
Mohd
Hay @Proger..
At least it detected the face of Putin’s care :) I think PHP can’t recognize Putin.. same of the rest of us, this is logic.
mrtaza
http://bit.ly/yZ7UxW
mrtaza
i have used the above class in this sample
http://bit.ly/yZ7UxW
works in most cases.
Dan
I have two other Haar Xml files, is there any way to convert these to .dat files for use in this PHP implementation?
Kind regards,
Dan
??????????? ?? ???? – PHP ????? | Siljanoski.com
[...] ?????????? ?????: http://www.emanueleferonato.com/2010/07/06/php-face-detection-class/ [...]
Muthukumar
This is not working to me
absfrm
hello
this is powerful.thanks to share
but can you answer my question?
i want to detect a face(save some detail for it as name or family).
and when detect that face again , system show me his/her detail.
can i do this action?
thanks a lot