Android Camera学习记录(二) 相机App开发技术初识(一)

上一篇博客,我简单的介绍了一下使用Camera录制视频的方法,回过细细琢磨,我好像跳过了使用相机拍照。因此,本文主要针对没有做过Camera开发的初学者,会讲的非常的细,因此大神们可以直接无视~哈哈哈


一、前言

首先,和录制视频一样,我们需要向系统申请使用权限,有需要的可能需要往系统中保存所拍到的图片。因此,我们常需要申请一下三种权限:

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.LOCATION_HARDWARE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
当然,很多朋友会在很多大神的博客中看到添加了
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
事实上,uses-permission 同 user-feature在某种程度上,都可以像系统申请使用的权限,但是他们侧重的方向并不相同:

uses-permission 仅仅是向你的手机申请权限,也就是申请使用该功能的权限;

user-feature 是用于确保你的手机有该功能的支持。

当然,针对于现在手机的Camera的开发来讲,这两个基本是没有什么区别的。


二、使用Camera

使用Camera可以分为两种方式来做,一种就是直接使用Intent调用系统的Camera,使用系统的相机进行拍照,另外一种就是调用系统的Camera,嵌入到自己的App中使用。本文仅针对第二种方式进行详细的讲解。


三、布局

与视频拍摄类似,我们在布局中需要使用SurfaceView作为相机的预览显示器,并且我们需要有一个控件来控制拍照操作,因此我仅仅是简单的写了两个主要控件来实现相应的方法:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="seeunsee.cameratext.MainActivity">

    <SurfaceView
        android:id="@+id/camera"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ImageView
        android:id="@+id/iv_takepic"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="8dp"
        android:src="@drawable/takepicture" />

</RelativeLayout>

四、初步使用

有了以上的准备工作,我们就可以开始着手Camera的开发了。那么我们就先实现一个相机预览的功能:

private void init() {
        sfv = (SurfaceView) findViewById(R.id.camera);
        ivTakePic = (ImageView) findViewById(R.id.iv_takepic);
        sfh = sfv.getHolder();
        // 实测不带这个参数也可以有效果,不过网上的资料显示,增加这个变量,可以使得预览的图像更流畅
        sfh.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        sfh.addCallback(this);
    }

private void cameraCreate() {
        if (camera != null) {
            return;
        }
        camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK); // 使用后置摄像头
        try {
            camera.setPreviewDisplay(sfh);
            camera.startPreview();
        } catch (IOException e) {
            camera.release();
        }
    }

其中,cameraCreate函数需要放在SurfaceHolder.Callback中,你可以选择放在surfaceCreated或者surfaceChanged中。区别在于surfaceCreated仅会在SurfaceView创建的时候被调用,而surfaceChanged无论如何都会在至少在surfaceCreated之后调用一次,且每次surfaceView发生改变的时候,都会再次调用。对于我而言,我更喜欢写在changed中,不过,如果你喜欢两个地方都写上,其实也不会有什么问题。

当然,为了保证其他进程使用Camera,我们最好是在surfaceview销毁的时候,将Camera重置:

@Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        camera.release();
        camera = null;
    }

OK,就让我们运行一下程序看看会有怎么样的结果


五、优化

阿嘞,我手机明明是竖着的,为啥预览的图像却是逆时针旋转了90度呢?不要急,你先把手机调整到水平模式来看看会有什么结果吧~

很明显,当我们把手机界面变成水平模式的时候,预览图像显示的角度就和我们所看的角度是一致的了。因此,我们可以得到系统相机的预览规律,当手机处于竖屏状态时,相机预览图像与实际图像呈90度角;当手机处于横屏状态时,相机预览图像与实际图像一致,因此,我们需要对这两种情况分别处理。

因此我们需要采用预览图像的旋转方法,将相机预览图像进行旋转。

当然,我们前文说过,我们只有在竖屏模式下才需要旋转预览图像,因此这里我们有两个可选的解决方式:

1:采用大部分相机App的方式,强行让应用处于垂直状态,在onCreate中添加

// 强行限制屏幕为纵向
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
然后cameraCreate()中对camera进行角度的设置

camera.setDisplayOrientation(90);

2:对屏幕的方向进行判断,根据不同的方向,对Camera预览的旋转角度进行设置:

if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT){
                // 如果手机屏幕处于垂直模式
		camera.setDisplayOrientation(90);
	} else { 
		// 如果手机屏幕处于水平模式 
		camera.setDisplayOrientation(0); 
	}	

OK,在运行一次,我们就会发现这回显示就完全正常了,但是细心的童鞋肯定会发现,为什么预览效果这么模糊呢?了解相机功能的童鞋肯定知道,这是因为相机对焦不正确导致的结果,那问题又来了,我们怎么才能设置相机对焦呢?
在解决这个问题,我们需要引入一个新的类Camera.Parameters。


六、Camera.Parameters类简介
Camera.Parameters类,主要是概述相机的服务设置,包括对相机预览图像的设置,以及获得拍照结果的设置。
与大部分创建对象方式不同,Parameters对象的创建方式为:

Camera.Parameters parameters = camera.getParameters();
其中camera 为我们创建的Camera对象。
在编译器中,我们使用Parameters,我们可以发现编译器给我们提供了很多不同的方法,所以下面我们先来了解一下常用的几个Parameters方法:

parameters.setPreviewSize(int width, int height); // 设置摄像预览的分辨率
parameters.setPictureSize(int width, int height); // 设置拍摄照片的分辨率
parameters.setRotation(int rotation); // 设置获得照片的旋转角度
parameters.setPictureFormat(int pixel_format); // 设置图片格式
parameters.setPreviewFpsRange(int min, int max); // 设置最小和最大的预览帧数

parameters.setFocusMode(String value); // 设置聚焦模式
// 常量有如下几种:
// FOCUS_MODE_AUTO 自动对焦模式
// FOCUS_MODE_CONTINUOUS_PICTURE 用于拍照的连续自动对焦模式
// FOCUS_MODE_CONTINUOUS_VIDEO 用于视频录制的连续自动对焦模式 
// FOCUS_MODE_EDOF 扩展景深(EDOF)
// FOCUS_MODE_FIXED 固定焦点
// FOCUS_MODE_INFINITY 焦点在无限远处
// FOCUS_MODE_MACRO 微距(特写)对焦模式

parameters.setWhiteBalance(String value); // 设置白平衡模式
// 常量有如下几种:
// WHITE_BALANCE_AUTO 自动模式
// WHITE_BALANCE_CLOUDY_DAYLIGHT 多云
// WHITE_BALANCE_DAYLIGHT 白天
// WHITE_BALANCE_FLUORESCENT 荧光灯下
// WHITE_BALANCE_INCANDESCENT 白炽灯下
// WHITE_BALANCE_SHADE 阴暗
// WHITE_BALANCE_TWILIGHT 黄昏
// WHITE_BALANCE_WARM_FLUORESCENT 温柔的日光下

parameters.setSceneMode(String value); // 设置场景模式(这个有点多-.-,有兴趣的童鞋可以去开发者网站看一下)
// 网址:https://developer.android.google.cn/reference/android/hardware/Camera.Parameters.html#SCENE_MODE_AUTO


七、优化(二)
大致的对Parameters有所了解,那么我们就可以继续优化我们的相机。
我们在camereCreate中调用parameters.getFocusMode(),发现返回值为auto,因此我们知道,在我们没有对相机进行设置的时候,相机的聚焦模式为自动对焦模式,然而从这里我们可以看出,这个自动对焦,实际上并没有说那么自动智能,完全无法达到我们对相片清晰度的要求,因此我们需要对相机的对焦模式进行修改。我在这里使用的是
FOCUS_MODE_CONTINUOUS_PICTURE
有兴趣的童鞋们也可以试试其他的对焦方式哦!


八、Android 6.0系统
写到这里,很多童鞋肯定会深感疑惑,为毛作者写的津津乐道,我一运行就会闪退呢!
这里我建议大家先看一下自己的手机系统,如果你是Android 6.0的系统,那么恭喜你,这段代码一定是会导致程序闪退的。为什么?因为Android 6.0 Google大大加入了运行时权限功能,并将几百种权限区分为普通权限、危险权限两种。如果你的开发涉及到危险权限,对于这部分权限的申请,必须要由用户手动点击授权才可以(至于具体的讲解,可以参考一下郭霖大神的第二行代码哦)。
因此,如果你的手机是Android6.0及其以上,你可以在oncreate()方法中,添加

// 6.0及其以上系统的手机,需要动态的申请权限,否则App会发生闪退现象
// 并且针对于6.0以下的手机来说,并没有什么改变
// 在这里,一旦点击拒绝,就直接会导致程序的闪退
// 因此,处理权限问题,应该放置在其他页面中进行,根据用户的选择进行跳转
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
动态的申请权限就可以了哦


如果,还有遇到什么以上没有涉及到的问题,也可以留言给我哦~


写到这里,我们就已经完成了对相机预览的简单编写,我们可以通过相机预览到方向正确、清晰的预览图像,那么下一篇,我将带大家走进拍照的深坑 偷笑



  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值