http://blog.csdn.net/candycat1992/article/details/21617741java
實現
以OpenCV的JavaCameraView爲例,首先須要定製本身的Camera,主要代碼以下:
- import java.util.ArrayList;
- import java.util.List;
-
- import org.opencv.android.JavaCameraView;
-
- import android.R.integer;
- import android.content.Context;
- import android.graphics.Rect;
- import android.graphics.RectF;
- import android.hardware.Camera;
- import android.hardware.Camera.AutoFocusCallback;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.widget.Toast;
-
- public class MTCameraView extends JavaCameraView implements AutoFocusCallback {
-
- public MTCameraView(Context context, int attrs) {
- super(context, attrs);
-
- }
-
- public List<Camera.Size> getResolutionList() {
- return mCamera.getParameters().getSupportedPreviewSizes();
- }
-
- public Camera.Size getResolution() {
- Camera.Parameters params = mCamera.getParameters();
- Camera.Size s = params.getPreviewSize();
- return s;
- }
-
- public void setResolution(Camera.Size resolution) {
- disconnectCamera();
- connectCamera((int)resolution.width, (int)resolution.height);
- }
-
- public void focusOnTouch(MotionEvent event) {
- Rect focusRect = calculateTapArea(event.getRawX(), event.getRawY(), 1f);
- Rect meteringRect = calculateTapArea(event.getRawX(), event.getRawY(), 1.5f);
-
- Camera.Parameters parameters = mCamera.getParameters();
- parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
-
- if (parameters.getMaxNumFocusAreas() > 0) {
- List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();
- focusAreas.add(new Camera.Area(focusRect, 1000));
-
- parameters.setFocusAreas(focusAreas);
- }
-
- if (parameters.getMaxNumMeteringAreas() > 0) {
- List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
- meteringAreas.add(new Camera.Area(meteringRect, 1000));
-
- parameters.setMeteringAreas(meteringAreas);
- }
-
- mCamera.setParameters(parameters);
- mCamera.autoFocus(this);
- }
-
-
- private Rect calculateTapArea(float x, float y, float coefficient) {
- float focusAreaSize = 300;
- int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();
-
- int centerX = (int) (x / getResolution().width * 2000 - 1000);
- int centerY = (int) (y / getResolution().height * 2000 - 1000);
-
- int left = clamp(centerX - areaSize / 2, -1000, 1000);
- int right = clamp(left + areaSize, -1000, 1000);
- int top = clamp(centerY - areaSize / 2, -1000, 1000);
- int bottom = clamp(top + areaSize, -1000, 1000);
-
- return new Rect(left, top, right, bottom);
- }
-
- private int clamp(int x, int min, int max) {
- if (x > max) {
- return max;
- }
- if (x < min) {
- return min;
- }
- return x;
- }
-
- public void setFocusMode (Context item, int type){
- Camera.Parameters params = mCamera.getParameters();
- List<String> FocusModes = params.getSupportedFocusModes();
-
- switch (type){
- case 0:
- if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO))
- params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
- else
- Toast.makeText(item, "Auto Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 1:
- if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
- params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
- else
- Toast.makeText(item, "Continuous Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 2:
- if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_EDOF))
- params.setFocusMode(Camera.Parameters.FOCUS_MODE_EDOF);
- else
- Toast.makeText(item, "EDOF Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 3:
- if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED))
- params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);
- else
- Toast.makeText(item, "Fixed Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 4:
- if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY))
- params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);
- else
- Toast.makeText(item, "Infinity Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 5:
- if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_MACRO))
- params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);
- else
- Toast.makeText(item, "Macro Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- }
-
- mCamera.setParameters(params);
- }
-
- public void setFlashMode (Context item, int type){
- Camera.Parameters params = mCamera.getParameters();
- List<String> FlashModes = params.getSupportedFlashModes();
-
- switch (type){
- case 0:
- if (FlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO))
- params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
- else
- Toast.makeText(item, "Auto Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 1:
- if (FlashModes.contains(Camera.Parameters.FLASH_MODE_OFF))
- params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
- else
- Toast.makeText(item, "Off Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 2:
- if (FlashModes.contains(Camera.Parameters.FLASH_MODE_ON))
- params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
- else
- Toast.makeText(item, "On Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 3:
- if (FlashModes.contains(Camera.Parameters.FLASH_MODE_RED_EYE))
- params.setFlashMode(Camera.Parameters.FLASH_MODE_RED_EYE);
- else
- Toast.makeText(item, "Red Eye Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- case 4:
- if (FlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH))
- params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
- else
- Toast.makeText(item, "Torch Mode not supported", Toast.LENGTH_SHORT).show();
- break;
- }
-
- mCamera.setParameters(params);
- }
-
- @Override
- public void onAutoFocus(boolean arg0, Camera arg1) {
-
- }
- }
在MainActivity中須要初始化MTCamera,而且實現OnTouchListener接口,以便在觸摸屏幕時能夠調用onTouch函數。其中主要代碼以下:
- private MTCameraView mOpenCvCameraView;
-
- public void init() {
- mOpenCvCameraView = new MTCameraView(this, -1);
- mOpenCvCameraView.setCvCameraViewListener(this);
- mOpenCvCameraView.setFocusable(true);
- mOpenCvCameraView.setOnTouchListener(MainActivity.this);
- mOpenCvCameraView.enableView();
-
- FrameLayout frame = new FrameLayout(this);
- frame.addView(mOpenCvCameraView);
-
- setContentView(frame);
- }
-
- @Override
- public boolean onTouch(View arg0, MotionEvent arg1) {
-
- mOpenCvCameraView.focusOnTouch(arg1);
- return true;
- }
init()函數是自定義的初始化函數,能夠在onCreate時使用。因爲這裏須要使用OpenCV庫,因此本項目是在加載完OpenCV庫並判斷成功後才調用init()函數的。
解釋
在發生觸摸事件時,MainActivity因爲實現了OnTouchListener接口,所以會調用重寫的onTouch函數,並把它的第二個參數MotionEvent傳遞給MTCamera,以便定位觸摸位置。
MTCamera的focusOnTouch函數繼續工做。它首先根據觸摸位置計算對焦和測光(metering)區域的大小(經過calculateTapArea函數),而後建立新的Camera.Parameters,並設置攝像機的對焦模式爲Auto。
而後,它分別判斷該設備的相機是否支持設置對焦區域和測光區域,若是支持就分別爲parameters設置以前計算好的聚焦和測光區域。
最後,讓Camera自動對焦。
- calculateTapArea函數
這個函數主要實現從屏幕座標系到對焦座標系的轉換。由MotionEvent.getRowX()獲得的是以屏幕座標系(即屏幕左上角爲原點,右下角爲你的當前屏幕分辨率,單位是一個像素)爲準的座標,而setFocusAreas接受的List<Area>中的每個Area的範圍是(-1000,-1000)到(1000, 1000),也就是說屏幕中心爲原點,左上角爲(-1000,-1000),右下角爲(1000,1000)。注意,若是超出這個範圍的話,會報setParemeters failed的錯誤哦!除此以外,咱們還提早定義了一個對焦框(測光框)的大小,而且接受一個參數(第三個參數coefficient)做爲百分比進行調節。
至此完成了觸摸對焦的功能。
可是,能夠發現MTCamera裏還有很大部分代碼,主要是兩個函數setFocusMode和setFlashMode。這兩個函數,主要是由於在項目中個人圖像常常是模糊的,但不知道系統支持那麼對焦模式。這時,就可使用這兩個函數進行測試。這還須要在MainActivity中添加菜單欄的代碼,以便進行選擇。代碼以下:
- private List<Camera.Size> mResolutionList;
-
- private MenuItem[] mResolutionMenuItems;
- private MenuItem[] mFocusListItems;
- private MenuItem[] mFlashListItems;
-
- private SubMenu mResolutionMenu;
- private SubMenu mFocusMenu;
- private SubMenu mFlashMenu;
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- Log.i(TAG, "called onCreateOptionsMenu");
-
- List<String> mFocusList = new LinkedList<String>();
- int idx =0;
-
- mFocusMenu = menu.addSubMenu("Focus");
-
- mFocusList.add("Auto");
- mFocusList.add("Continuous Video");
- mFocusList.add("EDOF");
- mFocusList.add("Fixed");
- mFocusList.add("Infinity");
- mFocusList.add("Makro");
- mFocusList.add("Continuous Picture");
-
- mFocusListItems = new MenuItem[mFocusList.size()];
-
- ListIterator<String> FocusItr = mFocusList.listIterator();
- while(FocusItr.hasNext()){
-
- String element = FocusItr.next();
- mFocusListItems[idx] = mFocusMenu.add(2,idx,Menu.NONE,element);
- idx++;
- }
-
- List<String> mFlashList = new LinkedList<String>();
- idx = 0;
-
- mFlashMenu = menu.addSubMenu("Flash");
-
- mFlashList.add("Auto");
- mFlashList.add("Off");
- mFlashList.add("On");
- mFlashList.add("Red-Eye");
- mFlashList.add("Torch");
-
- mFlashListItems = new MenuItem[mFlashList.size()];
-
- ListIterator<String> FlashItr = mFlashList.listIterator();
- while(FlashItr.hasNext()){
-
- String element = FlashItr.next();
- mFlashListItems[idx] = mFlashMenu.add(3,idx,Menu.NONE,element);
- idx++;
- }
-
- mResolutionMenu = menu.addSubMenu("Resolution");
- mResolutionList = mOpenCvCameraView.getResolutionList();
- mResolutionMenuItems = new MenuItem[mResolutionList.size()];
-
- ListIterator<Camera.Size> resolutionItr = mResolutionList.listIterator();
- idx = 0;
- while(resolutionItr.hasNext()) {
- Camera.Size element = resolutionItr.next();
- mResolutionMenuItems[idx] = mResolutionMenu.add(1, idx, Menu.NONE,
- Integer.valueOf((int) element.width).toString() + "x" + Integer.valueOf((int) element.height).toString());
- idx++;
- }
-
- return true;
- }
-
- public boolean onOptionsItemSelected(MenuItem item) {
- Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
-
- if (item.getGroupId() == 1)
- {
- int id = item.getItemId();
- Camera.Size resolution = mResolutionList.get(id);
- mOpenCvCameraView.setResolution(resolution);
- resolution = mOpenCvCameraView.getResolution();
- String caption = Integer.valueOf((int) resolution.width).toString() + "x" + Integer.valueOf((int) resolution.height).toString();
- Toast.makeText(this, caption, Toast.LENGTH_SHORT).show();
- }
- else if (item.getGroupId()==2){
-
- int focusType = item.getItemId();
-
- mOpenCvCameraView.setFocusMode(this, focusType);
- }
- else if (item.getGroupId()==3){
-
- int flashType = item.getItemId();
-
- mOpenCvCameraView.setFlashMode(this, flashType);
- }
-
- return true;
- }
這樣運行後,點擊菜單就能夠看見有三個菜籃列表:Focus(對焦模式),Flash(視頻模式),Resolution(支持的分辨率)。對焦模式和視頻模式中提供了幾種常見的模式供選擇,代碼會判斷當前設備是否支持該模式。而分辨率菜單欄會顯示出當前設備支持的全部分辨率種類。
參考