2010-11-11 19 views
12

¿Alguien sabe de una buena manera de hacer la detección de rostros en PHP? I came across some code here que dice hacer esto, pero parece que no puedo hacer que funcione correctamente. Me gustaría hacer que esto funcione (aunque será lento) y cualquier ayuda que me puedan dar sería muy apreciada.Detección de rostros en PHP

Aquí está el código del enlace:

<?php 
// 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 
//   [email protected] 
// @Contributor Maurice Svay 
//    [email protected] 

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; 
    } 
} 

Uso:

$detector = new Face_Detector('detection.dat'); 
$detector->face_detect('maurice_svay_150.jpg'); 
$detector->toJpeg(); 

El problema que estoy en, parece que puede venir en los comentarios en esa página también. "imagecolorat() [function.imagecolorat]: 320,1 está fuera de límites". Entonces, agregué un error_reporting (0) a la parte superior del archivo (no realmente la solución), y parece funcionar a veces, mientras que otras veces simplemente no hace nada.

¿Alguna idea?

+0

posible duplicado de [reconocimiento facial/dete ction PHP o software para galerías de fotos y videos] (http://stackoverflow.com/questions/1210672/facial-recognition-detection-php-or-software-for-photo-and-video-galleries) – Gordon

Respuesta

1

intente eliminar el +1 de estas líneas:

$ii_w = $image_width+1; 
$ii_h = $image_height+1; 

Este código está tratando de comprobar los colores de las posiciones 1 a 320 en lugar de 0 a 319 píxeles de la imagen de 320 en.

+0

Pensé que como bien, pero todavía recibo el mismo mensaje. Creo que los parámetros están al revés en la llamada a la función ImageColorAt también, pero cuando los cambio, obtengo un "error de compensación indefinido" en la línea "$ mean = ($ ii [($ y + $ w) * $ iiw + $ x + $ w] + $ ii [$ y * $ iiw + $ x] - $ ii [($ y + $ w) * $ iiw + $ x] - $ ii [$ y * $ iiw + $ x + $ w]) * $ inv_area; " –

3

Probablemente sería más fácil/más seguro hacerlo con OpenCV, que está escrito en el código de nivel inferior. Se interpreta PHP, por lo que es muy lento cuando se hace el trabajo.

Espero que esto ayude!

+0

Estoy buscando una respuesta que no implique algo como OpenCV.¡Gracias! –

3

Usted necesita desactivar el informe de errores del arreglo

<?php 

ini_set('display_errors', 1); 
error_reporting(E_ALL^E_NOTICE); 

require_once('face_detector.php'); 

$detector = new Face_Detector('detection.dat'); 
$detector->face_detect('img/8.jpg'); 
$detector->toJpeg(); 

?> 
+1

Creo que esto no tiene sentido. –

+2

Como está generando una imagen, no necesita mostrar ningún mensaje de advertencia php en el resultado, ya que dañará el archivo de imagen y no se mostrará. Esto es exactamente lo que estaba sucediendo en mi implementación. Y el resultado a veces da mensajes de advertencia, por lo que deshabilitar el informe de errores es lo que me ayudó. – vhanla

0

rápida: en la función compute_ii

Reemplazar:

$rgb = ImageColorAt($canvas, $j, $i); 

Con:

$rgb = ImageColorAt($canvas, $j-1, $i-1); 
0

Este es un tema viejo, pero todavía esta corrección es mejor que cualquiera que vi hasta ahora así, podría ayudar a alguien

// Turn off error reporting... 
$ctl = error_reporting(); 
error_reporting(0); 

$detector = new Face_Detector('detection.dat'); 
$detector->face_detect('img/8.jpg'); 
$detector->toJpeg(); 

// Turn on reporting...if you wish 
error_reporting($ctl); 
0

El proyecto se ha actualizado el repositorio GitHub siguiendo este enlace Face detection

El problema estaba en el bucle, el código funciona bien:

for ($i=1; $i<$ii_h-1; $i++) { 
     $ii[$i*$ii_w] = 0; 
     $ii2[$i*$ii_w] = 0; 
     $rowsum = 0; 
     $rowsum2 = 0; 
     for ($j=1; $j<$ii_w-1; $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; 
     } 
    } 

Buena suerte

Cuestiones relacionadas