Android Camera2 拍照入门学习

dingyou110 7年前
   <p>Android 5.0(21)之后, android.hardware.Camera 被废弃(下面称为 Camera1 ),还有一个 android.graphics.Camera ,这个 android.graphics.Camera 不是用来照相的,是用来处理图像的,可以做出 3D 的图像效果之类的,之前的 Camera1 则由 android.hardware.Camera2 来代替</p>    <p>Camera2 支持 RAW 输出,可以调节曝光,对焦模式,快门等,功能比原先 Camera 强大</p>    <h2>1.Camera1使用</h2>    <p>使用步骤:</p>    <ol>     <li>调用 Camera.open() ,打开相机,默认为后置,可以根据摄像头 ID 来指定打开前置还是后置</li>     <li>调用 Camera.getParameters() 得到一个 Camera.Parameters 对象</li>     <li>使用 步骤2 得到的 Camera.Parameters 对象,对拍照参数进行设置</li>     <li>调用 Camera.setPreviewDispaly(SurfaceHolder holder) ,指定使用哪个 SurfaceView 来显示预览图片</li>     <li>调用 Camera.startPreview() 方法开始预览取景</li>     <li>调用 Camera.takePicture() 方法进行拍照</li>     <li>拍照结束后,调用 Camera.stopPreview() 结束取景预览,之后再 replease() 方法释放资源</li>    </ol>    <p>这几个步骤从 疯狂Android讲义 中学到</p>    <h2>1.1简单使用</h2>    <p>使用 SurfaceView 进行取景的预览,点击屏幕进行拍照,用 ImageView 来展示拍的照片</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/37a3e9f75ca1c72de47b6e6bd86a33e8.png"></p>    <p style="text-align:center">取景</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/7433aa58d9c04c2981d31806f92e80e9.png"></p>    <p style="text-align:center">拍照预览</p>    <p>想买关于操作系统和C的书看,知乎很多人推荐这两本,就买了,感觉确实不错。然而,深入理解操作系统买早了,啃不动</p>    <p>布局文件:</p>    <pre>  <code class="language-java"><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></code></pre>    <p>Activity 代码:</p>    <pre>  <code class="language-java">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);              }          }      };  }</code></pre>    <p>权限:</p>    <pre>  <code class="language-java"><uses-permission android:name="android.permission.CAMERA" /></code></pre>    <p>在获得图片后,想要显示的效果是照片是竖直显示, resource 显示的却是逆时针旋转了 90° ,照片是横着的,就使用 matrix.setRotate(90) 进行旋转</p>    <h2>2.Camera2</h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/58e60406b9c26cec09eb1b42d87c9a08.png"></p>    <p style="text-align:center">Camera2拍照示意图</p>    <p>这里引用了管道的概念将安卓设备和摄像头之间联通起来,系统向摄像头发送 Capture 请求,而摄像头会返回 CameraMetadata。这一切建立在一个叫作 CameraCaptureSession 的会话中。</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/307f3aeb93c6f241f27b47fd493dd7fe.png"></p>    <p style="text-align:center">camera2中主要的类</p>    <ul>     <li>CameraManaer 摄像头管理器,用于检测摄像头,打开系统摄像头,调用 CameraManager.getCameraCharacteristics(String) 可以获取指定摄像头的相关特性</li>     <li>CameraCharacteristics 摄像头的特性</li>     <li>CameraDevice 摄像头,类似 android.hardware.Camera 也就是 Camera1 的 Camera</li>     <li>CameraCaptureSession 这个对象控制摄像头的预览或者拍照, setRepeatingRequest() 开启预览, capture() 拍照, CameraCaptureSession 提供了StateCallback、CaptureCallback两个接口来监听 CameraCaptureSession 的创建和拍照过程。</li>     <li>CameraRequest和CameraRequest.Builder,预览或者拍照时,都需要一个 CameraRequest 对象。CameraRequest表示一次捕获请求,用来对z照片的各种参数设置,比如对焦模式、曝光模式等。CameraRequest.Builder用来生成CameraRequest对象。</li>    </ul>    <h2>2.1 简单使用</h2>    <p>使用的依然是 SurfaceView 来进行展示预览</p>    <p>主要思路:</p>    <ol>     <li>获得摄像头管理器 CameraManager mCameraManager , mCameraManager.openCamera() 来打开摄像头</li>     <li>指定要打开的摄像头,并创建 openCamera() 所需要的 CameraDevice.StateCallback stateCallback</li>     <li>在 CameraDevice.StateCallback stateCallback 中调用 takePreview() ,这个方法中,使用 CaptureRequest.Builder 创建预览需要的 CameraRequest ,并初始化了 CameraCaptureSession ,最后调用了 setRepeatingRequest(previewRequest, null, childHandler) 进行了预览</li>     <li>点击屏幕,调用 takePicture() ,这个方法内,最终调用了 capture(mCaptureRequest, null, childHandler)</li>     <li>在 new ImageReader.OnImageAvailableListener(){} 回调方法中,将拍照拿到的图片进行展示</li>    </ol>    <p>代码:</p>    <pre>  <code class="language-java">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();          }      }  }</code></pre>    <p>布局代码以及权限与 Camera1 中一样,效果一样</p>    <p>预览时,是将 mSurfaceHolder.getSurface() 作为目标</p>    <p>显示拍照结果时,是将 mImageReader.getSurface() 作为目标</p>    <h2>3.最后</h2>    <p>Camera2 的功能很强大,暂时也只是学习了最基本的思路</p>    <p> </p>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/7f766eb2f4e7</p>    <p> </p>