zoukankan      html  css  js  c++  java
  • [Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现

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

    实现

     
    以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(支持的分辨率)。对焦模式和视频模式中提供了几种常见的模式供选择,代码会判断当前设备是否支持该模式。而分辨率菜单栏会显示出当前设备支持的所有分辨率种类。
     
     
     

    参考

     
  • 相关阅读:
    如何在iTerm2中配置oh my zsh?
    sublime中格式化jsx文件
    ES6 new syntax of Literal
    ES6 new syntax of Rest and Spread Operators
    How to preview html file in our browser at sublime text?
    ES6 new syntax of Default Function Parameters
    ES6 new syntax of Arrow Function
    七牛云2018春招笔试题
    Spring-使用注解开发(十二)
    Spring-声明式事物(十一)
  • 原文地址:https://www.cnblogs.com/jukan/p/6857881.html
Copyright © 2011-2022 走看看