~转载请注明http://blog.csdn.net/u013015161/article/details/46921257

介绍

这几天。写了一个自己定义照相机的demo。支持连续拍照和摄像头切换。因为自己曾经没接触过相关的编程。也算是一个学习的过程,在这里做一下记录,同一时候也分享出来,并附上源代码和project。

效果如图:



左上角switch切换摄像头,右边snapbutton进行拍照。

一般流程

Android进行拍照,须要调用摄像头类android.hardware.Camera。

而要进行预览。则须要用android.view.SurfaceView对每一帧的预览图进行显示。

实现自己定义相机一般流程为:

1、用addCallback给SurfaceView设置Callback接口对象,实现当中三个回调方法:surfaceCreated、surfaceChanged、surfaceDestroyed。

在surfaceCreated中打开摄像头,获得Camera对象,并设置其在surfaceview上预览;

在surfaceChanged中设置摄像头的參数;

在surfaceDestroyed释放摄像头。否则会导致退出之后其它应用无法调用摄像头,包含系统相机。

2、点击拍照button时。调用Camera对象的takePicture方法,其第三个參数为PictureCallback接口对象,当中的onPictureTaken回调方法參数中有一个byte数组。存储了拍摄到的图片数据,在方法中保存到本地就可以。

这样,一个基本可用、带预览的自己定义相机就做好了。但这样还远远不够。因为会出现各种各样的问题。

主要问题

预览变形

这个是最头疼的问题。

首先要知道3个宽高比:摄像头分辨率(PictureSize)宽高比、预览分辨率(PreviewSize)宽高比以及用作预览的SurfaceView的宽高比。

假设要让预览不变形,这三个宽高比须要保持一致。这样的一致性的保持在设置摄像头參数时进行。代码例如以下:

public void setCameraAndDisplay(int width, int height)
{
Camera.Parameters parameters = camera.getParameters();
/*获取摄像头支持的PictureSize列表*/
List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
/*从列表中选取合适的分辨率*/
Size picSize = CameraUtils.getProperSize(pictureSizeList, ((float)width)/height);
if(null != picSize)
{
parameters.setPictureSize(picSize.width, picSize.height);
}
else
{
picSize = parameters.getPictureSize();
}
/*获取摄像头支持的PreviewSize列表*/
List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
Size preSize = CameraUtils.getProperSize(previewSizeList, ((float)width)/height);
if(null != preSize)
{Log.v("TestCameraActivityTag", preSize.width + "," + preSize.height);
parameters.setPreviewSize(preSize.width, preSize.height);
} /*依据选出的PictureSize又一次设置SurfaceView大小*/
float w = picSize.width;
float h = picSize.height;
surfaceView.setLayoutParams(new RelativeLayout.LayoutParams( (int)(height*(w/h)), height)); parameters.setJpegQuality(100); // 设置照片质量
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
{
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} camera.cancelAutoFocus();//仅仅有加上了这一句,才会自己主动对焦。
camera.setDisplayOrientation(0);
camera.setParameters(parameters);
}

方法里传进去的參数为SurfaceView如今的宽高。在保证surfaceview宽高比不变的情况下(比方为了保证全屏预览)。分别去寻找符合条件的PictureSize和PreviewSize。假设找不到,就返回默认宽高比(我设置为4:3)的PictureSize和PreviewSize, 同一时候为保证3个宽高比一致,surfaceView的宽高比也要重设。

提供寻找合适的PictureSize和PreviewSize方法的类例如以下:

public class CameraUtils {

    public static Size getProperSize(List<Size> sizeList, float displayRatio)
{
//先对传进来的size列表进行排序
Collections.sort(sizeList, new SizeComparator()); Size result = null;
for(Size size: sizeList)
{
float curRatio = ((float)size.width) / size.height;
if(curRatio - displayRatio == 0)
{
result = size;
}
}
if(null == result)
{
for(Size size: sizeList)
{
float curRatio = ((float)size.width) / size.height;
if(curRatio == 3f/4)
{
result = size;
}
}
}
return result;
} static class SizeComparator implements Comparator<Size>
{ @Override
public int compare(Size lhs, Size rhs) {
// TODO Auto-generated method stub
Size size1 = lhs;
Size size2 = rhs;
if(size1.width < size2.width
|| size1.width == size2.width && size1.height < size2.height)
{
return -1;
}
else if(!(size1.width == size2.width && size1.height == size2.height))
{
return 1;
}
return 0;
} }
}

因为不同的手机返回的支持分辨率的排序不一样(我手中一款联想从小到大排序,而还有一部nexus 4从大到小排序),所以须要先对列表统一进行从小到大排序。这样,方法返回的就是符合条件宽高比的最大分辨率,能够保证照片的清晰度。

照片方向错误

解决方法是监听手机方向的改变。监听到方向发生变化,就调用Camera.Parameters 对象(Camera对象调用getParameters()方法获得)的setRotation方法又一次设置成像方向。

监听的方法是。在Activity设置一个实现了OrientationEventListener接口 的对象。并调用其enable()方法激活。

IOrientationEventListener iOriListener;
... ...
iOriListener.enalbe();

实现OrientationEventListener接口的类:

public class IOrientationEventListener extends OrientationEventListener{

        public IOrientationEventListener(Context context) {
super(context);
// TODO Auto-generated constructor stub
} @Override
public void onOrientationChanged(int orientation) {
// TODO Auto-generated method stub
if(ORIENTATION_UNKNOWN == orientation)
{
return;
}
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(camera_id, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if(info.facing == CameraInfo.CAMERA_FACING_FRONT)
{
rotation = (info.orientation - orientation + 360) % 360;
}
else
{
rotation = (info.orientation + orientation) % 360;
}
if(null != camera)
{
Camera.Parameters parameters = camera.getParameters();
parameters.setRotation(rotation);
camera.setParameters(parameters);
} } }

当中设置rotation的公式由google官方提供。

预览方向错误

因为我设置了相机的Activity的方向为ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,即横屏模式,所以没有遇到这个问题。

只是上一篇我转载的博文里,有提到相关问题的解决。相关代码摘录出来。供大家參考。

下面代码放在surfaceview的callback中surfaceChanged方法里执行:

if(this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE)

{

//假设是竖屏

parameters.set(“orientation”, “portrait”);

//在2.2以上能够使用

//camera.setDisplayOrientation(90);

}

else

{

parameters.set(“orientation”, “landscape”);

//在2.2以上能够使用

//camera.setDisplayOrientation(0);

}

连续对焦

通过连续对焦,能够拍出清晰的照片。代码在上面的代码段里出现过

/*先推断是否支持,否则可能报错*/
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE))
{
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
}
camera.cancelAutoFocus();//仅仅有加上了这一句,才会自己主动对焦。

照相机Activity的代码就不全贴了,更详细的能够參考demoproject。

project下载

点此下载自己定义相机demoproject

如过上面那句话点击无效 ,说明资源还在审核。。。

能够去百度云盘下载:

http://pan.baidu.com/s/1c077rDA

因为本人手中測试机型仅仅有两台,执行了上述demo的朋友方便的话能够 告知下执行效果。

【Android】自己定义相机的实现(支持连续拍照、前后摄像头切换、连续对焦)的更多相关文章

  1. Android 手把手带你玩转自己定义相机

    本文已授权微信公众号<鸿洋>原创首发,转载请务必注明出处. 概述 相机差点儿是每一个APP都要用到的功能,万一老板让你定制相机方不方?反正我是有点方. 关于相机的两天奋斗总结免费送给你. ...

  2. Android调用系统相机、自己定义相机、处理大图片

    Android调用系统相机和自己定义相机实例 本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,而且因为涉及到要把拍到的照片显示出来,该样例也会涉及到Android载入大图片时候的处 ...

  3. android开发——自己定义相机(Camera)开发总结

    近期这段时间我一直在开发自己定义相机.谷歌了些网上的demo.发现有非常多各种各样的问题.终于还是从API的camera类開始学习,进行改进. 以下对之前的实现进行一些总结. 官方camera API ...

  4. AIDL —— Android接口定义语言

    AIDL:Android Interface Definition Language,即Android接口定义语言,是Android进程间通信比较常用的一种方式.翻译一下,就是为了让某个Service ...

  5. ANDROID自己定义视图——onLayout源代码 流程 思路具体解释

    转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 简单介绍: 在自己定义view的时候.事实上非常easy.仅仅须要知道3步骤: 1.測量- ...

  6. Android自己定义控件系列二:自己定义开关button(一)

    这一次我们将会实现一个完整纯粹的自己定义控件,而不是像之前的组合控件一样.拿系统的控件来实现.计划分为三部分:自己定义控件的基本部分,自己定义控件的触摸事件的处理和自己定义控件的自己定义属性: 以下就 ...

  7. Android调用系统相机、自定义相机、处理大图片

    Android调用系统相机和自定义相机实例 本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显示出来,该例子也会涉及到Android加载大图片时候的处理 ...

  8. 【Java/Android性能优 4】PreloadDataCache支持预取的数据缓存,使用简单,支持多种缓存算法,支持不同网络类型,扩展性强

    本文转自:http://www.trinea.cn/android/preloaddatacache/ 本文主要介绍一个支持自动向前或向后获取新数据的缓存的使用及功能.Android图片内存缓存可见I ...

  9. Android 自己定义控件实现刮刮卡效果 真的就仅仅是刮刮卡么

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40162163 , 本文出自:[张鸿洋的博客] 非常久以前也过一个html5的刮刮 ...

随机推荐

  1. Java之旅hibernate(8)——基本关系映射

    何为关系,何为映射,关系这个词想必大家都不陌生.比方你和老师之间是师生关系,你和父母之间是父子或者父女(母子或者母女关系). 关系是存在某种联系物体之间产生的.什么都是可能的.比方你和工具,你仅仅能使 ...

  2. C语言 · 三角形面积

     算法提高 三角形面积   时间限制:1.0s   内存限制:256.0MB      问题描述 由三角形的三边长,求其面积. 提示:由三角形的三边a,b,c求面积可以用如下的公式: s=(a+b+c ...

  3. dp + 状态压缩 - Codeforces 580D Kefa and Dishes

    Kefa and Dishes Problem's Link Mean: 菜单上有n道菜,需要点m道.每道菜的美味值为ai. 有k个规则,每个规则:在吃完第xi道菜后接着吃yi可以多获得vi的美味值. ...

  4. 如何创建Cookie? (选择1项)

    如何创建Cookie? (选择1项) A. 使用new Cookie语句 B. 调用response.addCookie方法 C. 使用Cookie的setMaxAge方法 D. setCookie方 ...

  5. SSH开发环境整合搭建

    1.建立动态web工程,加入必要的jar包. antlr-2.7.7.jar asm-3.3.jar asm-commons-3.3.jar asm-tree-3.3.jar c3p0-0.9.1.2 ...

  6. 如何用ChemFinder制作子表单

    通过使用ChemFinder这一插件,用户可以建立自己的ChemFinder数据库,数据库是由表单集合而成,所以建立数据库的前提是要制作表单.在之前的教程中已经介绍了制作表单的方法,本节ChemDra ...

  7. JavaScript设计模式——观察者模式

    观察者模式,又称发布-订阅模式或消息机制,定义了一种依赖关系,解决了主题对象与观察者之间功能的耦合. 通过运用观察者模式,可以解决团队开发中的模块间通讯问题,这是模块间解耦的一种可行方案. 首先,我们 ...

  8. 通过HttpWebRequest在后台对WebService进行调用

    目录: 1 后台调用Webservice的业务需求 2 WebService支持的交互协议 3 如何配置WebService支持的协议 4 后台对WebService的调用 4.1 SOAP 1.1 ...

  9. 《SQL Server 2000设计与T-SQL编程》

    <SQL Server 2000设计与T-SQL编程> <SQL Server 2000设计与T-SQL编程>笔记1 http://dukedingding.blog.sohu ...

  10. Java Tomcat 注册为Windows系统服务

    注册方法: 1. 在DOS命令行模式下,cd到tomcat的bin目录下 cd tomcatpath 根目录加:后回车 进入到tomcat安装目录,cd bin,进入tomcat启动目录 2.在tom ...