Android Camera2 拍照入门学习
来源:互联网 发布:mac os.ios镜像文件 编辑:程序博客网 时间:2024/05/16 15:49
学习资料:
- 肾虚将军android camera2 详解说明
- 极客学院android.hardware.camera2 使用指南
Android 5.0(21)之后,android.hardware.Camera
被废弃(下面称为Camera1
),还有一个android.graphics.Camera
,这个android.graphics.Camera
不是用来照相的,是用来处理图像的,可以做出3D
的图像效果之类的,之前的Camera1
则由android.hardware.Camera2
来代替
Camera2
支持RAW
输出,可以调节曝光,对焦模式,快门等,功能比原先Camera
强大
1.Camera1使用
使用步骤:
- 调用
Camera.open()
,打开相机,默认为后置,可以根据摄像头ID
来指定打开前置还是后置 - 调用
Camera.getParameters()
得到一个Camera.Parameters
对象 - 使用
步骤2
得到的Camera.Parameters
对象,对拍照参数进行设置 - 调用
Camera.setPreviewDispaly(SurfaceHolder holder)
,指定使用哪个SurfaceView
来显示预览图片 - 调用
Camera.startPreview()
方法开始预览取景 - 调用
Camera.takePicture()
方法进行拍照 - 拍照结束后,调用
Camera.stopPreview()
结束取景预览,之后再replease()
方法释放资源
这几个步骤从疯狂Android讲义
中学到
1.1简单使用
使用SurfaceView
进行取景的预览,点击屏幕进行拍照,用ImageView
来展示拍的照片
想买关于操作系统和C的书看,知乎很多人推荐这两本,就买了,感觉确实不错
布局文件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <SurfaceView android:id="@+id/surface_view_camera2_activity" android:layout_width="match_parent" android:layout_height="match_parent" /> <ImageView android:id="@+id/iv_show_camera2_activity" android:layout_width="180dp" android:layout_height="320dp" android:visibility="gone" android:layout_centerInParent="true" android:scaleType="centerCrop" /></RelativeLayout>
Activity
代码:
public class CameraActivity extends AppCompatActivity implements View.OnClickListener { private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; private Camera mCamera; private ImageView iv_show; private int viewWidth, viewHeight;//mSurfaceView的宽和高 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera2); initView(); } /** * 初始化控件 */ private void initView() { iv_show = (ImageView) findViewById(R.id.iv_show_camera2_activity); //mSurfaceView mSurfaceView = (SurfaceView) findViewById(R.id.surface_view_camera2_activity); mSurfaceHolder = mSurfaceView.getHolder(); // mSurfaceView 不需要自己的缓冲区 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // mSurfaceView添加回调 mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建 // 初始化Camera initCamera(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁 // 释放Camera资源 if (mCamera != null) { mCamera.stopPreview(); mCamera.release(); } } }); //设置点击监听 mSurfaceView.setOnClickListener(this); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (mSurfaceView != null) { viewWidth = mSurfaceView.getWidth(); viewHeight = mSurfaceView.getHeight(); } } /** * SurfaceHolder 回调接口方法 */ private void initCamera() { mCamera = Camera.open();//默认开启后置 mCamera.setDisplayOrientation(90);//摄像头进行旋转90° if (mCamera != null) { try { Camera.Parameters parameters = mCamera.getParameters(); //设置预览照片的大小 parameters.setPreviewFpsRange(viewWidth, viewHeight); //设置相机预览照片帧数 parameters.setPreviewFpsRange(4, 10); //设置图片格式 parameters.setPictureFormat(ImageFormat.JPEG); //设置图片的质量 parameters.set("jpeg-quality", 90); //设置照片的大小 parameters.setPictureSize(viewWidth, viewHeight); //通过SurfaceView显示预览 mCamera.setPreviewDisplay(mSurfaceHolder); //开始预览 mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } } /** * 点击回调方法 */ @Override public void onClick(View v) { if (mCamera == null) return; //自动对焦后拍照 mCamera.autoFocus(autoFocusCallback); } /** * 自动对焦 对焦成功后 就进行拍照 */ Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() { @Override public void onAutoFocus(boolean success, Camera camera) { if (success) {//对焦成功 camera.takePicture(new Camera.ShutterCallback() {//按下快门 @Override public void onShutter() { //按下快门瞬间的操作 } }, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) {//是否保存原始图片的信息 } }, pictureCallback); } } }; /** * 获取图片 */ Camera.PictureCallback pictureCallback = new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { final Bitmap resource = BitmapFactory.decodeByteArray(data, 0, data.length); if (resource == null) { Toast.makeText(CameraActivity.this, "拍照失败", Toast.LENGTH_SHORT).show(); } final Matrix matrix = new Matrix(); matrix.setRotate(90); final Bitmap bitmap = Bitmap.createBitmap(resource, 0, 0, resource.getWidth(), resource.getHeight(), matrix, true); if (bitmap != null && iv_show != null && iv_show.getVisibility() == View.GONE) { mCamera.stopPreview(); iv_show.setVisibility(View.VISIBLE); mSurfaceView.setVisibility(View.GONE); Toast.makeText(CameraActivity.this, "拍照", Toast.LENGTH_SHORT).show(); iv_show.setImageBitmap(bitmap); } } };}
权限:
<uses-permission android:name="android.permission.CAMERA" />
在获得图片后,想要显示的效果是照片是竖直显示,resource
显示的却是逆时针旋转了90°
,照片是横着的,就使用matrix.setRotate(90)
进行旋转
2.Camera2
这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession 的会话中。
以上从极客学院android.hardware.camera2 使用指南摘抄
- CameraManaer 摄像头管理器,用于检测摄像头,打开系统摄像头,调用
CameraManager.getCameraCharacteristics(String)
可以获取指定摄像头的相关特性 - CameraCharacteristics 摄像头的特性
- CameraDevice 摄像头,类似
android.hardware.Camera
也就是Camera1
的Camera
- CameraCaptureSession 这个对象控制摄像头的预览或者拍照,
setRepeatingRequest()
开启预览,capture()
拍照,CameraCaptureSession
提供了StateCallback、CaptureCallback两个接口来监听CameraCaptureSession
的创建和拍照过程。 - CameraRequest和CameraRequest.Builder,预览或者拍照时,都需要一个
CameraRequest
对象。CameraRequest表示一次捕获请求,用来对z照片的各种参数设置,比如对焦模式、曝光模式等。CameraRequest.Builder用来生成CameraRequest对象。
以上从肾虚将军的android camera2 详解说明摘抄
2.1 简单使用
使用的依然是SurfaceView
来进行展示预览
主要思路:
- 获得摄像头管理器
CameraManager mCameraManager
,mCameraManager.openCamera()
来打开摄像头 - 指定要打开的摄像头,并创建
openCamera()
所需要的CameraDevice.StateCallback stateCallback
- 在
CameraDevice.StateCallback stateCallback
中调用takePreview()
,这个方法中,使用CaptureRequest.Builder
创建预览需要的CameraRequest
,并初始化了CameraCaptureSession
,最后调用了setRepeatingRequest(previewRequest, null, childHandler)
进行了预览 - 点击屏幕,调用
takePicture()
,这个方法内,最终调用了capture(mCaptureRequest, null, childHandler)
- 在
new ImageReader.OnImageAvailableListener(){}
回调方法中,将拍照拿到的图片进行展示
代码:
public class Camera2Activity extends AppCompatActivity implements View.OnClickListener { private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); ///为了使照片竖直显示 static { ORIENTATIONS.append(Surface.ROTATION_0, 90); ORIENTATIONS.append(Surface.ROTATION_90, 0); ORIENTATIONS.append(Surface.ROTATION_180, 270); ORIENTATIONS.append(Surface.ROTATION_270, 180); } private SurfaceView mSurfaceView; private SurfaceHolder mSurfaceHolder; private ImageView iv_show; private CameraManager mCameraManager;//摄像头管理器 private Handler childHandler, mainHandler; private String mCameraID;//摄像头Id 0 为后 1 为前 private ImageReader mImageReader; private CameraCaptureSession mCameraCaptureSession; private CameraDevice mCameraDevice; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_camera2); initVIew(); } /** * 初始化 */ private void initVIew() { iv_show = (ImageView) findViewById(R.id.iv_show_camera2_activity); //mSurfaceView mSurfaceView = (SurfaceView) findViewById(R.id.surface_view_camera2_activity); mSurfaceView.setOnClickListener(this); mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.setKeepScreenOn(true); // mSurfaceView添加回调 mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建 // 初始化Camera initCamera2(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁 // 释放Camera资源 if (null != mCameraDevice) { mCameraDevice.close(); Camera2Activity.this.mCameraDevice = null; } } }); } /** * 初始化Camera2 */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void initCamera2() { HandlerThread handlerThread = new HandlerThread("Camera2"); handlerThread.start(); childHandler = new Handler(handlerThread.getLooper()); mainHandler = new Handler(getMainLooper()); mCameraID = "" + CameraCharacteristics.LENS_FACING_FRONT;//后摄像头 mImageReader = ImageReader.newInstance(1080, 1920, ImageFormat.JPEG,1); mImageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { //可以在这里处理拍照得到的临时照片 例如,写入本地 @Override public void onImageAvailable(ImageReader reader) { mCameraDevice.close(); mSurfaceView.setVisibility(View.GONE); iv_show.setVisibility(View.VISIBLE); // 拿到拍照照片数据 Image image = reader.acquireNextImage(); ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes);//由缓冲区存入字节数组 final Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); if (bitmap != null) { iv_show.setImageBitmap(bitmap); } } }, mainHandler); //获取摄像头管理 mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); try { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } //打开摄像头 mCameraManager.openCamera(mCameraID, stateCallback, mainHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } /** * 摄像头创建监听 */ private CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(CameraDevice camera) {//打开摄像头 mCameraDevice = camera; //开启预览 takePreview(); } @Override public void onDisconnected(CameraDevice camera) {//关闭摄像头 if (null != mCameraDevice) { mCameraDevice.close(); Camera2Activity.this.mCameraDevice = null; } } @Override public void onError(CameraDevice camera, int error) {//发生错误 Toast.makeText(Camera2Activity.this, "摄像头开启失败", Toast.LENGTH_SHORT).show(); } }; /** * 开始预览 */ private void takePreview() { try { // 创建预览需要的CaptureRequest.Builder final CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); // 将SurfaceView的surface作为CaptureRequest.Builder的目标 previewRequestBuilder.addTarget(mSurfaceHolder.getSurface()); // 创建CameraCaptureSession,该对象负责管理处理预览请求和拍照请求 mCameraDevice.createCaptureSession(Arrays.asList(mSurfaceHolder.getSurface(), mImageReader.getSurface()), new CameraCaptureSession.StateCallback() // ③ { @Override public void onConfigured(CameraCaptureSession cameraCaptureSession) { if (null == mCameraDevice) return; // 当摄像头已经准备好时,开始显示预览 mCameraCaptureSession = cameraCaptureSession; try { // 自动对焦 previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 打开闪光灯 previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 显示预览 CaptureRequest previewRequest = previewRequestBuilder.build(); mCameraCaptureSession.setRepeatingRequest(previewRequest, null, childHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) { Toast.makeText(Camera2Activity.this, "配置失败", Toast.LENGTH_SHORT).show(); } }, childHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } /** * 点击事件 */ @Override public void onClick(View v) { takePicture(); } /** * 拍照 */ private void takePicture() { if (mCameraDevice == null) return; // 创建拍照需要的CaptureRequest.Builder final CaptureRequest.Builder captureRequestBuilder; try { captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); // 将imageReader的surface作为CaptureRequest.Builder的目标 captureRequestBuilder.addTarget(mImageReader.getSurface()); // 自动对焦 captureRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // 自动曝光 captureRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 获取手机方向 int rotation = getWindowManager().getDefaultDisplay().getRotation(); // 根据设备方向计算设置照片的方向 captureRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation)); //拍照 CaptureRequest mCaptureRequest = captureRequestBuilder.build(); mCameraCaptureSession.capture(mCaptureRequest, null, childHandler); } catch (CameraAccessException e) { e.printStackTrace(); } }}
布局代码以及权限与Camera1
中一样,效果一样
预览时,是将mSurfaceHolder.getSurface()
作为目标
显示拍照结果时,是将mImageReader.getSurface()
作为目标
3.最后
Camera2
的功能很强大,暂时也只是学习了最基本的思路
住的地方,没有桌子,于是坐地上,趴在床上敲代码,腰疼。逛淘宝买桌子去
感谢极客学院和肾虚将军的学习资料
原文链接:http://www.jianshu.com/p/7f766eb2f4e7
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
- Android Camera2 拍照入门学习
- Android Camera2 拍照入门学习
- Android Camera2 拍照入门学习
- android camera2 拍照流程
- Android开发 之 Camera2之拍照
- Android Camera2 学习笔记
- Android Camera2拍照(一)——使用SurfaceView
- Android Camera2 拍照(二)——使用TextureView
- Android Camera2 拍照(四)——对焦模式
- Camera2拍照(备忘)
- android camera2
- Android camera2
- 摄像头拍照功能5.0 Camera2
- Camera2.0 控制摄像头拍照
- Android Camera2教程之打开相机、开启预览、实现PreviewCallback、拍照
- Android Camera2 拍照(三)——切换摄像头,延时拍摄和闪光模式
- Android开发之一个类实现Camera2预览和拍照效果
- Android Camera2.0 结合ImageReader拍照并解决图片偏转问题
- 第 16 章 反射(Reflection)
- Codeforces #386 B 746B Decoding
- Centos6.4 用rpm方式安装MySql5.6
- BUAA 540 概率dp
- 据说年薪30万的Android程序员必须知道的帖子
- Android Camera2 拍照入门学习
- JAVA正则表达式:Pattern类与Matcher类详解(转)
- 随身感想
- Stm32CubeMX快速配置与STM32HAL库高频词汇(一):CubeMX使用
- Power of Cryptography(POJ 2109)(二分)
- CentOS7.3下安装PHPUnit
- java代码操作Excel表格
- Verilog中的数据类型
- pip被墙,修改国内源方法