首页 > [Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现

[Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现

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

实现

以OpenCV的JavaCameraView为例,首先需要定制自己的Camera,主要代码如下:
[java] view plaincopy
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 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 focusAreas = new ArrayList();  
  47.             focusAreas.add(new Camera.Area(focusRect, 1000));  
  48.           
  49.             parameters.setFocusAreas(focusAreas);  
  50.         }  
  51.   
  52.         if (parameters.getMaxNumMeteringAreas() > 0) {  
  53.             List meteringAreas = new ArrayList();  
  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 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 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 plaincopy
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的范围是(-1000,-1000)到(1000, 1000),也就是说屏幕中心为原点,左上角为(-1000,-1000),右下角为(1000,1000)。注意,如果超出这个范围的话,会报setParemeters failed的错误哦!除此之外,我们还提前定义了一个对焦框(测光框)的大小,并且接受一个参数(第三个参数coefficient)作为百分比进行调节。





至此完成了触摸对焦的功能。
但是,可以发现MTCamera里还有很大部分代码,主要是两个函数setFocusMode和setFlashMode。这两个函数,主要是因为在项目中我的图像经常是模糊的,但不知道系统支持那么对焦模式。这时,就可以使用这两个函数进行测试。这还需要在MainActivity中添加菜单栏的代码,以便进行选择。代码如下:
[java] view plaincopy
print?在CODE上查看代码片派生到我的代码片
  1. private List 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 mFocusList = new LinkedList();  
  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 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 mFlashList = new LinkedList();  
  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 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 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(支持的分辨率)。对焦模式和视频模式中提供了几种常见的模式供选择,代码会判断当前设备是否支持该模式。而分辨率菜单栏会显示出当前设备支持的所有分辨率种类。

参考

  • StackOverFlow上关于触摸对焦的讨论
  • Android多媒体和相机讲解十
  • 解读Android 4.0 Camera原生应用程序的设计思路
  • OpenCV上的提问:ANDROID: Use autofocus with CameraBridgeViewBase?

转载于:https://www.cnblogs.com/jukan/p/6857881.html

更多相关:

  •         Apache POI是一个开源的利用Java读写Excel,WORD等微软OLE2组件文档的项目。        我的需求是对Excel的数据进行导入或将数据以Excel的形式导出。先上简单的测试代码:package com.xing.studyTest.poi;import java.io.FileInputSt...

  • 要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。 要取得a到b之间的...

  • 利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) image,计算图像的reflectance image。 Reflectance Image 是指在变化的光照条件下能够维持不变的图像部分...

  • 题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 解题: cl...

  • 题目:二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树:      5     /    2   6   /  1   3示例 1: 输入: [1,6,3,2,5] 输出...

  • #include #include #include #include #include #include #include

  • 题目:表示数值的字符串 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"0123"及"-1E-16"都表示数值,但"12e"、"1a3.14"、"1.2.3"、"+-5"及"12e+5.4"都不是。 解题: 数值错误的形式有多种多样,但是正确的...

  • 加法伺候  //超过20位数值相加---------------------------------------- function bigNumAdd(a, b) {if (!(typeof a === "string" && typeof b === "string")) return console.log("传入参数必...

  • 业务场景: 从中文字句中匹配出指定的中文子字符串 .这样的情况我在工作中遇到非常多, 特梳理总结如下. 难点: 处理GBK和utf8之类的字符编码, 同时正则匹配Pattern中包含汉字,要汉字正常发挥作用,必须非常谨慎.推荐最好统一为utf8编码,如果不是这种最优情况,也有酌情处理. 往往一个具有普适性的正则表达式会简化程...

  • 简单record 一下 #include // 'struct sockaddr_in' #include #include // 'struct ifreq' and 'struct if_nameindex' #include #inc...