Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. <?php
  2. class Face_Detector {
  3.    
  4.     protected $detection_data;
  5.     protected $canvas;
  6.     protected $face;
  7.     private $reduced_canvas;
  8.    
  9.     public function __construct($detection_file = 'detection.dat') {
  10.         if (is_file($detection_file)) {
  11.             $this->detection_data = unserialize(file_get_contents($detection_file));
  12.         } else {
  13.             throw new Exception("Couldn't load detection data");
  14.         }
  15.     }
  16.    
  17.     public function face_detect($file) {
  18.         if (is_resource($file)) {
  19.             $this->canvas = $file;
  20.         }
  21.         elseif (is_file($file)) {
  22.             $this->canvas = imagecreatefromjpeg($file);
  23.         }
  24.         else {
  25.             throw new Exception("Can not load $file");
  26.         }
  27.        
  28.         $im_width = imagesx($this->canvas);
  29.         $im_height = imagesy($this->canvas);
  30.  
  31.         //Resample before detection?
  32.         $ratio = 0;
  33.         $diff_width = 320 - $im_width;
  34.         $diff_height = 240 - $im_height;
  35.         if ($diff_width > $diff_height) {
  36.             $ratio = $im_width / 320;
  37.         } else {
  38.             $ratio = $im_height / 240;
  39.         }
  40.  
  41.         if ($ratio != 0) {
  42.             $this->reduced_canvas = imagecreatetruecolor($im_width / $ratio, $im_height / $ratio);
  43.             imagecopyresampled($this->reduced_canvas, $this->canvas, 0, 0, 0, 0, $im_width / $ratio, $im_height / $ratio, $im_width, $im_height);
  44.            
  45.             $stats = $this->get_img_stats($this->reduced_canvas);
  46.             $this->face = $this->do_detect_greedy_big_to_small($stats['ii'], $stats['ii2'], $stats['width'], $stats['height']);
  47.             if ($this->face['w'] > 0) {
  48.                 $this->face['x'] *= $ratio;
  49.                 $this->face['y'] *= $ratio;
  50.                 $this->face['w'] *= $ratio;
  51.             }
  52.         } else {
  53.             $stats = $this->get_img_stats($this->canvas);
  54.             $this->face = $this->do_detect_greedy_big_to_small($stats['ii'], $stats['ii2'], $stats['width'], $stats['height']);
  55.         }
  56.         return ($this->face['w'] > 0);
  57.     }
  58.    
  59.    
  60.     public function toJpeg() {
  61.         $color = imagecolorallocate($this->canvas, 255, 0, 0); //red
  62.         imagerectangle($this->canvas, $this->face['x'], $this->face['y'], $this->face['x']+$this->face['w'], $this->face['y']+ $this->face['w'], $color);
  63.         header('Content-type: image/jpeg');
  64.         imagejpeg($this->canvas);
  65.     }
  66.    
  67.     public function toJson() {
  68.         return json_encode($this->face);
  69.     }
  70.    
  71.     public function getFace() {
  72.         return $this->face;
  73.     }
  74.    
  75.     protected function get_img_stats($canvas){
  76.         $image_width = imagesx($canvas);
  77.         $image_height = imagesy($canvas);    
  78.         $iis =  $this->compute_ii($canvas, $image_width, $image_height);
  79.         return array(
  80.             'width' => $image_width,
  81.             'height' => $image_height,
  82.             'ii' => $iis['ii'],
  83.             'ii2' => $iis['ii2']
  84.         );        
  85.     }
  86.    
  87.     protected function compute_ii($canvas, $image_width, $image_height ){
  88.         $ii_w = $image_width+1;
  89.         $ii_h = $image_height+1;
  90.         $ii = array();
  91.         $ii2 = array();      
  92.                                
  93.         for($i=0; $i<$ii_w; $i++ ){
  94.             $ii[$i] = 0;
  95.             $ii2[$i] = 0;
  96.         }                        
  97.                                    
  98.         for($i=1; $i<$ii_h-1; $i++ ){  
  99.             $ii[$i*$ii_w] = 0;      
  100.             $ii2[$i*$ii_w] = 0;
  101.             $rowsum = 0;
  102.             $rowsum2 = 0;
  103.             for($j=1; $j<$ii_w-1; $j++ ){
  104.                 $rgb = ImageColorAt($canvas, $j, $i);
  105.                 $red = ($rgb >> 16) & 0xFF;
  106.                 $green = ($rgb >> 8) & 0xFF;
  107.                 $blue = $rgb & 0xFF;
  108.                 $grey = ( 0.2989*$red + 0.587*$green + 0.114*$blue )>>0;  // this is what matlab uses
  109.                 $rowsum += $grey;
  110.                 $rowsum2 += $grey*$grey;
  111.                
  112.                 $ii_above = ($i-1)*$ii_w + $j;
  113.                 $ii_this = $i*$ii_w + $j;
  114.                
  115.                 $ii[$ii_this] = $ii[$ii_above] + $rowsum;
  116.                 $ii2[$ii_this] = $ii2[$ii_above] + $rowsum2;
  117.             }
  118.         }
  119.         return array('ii'=>$ii, 'ii2' => $ii2);
  120.     }
  121.    
  122.     protected function do_detect_greedy_big_to_small( $ii, $ii2, $width, $height ){
  123.         $s_w = $width/20.0;
  124.         $s_h = $height/20.0;
  125.         $start_scale = $s_h < $s_w ? $s_h : $s_w;
  126.         $scale_update = 1 / 1.2;
  127.         for($scale = $start_scale; $scale > 1; $scale *= $scale_update ){
  128.             $w = (20*$scale) >> 0;
  129.             $endx = $width - $w - 1;
  130.             $endy = $height - $w - 1;
  131.             $step = max( $scale, 2 ) >> 0;
  132.             $inv_area = 1 / ($w*$w);
  133.             for($y = 0; $y < $endy ; $y += $step ){
  134.                 for($x = 0; $x < $endx ; $x += $step ){
  135.                     $passed = $this->detect_on_sub_image( $x, $y, $scale, $ii, $ii2, $w, $width+1, $inv_area);
  136.                     if( $passed ) {
  137.                         return array('x'=>$x, 'y'=>$y, 'w'=>$w);
  138.                     }
  139.                 } // end x
  140.             } // end y
  141.         }  // end scale
  142.         return null;
  143.     }
  144.    
  145.     protected function detect_on_sub_image( $x, $y, $scale, $ii, $ii2, $w, $iiw, $inv_area){
  146.         $mean = ( $ii[($y+$w)*$iiw + $x + $w] + $ii[$y*$iiw+$x] - $ii[($y+$w)*$iiw+$x] - $ii[$y*$iiw+$x+$w]  )*$inv_area;
  147.         $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);    
  148.         $vnorm = $vnorm > 1 ? sqrt($vnorm) : 1;
  149.        
  150.         $passed = true;
  151.         for($i_stage = 0; $i_stage < count($this->detection_data); $i_stage++ ){
  152.             $stage = $this->detection_data[$i_stage];  
  153.             $trees = $stage[0];  
  154.  
  155.             $stage_thresh = $stage[1];
  156.             $stage_sum = 0;
  157.                              
  158.             for($i_tree = 0; $i_tree < count($trees); $i_tree++ ){
  159.                 $tree = $trees[$i_tree];
  160.                 $current_node = $tree[0];    
  161.                 $tree_sum = 0;
  162.                 while( $current_node != null ){
  163.                     $vals = $current_node[0];
  164.                     $node_thresh = $vals[0];
  165.                     $leftval = $vals[1];
  166.                     $rightval = $vals[2];
  167.                     $leftidx = $vals[3];
  168.                     $rightidx = $vals[4];
  169.                     $rects = $current_node[1];
  170.                    
  171.                     $rect_sum = 0;
  172.                     for( $i_rect = 0; $i_rect < count($rects); $i_rect++ ){
  173.                         $s = $scale;
  174.                         $rect = $rects[$i_rect];
  175.                         $rx = ($rect[0]*$s+$x)>>0;
  176.                         $ry = ($rect[1]*$s+$y)>>0;
  177.                         $rw = ($rect[2]*$s)>>0;  
  178.                         $rh = ($rect[3]*$s)>>0;
  179.                         $wt = $rect[4];
  180.                        
  181.                         $r_sum = ( $ii[($ry+$rh)*$iiw + $rx + $rw] + $ii[$ry*$iiw+$rx] - $ii[($ry+$rh)*$iiw+$rx] - $ii[$ry*$iiw+$rx+$rw] )*$wt;
  182.                         $rect_sum += $r_sum;
  183.                     }
  184.                      
  185.                     $rect_sum *= $inv_area;
  186.                          
  187.                     $current_node = null;
  188.                     if( $rect_sum >= $node_thresh*$vnorm ){
  189.                         if( $rightidx == -1 )
  190.                             $tree_sum = $rightval;
  191.                         else
  192.                             $current_node = $tree[$rightidx];
  193.                     } else {
  194.                         if( $leftidx == -1 )
  195.                             $tree_sum = $leftval;
  196.                         else
  197.                             $current_node = $tree[$leftidx];
  198.                     }
  199.                 }
  200.                 $stage_sum += $tree_sum;
  201.             }
  202.             if( $stage_sum < $stage_thresh ){
  203.                 return false;
  204.             }
  205.         }
  206.         return true;
  207.     }
  208. }