Режим фокусировки камеры Android

Я пытаюсь создать собственное приложение для камеры Я хочу, чтобы пользователи могли выбирать режим фокусировки в этом приложении.

Режим фокусировки - автоматический и сенсорный для фокусировки

Если мы хотим использовать touch-to-focus в камере, как начать с?

Ответы

Ответ 1

Попробуйте следующее:

public void takePhoto(File photoFile, String workerName, int width, int height, int    quality) {
if (getAutoFocusStatus()){
    camera.autoFocus(new AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
            camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        }
    }); 
}else{
    camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}

Однако, я также видел, что это работает, возможно, более точно:

if (getAutoFocusStatus()){
    camera.autoFocus(new AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
           if(success) camera.takePicture(shutterCallback, rawCallback, jpegCallback);
        }
    }); 
}else{
    camera.takePicture(shutterCallback, rawCallback, jpegCallback);
}

Последний снимает картину в момент успешного завершения фокусировки. Он отлично работает для использования с QR-кодами сканирования. Я считаю, что то же самое относится к таким случаям.

Ответ 2

Эта функция связана с программным обеспечением/аппаратным обеспечением/производством, поэтому я предполагаю, что сначала вы обнаружите, что телефон Galaxy Nexus вспыхнул с Android 4.x, а затем попробуйте файл android.hardware.Camera.Parameters.getMaxNumFocusAreas(), если возвращаемое значение больше нуля, тогда вам повезло, и затем можно использовать setFocusAreas() для реализации вашей функции "touch to focus".

Почему:

В старых версиях Android нет открытого API для установки областей фокусировки. Хотя многим производителям удалось создать свой собственный API и реализацию, они не будут делиться.

Android представила API-интерфейсы областей фокусировки на уровне API 14, однако производители телефонов могут отказаться от реализации (например, придерживаться своих собственных решений). Чтобы проверить, поддерживается ли API, вы можете сначала вызвать getMaxNumFocusAreasa(), если он вернет положительное целое число, которое означает, что телефон реализует API, и вы можете включить функцию "touch focus" в приложении вашей камеры. (API также является одним из средств защиты функции распознавания лиц, когда распознаются лица, приложение камеры использует API, чтобы камера автоматически фокусировалась на них.)

Вы можете обратиться к исходному коду приложения для камеры Android от Vanilla, чтобы правильно использовать API.

Литература:

  • API камеры Android

getMaxNumFocusAreas()

setFocusAreas()

  • Исходный код приложения для Android 4.0

mInitialParams.getMaxNumFocusAreas()

mParameters.setFocusAreas()

Привет

Ziteng Chen

Ответ 3

Это уже реализовано, но нужно изменить это, если я хочу добавить касание к фокусу?

public void takePhoto(File photoFile, String workerName, int width, int height, int    quality) {
    if (getAutoFocusStatus()){
        camera.autoFocus(new AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                camera.takePicture(shutterCallback, rawCallback, jpegCallback);
            }
        }); 
    }else{
        camera.takePicture(shutterCallback, rawCallback, jpegCallback);
    }

    this.photoFile = photoFile;
    this.workerName = workerName;
    this.imageOutputWidth = width;
    this.imageOutputHeight = height;
}

public void takePhoto(File photoFile, int width, int height, int quality) {
    takePhoto(photoFile, null, width, height, quality);
}

Ответ 4

Я пытался реализовать функцию фокуса в своем приложении и реализовал эту функциональность так, как хотел. Для реализации Touch to Focus см. Код ниже.

CameraPreview.java

public class CameraPreview extends SurfaceView implements
    SurfaceHolder.Callback {
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
private OnFocusListener onFocusListener;

private boolean needToTakePic = false;

private Camera.AutoFocusCallback myAutoFocusCallback = new Camera.AutoFocusCallback() {

    @Override
    public void onAutoFocus(boolean arg0, Camera arg1) {
        if (arg0) {
            mCamera.cancelAutoFocus();
        }
    }
};

// Constructor that obtains context and camera
@SuppressWarnings("deprecation")
public CameraPreview(Context context, Camera camera) {
    super(context);
    this.mCamera = camera;
    this.mSurfaceHolder = this.getHolder();
    this.mSurfaceHolder.addCallback(this);
    this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    this.onFocusListener = (OnFocusListener) context;
}

@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
    try {
        mCamera.setPreviewDisplay(surfaceHolder);
        mCamera.getParameters().setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        mCamera.setDisplayOrientation(90);
        mCamera.startPreview();
    } catch (IOException e) {
        // left blank for now
        e.printStackTrace();
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
    mCamera.stopPreview();
    this.mSurfaceHolder.removeCallback(this);
    mCamera.release();
}

@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
                           int width, int height) {
    // start preview with new settings
    try {
        mCamera.setPreviewDisplay(surfaceHolder);
        mCamera.startPreview();
    } catch (Exception e) {
        // intentionally left blank for a test
        e.printStackTrace();
    }
}

/**
 * Called from PreviewSurfaceView to set touch focus.
 *
 * @param - Rect - new area for auto focus
 */
public void doTouchFocus(final Rect tfocusRect) {
    try {
        List<Camera.Area> focusList = new ArrayList<Camera.Area>();
        Camera.Area focusArea = new Camera.Area(tfocusRect, 1000);
        focusList.add(focusArea);

        Camera.Parameters param = mCamera.getParameters();
        param.setFocusAreas(focusList);
        param.setMeteringAreas(focusList);
        mCamera.setParameters(param);

        mCamera.autoFocus(myAutoFocusCallback);
    } catch (Exception e) {
        e.printStackTrace();
    }

    if (isNeedToTakePic()) {
        onFocusListener.onFocused();
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        float x = event.getX();
        float y = event.getY();

        Rect touchRect = new Rect(
                (int) (x - 100),
                (int) (y - 100),
                (int) (x + 100),
                (int) (y + 100));


        final Rect targetFocusRect = new Rect(
                touchRect.left * 2000 / this.getWidth() - 1000,
                touchRect.top * 2000 / this.getHeight() - 1000,
                touchRect.right * 2000 / this.getWidth() - 1000,
                touchRect.bottom * 2000 / this.getHeight() - 1000);

        doTouchFocus(targetFocusRect);
    }

    return false;
}

public boolean isNeedToTakePic() {
    return needToTakePic;
}

public void setNeedToTakePic(boolean needToTakePic) {
    this.needToTakePic = needToTakePic;
}
}

MainActivity.java

public class MainActivity extends Activity
    implements OnFocusListener {
private Button captureButton, switchCameraButton;
private Camera mCamera;
private CameraPreview mCameraPreview;
private int currentCameraId;

/**
 * Called when the activity is first created.
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if (getIntent().hasExtra("camera_id")) {
        currentCameraId = getIntent().getIntExtra("camera_id", Camera.CameraInfo.CAMERA_FACING_BACK);
    } else {
        currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
    }

    captureButton = (Button) findViewById(R.id.button_capture);
    captureButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(final View v) {
            // Obtain MotionEvent object
            v.setEnabled(false);
            mCameraPreview.setNeedToTakePic(true);
            long downTime = SystemClock.uptimeMillis();
            long eventTime = SystemClock.uptimeMillis() + 100;
            float x = mCameraPreview.getWidth() / 2;
            float y = mCameraPreview.getHeight() / 2;
            // List of meta states found here:     developer.android.com/reference/android/view/KeyEvent.html#getMetaState()
            int metaState = 0;
            MotionEvent motionEvent = MotionEvent.obtain(
                    downTime,
                    eventTime,
                    MotionEvent.ACTION_DOWN,
                    x,
                    y,
                    metaState
            );

            // Dispatch touch event to view
            mCameraPreview.dispatchTouchEvent(motionEvent);
        }
    });

    switchCameraButton = (Button) findViewById(R.id.button_switch_camera);
    switchCameraButton.setVisibility(
            Camera.getNumberOfCameras() > 1 ? View.VISIBLE : View.GONE);
    switchCameraButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mCamera.stopPreview();
            //NB: if you don't release the current camera before switching, you app will crash
            mCameraPreview.getHolder().removeCallback(mCameraPreview);
            mCamera.release();

            //swap the id of the camera to be used
            if (currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
                currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
            } else {
                currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
            }

            mCamera = getCameraInstance(currentCameraId);
            mCameraPreview = new CameraPreview(MainActivity.this, mCamera);
            FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
            preview.removeAllViews();
            preview.addView(mCameraPreview);
        }
    });
}

@Override
protected void onResume() {
    super.onResume();
    mCamera = getCameraInstance(currentCameraId);
    mCameraPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mCameraPreview);
}

/**
 * Helper method to access the camera returns null if it cannot get the
 * camera or does not exist
 *
 * @return
 */
private Camera getCameraInstance(int currentCameraId) {
    Camera camera = null;
    try {
        camera = Camera.open(currentCameraId);
    } catch (Exception e) {
        // cannot get camera or does not exist
    }
    return camera;
}

Camera.PictureCallback mPicture = new Camera.PictureCallback() {
    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        File pictureFile = getOutputMediaFile();
        if (pictureFile == null) {
            return;
        }
        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
};

private static File getOutputMediaFile() {
    File mediaStorageDir = new File(
            Environment
                    .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "MyCameraApp");
    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }
    // Create a media file name
    //        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
    //                .format(new Date());
    File mediaFile;
    mediaFile = new File(mediaStorageDir.getPath() + File.separator
            + "IMG_" + "DEMO_" + ".jpg");
    if (mediaFile.exists()) mediaFile.delete();

    return mediaFile;
}

@Override
public void onFocused() {
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            mCamera.takePicture(null, null, mPicture);
            mCameraPreview.setNeedToTakePic(false);
            captureButton.setEnabled(true);
        }
    }, 1500);
}
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">

<FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:layout_weight="1" />

<Button
    android:id="@+id/button_switch_camera"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="Switch Camera" />

<Button
    android:id="@+id/button_capture"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:text="Capture" />

</LinearLayout>

Вы можете найти пример приложения Github - Custom Camera App

Ответ 5

Вызовите это, чтобы включить режим Touch-To-Focus:

private void setTouchToFocusMode(Camera.Parameters parameters){
    String focusMode;
    if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
        focusMode = Camera.Parameters.FOCUS_MODE_AUTO;
    }
    if (focusMode != null && focusMode.length() > 0){
        parameters.setFocusMode(focusMode);
    }
}

Когда пользователь нажимает на экран, вызовите это ниже, чтобы установить область фокусировки:

private static final int FOCUS_WIDTH = 80;
private static final int FOCUS_HEIGHT = 80;

public static String setFocalPoint(Camera.Parameters params, int x, int y){
    String focusMode = "";
    if (params != null && params.getMaxNumFocusAreas() > 0) {
        List<Camera.Area> focusArea = new ArrayList<Camera.Area>();
        focusArea.add(new Camera.Area(new Rect(x, y, x + FOCUS_WIDTH, y + FOCUS_HEIGHT), 1000));

        params.setFocusAreas(focusArea);

        if(params.getMaxNumMeteringAreas() > 0) {
            params.setMeteringAreas(focusArea);
        }
        if(params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            focusMode = Camera.Parameters.FOCUS_MODE_AUTO;
        }
    }
    return focusMode;
}

Вызов autoFocus/cancelAutoFocus для действия:

mCamera.cancelAutoFocus();    
mCamera.autoFocus(mAutoFocusCallback);