PHP face detection class
- July 6, 2010 by Emanuele Feronato
- Filed under Php, Users contributions | 17 Comments
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:
<?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
$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
17 Responses
Leave a Reply
TUTORIAL SERIES:
- Una guida completa al gioco del poker online e una selezione dei migliori casino online.
- casino online
- migliori casino online
- BlackJack online
- casinò online



Holy sh*t. Never even thought about detecting faces in php. Thumbs up!
Sorry for my bad language.
This article proves it, we’re on 21st century.
So, what are the logics that make it work?
face.com had release a API for face detection, you can even use the code to detect the location of eye, nose and mouth
[...] PHP face detection class – gut erkannt mit Emanuele Feronato. [...]
I have a question… why are .dat file for?
Absolutely yes!! I’ve never ever thought about PHP for detecting faces!!!
Thank you very much :))
Very good, congratuloations and tks for your contribe
Amazing might use it in my next project :)
very nice.. thanks..
[...] Source: http://www.emanueleferonato.com/2010/07/06/php-face-detection-class/ [...]
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 !
Amazing….. No words to say ….
Thumbs up !
This is amazing! Never thought you’d be able to do this with PHP!
how long your execution time to do this?
I’ve never tought that PHP could do this thing too. It’s awesome
thank you:D