您的位置:首页 > 移动开发 > Android开发

android开发摄像头开发,在自己的SurfaceView里预览,并且解决摄像头预览变形问题--懒人笔记02

2016-11-03 09:52 543 查看
本来想只贴设置预览尺寸的部分了,后来想想就直接写个最简单的完整的demo吧

先在mainfeast中加入权限

<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />

然后是anctivity_main文件中的代码

<pre name="code" class="html"><?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

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

<Button
android:id="@+id/main_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="10dp"
android:text="拍照" />
</FrameLayout>


先贴这两段代码的原因就是这两个文件是不用分步骤的写,而且一看就懂,不用做什么说明,当然你也可以用自己喜欢的布局,都一样的

接下来看MainActivity中的代码,

首先要做的事情就是把摄像里的东西显示到SurfaceView中去,不管显示成什么样子,先看到它有反应再说

第一个版本

</pre><pre>

package com.camerademo;

import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {

private SurfaceView surfaceView;//预览摄像头
private SurfaceHolder surfaceHolder;
private Button button;//拍照按钮
private Camera camera;//摄像头

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
initListener();
}

//初始化View的方法,其实少的话都放到
private void initView() {
surfaceView = (SurfaceView) findViewById(R.id.main_surface_view);
button = (Button) findViewById(R.id.main_button);
}

private void initData() {
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
}

private void initListener() {
surfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "surfaceView", Toast.LENGTH_SHORT).show();
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "button", Toast.LENGTH_SHORT).show();
}
});
}

private void initCamera() {
camera.startPreview();
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();
camera.setPreviewDisplay(surfaceHolder);
} catch (Exception e) {
if (null != camera) {
camera.release();
camera = null;
}
e.printStackTrace();
Toast.makeText(MainActivity.this, "启动摄像头失败,请开启摄像头权限", Toast.LENGTH_SHORT).show();
}
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
initCamera();
}

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

这个版本我们主要做的事情

1、为我们的程序添加摄像头相关权限

2、写一个简单的布局

3、找到layout中所有的View,并为View设置测试用的监听

4、实现一个SurfaceHolder.CallBack,赋给SurfaceHolder,并且在OnSurfaceCreated里获取Camera实例,将SurfaceHolder赋给camera实例,在onSurfaceChange里面显示预览,在onSurfaceDestroy里面停止预览并且释放掉camera实例(这里可能有点绕,多过几遍代码就好了)

程序写完以后当然是迫不及待的运行一下,果不其然,界面上是有反应的,但是跟我们想象中的好像还有些不一样,界面显示出来的东西好像被旋转了,旋转屏幕观察下(现象自己观察咯)

这个处理方法有很多,可以直接将这个activity在mainfeast中设置成横屏,为了尽量多的用到API,我选择让这个activity默认竖屏

默认竖屏的代码,在mainfeast中,下边代码红色的部分让activity竖屏

<activity android:name=".MainActivity"
<span style="color:#ff0000;">android:screenOrientation="portrait"</span>
>
<intent-filter>
<action android:name=
bc37
"android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
竖屏以后屏幕中的预览还是旋转了90度呢,我们在MainActivity中的initCamera方法中加一些代码,红色的部分为新加的代码

private void initCamera() {
camera.startPreview();//开始预览
camera.setDisplayOrientation(90);//将预览旋转90度
}
好,加了上边几行代码后我们再运行一下吧,发现图像是转过来了哈,不过貌似不是所有的手机看上去都正常,不出意外的话应该是有些手机的预览图像是会有变形的,android开发处处是坑哈,下边我们接着处理变形问题

继续在MainActivity中的initCamera方法中加代码

private void initCamera() {
Camera.Parameters parameters = camera.getParameters();//获取camera的parameter实例
List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();//获取所有支持的camera尺寸
Camera.Size optionSize = getOptimalPreviewSize(sizeList, surfaceView.getWidth(), surfaceView.getHeight());//获取一个最为适配的camera.size
parameters.setPreviewSize(optionSize.width,optionSize.height);//把camera.size赋值到parameters
camera.setParameters(parameters);//把parameters设置给camera
camera.startPreview();//开始预览
camera.setDisplayOrientation(90);//将预览旋转90度
}
咦,楼主你是不是在坑我,根本就没有getOptimalPreviewSize这个方法啊,别着急嘛,下边我给你贴出来,这个放我我抄的别人的,不是我写的啊,不过好用
getOptimalPreviewSize方法

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;

Size optimalSize = null;
double minDiff = Double.MAX_VALUE;

int targetHeight = h;

// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}

// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
运行一下程序,好啦,变形问题和旋转问题解决了,下边加点击屏幕自动对焦,直接上代码吧,也没什么好说的
package com.camerademo;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.util.List;

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {

private SurfaceView surfaceView;//预览摄像头
private SurfaceHolder surfaceHolder;
private Button button;//拍照按钮
private Camera camera;
<span style="color:#ff0000;">private Camera.AutoFocusCallback myAutoFocusCallback1 = null;//只对焦不拍照
public static final int only_auto_focus = 110;
int issuccessfocus = 0;</span>

<span style="color:#ff0000;">private Handler mHandler = new Handler() {

@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case only_auto_focus:
if (camera != null)
camera.autoFocus(myAutoFocusCallback1);
break;
}
}
};</span>

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
initListener();
}

private void initView() {
surfaceView = (SurfaceView) findViewById(R.id.main_surface_view);
button = (Button) findViewById(R.id.main_button);
}

private void initData() {
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
<span style="color:#ff0000;">myAutoFocusCallback1 = new Camera.AutoFocusCallback() {

public void onAutoFocus(boolean success, Camera camera) {
// TODO Auto-generated method stub
if (success)//success表示对焦成功
{
issuccessfocus++;
if (issuccessfocus <= 1)
mHandler.sendEmptyMessage(only_auto_focus);
Log.i("qtt", "myAutoFocusCallback1: success..." + issuccessfocus);
} else {
//if (issuccessfocus == 0) {
mHandler.sendEmptyMessage(only_auto_focus);
//}
Log.i("qtt", "myAutoFocusCallback1: 失败...");
}
}
};</span>
}

private void initListener() {
surfaceView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (camera != null) {
if (camera != null)
camera.autoFocus(myAutoFocusCallback1);
}
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "button", Toast.LENGTH_SHORT).show();
}
});
}

private void initCamera() {
Camera.Parameters parameters = camera.getParameters();//获取camera的parameter实例
List<Camera.Size> sizeList = parameters.getSupportedPreviewSizes();//获取所有支持的camera尺寸
Camera.Size optionSize = getOptimalPreviewSize(sizeList, surfaceView.getWidth(), surfaceView.getHeight());//获取一个最为适配的屏幕尺寸
parameters.setPreviewSize(optionSize.width, optionSize.height);//把只存设置给parameters
camera.setParameters(parameters);//把parameters设置给camera上
camera.startPreview();//开始预览
camera.setDisplayOrientation(90);//将预览旋转90度
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
camera = Camera.open();
camera.setPreviewDisplay(surfaceHolder);
} catch (Exception e) {
if (null != camera) {
camera.release();
camera = null;
}
e.printStackTrace();
Toast.makeText(MainActivity.this, "启动摄像头失败,请开启摄像头权限", Toast.LENGTH_SHORT).show();
}
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
initCamera();
}

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

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) return null;

Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;

int targetHeight = h;

// Try to find an size match aspect ratio and size
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}

// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}


就到这里吧,拍照的话与自动对焦的套路差不过,用到了camera.tackpicture方法,这篇就到这里吧
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐