Android – Face Detection

De curând am avut de realizat pentru o materie de la master un proiect/ o aplicație care să exemplifice tehnici de a detecta fețe umane. Și cum Verzișorul (a se citi Android OS) știu că dispune de o clasă care permite detectarea fețelor am decis să realizez o astfel de aplicație care să îmi aducă o notă mare ( aveam 2 variante posibile: să iau 10 sau să iau 10 ).  🙂

Așadar am început minunatul proces de implementare, dar înainte de a scrie cod a trebuit să ma documentez în legătură cu această temă. Iată ce am aflat:

  • clasa FaceDetector utilizează ochii ca și reper de identificare a feței, așa că prieteni jos ochelarii de soare dacă vreți ca Verzișorul să nu se supere pe voi. 😀
  • bitmap-urile folosite trebuie să fie utilizate în formatul RGB565. A funcționat și utilizând constructorul default, dar recomand totuși RGB565, just in case (să nu spuneți apoi că nu v-am avertizat).
  • referitor la câte fețe pot  fi detectate…pot răspunde cu: multe. Vom testa pentru 5.
  • clasa FaceDetector.Face nu poate fi extinsă.

Acum fiind informați să trecem la fapte! Am  realizat o aplicație care să permită preluarea de imagini fie din galeria proprie a telefonului, fie să obținem una nouă cu ajutorul camerei. Fețele identificate vor fi încadrate într-un pătrat verde.

Pasul 1: Design-ul

detectlayout.xm

</pre>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:background="@drawable/white">
 <ImageView android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:id="@+id/image_view"
 android:layout_weight="1.0" />
 <RelativeLayout android:layout_width="fill_parent"
 android:layout_height="wrap_content">
 <Button android:layout_width="150dip"
 android:layout_height="50dip"
 android:onClick="btnRestart_onClick"
 android:background="@drawable/style_button"
 android:text="Take a new photo"
 android:layout_alignParentLeft="true">
 </Button>
 <Button android:layout_width="150dip"
 android:layout_height="50dip"
 android:layout_alignParentRight="true"
 android:background="@drawable/style_button"
 android:onClick="btnDetectFace_onClick"
 android:text="@string/detect_face">
 </Button>
 </RelativeLayout>
</LinearLayout>
<pre>

Pasul 2: Codul Java

Secretul reușitei acestei aplicații este determinat de o metodă, și anume detectFaces() din unica activitate existentă FaceDetectAndroidActivity :

</pre>
private void detectFaces()
 {
 if(null != cameraBitmap)
 {
 int width = cameraBitmap.getWidth();
 int height = cameraBitmap.getHeight();

 FaceDetector detector = new FaceDetector(width, height, FaceDetectAndroidActivity.MAX_FACES);
 Face[] faces = new Face[FaceDetectAndroidActivity.MAX_FACES];

 Bitmap bitmap565 = Bitmap.createBitmap(width, height, Config.RGB_565);
 Paint ditherPaint = new Paint();
 Paint drawPaint = new Paint();

 ditherPaint.setDither(true);
 drawPaint.setColor(Color.RED);
 drawPaint.setStyle(Paint.Style.STROKE);
 drawPaint.setStrokeWidth(2);

 Canvas canvas = new Canvas();
 canvas.setBitmap(bitmap565);
 canvas.drawBitmap(cameraBitmap, 0, 0, ditherPaint);

 int facesFound = detector.findFaces(bitmap565, faces);

 PointF midPoint = new PointF();
 float eyeDistance = 0.0f;
 float confidence = 0.0f;

 ArrayList<String> listConfidence = new ArrayList<String>();
 ArrayList<String> listEyeDistances = new ArrayList<String>();
 ArrayList<String> listPoints = new ArrayList<String>();

 if(facesFound > 0)
 {
 for(int index=0; index<facesFound; ++index)
 {
 faces[index].getMidPoint(midPoint);
 eyeDistance = faces[index].eyesDistance();
 confidence = faces[index].confidence();

 Log.i("FaceDetector",
 "Confidence: " + confidence +
 ", Eye distance: " + eyeDistance +
 ", Mid Point: (" + midPoint.x + ", " + midPoint.y + ")");

 listConfidence.add(String.format("%.3f", confidence) + "");
 listEyeDistances.add(String.format("%.3f", eyeDistance) + "");
 listPoints.add("(" + String.format("%.3f", midPoint.x) + ", " +String.format("%.3f", midPoint.y) + ")\n");

 // Draw a small rectangle frame around the eye
 canvas.drawRect((int)midPoint.x - eyeDistance ,
 (int)midPoint.y - eyeDistance ,
 (int)midPoint.x + eyeDistance,
 (int)midPoint.y + eyeDistance, drawPaint);
 }
 }
 else
 {
 AlertDialog alertDialog = new AlertDialog.Builder(this).create();
 alertDialog.setTitle("Alert");
 alertDialog.setMessage("No faces found!");
 alertDialog.setButton("OK", new DialogInterface.OnClickListener()
 {
 public void onClick(DialogInterface dialog, int which){}
 });
 alertDialog.setIcon(R.drawable.ic_app);
 alertDialog.show();
 }

 String filepath = Environment.getExternalStorageDirectory() + "/facedetect" + System.currentTimeMillis() + ".jpg";
 Log.e("file path", filepath);
 try
 {
 FileOutputStream fos = new FileOutputStream(filepath);

 bitmap565.compress(CompressFormat.JPEG, 90, fos);

 fos.flush();
 fos.close();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 }

 ImageView imageView = (ImageView)findViewById(R.id.image_view);
 imageView.setImageBitmap(bitmap565);

 DetailsDialog detailsDialog = new DetailsDialog(this, this, facesFound + " faces", listConfidence.toString(), listEyeDistances.toString(), listPoints);
 detailsDialog.show();

 }
 }
<pre>
 
Ideea implementării este simplă: se obține bitmap-ul imaginii preluate din galerie sau realizată cu ajutorul camerei, după care clasa FaceDetector împreună cu ale ei metode intră în acțiune. (APK)
Spor la detectat fețe! 🙂
Advertisements
Android – Face Detection

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s