1. 程式人生 > >Android 使Camera預覽清晰,迴圈自動對焦處理

Android 使Camera預覽清晰,迴圈自動對焦處理

我們經常使用SurfaceView顯示Camera預覽畫面,但畫面基本都不清晰。主要是因為沒有自動對焦,而自動對焦觸發是通過mCamera.autoFocus(autoFocusCallback);這個函式,但是隻會起一次作用,後面畫面清晰度有一直這樣,但是隨著拍攝目標的距離變化,這個畫面不在清晰,需要再次對焦。所以我這裡主要通過迴圈自動對焦來完成。

SurfaceView如何顯示Camera預覽畫面,這個我不多說

建立一個Handler用來觸發自動對焦

        handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                Log.v("zzw",""+msg.what);
                switch (msg.what){
                    case MSG_AUTOFUCS:
                        mCamera.autoFocus(autoFocusCallback);
                        break;
                }
            }
        };
然後我們如果要呼叫autoFocus函式,就需要例項化AutoFocusCallback,然後我們在他自動對焦返回結果的函式裡,新增呼叫handler延遲1.3秒來觸發自動對焦
final class AutoFocusCallback implements Camera.AutoFocusCallback {
    private static final String TAG = AutoFocusCallback.class.getName();
    private static final long AUTO_FOCUS_INTERVAL_MS = 1300L; //自動對焦時間

    private Handler mAutoFocusHandler;
    private int mAutoFocusMessage;

    void setHandler(Handler autoFocusHandler, int autoFocusMessage) {
        this.mAutoFocusHandler = autoFocusHandler;
        this.mAutoFocusMessage = autoFocusMessage;
    }

    @Override
    public void onAutoFocus(boolean success, Camera camera) {
        Log.v("zzw", "autof focus "+success);
        if (mAutoFocusHandler != null) {
            mAutoFocusHandler.sendEmptyMessageDelayed(mAutoFocusMessage,AUTO_FOCUS_INTERVAL_MS);
//            mAutoFocusHandler = null;
        } else {
            Log.v(TAG, "Got auto-focus callback, but no handler for it");
        }
    }
}

所以我們在Activity的onCreate裡還需要將handler和msg.what編號給AutoFocusCallback

        autoFocusCallback = new AutoFocusCallback();
        autoFocusCallback.setHandler(handler,MSG_AUTOFUCS);

以下是Activity的完整程式碼

public class TwoActivity extends Activity implements SurfaceHolder.Callback{
    private static final String TAG = "ChrisAcvitity";
    private Camera mCamera;
    private SurfaceHolder mHolder;
    private SurfaceView mView;
    private static final int MSG_AUTOFUCS = 1001;

    private Handler handler;
    AutoFocusCallback autoFocusCallback;
    @Override
    // 建立Activity時執行的動作
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_two);

        mView = (SurfaceView) findViewById(R.id.sv);
        mHolder = mView.getHolder();
        mHolder.addCallback(this);


        handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                Log.v("zzw",""+msg.what);
                switch (msg.what){
                    case MSG_AUTOFUCS:
                        mCamera.autoFocus(autoFocusCallback);
                        break;
                }
            }
        };
        autoFocusCallback = new AutoFocusCallback();
        autoFocusCallback.setHandler(handler,MSG_AUTOFUCS);
    }

    @Override
    // apk暫停時執行的動作:把相機關閉,避免佔用導致其他應用無法使用相機
    protected void onPause() {
        super.onPause();
        handler.removeCallbacksAndMessages(null);
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }

    @Override
    // 恢復apk時執行的動作
    protected void onResume() {
        super.onResume();
        if (null!=mCamera){
            mCamera = getCameraInstance();
            try {
                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();
            } catch(IOException e) {
                Log.d(TAG, "Error setting camera preview: " + e.getMessage());
            }
        }
    }


    // SurfaceHolder.Callback必須實現的方法
    public void surfaceCreated(SurfaceHolder holder){
        mCamera = getCameraInstance();
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch(IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    // SurfaceHolder.Callback必須實現的方法
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){
        refreshCamera(); // 這一步是否多餘?在以後複雜的使用場景下,此步驟是必須的。
        int rotation = getDisplayOrientation(); //獲取當前視窗方向
        mCamera.setDisplayOrientation(rotation); //設定相機顯示方向
    }

    // SurfaceHolder.Callback必須實現的方法
    public void surfaceDestroyed(SurfaceHolder holder){
        mHolder.removeCallback(this);
        if(mCamera != null){
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }

    }

    // === 以下是各種輔助函式 ===

    // 獲取camera例項
    public static Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open();
        } catch(Exception e){
            Log.d("TAG", "camera is not available");
        }
        return c;
    }

    // 獲取當前視窗管理器顯示方向
    private int getDisplayOrientation(){
        WindowManager windowManager = getWindowManager();
        Display display = windowManager.getDefaultDisplay();
        int rotation = display.getRotation();
        int degrees = 0;
        switch (rotation){
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }

        android.hardware.Camera.CameraInfo camInfo =
                new android.hardware.Camera.CameraInfo();
        android.hardware.Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, camInfo);

        // 這裡其實還是不太懂:為什麼要獲取camInfo的方向呢?相當於相機標定??
        int result = (camInfo.orientation - degrees + 360) % 360;

        return result;
    }

    // 重新整理相機
    private void refreshCamera(){
        if (mHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            mCamera.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 {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
            mCamera.autoFocus(autoFocusCallback);
        } catch (Exception e) {

        }
    }

}

還有許可權

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />