将相机坐标转换为自定义视图坐标

时间:2014-05-09 15:41:17

标签: android android-camera android-canvas android-custom-view coordinate-systems

我正在尝试制作一个简单的人脸检测应用,其中包含SurfaceView(基本上是相机预览)和自定义View(用于绘图目的),堆叠在顶部。这两个视图的大小基本相同,在RelativeLayout中相互堆叠。当检测到某人的脸部时,我想在脸部周围的自定义View上绘制一个白色矩形。

Camera.Face.rect对象使用解释here的坐标系返回面部边界坐标,自定义视图使用this question答案中描述的坐标系。在我可以使用它在画布上绘制之前,需要进行某种转换。

因此,我在自定义视图类(下面)中编写了另一个方法ScaleFacetoView()。每次通过覆盖OnFaceDetection()方法检测到面部时,我会重绘自定义视图。结果是当面部位于中心时,白框会正确显示。我注意到的问题是,当它移动到屏幕的其他部分时,它无法正确跟踪我的脸部。

即如果我移动我的脸:

  • 向上 - 框左转
  • 向下 - 方框右转
  • 对 - 方框向上
  • 左 - 框下降

在缩放坐标时,我似乎错误地映射了值。 Android文档使用矩阵提供转换this method,但它相当混乱,我不知道它在做什么。任何人都可以提供一些关于将Camera.Face坐标转换为View坐标的正确方法的代码吗?

以下是我的ScaleFacetoView()方法的代码。

public void ScaleFacetoView(Face[] data, int width, int height, TextView a){

     //Extract data from the face object and accounts for the 1000 value offset 
     mLeft = data[0].rect.left + 1000;
     mRight = data[0].rect.right + 1000;
     mTop = data[0].rect.top + 1000;
     mBottom = data[0].rect.bottom + 1000;

     //Compute the scale factors
     float xScaleFactor = 1;
     float yScaleFactor = 1;

     if (height > width){
         xScaleFactor = (float) width/2000.0f;
         yScaleFactor = (float) height/2000.0f;          
     }
     else if (height < width){
         xScaleFactor = (float) height/2000.0f;
         yScaleFactor = (float) width/2000.0f;
     }

     //Scale the face parameters
     mLeft = mLeft * xScaleFactor; //X-coordinate
     mRight = mRight * xScaleFactor; //X-coordinate
     mTop = mTop * yScaleFactor; //Y-coordinate
     mBottom = mBottom * yScaleFactor; //Y-coordinate

}

如上所述,我像这样调用自定义视图:

@Override
public void onFaceDetection(Face[] arg0, Camera arg1) {
    if(arg0.length == 1){

        //Get aspect ratio of the screen
        View parent = (View) mRectangleView.getParent();            
        int width = parent.getWidth();
        int height = parent.getHeight();

        //Modify xy values in the view object
        mRectangleView.ScaleFacetoView(arg0, width, height);
        mRectangleView.setInvalidate();
        //Toast.makeText( cc ,"Redrew the face.", Toast.LENGTH_SHORT).show();
        mRectangleView.setVisibility(View.VISIBLE);
  //rest of code

2 个答案:

答案 0 :(得分:4)

使用Kenny给出的解释我设法做了以下事情。

此示例使用前置摄像头。

RectF rectF = new RectF(face.rect);
Matrix matrix = new Matrix();
matrix.setScale(1, 1);
matrix.postScale(view.getWidth() / 2000f, view.getHeight() / 2000f);
matrix.postTranslate(view.getWidth() / 2f, view.getHeight() / 2f);
matrix.mapRect(rectF);

矩阵返回的Rectangle具有绘制到画布中的所有正确坐标。

如果您使用后置摄像头,我认为只需将比例调整为:

matrix.setScale(-1, 1);

但我没有尝试过。

答案 1 :(得分:0)

Camera.Face类使用手机将保存到其内部存储器中的图像帧返回面部边界坐标,而不是使用“相机预览”中显示的图像。在我的情况下,图像以与摄像机不同的方式保存,导致映射不正确。我不得不手动考虑差异,取坐标,逆时针旋转90度并在y轴上翻转,然后将其缩放到用于自定义视图的画布。

编辑: 通过使用Camera.Parameters.setRotation(int)方法修改摄像机捕获方向,您似乎也无法更改面绑定坐标的返回方式。