【转】[Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现
参考
http://stackoverflow.com/questions/18460647/android-setfocusarea-and-auto-focus
http://blog.csdn.net/candycat1992/article/details/21617741
写在前面
实现
- 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);
- // TODO Auto-generated constructor stub
- }
- 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);
- }
- /**
- * Convert touch position x:y to {@link Camera.Area} position -1000:-1000 to 1000:1000.
- */
- 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) {
- // TODO Auto-generated method stub
- mOpenCvCameraView.focusOnTouch(arg1);
- return true;
- }
init()函数是自定义的初始化函数,可以在onCreate时使用。由于这里需要使用OpenCV库,所以本项目是在加载完OpenCV库并判断成功后才调用init()函数的。
解释
- calculateTapArea函数
这个函数主要实现从屏幕坐标系到对焦坐标系的转换。由MotionEvent.getRowX()得到的是以屏幕坐标系(即屏幕左上角为原点,右下角为你的当前屏幕分辨率,单位是一个像素)为准的坐标,而setFocusAreas接受的List<Area>中的每一个Area的范围是(-1000,-1000)到(1000, 1000),也就是说屏幕中心为原点,左上角为(-1000,-1000),右下角为(1000,1000)。注意,如果超出这个范围的话,会报setParemeters failed的错误哦!除此之外,我们还提前定义了一个对焦框(测光框)的大小,并且接受一个参数(第三个参数coefficient)作为百分比进行调节。
至此完成了触摸对焦的功能。
- 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()){
- // add the element to the mDetectorMenu submenu
- 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()){
- // add the element to the mDetectorMenu submenu
- 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(支持的分辨率)。对焦模式和视频模式中提供了几种常见的模式供选择,代码会判断当前设备是否支持该模式。而分辨率菜单栏会显示出当前设备支持的所有分辨率种类。
参考
【转】[Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现的更多相关文章
- [Android编程心得] Camera(OpenCV)自动对焦和触摸对焦的实现
写在前面 最近在从零开始写一个移动端的AR系统,坑实在是太多了!!!整个项目使用了OpenCV第三方库,但对于摄像机来说,和原生Camera的方法基本相同. 实现 以OpenCV的JavaCamera ...
- Android编程心得-在任意类中获取当前屏幕宽高
进行Android编程时,很多时候都需要获取当前屏幕的宽度与高度,但是当我们需要在别的类中调用屏幕宽高时,直接用原来的方法是不行的,下面我来介绍如何在任意类中调用宽度高度的两种方法. public v ...
- Android编程心得-ListView的Item高亮显示的办法
在我们使用ListView的时候,经常会遇到某一项(Item)需要高亮显示的情况,如下图,有人说当我们点击子项的时候会变亮,但有时候业务逻辑需要让ITEM根据条件自动变亮,下面我来介绍一下我自己的解决 ...
- Android编程心得-JSON使用心得(二)
在Android开发中,我们经常会用到JSON来与网络数据进行交互,下面我来介绍如何对JSON数据进行解析与制造 1.当我们需要对如下JSON串进行制造时: { "download" ...
- Android编程心得-设计一个可重用的自定义Dialog
我们在实际开发过程中,会遇到一个问题,我们的Dialog如果使用一般的方法进行设置调用出来,会有很多的重复代码,如何将Dialog按照自己的思路设计呢,并让其可重用呢,下面我来介绍一下 ...
- Android编程心得-图片自适应心得
在Android 的开发过程中,我们知道存放图片资源的文件夹是drawable,与它类似的名字的文件夹drawble-hdpi,drawable-ldpi,drawable-mdpi,drawable ...
- Android编程心得-Service数据绑定初步
在Android里,Service的数据绑定是一种重要的用法,我们知道Service与Activity一样是运行在当前应用进程的主线程里面的,他们之间交互的方式有多种,下面我来介绍一下如何使用数据绑定 ...
- Android编程心得-使用ActionBar+Fragment+ViewPager实现动态切换Menu效果
1.首先上效果图 2.本例实现的效果主要适用于当前页面有多个页签时.进行Fragment切换时,能够利用不同的Menu样式与当前Fragment中的内容进行配合,能够大大添加复用性,看到效果图后,以下 ...
- Android编程心得-Handler与子线程的交互初步
在编写项目的时候,本人发现一个关于线程与Handler很容易犯的错误. 我有两个Activity,一个Activity在后台创建了一个线程并且启动,这个线程对象对应的实体实在另外一个Activity的 ...
随机推荐
- Educational Codeforces Round 6 D. Professor GukiZ and Two Arrays
Professor GukiZ and Two Arrays 题意:两个长度在2000的-1e9~1e9的两个序列a,b(无序);要你最多两次交换元素,使得交换元素后两序列和的差值的绝对值最小:输出这 ...
- cocos2dx 3.3创建新项目 和 VS2012解决方案加载失败问题
首先创建新项目,步骤如下: 1.进入cocos2d-x-3.3\tools\cocos2d-console\bin目录,按住shift+鼠标右键 2.输入 cocos new 项目名 –p 包名 – ...
- JavaScript高级之函数的四种调用形式
主要内容 分析函数的四种调用形式 弄清楚函数中this的意义 明确构造函对象的过程 学会使用上下文调用函数 了解函数的调用过程有助于深入学习与分析JavaScript代码. 本文是JavaScript ...
- [原博客] POI系列(3)
正规.严谨.精妙. -POI BZOJ 1131 : [POI2008]Sta 树形dp吧,让求找一个点使以这个点深度和最小.首先可以随便整出来一棵树,对于每个节点记录down[i]以i为根下面的点的 ...
- 【转】Spring 注解学习手札(超好的springmvc注解教程)
Spring 注解学习手札(一) 构建简单Web应用 Spring 注解学习手札(二) 控制层梳理 Spring 注解学习手札(三) 表单页面处理 Spring 注解学习手札(四) 持久层浅析 Spr ...
- uva 1449 - Dominating Patterns
简单的AC自动机: #include<cstdio> #include<cstring> #include<queue> #define maxn 150005 u ...
- 教你如何监控 Apache?
什么是 Apache? Apache 是一款 HTTP 服务器软件,现在更名为 "http",而 Apache 则成了一个(包含httpd的项目)巨大的基金组织,根据习惯后文都用 ...
- 搭建mongodb分片
搭建mongodb分片 http://gong1208.iteye.com/blog/1622078 Sharding分片概念 这是一种将海量的数据水平扩展的数据库集群系统,数据分表存储在shardi ...
- easyui datagrid单击单元格选择此列
示例代码实现单击jquery easyui datagrid的单元格时,取消datagrid默认选中高亮此行的样式,改为选中单击的单元格所在的列,高亮此列上的所有单元格.可以配置全局single变量, ...
- [转贴] 从零开始学C++之异常(二):程序错误、异常(语法、抛出、捕获、传播)、栈展开
一.程序错误 编译错误,即语法错误.程序就无法被生成运行代码. 运行时错误 不可预料的逻辑错误 可以预料的运行异常 例如: 动态分配空间时可能不会成功 打开文件可能会失败 除法运算时分母可能为0 整数 ...