Chromium Code Reviews| Index: content/public/android/java/src/org/chromium/content/browser/shapedetection/ShapeDetectionImpl.java |
| diff --git a/content/public/android/java/src/org/chromium/content/browser/shapedetection/ShapeDetectionImpl.java b/content/public/android/java/src/org/chromium/content/browser/shapedetection/ShapeDetectionImpl.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..96bc8f2b8109f03a3cd4203d8fc42a438abf8443 |
| --- /dev/null |
| +++ b/content/public/android/java/src/org/chromium/content/browser/shapedetection/ShapeDetectionImpl.java |
| @@ -0,0 +1,105 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.content.browser.shapedetection; |
| + |
| +import android.content.Context; |
| +import android.graphics.Bitmap; |
| +import android.graphics.PointF; |
| +import android.media.FaceDetector; |
| +import android.media.FaceDetector.Face; |
| + |
| +import org.chromium.blink.mojom.FaceDetectionResult; |
| +import org.chromium.blink.mojom.ShapeDetection; |
| +import org.chromium.gfx.mojom.RectF; |
| +import org.chromium.mojo.system.MojoException; |
| +import org.chromium.mojo.system.SharedBufferHandle; |
| +import org.chromium.mojo.system.SharedBufferHandle.MapFlags; |
| +import org.chromium.services.shell.InterfaceFactory; |
| + |
| +import java.nio.ByteBuffer; |
| + |
| +/** |
| + * Android implementation of the shapedetection service defined in |
| + * third_party/WebKit/public/platform/modules/shapedetection/shapedetection.mojom |
| + */ |
| + |
| +public class ShapeDetectionImpl implements ShapeDetection { |
| + private static final String TAG = "ShapeDetectionImpl"; |
| + // By default, there is no limit in the number of faces detected. |
| + private static final int MAX_FACES = 10; |
| + |
| + public ShapeDetectionImpl() {} |
| + |
| + @Override |
| + public void detectFace( |
| + SharedBufferHandle frameData, int width, int height, DetectFaceResponse callback) { |
| + final int numBytes = width * height * 4; |
| + ByteBuffer imageBuffer = frameData.map(0, numBytes, MapFlags.none()); |
| + |
| + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); |
| + // An int array is needed to construct a bitmap. However the bytebuffer |
| + // we get from sharedBufferHandle is directly allocated and does not |
| + // have a supporting array. Therefore we need to create copy from |
| + // bytebuffer to create this intermediate bitmap. |
|
mcasas
2016/10/11 23:04:49
If you are talking about types, use camel case:
Bi
xianglu
2016/10/12 18:25:17
Done.
|
| + bitmap.copyPixelsFromBuffer(imageBuffer); |
| + |
| + // The bitmap must be in 565 format for findFaces() to work. See |
| + // http://androidxref.com/7.0.0_r1/xref/frameworks/base/media/java/android/media/FaceDetector.java#124 |
| + // |
| + // It turns out that facedetector is not able to detect correctly if |
|
mcasas
2016/10/11 23:04:48
Same here and in l.48: |bitmap|, FaceDetector.
ni
xianglu
2016/10/12 18:25:17
Done.
|
| + // you simply use pixmap.setConfig(). I believe this is because |
|
mcasas
2016/10/11 23:04:48
Maybe s/I believe this is/This might be/
Usually a
xianglu
2016/10/12 18:25:17
Done.
|
| + // findFaces() needs non-premultiplied ARGB arrangement, while the |
| + // alphatype in original image is premultiplied. We can use getPixels() |
|
mcasas
2016/10/11 23:04:49
Here, not being subject, usually needs determinant
xianglu
2016/10/12 18:25:17
Done.
|
| + // which does the unmultiplication while copying to a new array. See |
| + // http://androidxref.com/7.0.0_r1/xref/frameworks/base/graphics/java/android/graphics/Bitmap.java#538 |
| + int[] pixels = new int[width * height]; |
| + bitmap.getPixels(pixels, 0, width, 0, 0, width, height); |
| + Bitmap bitmapUnpremul = Bitmap.createBitmap(pixels, width, height, Bitmap.Config.RGB_565); |
|
mcasas
2016/10/11 23:04:48
s/bitmpUnpremul/unPremultipliedBitmap/
(no abbrevi
xianglu
2016/10/12 18:25:17
Done.
|
| + |
| + FaceDetector detector = new FaceDetector(width, height, MAX_FACES); |
| + Face[] detectedFaces = new Face[MAX_FACES]; |
| + final int numberOfFaces = detector.findFaces(bitmapUnpremul, detectedFaces); |
| + |
| + FaceDetectionResult faceDetectionResult = new FaceDetectionResult(); |
| + faceDetectionResult.boundingBoxes = new RectF[numberOfFaces]; |
| + for (int i = 0; i < numberOfFaces; i++) { |
| + final Face face = detectedFaces[i]; |
| + final PointF midPoint = new PointF(); |
| + face.getMidPoint(midPoint); |
| + final float eyesDistance = face.eyesDistance(); |
| + |
| + RectF boundingBox = new RectF(); |
| + boundingBox.x = midPoint.x - eyesDistance; |
| + boundingBox.y = midPoint.y - eyesDistance; |
| + boundingBox.width = 2 * eyesDistance; |
| + boundingBox.height = 2 * eyesDistance; |
| + |
| + // TODO(xianglu): Consider adding Face.confidence and Face.pose. |
| + faceDetectionResult.boundingBoxes[i] = boundingBox; |
| + } |
| + |
| + callback.call(faceDetectionResult); |
| + } |
| + |
| + @Override |
| + public void close() {} |
| + |
| + @Override |
| + public void onConnectionError(MojoException e) { |
| + close(); |
| + } |
| + |
| + /** |
| + * A factory method for registry in InterfaceRegistrarImpl.java. |
| + */ |
| + public static class Factory implements InterfaceFactory<ShapeDetection> { |
| + public Factory(Context context) {} |
| + |
| + @Override |
| + public ShapeDetection createImpl() { |
| + return new ShapeDetectionImpl(); |
| + } |
| + } |
| +} |