Подтвердить что ты не робот

Android setFocusArea и автофокус

Я боролся с этой функцией уже пару дней...

Кажется, что камера игнорирует (?) области фокусировки, которые я определил. Вот фрагменты кода:

Фокусировка:

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 не показывают заметного эффекта.

4b9b3361

Ответ 1

Моя проблема была намного проще:)

Все, что мне нужно было сделать, это отменить ранее называемую автофокусом. В принципе, правильный порядок действий таков:

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);
    }
}

Update

@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;
}

Ответ 2

Рядом с настройкой:

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);

В Samsung S6 вы должны установить это с небольшой задержкой (~ 500 мс) после предварительного просмотра камеры.

Ответ 3

У меня была эта проблема сегодня:/

И после нескольких часов борьбы я нашел решение!

Странно, но кажется, что настройка фокус-режима на "макро" прямо перед настройкой областей фокусировки решила проблему;)

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

У меня Galaxy S3 с Android 4.1.2

Я надеюсь, что это сработает для вас:)

Ответ 4

использовать 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);

Ответ 5

Здравствуйте, попробуйте скопировать код ниже и измените для себя

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 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());
        }

    }

    ...

}