2010-11-11 144 views
12

有誰知道在PHP中進行人臉檢測的好方法嗎? I came across some code here聲稱這樣做,但我似乎無法讓它正常工作。我想做這個工作(儘管它會很慢),任何幫助你可以給我會非常感激。PHP中的人臉檢測

下面是來自鏈接代碼:

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

用法:

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

我遇到的問題,似乎在頁面上的註釋中來了也。 「imagecolorat()[function.imagecolorat]:320,1超出範圍。」所以,我在文件的頂部添加了一個error_reporting(0)(不是真正的解決方案),而且有時它似乎有效,而其他時候它不會執行任何操作。

有什麼想法?

+0

可能重複ction PHP或軟件的照片和視頻畫廊](http://stackoverflow.com/questions/1210672/facial-recognition-detection-php-or-software-for-photo-and-video-galleries) – Gordon 2010-11-12 08:20:05

回答

1

嘗試刪除從這些行的1:

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

此代碼試圖從320像素的圖像中的位置1至320,而不是0到319檢查顏色。

+0

我認爲,作爲好吧,但我仍然得到相同的信息。我認爲參數在ImageColorAt函數調用中也是向後的,但是當我切換它們時,我會在「$ mean =($ ii [($ y + $ w)* $ iiw + $ x $ w $ + $ ii $ $ $ iiw + $ x $ ii $($ y + $ w)* $ iiw + $ x] - $ ii [$ y * $ iiw + $ x + $ w])* $ inv_area;」 – 2010-11-11 22:47:48

3

OpenCV這樣做可能會更簡單/更安全,這是用較低級代碼編寫的。 PHP被解釋,所以在做這項工作時可能會很慢。

希望這會有所幫助!

+0

我正在尋找一個不涉及OpenCV之類的答案。雖然謝謝! – 2010-11-12 01:41:05

3

您需要關閉錯誤報告

<?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

我認爲這錯過了觀點。 – 2012-02-21 15:43:07

+2

由於您正在生成一張圖片,因此它不需要顯示php警告消息,因爲它會損壞圖像文件而不會顯示。這正是我實施過程中發生的情況。結果有時會給出警告消息,因此禁用錯誤報告對我有幫助。 – vhanla 2012-05-11 18:09:50

0

快速修復:在compute_ii功能

替換:

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

有了:

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

這是一個老話題,但仍然此修復程序是比任何我看到到目前爲止,一切都更好,這可能會幫助別人

// 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

該項目已通過以下鏈接Face detection

升級GitHub上庫問題是環路,該代碼工作正常:

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

好運

[面部識別/ DETE的