Android 人脸检测仅适用于可绘制对象,不适用于 SD 卡中的图像

标签 android

所以我有代码可以在任何给定的图像文件中检测多达 10 张面孔,并向我返回信息,例如眼睛的位置和其他类似信息。因此,当我告诉它使用存储在我的项目资源的可绘制文件夹中的图像文件时,它工作得很好。但是当我尝试从我从 SD 卡导入的位图中查找人脸时,它找不到任何人脸。但这些是完全相同的图像。有任何想法吗?我的代码如下:

编辑: 经过进一步检查,我发现当我插入这行代码时 System.out.println("Row Bytes: "+ sourceImage.getRowBytes()); 我得到的 drawable 是 352,SD 卡图像是 704。我认为这意味着 drawable 被压缩在 .apk 文件中,但 SD 卡图像显然不是。不确定这是否会产生任何影响。

 public class FaceView extends View {
           private static final int NUM_FACES = 10; // max is 64
           private static final boolean DEBUG = true;

           private FaceDetector arrayFaces;
           private FaceDetector.Face getAllFaces[] = new FaceDetector.Face[NUM_FACES];
           private FaceDetector.Face getFace = null;

           private PointF eyesMidPts[] = new PointF[NUM_FACES];
           private float  eyesDistance[] = new float[NUM_FACES];

           private Bitmap sourceImage;

           private Paint tmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
           private Paint pOuterBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);
           private Paint pInnerBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);

           private int picWidth, picHeight;
           private float xRatio, yRatio;

           public FaceView(Context context) {
                   super(context);

                   pInnerBullsEye.setStyle(Paint.Style.FILL);
                   pInnerBullsEye.setColor(Color.RED);

                   pOuterBullsEye.setStyle(Paint.Style.STROKE);
                   pOuterBullsEye.setColor(Color.RED);

                   tmpPaint.setStyle(Paint.Style.STROKE);
                   tmpPaint.setTextAlign(Paint.Align.CENTER);

                   BitmapFactory.Options bfo = new BitmapFactory.Options();
                   bfo.inPreferredConfig = Bitmap.Config.RGB_565;

                   //********This code imports the image from the SD card which does not work
                   String imageInSD = Environment.getExternalStorageDirectory()
                        .getAbsolutePath() + "/testfolder/" + "face1" + ".png";

                   Bitmap sourceImage = BitmapFactory.decodeFile(imageInSD,bfo);

                   //**********This code uses an image in the projects drawable folder, this code works.
                   sourceImage = BitmapFactory.decodeResource( getResources() ,R.drawable.face1, bfo);

                   picWidth = sourceImage.getWidth();
                   picHeight = sourceImage.getHeight();

                   arrayFaces = new FaceDetector( picWidth, picHeight, NUM_FACES );
                   arrayFaces.findFaces(sourceImage, getAllFaces);

                   for (int i = 0; i < getAllFaces.length; i++)
                   {
                           getFace = getAllFaces[i];
                           try {
                                   PointF eyesMP = new PointF();
                                   getFace.getMidPoint(eyesMP);
                                   eyesDistance[i] = getFace.eyesDistance();
                                   eyesMidPts[i] = eyesMP;

                                   if (DEBUG)
                                   {
                                           Log.i("Face",
                                                   i +  " " + getFace.confidence() + " " + getFace.eyesDistance() + " "
                                                   + "Pose: ("+ getFace.pose(FaceDetector.Face.EULER_X) + ","
                                                   + getFace.pose(FaceDetector.Face.EULER_Y) + ","
                                                   + getFace.pose(FaceDetector.Face.EULER_Z) + ")"
                                                   + "Eyes Midpoint: ("+eyesMidPts[i].x + "," + eyesMidPts[i].y +")"
                                           );
                                   }
                           }
                           catch (Exception e)
                           {
                                   if (DEBUG) Log.e("Face", i + " is null");
                           }

                   }


           }

           @Override
           protected void onDraw(Canvas canvas)
           {
                   xRatio = getWidth()*1.0f / picWidth;
                   yRatio = getHeight()*1.0f / picHeight;
                   canvas.drawBitmap( sourceImage, null , new Rect(0,0,getWidth(),getHeight()),tmpPaint);
                   for (int i = 0; i < eyesMidPts.length; i++)
                   {
                           if (eyesMidPts[i] != null)
                           {
                                   pOuterBullsEye.setStrokeWidth(eyesDistance[i] /6);
                                   canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 2 , pOuterBullsEye);
                                   canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 6 , pInnerBullsEye);
                           }
                   }


           }  

}

最佳答案

好的,我相信我知道您的问题是什么。设备无法将图像渲染为位图图像,因为它位于外部存储器中。人脸识别正在发挥作用,只是没有出现在 Canvas 上。所有设备对我的 xoom 都有渲染限制 (2048x2048) 我发现 here .当您将图像添加为资源时它起作用的原因是因为您的文件在构建 .apk 时缩小了尺寸(老实说我不确定为什么这样做,但我留下了一些 println 用于测试,其他人可以更好地回答)。无论如何,我只是在您的代码查找面孔之后以及尝试将位图渲染到 Canvas 之前通过除以 2 来缩放位图。现在一切似乎都正常。您可能想要调整您的面部指示器,但它的功能。我希望这会有所帮助。

public class FaceView extends View {
private static final int NUM_FACES = 1; // max is 64
private static final boolean DEBUG = true;

private FaceDetector arrayFaces;
private FaceDetector.Face getAllFaces[] = new FaceDetector.Face[NUM_FACES];
private FaceDetector.Face getFace = null;

private PointF eyesMidPts[] = new PointF[NUM_FACES];
private float  eyesDistance[] = new float[NUM_FACES];

private Bitmap sourceImage;

private Paint tmpPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pOuterBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pInnerBullsEye = new Paint(Paint.ANTI_ALIAS_FLAG);

private int picWidth, picHeight;
private float xRatio, yRatio;

public FaceView(Context context) {
        super(context);

        pInnerBullsEye.setStyle(Paint.Style.FILL);
        pInnerBullsEye.setColor(Color.RED);

        pOuterBullsEye.setStyle(Paint.Style.STROKE);
        pOuterBullsEye.setColor(Color.RED);

        tmpPaint.setStyle(Paint.Style.STROKE);
        tmpPaint.setTextAlign(Paint.Align.CENTER);

        BitmapFactory.Options bfo = new BitmapFactory.Options();
        bfo.inPreferredConfig = Bitmap.Config.RGB_565;

        //********This code imports the image from the SD card which does not work
        String imageInSD = Environment.getExternalStorageDirectory().getAbsolutePath() + "/face1" + ".jpg";

        System.out.println(imageInSD);

        sourceImage = BitmapFactory.decodeFile(imageInSD, bfo);

        //Bitmap sourceImage;// = BitmapFactory.decodeFile(imageInSD,bfo);


        //**********This code uses an image in the projects drawable folder, this code works.
        //sourceImage = BitmapFactory.decodeResource( getResources() ,R.drawable.face1, bfo);

        picWidth = sourceImage.getWidth();
        picHeight = sourceImage.getHeight(); 

        System.out.println(picWidth + "x" + picHeight);

        arrayFaces = new FaceDetector( picWidth, picHeight, NUM_FACES );
        arrayFaces.findFaces(sourceImage, getAllFaces);

        sourceImage = Bitmap.createScaledBitmap (sourceImage, picWidth/2, picHeight/2, false);

        for (int i = 0; i < getAllFaces.length; i++)
        {
                getFace = getAllFaces[i];
                try {
                        PointF eyesMP = new PointF();
                        getFace.getMidPoint(eyesMP);
                        eyesDistance[i] = getFace.eyesDistance();
                        eyesMidPts[i] = eyesMP;

                        if (DEBUG)
                        {
                                Log.i("Face",
                                        i +  " " + getFace.confidence() + " " + getFace.eyesDistance() + " "
                                        + "Pose: ("+ getFace.pose(FaceDetector.Face.EULER_X) + ","
                                        + getFace.pose(FaceDetector.Face.EULER_Y) + ","
                                        + getFace.pose(FaceDetector.Face.EULER_Z) + ")"
                                        + "Eyes Midpoint: ("+eyesMidPts[i].x + "," + eyesMidPts[i].y +")"
                                );
                        }
                }
                catch (Exception e)
                {
                        if (DEBUG) Log.e("Face", i + " is null");
                }

        }


}

@Override
protected void onDraw(Canvas canvas)
{
        xRatio = getWidth()*1.0f / picWidth; 
        yRatio = getHeight()*1.0f / picHeight;
        canvas.drawBitmap( sourceImage, null , new Rect(0,0,getWidth(),getHeight()),tmpPaint);
        for (int i = 0; i < eyesMidPts.length; i++)
        {
                if (eyesMidPts[i] != null)
                {
                        pOuterBullsEye.setStrokeWidth(eyesDistance[i] /6);
                        canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 2 , pOuterBullsEye);
                        canvas.drawCircle(eyesMidPts[i].x*xRatio, eyesMidPts[i].y*yRatio, eyesDistance[i] / 6 , pInnerBullsEye);
                }
        }


}

关于Android 人脸检测仅适用于可绘制对象,不适用于 SD 卡中的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9656144/

相关文章:

android - 如何在混合 React-native 应用程序中传递初始属性

android - 如何使用 fragment 的 getActivity() 方法传递上下文?

android - Environment.getExternalStorageDirectory().listFiles() 返回 null

android - 应用在启动时崩溃

android - 如何在android中使用外部数据库

android - 如何定义以编程方式从 sqlite 检索数据的过程?

javascript - 如何使用 IP 网络摄像头应用程序中的 jpeg 流作为 html5 视频标签中的 src?

java - 声明并填充 String[][] 数组

android - 根据用户与布局的交互顺时针和逆时针旋转布局

javascript - 如何生成React Native项目的apk或ios文件