40

这几天我一直在和这个功能作斗争......

看来,该相机忽略了(?)我定义的焦点区域。以下是代码片段:

聚焦:

protected void focusOnTouch(MotionEvent event) {
    if (camera != null) {
        Rect rect = calculateFocusArea(event.getX(), event.getY());

        Parameters parameters = camera.getParameters();
        parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
        parameters.setFocusAreas(Lists.newArrayList(new Camera.Area(rect, 500)));

        camera.setParameters(parameters);
        camera.autoFocus(this);
    }
}

焦点区域计算:

private Rect calculateFocusArea(float x, float y) {
    int left = clamp(Float.valueOf((x / getSurfaceView().getWidth()) * 2000 - 1000).intValue(), focusAreaSize);
    int top = clamp(Float.valueOf((y / getSurfaceView().getHeight()) * 2000 - 1000).intValue(), focusAreaSize);

    return new Rect(left, top, left + focusAreaSize, top + focusAreaSize);
}

几个日志事件来自Camera.AutoFocusCallback#onAutoFocus

Log.d(TAG, String.format("Auto focus success=%s. Focus mode: '%s'. Focused on: %s", focused, camera.getParameters().getFocusMode(), camera.getParameters().getFocusAreas().get(0).rect.toString()));

08-27 11:19:42.240: DEBUG/MyCameraActivity(26268): Auto focus success=true. Focus mode: 'auto'. Focused on: Rect(-109, 643 - -13, 739)
08-27 11:19:55.514: DEBUG/MyCameraActivity(26268): Auto focus success=true. Focus mode: 'auto'. Focused on: Rect(20, 457 - 116, 553)
08-27 11:19:58.037: DEBUG/MyCameraActivity(26268): Auto focus success=true. Focus mode: 'auto'. Focused on: Rect(-159, 536 - -63, 632)
08-27 11:20:00.129: DEBUG/MyCameraActivity(26268): Auto focus success=true. Focus mode: 'auto'. Focused on: Rect(-28, 577 - 68, 673)

视觉上看起来焦点在已记录区域上成功,但突然失去焦点并集中在中心(0, 0),或者获得了更大的部分SurfaceView

focusAreaSize计算中使用的大约是 210px (96dp)。在 HTC One 上测试在Camera.getParameters().getMaxNumFocusAreas()哪里1

初始对焦模式(第一次点击之前)设置为FOCUS_MODE_CONTINUOUS_PICTURE

我在这里做错了吗?修改Camera.Area矩形大小或重量不会显示任何明显的效果。

4

5 回答 5

54

我的问题要简单得多:)

我所要做的就是取消以前称为自动对焦的操作。基本上正确的操作顺序是这样的:

protected void focusOnTouch(MotionEvent event) {
    if (camera != null) {

        camera.cancelAutoFocus();
        Rect focusRect = calculateTapArea(event.getX(), event.getY(), 1f);
        Rect meteringRect = calculateTapArea(event.getX(), event.getY(), 1.5f);

        Parameters parameters = camera.getParameters();
        parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
        parameters.setFocusAreas(Lists.newArrayList(new Camera.Area(focusRect, 1000)));

        if (meteringAreaSupported) {
            parameters.setMeteringAreas(Lists.newArrayList(new Camera.Area(meteringRect, 1000)));
        }

        camera.setParameters(parameters);
        camera.autoFocus(this);
    }
}

更新

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    ...
    Parameters p = camera.getParameters();
    if (p.getMaxNumMeteringAreas() > 0) {
       this.meteringAreaSupported = true;
    }
    ...
}

/**
 * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
 */
private Rect calculateTapArea(float x, float y, float coefficient) {
    int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();

    int left = clamp((int) x - areaSize / 2, 0, getSurfaceView().getWidth() - areaSize);
    int top = clamp((int) y - areaSize / 2, 0, getSurfaceView().getHeight() - areaSize);

    RectF rectF = new RectF(left, top, left + areaSize, top + areaSize);
    matrix.mapRect(rectF);

    return new Rect(Math.round(rectF.left), Math.round(rectF.top), Math.round(rectF.right), Math.round(rectF.bottom));
}

private int clamp(int x, int min, int max) {
    if (x > max) {
        return max;
    }
    if (x < min) {
        return min;
    }
    return x;
}
于 2013-10-09T12:34:11.107 回答
5

除了设置:

parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);

你需要设置:

parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

如果您想要真正的“实时”自动对焦。此外,最好检查可用的焦点:

List<String> focusModes = parameters.getSupportedFocusModes();
LLog.d("focusModes=" + focusModes);
if (focusModes.contains(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
    parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);

在三星 S6 上,您必须在获得相机预览后以很小的延迟(约 500 毫秒)进行设置。

于 2016-03-27T14:24:58.483 回答
3

我今天遇到了这个问题:/

经过几个小时的努力,我找到了解决方案!

这很奇怪,但似乎在设置焦点区域之前将焦点模式设置为“宏”解决了问题;)

params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
params.setFocusAreas(focusAreas);
mCamera.setParameters(params);

我有搭载 Android 4.1.2 的 Galaxy S3

我希望这对你也有用:)

于 2013-09-29T00:28:53.870 回答
2

使用 FOCUS_MODE_FIXED

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
        mCamera = Camera.open(mCameraId);
    } else {
        mCamera = Camera.open();
    }
cameraParams = mCamera.getParameters();
// set the focus mode
cameraParams.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
// set Camera parameters
mCamera.setParameters(cameraParams);
于 2017-01-12T15:26:11.503 回答
0

嗨,试试下面的代码副本并自己更改

public class CameraActivity extends AppCompatActivity implements Camera.AutoFocusCallback {

    private Camera camera;
    private FrameLayout fl_camera_preview;

    ...

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView( R.layout.camera_activity );
        //this View, is lens camera 
        fl_camera_preview = findViewById( R.id.fl_camera_preview );
        Button someButtonCapturePicture = findViewById(R.id.someButtonCapturePicture);

        pictureCall = getPictureCallback();

        //check camera access
        if ( getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA) ) {

            if ( safeCameraOpen(0) ) {

                cameraPreview = new CameraPreview( this, camera );
                fl_camera_preview.addView( cameraPreview );

                someButtonCapturePicture.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {

                        camera.takePicture(null, null, pictureCall);

                    }
                });

            } else {
                Log.w(TAG, "getCameraInstance:  Camera is not available (in use or does not exist)." );
            }        

        }

    }

    private boolean safeCameraOpen(int id) {

        boolean qOpened = false;

        try {

            camera = Camera.open( id );
            // set some parameters
            Camera.Parameters par = camera.getParameters();

        List<Camera.Size> supportedPreviewSizes = par.getSupportedPreviewSizes();

            for ( Camera.Size cs : supportedPreviewSizes ) {
              if ( cs.height == 720 ) {
                 par.setPictureSize(cs.width, cs.height);
                 par.setPreviewSize(cs.width, cs.height);
                 break;
              }
            }

            camera.setParameters(par);

            qOpened = ( camera != null );

        } catch (Exception e) {
            Log.e(TAG, "safeCameraOpen: failed to open Camera");
            e.printStackTrace();
        }

        return qOpened;

    }

    public void touchFocusCamera( final Rect touchFocusRect ) {

        //Convert touche coordinate, in width and height to -/+ 1000 range
        final Rect targetFocusRect = new Rect(
                touchFocusRect.left * 2000/fl_camera_preview.getWidth() - 1000,
                touchFocusRect.top * 2000/fl_camera_preview.getHeight() - 1000,
                touchFocusRect.right * 2000/fl_camera_preview.getWidth() - 1000,
                touchFocusRect.bottom * 2000/fl_camera_preview.getHeight() - 1000);

        final List<Camera.Area> focusList = new ArrayList<Camera.Area>();
        Camera.Area focusArea = new Camera.Area(targetFocusRect, 1000);
        focusList.add(focusArea);

        Camera.Parameters para = camera.getParameters();
        List<String> supportedFocusModes = para.getSupportedFocusModes();
        if ( supportedFocusModes != null &&
                supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO) ) {

            try {

                para.setFocusAreas(focusList);
                para.setMeteringAreas(focusList);
                camera.setParameters(para);

                camera.autoFocus( CameraActivity.this );

            } catch (Exception e) {
                Log.e(TAG, "handleFocus: " + e.getMessage() );
            }

        }

    }

    @Override
    public void onAutoFocus(boolean success, Camera camera) {

        if ( success ) {
            camera.cancelAutoFocus();
        }

        float focusDistances[] = new float[3];
        camera.getParameters().getFocusDistances(focusDistances);

    }

    /**
     * Get Bitmap from camera
     * @return picture
     */
    private Camera.PictureCallback getPictureCallback() {

        Camera.PictureCallback picture = new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] data, Camera camera) {

                Log.i(TAG, "onPictureTaken: size bytes photo: " + data.length );

            }
        };

        return picture;

    }

    ...

}

//And SurfaceView with Callback
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "CameraPreview";
    SurfaceHolder holder;
    Camera camera;

    public CameraPreview( Context context, Camera _camera ) {
        super(context);

        camera = _camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        holder = getHolder();
        holder.addCallback(this);

        // deprecated setting, but required on Android versions prior to 3.0
        holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        // The Surface has been created, now tell the camera where to draw the preview.
        try {

            camera.setPreviewDisplay(holder);
            camera.startPreview();

        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        if( event.getAction() == MotionEvent.ACTION_DOWN ) {

            // Get the pointer's current position
            float x = event.getX();
            float y = event.getY();
            float touchMajor = event.getTouchMajor();
            float touchMinor = event.getTouchMinor();

            Rect touchRect = new Rect(
                    (int)(x - touchMajor/2),
                    (int)(y - touchMinor/2),
                    (int)(x + touchMajor/2),
                    (int)(y + touchMinor/2));

            ((CameraActivity)getContext())
                        .touchFocusCamera( touchRect );

        }

        return true;

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (this.holder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            camera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            camera.setPreviewDisplay(this.holder);
            camera.startPreview();

        } catch (Exception e) {
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }

    }

    ...

}
于 2019-10-08T08:22:19.207 回答