如何实现Android手机android 摄像头对焦的自动对焦

当前位置: >>>
android摄像头获取图像――第二弹
使用android内的Camera对象 (1)Camera是控制着摄像头的api,拥有一系列控制摄像头的上层方法;camera类能够调用底层的摄像头接口,完成启动摄像头、预览摄像头图像、拍照等功能; (2)功能 首先,可以在主activity中通过sufaceView接收camera的图像,并开启camera的start
& & & & & & & & & &使用android内的Camera对象
(1)Camera是控制着摄像头的api,拥有一系列控制摄像头的上层方法;camera类能够调用底层的摄像头接口,完成启动摄像头、预览摄像头图像、拍照等功能;
首先,可以在主activity中通过sufaceView接收camera的图像,并开启camera的startpreview方法,达到图像显示的目的;
如果不想在主activity中预览,只想得到图像或使用其他方式在activity中显示,可以通过重写callback函数,通过其中传入的&
数据,生成相应的图像并返回Bitmap格式(具体的调用方法将在下文提到)
然后,可以调用takePicture函数,进行拍照处理;使用autofocus方法可以先自动对焦再进行拍照;
最后,可以捕获相关的视频,本文主要讲解如何捕获图像,详细内容还是看头部连接,^_^ ;
(3)一般调用步骤
?检测并访问摄像头 ―― 创建代码以检查摄像头存在与否并请求访问。
?创建预览类 ―― 创建继承自SurfaceView 并实现SurfaceHolder 接口的摄像预览类。此类能预览摄像的实时图像。
?建立预览布局Preview Layout ―― 一旦有了摄像预览类,即可创建一个view layout,用于把预览画面与设计好的用户界面控&
件融合在一起。
?为捕获设置侦听器Listener ―― 将用户界面控件连接到listener,使其能响应用户操作开始捕获图像或视频,比如按下按钮&
?捕获并保存文件 ―― 建立捕获图片或视频并保存到输出文件的代码。
?释放摄像头 ―― 摄像头使用完毕后,应用程序必须正确地将其释放,便于其它程序的使用。
(4)主要类型与方法介绍
――surfaceView:SurfaceView为一个显示面板,可以用于显示图像;相当于mvc中view;
――SurfaceHolder:控制surface中的图像显示;相当于mvc模式中的的control;
――用户可以通过surfaceView的getHolder()方法得到该surfaceView的控制器对象:SurfaceHolder;并调用SurfaceHolder的&
addCallback方法加入用户重写的继承自SurfaceHolder.Callback接口的对象:
mSurfaceView = (SurfaceView) findViewById(R.id.mSurfaceView);
holder = mSurfaceView.getHolder();
holder.addCallback(EX07_16);//
――SurfaceHolder.Callback接口的主要方法有:
public void surfaceCreated(SurfaceHolder surfaceholder)//在surfaceView创建时调用
其他两个方法分别为改动和销毁时调用。
――将SurfaceHolder加入camera中,以便预览时调用该对象显示图像:mCamera.setPreviewDisplay(holder);
误区:开始时觉得cam必须加入surfaceView的功能才能实现预览,但是后来的测试证明不需要加入surfaceView,即可实现camera&
的预览功能,只是图片不会显示。(这是理所应当的,因为camera有没有获得图像与是否有显示图像的面板没有任何关系;这证&
明了androidAPI还是比较开放的)
――Camera类的open()/opent(int i)方法用于打开摄像机
――Camera类中的一些处理都是通过callback来进行的:
/* 自动对焦后拍照 */
mCamera.autoFocus(mAutoFocusCallback);
其中mAutoFocusCallback继承自Camera.AutoFocusCallback接口,用户可以自定义的是对焦完成后的操作(比如延迟拍照等);
同样这里面preview和takepicture操作都需要放入callback进行用户自定义操作。
――mCamera.takePicture(shutterCallback, rawCallback, jpegCallback);在takePicture方法里输入几个callback方法,实现&
用户的自定义操作。
――mCamera.setPreviewCallback(pre);设置相机的预览回调函数,每当相机获取一幅图像的时候,都会调用这个对象的函数(这是最为重要的一个方法)
/** * @Title: Test.java
* @Package cn.edu.zjut.androidcam
* @Description: 下位机端android界面,用于获取android摄像头获取的图像,并传输给
* @author Alfred.M
下午12:33:57
* @version V1.
welcome to the magic program world!
* Copyright (c) 2011, 浙江工业大学信息工程学院212实验室
All Rights Reserved. */ package cn.edu.zjut. import java.io.BufferedOutputS import java.io.ByteArrayOutputS import java.io.F import java.io.FileOutputS import java.io.IOE import android.app.A import android.content.C import android.content.I import android.content.pm.PackageM import android.graphics.B import android.graphics.BitmapF import android.graphics.ImageF import android.graphics.R import android.graphics.YuvI import android.hardware.C import android.hardware.Camera.PictureC import android.hardware.Camera.ShutterC import android.hardware.Camera.S import android.os.B import android.os.E import android.util.L import android.view.SurfaceH import android.view.SurfaceV import android.view.V import android.view.View.OnClickL import android.view.W import android.view.WindowM import android.widget.ImageV public class MainGUI extends Activity implements SurfaceHolder.Callback { private Camera mC// Camera对象 private ImageView mB// 右侧条框,点击出发保存图像(拍照)的事件 private SurfaceView mSurfaceV// 显示图像的surfaceView private SurfaceH// SurfaceView的控制器 private AutoFocusCallback mAutoFocusCallback = new AutoFocusCallback();// AutoFocusCallback自动对焦的回调对象 private ImageView sendImageIv;// 发送图片的imageview,位于右侧条框 private String strCaptureFilePath = Environment
.getExternalStorageDirectory() + "/DCIM/Camera/";// 保存图像的路径
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (checkCameraHardware(this)) {
Log.e("============", "摄像头存在");// 验证摄像头是否存在
} /* 隐藏状态栏 */ this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN); /* 隐藏标题栏 */ requestWindowFeature(Window.FEATURE_NO_TITLE); /* 设定屏幕显示为横向 */ // this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
setContentView(R.layout.another);// ---------------------- /* SurfaceHolder设置 */ mSurfaceView = (SurfaceView) findViewById(R.id.mSurfaceView);
holder = mSurfaceView.getHolder();
holder.addCallback(this); // holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); /* 设置拍照Button的OnClick事件处理 */ mButton = (ImageView) findViewById(R.id.myButton);
mButton.setOnClickListener(new OnClickListener() {
@Override public void onClick(View arg0) { /* 自动对焦后拍照 */ mCamera.autoFocus(mAutoFocusCallback);// 调用mCamera的
takePicture();
sendImageIv = (ImageView) findViewById(R.id.send_image);
sendImageIv.setOnClickListener(new OnClickListener() {
@Override public void onClick(View v) {
Intent i = new Intent();
i.setType("image/*");
i.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(i, Activity.DEFAULT_KEYS_SHORTCUT);
} // ///////----------重写SurfaceHolder.Callback接口的方法, // 在创建面板的时候调用的方法
@Override public void surfaceCreated(SurfaceHolder surfaceholder) { try {
mCamera = null; try {
mCamera = Camera.open(0);//打开相机;在低版本里,只有open()方法;高级版本加入此方法的意义是具有打开多个 //摄像机的能力,其中输入参数为摄像机的编号 //在manifest中设定的最小版本会影响这里方法的调用,如果最小版本设定有误(版本过低),在ide里将不允许调用有参的 //open方法; //如果模拟器版本较高的话,无参的open方法将会获得null值!所以尽量使用通用版本的模拟器和API; } catch (Exception e) {
Log.e("============", "摄像头被占用");
} if (mCamera == null) {
Log.e("============", "摄像机为空");
System.exit(0);
mCamera.setPreviewDisplay(holder);//设置显示面板控制器 priviewCallBack pre = new priviewCallBack();//建立预览回调对象 mCamera.setPreviewCallback(pre); //设置预览回调对象 //mCamera.getParameters().setPreviewFormat(ImageFormat.JPEG); mCamera.startPreview();//开始预览,这步操作很重要 } catch (IOException exception) {
mCamera.release();
mCamera = null;
} // 不添加显示面板的代码: /* * 打开相机, mCamera = try { mCamera = Camera.open(0); } catch
* (Exception e) { Log.e("============", "摄像头被占用"); } if (mCamera ==
* null) { Log.e("============", "返回结果为空"); System.exit(0); } //
* mCamera.setPreviewDisplay(holder); priviewCallBack pre = new
* priviewCallBack(); mCamera.setPreviewCallback(pre); Log.w("wwwwwwww",
* mCamera.getParameters().getPreviewFormat() + "");
* mCamera.startPreview(); */ } // 在面板改变的时候调用的方法
@Override public void surfaceChanged(SurfaceHolder surfaceholder, int format, int w, int h) { /* 相机初始化 */ initCamera();
} // 销毁面板时的方法
@Override public void surfaceDestroyed(SurfaceHolder surfaceholder) {
stopCamera();
mCamera.release();
mCamera = null;
} /* 拍照的method */ private void takePicture() { if (mCamera != null) {
mCamera.takePicture(shutterCallback, rawCallback, jpegCallback);
} private ShutterCallback shutterCallback = new ShutterCallback() { public void onShutter() { /* 按下快门瞬间会调用这里的程序 */ }
}; private PictureCallback rawCallback = new PictureCallback() { public void onPictureTaken(byte[] _data, Camera _camera) { /* 要处理raw data?写?否 */ }
}; //在takepicture中调用的回调方法之一,接收jpeg格式的图像 private PictureCallback jpegCallback = new PictureCallback() { public void onPictureTaken(byte[] _data, Camera _camera) { /* * if (Environment.getExternalStorageState().equals(
* Environment.MEDIA_MOUNTED)) // 判断SD卡是否存在,并且可以可以读写 {
* } else { Toast.makeText(EX07_16.this, "SD卡不存在或写保护",
* Toast.LENGTH_LONG) .show(); } */ // Log.w("============", _data[55] + ""); try { /* 取得相片 */ Bitmap bm = BitmapFactory.decodeByteArray(_data, 0,
_data.length); /* 创建文件 */ File myCaptureFile = new File(strCaptureFilePath, "1.jpg");
BufferedOutputStream bos = new BufferedOutputStream( new FileOutputStream(myCaptureFile)); /* 采用压缩转档方法 */ bm.pressFormat.JPEG, 100, bos); /* 调用flush()方法,更新BufferStream */ bos.flush(); /* 结束OutputStream */ bos.close(); /* 让相片显示3秒后圳重设相机 */ // Thread.sleep(2000); /* 重新设定Camera */ stopCamera();
initCamera();
} catch (Exception e) {
e.printStackTrace();
}; /* 自定义class AutoFocusCallback */ public final class AutoFocusCallback implements android.hardware.Camera.AutoFocusCallback { public void onAutoFocus(boolean focused, Camera camera) { /* 对到焦点拍照 */ if (focused) {
takePicture();
}; /* 相机初始化的method */ private void initCamera() { if (mCamera != null) { try {
Camera.Parameters parameters = mCamera.getParameters(); /* * 设定相片大小为, 格式为JPG */ // parameters.setPictureFormat(PixelFormat.JPEG); parameters.setPictureSize();
mCamera.setParameters(parameters); /* 打开预览画面 */ mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
} /* 停止相机的method */ private void stopCamera() { if (mCamera != null) { try { /* 停止预览 */ mCamera.stopPreview();
} catch (Exception e) {
e.printStackTrace();
} // 检测摄像头是否存在的私有方法 private boolean checkCameraHardware(Context context) { if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA)) { // 摄像头存在 return true;
} else { // 摄像头不存在 return false;
} // 每次cam采集到新图像时调用的回调方法,前提是必须开启预览 class priviewCallBack implements Camera.PreviewCallback {
@Override public void onPreviewFrame(byte[] data, Camera camera) { // TODO Auto-generated method stub // Log.w("wwwwwwwww", data[5] + ""); // Log.w("支持格式", mCamera.getParameters().getPreviewFormat()+"");
decodeToBitMap(data, camera);
} public void decodeToBitMap(byte[] data, Camera _camera) {
Size size = mCamera.getParameters().getPreviewSize(); try {
YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width,
size.height, null);
Log.w("wwwwwwwww", size.width + " " + size.height); if (image != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
pressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);
Bitmap bmp = BitmapFactory.decodeByteArray(
stream.toByteArray(), 0, stream.size());
Log.w("wwwwwwwww", bmp.getWidth() + " " + bmp.getHeight());
Log.w("wwwwwwwww",
(bmp.getPixel(100, 100) & 0xff) + "
+ ((bmp.getPixel(100, 100) && 8) & 0xff) + "
+ ((bmp.getPixel(100, 100) && 16) & 0xff));
stream.close();
} catch (Exception ex) {
Log.e("Sys", "Error:" + ex.getMessage());
&RelativeLayout xmlns:android="/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="center_horizontal" & &SurfaceView android:id="@+id/mSurfaceView" android:visibility="visible" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_gravity="center_horizontal" android:layout_alignParentLeft="true" android:layout_toLeftOf="@+id/camera_linearLayout" /& &RelativeLayout android:id="@+id/camera_linearLayout" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_alignParentRight="true" & &ImageView android:id="@+id/send_image1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/myButton" android:layout_alignRight="@+id/myButton" android:layout_alignParentTop="true" android:contentDescription="@string/app_name" /& &ImageView android:id="@+id/myButton" android:paddingLeft="18.0dip" android:paddingRight="18.0dip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/send_image1" android:layout_marginTop="0px" android:layout_above="@+id/send_image" android:layout_marginBottom="0px" android:contentDescription="@string/app_name" /& &ImageView android:id="@+id/send_image" android:paddingLeft="18.0dip" android:paddingRight="18.0dip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:contentDescription="@string/app_name" /& &/RelativeLayout& &/RelativeLayout&
(责任编辑:简单的工作室)
------分隔线----------------------------&&国之画&&&& &&&&&&
&& &&&&&&&&&&&&&&&&&&
鲁ICP备号-4
打开技术之扣,分享程序人生!简单游戏 快乐生活
全国门店目录
您当前的位置:
>> >> >>掌控手机拍照技巧&教你如何玩转独立测光功能
掌控手机拍照技巧&教你如何玩转独立测光功能
作者:kezz
来源:本站原创
发布时间: 15:21:46
  “测光”对很多入门级的手机拍照用户而言是个陌生的词汇,不过它实际贯穿在所有成像设备拍照时的始终,所谓的测光指的是为了让最终成像表现出合理的亮度,在正式拍摄前对所摄场景的评估,并最终确定该用上哪些曝光参数――这话说得又有些复杂了,说简单些,即是为了让照片达到用户理想中的亮度而进行的前期准备工作。    之所以要有测光过程,原因在于普通民用成像设备,甚至包括单反,在碰到所摄场景最亮处和最暗处反差很大的时候是无法兼顾两端的,此时最终成像要么局部过曝、要么局部欠曝,也就是画面某些部位过亮或过暗。这实际是个无解的命题,典型的场景像是逆光拍摄。所以我们常常看到逆光拍下的画面往往前景一片死黑。这也是测光成为摄影中一个难点所在的原因。
  为了解决这个问题,以iPhone为代表的手机提出了一种解决方案,即点选拍摄界面中的某个位置,则测光系统以用户选择这个点的事物为呈现重点,也就是为了保证用户所选此点的亮度,测光系统以此点为参考,对整个画面的亮度做调整。比如在逆光环境下拍照时,点选画面中前景较暗的位置,则画面不惜让背景过曝,来获得合理的前景亮度。    这种方案在很多时候是比较有效的,但有些时候却无法满足拍摄需求,因为用户在拍摄时,所选的点不仅作为测光系统的参考,此点同时又是对焦点――相信很多人对对焦点更了解一些――对焦点是指画面中最清晰呈现的位置:也就是在选择对焦点的同时,也是在选测光重点。比如说我们期望拍摄一个剪影,对焦需要对在前景主体上,但此时如果测光也放在前景主体,则整个画面会太亮,拍不到剪影效果,这就是这套方案的局限所在。
  好在努比亚智能手机在NeoVision 2.0成像系统时代就提出了将对焦和测光分离的解决方案,这种方案原本在单反中才看得到,后来出现在了努比亚全部系列的手机中。最新的nubia Z7、Z7 Max、Z7 mini都延续了这一解决方案。所以我们在手机拍照界面的Pro专业模式下会发现,除了正方形的对焦点,还多出了一个圆形的测光参考点,实现的恰是将对焦和测光分离开来,也就是传说中的“独立测光”。
  初上手的用户大概会不明白这两个框究竟怎么用,但用过之后会发现对其依赖性逐渐增强。上图以nubia Z7 Max为实战设备,首先移动正方形的绿色框,将之移动到需要对焦的位置,在对焦过程完成后就可以去移动圆形的红色框了,将红色框移至画面不同亮度的不同位置,就会发现整个画面的亮度会随之发生变化,但对焦点并没有变。在体验过这个过程之后,相信大部分人就能够理解独立测光的精髓所在了,关键在于成像的亮度真正掌控在了用户手中。
  独立测光的解决方案对于拍照的灵活性是有很大帮助了,除了上面提到拍摄剪影这样的具体需求,绝大部分明暗反差很大的场景都能用上独立测光系统。因为照片的亮度并没有好坏之分,仅在于用户想要用某种亮度达成怎样的氛围和效果,或者想要着重呈现画面中的亮部还是暗部――无论是多么智能的手机都不可能猜测用户所想,于是将测光和对焦分离开,由用户自行决定画面亮度就显得相当明智了,在灵活性上又比调节曝光补偿来得方便和高效。微博上出现的不少用nubia Z7系列手机拍摄的高段位照片都有独立测光的参与,至少在掌握这项技能以后,玩转场景亮度就不是问题了,这是成为手机摄影高手的重要一步。
你有遇到过玩游戏时切换出来查看攻略,不幸导致游戏崩溃的情况吗?下载,边玩游戏边用手机看攻略,轻松愉快,大家都在用。
关注安卓中文网官方微信
扫描左侧二维码即可添加安卓中文网官方微信
您也可以在微信上搜索“安卓中文网”或“anzhuozww”,获取更多数码资讯
24小时热点22363人阅读
android系列(2)
& & & &发现好多人都在解决一个问题那就是,如何实现android相机的自动对焦,而且是连续自动对焦的。当然直接调用系统相机就不用说了,那个很简单的。下面我们主要来看看如如何自己实现一个相机,并且实现自动连续对焦。
& & &根据网上的资料有如下几种:
& & & & 1 极端人物的做法: &使用一个定时器,设定定时时间,然后不间断的对焦。
& & & & 2 &极客人物的做法: &那就是利用驱动层实现,但是这个一般人还是算了吧
& & & & 3 &就我我这样的懒汉人物: 观察系统的原生相机得知,这东东也没用定时器啊,貌似也不可能复杂到全用驱动来实现,即使底层用的是C 实现,但是理论上讲,google肯定会提供这个封装好东东。于是果断的去查阅 DOC &一看,发现果然有这个东东 &: 代码如下
public class MainActivity extends Activity {
private SurfaceView surfaceV
private SurfaceHolder surfaceH
private boolean flag =
private String fileUrl=&&;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView =
(SurfaceView) findViewById(R.id.surfaceView1);
button=(Button) findViewById(R.id.takepicture);
surfaceHolder =
surfaceView.getHolder();
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceHolder.setKeepScreenOn(true);
surfaceView.setFocusable(true);
surfaceView.setBackgroundColor(TRIM_MEMORY_BACKGROUND);
surfaceHolder.addCallback(new Callback() {
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
camera.stopPreview();
camera.release();
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
if(null==camera){
camera=Camera.open();
camera.setPreviewDisplay(surfaceHolder);
initCamera();
camera.startPreview();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height){
//实现自动对焦
camera.autoFocus(new AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
if(success){
initCamera();//实现相机的参数初始化
camera.cancelAutoFocus();//只有加上了这一句,才会自动对焦。
//相机参数的初始化设置
private void initCamera()
parameters=camera.getParameters();
parameters.setPictureFormat(PixelFormat.JPEG);
//parameters.setPictureSize(surfaceView.getWidth(), surfaceView.getHeight());
// 部分定制手机,无法正常识别该方法。
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//1连续对焦
setDispaly(parameters,camera);
camera.setParameters(parameters);
camera.startPreview();
camera.cancelAutoFocus();// 2如果要实现连续的自动对焦,这一句必须加上
//控制图像的正确显示方向
private void setDispaly(Camera.Parameters parameters,Camera camera)
if (Integer.parseInt(Build.VERSION.SDK) &= 8){
setDisplayOrientation(camera,90);
parameters.setRotation(90);
//实现的图像的正确显示
private void setDisplayOrientation(Camera camera, int i) {
Method downP
downPolymorphic=camera.getClass().getMethod(&setDisplayOrientation&, new Class[]{int.class});
if(downPolymorphic!=null) {
downPolymorphic.invoke(camera, new Object[]{i});
catch(Exception e){
Log.e(&Came_e&, &图像出错&);
public boolean onCreateOptionsMenu(Menu menu) {
// I this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:47887次
排名:千里之外
转载:13篇
评论:13条
(1)(1)(1)(3)(2)(1)(1)(3)(2)(7)}

我要回帖

更多关于 自动对焦摄像头 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信