[Android編程心得] Camera(OpenCV)自動對焦和觸摸對焦的實現

http://blog.csdn.net/candycat1992/article/details/21617741java

實現

 
以OpenCV的JavaCameraView爲例,首先須要定製本身的Camera,主要代碼以下:
[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到個人代碼片
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. import org.opencv.android.JavaCameraView;  
  5.   
  6. import android.R.integer;  
  7. import android.content.Context;  
  8. import android.graphics.Rect;  
  9. import android.graphics.RectF;  
  10. import android.hardware.Camera;  
  11. import android.hardware.Camera.AutoFocusCallback;  
  12. import android.util.AttributeSet;  
  13. import android.view.MotionEvent;  
  14. import android.widget.Toast;  
  15.   
  16. public class MTCameraView extends JavaCameraView implements AutoFocusCallback {  
  17.   
  18.     public MTCameraView(Context context, int attrs) {  
  19.         super(context, attrs);  
  20.         // TODO Auto-generated constructor stub  
  21.     }  
  22.   
  23.     public List<Camera.Size> getResolutionList() {        
  24.         return  mCamera.getParameters().getSupportedPreviewSizes();        
  25.     }  
  26.       
  27.     public Camera.Size getResolution() {  
  28.         Camera.Parameters params = mCamera.getParameters();   
  29.         Camera.Size s = params.getPreviewSize();  
  30.         return s;  
  31.     }  
  32.       
  33.     public void setResolution(Camera.Size resolution) {  
  34.         disconnectCamera();  
  35.         connectCamera((int)resolution.width, (int)resolution.height);         
  36.     }  
  37.       
  38.     public void focusOnTouch(MotionEvent event) {  
  39.         Rect focusRect = calculateTapArea(event.getRawX(), event.getRawY(), 1f);  
  40.         Rect meteringRect = calculateTapArea(event.getRawX(), event.getRawY(), 1.5f);  
  41.   
  42.         Camera.Parameters parameters = mCamera.getParameters();  
  43.         parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);  
  44.           
  45.         if (parameters.getMaxNumFocusAreas() > 0) {  
  46.             List<Camera.Area> focusAreas = new ArrayList<Camera.Area>();  
  47.             focusAreas.add(new Camera.Area(focusRect, 1000));  
  48.           
  49.             parameters.setFocusAreas(focusAreas);  
  50.         }  
  51.   
  52.         if (parameters.getMaxNumMeteringAreas() > 0) {  
  53.             List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();  
  54.             meteringAreas.add(new Camera.Area(meteringRect, 1000));  
  55.               
  56.             parameters.setMeteringAreas(meteringAreas);  
  57.         }  
  58.   
  59.         mCamera.setParameters(parameters);  
  60.         mCamera.autoFocus(this);  
  61.     }  
  62.       
  63.     /** 
  64.      * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000. 
  65.      */  
  66.     private Rect calculateTapArea(float x, float y, float coefficient) {  
  67.         float focusAreaSize = 300;  
  68.         int areaSize = Float.valueOf(focusAreaSize * coefficient).intValue();  
  69.   
  70.         int centerX = (int) (x / getResolution().width * 2000 - 1000);  
  71.         int centerY = (int) (y / getResolution().height * 2000 - 1000);  
  72.   
  73.         int left = clamp(centerX - areaSize / 2, -1000, 1000);  
  74.         int right = clamp(left + areaSize, -1000, 1000);  
  75.         int top = clamp(centerY - areaSize / 2, -1000, 1000);  
  76.         int bottom = clamp(top + areaSize, -1000, 1000);  
  77.   
  78.         return new Rect(left, top, right, bottom);  
  79.         }  
  80.   
  81.     private int clamp(int x, int min, int max) {  
  82.         if (x > max) {  
  83.             return max;  
  84.         }  
  85.         if (x < min) {  
  86.             return min;  
  87.         }  
  88.         return x;  
  89.     }  
  90.       
  91.     public void setFocusMode (Context item, int type){  
  92.         Camera.Parameters params = mCamera.getParameters();   
  93.         List<String> FocusModes = params.getSupportedFocusModes();  
  94.   
  95.         switch (type){  
  96.         case 0:  
  97.             if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO))  
  98.                 params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);  
  99.             else   
  100.                 Toast.makeText(item, "Auto Mode not supported", Toast.LENGTH_SHORT).show();  
  101.             break;  
  102.         case 1:           
  103.             if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))  
  104.                 params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);  
  105.             else  
  106.                 Toast.makeText(item, "Continuous Mode not supported", Toast.LENGTH_SHORT).show();  
  107.             break;  
  108.         case 2:           
  109.             if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_EDOF))  
  110.                 params.setFocusMode(Camera.Parameters.FOCUS_MODE_EDOF);  
  111.             else  
  112.                 Toast.makeText(item, "EDOF Mode not supported", Toast.LENGTH_SHORT).show();  
  113.             break;  
  114.         case 3:  
  115.             if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_FIXED))  
  116.                 params.setFocusMode(Camera.Parameters.FOCUS_MODE_FIXED);  
  117.             else  
  118.                 Toast.makeText(item, "Fixed Mode not supported", Toast.LENGTH_SHORT).show();  
  119.             break;  
  120.         case 4:  
  121.             if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_INFINITY))  
  122.                 params.setFocusMode(Camera.Parameters.FOCUS_MODE_INFINITY);  
  123.             else  
  124.                 Toast.makeText(item, "Infinity Mode not supported", Toast.LENGTH_SHORT).show();  
  125.             break;  
  126.         case 5:  
  127.             if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_MACRO))  
  128.                 params.setFocusMode(Camera.Parameters.FOCUS_MODE_MACRO);  
  129.             else  
  130.                 Toast.makeText(item, "Macro Mode not supported", Toast.LENGTH_SHORT).show();  
  131.             break;        
  132.         }  
  133.   
  134.         mCamera.setParameters(params);  
  135.     }  
  136.       
  137.     public void setFlashMode (Context item, int type){  
  138.         Camera.Parameters params = mCamera.getParameters();  
  139.         List<String> FlashModes = params.getSupportedFlashModes();  
  140.   
  141.         switch (type){  
  142.         case 0:  
  143.             if (FlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO))  
  144.                 params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);  
  145.             else  
  146.                 Toast.makeText(item, "Auto Mode not supported", Toast.LENGTH_SHORT).show();  
  147.             break;  
  148.         case 1:  
  149.             if (FlashModes.contains(Camera.Parameters.FLASH_MODE_OFF))  
  150.                 params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);  
  151.             else  
  152.                 Toast.makeText(item, "Off Mode not supported", Toast.LENGTH_SHORT).show();            
  153.             break;  
  154.         case 2:  
  155.             if (FlashModes.contains(Camera.Parameters.FLASH_MODE_ON))  
  156.                 params.setFlashMode(Camera.Parameters.FLASH_MODE_ON);  
  157.             else  
  158.                 Toast.makeText(item, "On Mode not supported", Toast.LENGTH_SHORT).show();         
  159.             break;  
  160.         case 3:  
  161.             if (FlashModes.contains(Camera.Parameters.FLASH_MODE_RED_EYE))  
  162.                 params.setFlashMode(Camera.Parameters.FLASH_MODE_RED_EYE);  
  163.             else  
  164.                 Toast.makeText(item, "Red Eye Mode not supported", Toast.LENGTH_SHORT).show();            
  165.             break;  
  166.         case 4:  
  167.             if (FlashModes.contains(Camera.Parameters.FLASH_MODE_TORCH))  
  168.                 params.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);  
  169.             else  
  170.                 Toast.makeText(item, "Torch Mode not supported", Toast.LENGTH_SHORT).show();          
  171.             break;  
  172.         }  
  173.   
  174.         mCamera.setParameters(params);  
  175.     }  
  176.   
  177.     @Override  
  178.     public void onAutoFocus(boolean arg0, Camera arg1) {  
  179.            
  180.     }  
  181. }  

在MainActivity中須要初始化MTCamera,而且實現OnTouchListener接口,以便在觸摸屏幕時能夠調用onTouch函數。其中主要代碼以下:
[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到個人代碼片
  1. private MTCameraView mOpenCvCameraView;  
  2.   
  3. public void init() {  
  4.     mOpenCvCameraView = new MTCameraView(this, -1);  
  5.     mOpenCvCameraView.setCvCameraViewListener(this);  
  6.     mOpenCvCameraView.setFocusable(true);  
  7.     mOpenCvCameraView.setOnTouchListener(MainActivity.this);  
  8.     mOpenCvCameraView.enableView();  
  9.       
  10.     FrameLayout frame = new FrameLayout(this);  
  11.     frame.addView(mOpenCvCameraView);  
  12.       
  13.     setContentView(frame);  
  14.      }  
  15.   
  16. @Override  
  17. public boolean onTouch(View arg0, MotionEvent arg1) {  
  18.     // TODO Auto-generated method stub  
  19.     mOpenCvCameraView.focusOnTouch(arg1);  
  20.     return true;  
  21. }  

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中添加菜單欄的代碼,以便進行選擇。代碼以下:
[java]  view plain  copy
 
 print?在CODE上查看代碼片派生到個人代碼片
  1. private List<Camera.Size> mResolutionList;  
  2.   
  3. private MenuItem[] mResolutionMenuItems;  
  4. private MenuItem[] mFocusListItems;  
  5. private MenuItem[] mFlashListItems;  
  6.   
  7. private SubMenu mResolutionMenu;  
  8. private SubMenu mFocusMenu;  
  9. private SubMenu mFlashMenu;  
  10.   
  11. @Override  
  12. public boolean onCreateOptionsMenu(Menu menu) {  
  13.     Log.i(TAG, "called onCreateOptionsMenu");  
  14.       
  15.     List<String> mFocusList = new LinkedList<String>();  
  16.  int idx =0;  
  17.   
  18.  mFocusMenu = menu.addSubMenu("Focus");  
  19.   
  20.  mFocusList.add("Auto");  
  21.  mFocusList.add("Continuous Video");  
  22.  mFocusList.add("EDOF");  
  23.  mFocusList.add("Fixed");  
  24.  mFocusList.add("Infinity");  
  25.  mFocusList.add("Makro");  
  26.  mFocusList.add("Continuous Picture");  
  27.   
  28.  mFocusListItems = new MenuItem[mFocusList.size()];  
  29.   
  30.  ListIterator<String> FocusItr = mFocusList.listIterator();  
  31.  while(FocusItr.hasNext()){  
  32.      // add the element to the mDetectorMenu submenu  
  33.      String element = FocusItr.next();  
  34.      mFocusListItems[idx] = mFocusMenu.add(2,idx,Menu.NONE,element);  
  35.      idx++;  
  36.  }  
  37.   
  38.  List<String> mFlashList = new LinkedList<String>();  
  39.  idx = 0;  
  40.   
  41.  mFlashMenu = menu.addSubMenu("Flash");  
  42.   
  43.  mFlashList.add("Auto");  
  44.  mFlashList.add("Off");  
  45.  mFlashList.add("On");  
  46.  mFlashList.add("Red-Eye");  
  47.  mFlashList.add("Torch");  
  48.   
  49.  mFlashListItems = new MenuItem[mFlashList.size()];  
  50.   
  51.  ListIterator<String> FlashItr = mFlashList.listIterator();  
  52.  while(FlashItr.hasNext()){  
  53.      // add the element to the mDetectorMenu submenu  
  54.      String element = FlashItr.next();  
  55.      mFlashListItems[idx] = mFlashMenu.add(3,idx,Menu.NONE,element);  
  56.      idx++;  
  57.  }  
  58.   
  59.  mResolutionMenu = menu.addSubMenu("Resolution");  
  60.  mResolutionList = mOpenCvCameraView.getResolutionList();  
  61.  mResolutionMenuItems = new MenuItem[mResolutionList.size()];  
  62.   
  63.  ListIterator<Camera.Size> resolutionItr = mResolutionList.listIterator();  
  64.  idx = 0;  
  65.  while(resolutionItr.hasNext()) {  
  66.      Camera.Size element = resolutionItr.next();  
  67.      mResolutionMenuItems[idx] = mResolutionMenu.add(1, idx, Menu.NONE,  
  68.              Integer.valueOf((int) element.width).toString() + "x" + Integer.valueOf((int) element.height).toString());  
  69.      idx++;  
  70.   }  
  71.   
  72.  return true;  
  73. }  
  74.   
  75. public boolean onOptionsItemSelected(MenuItem item) {  
  76.     Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);  
  77.   
  78.     if (item.getGroupId() == 1)  
  79.  {  
  80.      int id = item.getItemId();  
  81.      Camera.Size resolution = mResolutionList.get(id);  
  82.      mOpenCvCameraView.setResolution(resolution);  
  83.      resolution = mOpenCvCameraView.getResolution();  
  84.      String caption = Integer.valueOf((int) resolution.width).toString() + "x" + Integer.valueOf((int) resolution.height).toString();  
  85.      Toast.makeText(this, caption, Toast.LENGTH_SHORT).show();  
  86.  }   
  87.  else if (item.getGroupId()==2){  
  88.   
  89.     int focusType = item.getItemId();  
  90.   
  91.     mOpenCvCameraView.setFocusMode(this, focusType);  
  92.  }  
  93.  else if (item.getGroupId()==3){  
  94.   
  95.     int flashType = item.getItemId();  
  96.   
  97.     mOpenCvCameraView.setFlashMode(this, flashType);  
  98.  }  
  99.   
  100.     return true;  
  101. }  

這樣運行後,點擊菜單就能夠看見有三個菜籃列表:Focus(對焦模式),Flash(視頻模式),Resolution(支持的分辨率)。對焦模式和視頻模式中提供了幾種常見的模式供選擇,代碼會判斷當前設備是否支持該模式。而分辨率菜單欄會顯示出當前設備支持的全部分辨率種類。
 
 
 

參考

 
相關文章
相關標籤/搜索