2010年11月24日 星期三

[Android] 人臉偵測 FaceDetector



今天在找資料的時候無意間發現這個Class : android.media.FaceDetector 覺得相當有趣 , 馬上放下手邊的事情尋找關於FaceDetector的資料 , 找了那麼多資料所以在這邊做個統整 , 首先這邊有關於FaceDetector的Source Code  , 想進一步研究的人可以去參考 , 不過關於API Doc的描述 , 進行偵測的圖片必須是RGB565的格式 , 再來是實作程式碼的部分




import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.media.FaceDetector;
import android.media.FaceDetector.Face;
import android.os.Bundle;
import android.view.View;

 
public class FaceDetector_Test extends Activity
{
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(new FaceView(this));
    }  
    
    public static class FaceView extends View
    {
  int imageWidth, imageHeight;
        int numberOfFace = 10;
        //自訂能偵測出的臉孔數目
        FaceDetector myFaceDetect;
        FaceDetector.Face[] myFace;
        float myEyesDistance;
        int numberOfFaceDetected;
 
        Bitmap myBitmap;
        
        public FaceView(Context context)
        {
   super(context);
   // TODO Auto-generated constructor stub
   
   BitmapFactory.Options BFO = new BitmapFactory.Options();
            BFO.inPreferredConfig = Bitmap.Config.RGB_565;
            //由於FaceDetector只能處理RGB565格式的圖片 , 所以我們要對
            //圖片進行前處理的動作
            
            myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.play, BFO);
            //從getResources()中的物件找出在res/drawable裡的圖片
            //並以RGB565處理解譯成Bitmap物件
            
            imageWidth = myBitmap.getWidth();
            imageHeight = myBitmap.getHeight();            
            myFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace);
            //Note that the width of the image must be even.
            //Doc中有描述上面這句 , 不過不是很清楚用意
            
            myFace = new FaceDetector.Face[numberOfFace];
            //宣告一個FaceDetector.Face陣列 , 準備儲存所偵測到的臉孔位置資訊
            //所以陣列容量必定要和之前自訂的臉孔可偵測數目一樣
            
            numberOfFaceDetected = myFaceDetect.findFaces(myBitmap, myFace);
        }
        
        @Override
        protected void onDraw(Canvas canvas)
        {
            // TODO Auto-generated method stub
 
            canvas.drawBitmap(myBitmap, 0, 0, null);
 
            Paint myPaint = new Paint();
            myPaint.setColor(Color.GREEN);
            myPaint.setStyle(Paint.Style.STROKE);
            myPaint.setStrokeWidth(3);
 
            for(int i=0; i < numberOfFaceDetected; i++)
            {
             //將每個偵測出來的臉孔當畫上框框 
                Face face = myFace[i];
                PointF myMidPoint = new PointF();
                face.getMidPoint(myMidPoint);
                //兩眼中心點的point
                myEyesDistance = face.eyesDistance();
                //兩眼之間的距離
                canvas.drawRect(
                        (int)(myMidPoint.x - myEyesDistance),
                        (int)(myMidPoint.y - myEyesDistance),
                        (int)(myMidPoint.x + myEyesDistance),
                        (int)(myMidPoint.y + myEyesDistance),
                        myPaint);
                //如果用兩眼的距離能抓到臉長寬的比例
                //畫出的框框大概就可以框住臉了
            }            
        }
    }
}

 戴眼鏡的照片而且成功的結果

 失敗的結果....臉太紅? 眼睛太假?

最後把網路上一些開發者的建議做一個整理:
1. 其實看完程式碼大概可以能知道他是靠偵測眼睛來判斷人臉的位置 , 其他五官的細節就沒辦法偵測到了 , 所以雙眼必須同時出現在照片上才可以進行偵測,並且太陽眼鏡/眼鏡會影響檢測的效果。
2. 對於要偵測圖片的Pixels建議不要小於100x100 pixels否則會偵測不到 , 但是也不要太大 , 否則偵測得過程太久還有可能出現加載圖片例外的狀況 , 大概小於800x800 pixels效果不錯
3. 可以考慮開一個獨立的Thread來處理
4. 經過我的測試結果 , 如果說放了一張多人團體照的話 , 但是建構子中的 int maxFaces 參數設的很小例如"2" , 我猜測此時API會取他所分析出可能是人臉中 , Rank最高的前兩名作回報 , 所以把 maxFaces 調高一點可以讓團體照偵測的結果準很多 , 對於單人照其實沒太大差別。

下面是關於findFaces function的API Doc , 我特別把一段話標了起來

public int findFaces (Bitmap bitmap, Face[] faces)

Since: API Level 1
Finds all the faces found in a given Bitmap. The supplied array is populated with 
FaceDetector.Faces for each face found. The bitmap must be in 565 format (for now).
Parameters
bitmapthe Bitmap graphic to be analyzed
facesan array in which to place all found FaceDetector.Faces. The array must be sized equal to themaxFaces value set at initialization


沒有留言:

張貼留言

Google Analytics