• OPhone Camera教程 如何在程序中使用照相机


    在本教程中将介绍如何在程序中使用OPhone手机的摄像头来拍照,有些程序是需要使用手机摄像头作为输入设备的,例如二维码识别软件。

    OPhone Camera 介绍

    在OPhone手机中通过android.hardware.Camera类来控制摄像头设备,通过Camera类可以与摄像头服务取得(断开)链接、可以设置摄像头的各种属性、开始(结束)图像预览、拍照或则录像。要使用Camera只有通过调用Camera的open() 函数来得到一个Camera对象。另外OPhone系统还提供了一些接口来控制Camera的状态:

    • android.hardware.Camera.AutoFocusCallback :当摄像头自动对焦的时候调用,该接口具有一个函数 voidonAutoFocus(boolean success, Camera camera);当自动对焦成功的时候success参数的值为true,否则为false。
    • android.hardware.Camera.ErrorCallback :当摄像头出错的时候调用,该接口具有一个函数 void onError(interror, Camera camera); 参数error为错误类型,其取值为Camera类中的常量CAMERA_ERROR_UNKNOWNCAMERA_ERROR_SERVER_DIED;前者表明错误类型不明确,后者表明服务已关闭,在这种情况下必须释放当前的Camera对象然后重新初始化一个。
    • android.hardware.Camera.PreviewCallback :在图像预览时候调用,该接口具有一个函数voidonPreviewFrame(byte[] data, Camera camera); 参数data为每帧图像的数据流。
    • android.hardware.Camera.ShutterCallback :当摄像头快门关闭的时候调用,该接口具有一个函数voidonShutter(); 可以在该函数中通知用户快门已关闭,例如播放一个声音。
    • android.hardware.Camera.PictureCallback :当拍摄照片的时候调用,该接口具有一个函数voidonPictureTaken(byte[] data, Camera camera); 参数data为拍摄照片的数据流。

    当取得照片的数据流后可以通过BitmapFactory的 decodeByteArray() 函数来解析图片。

    另外还可以通过Camera对象的getParameters()函数得到一个android.hardware.Camera.Parameters对象,Parameters提供了一些接口来设置Camera的属性:

    • setPictureFormat(int pixel_format):设置图片的格式,其取值为PixelFormat.YCbCr_420_SP、PixelFormat.RGB_565或则PixelFormat.JPEG。
    • setPreviewFormat(int pixel_format):设置图片预览的格式,取值同上。
    • setPictureSize(int width, int height):设置图片的高度和宽度,单位为像素。
    • setPreviewSize(int width, int height):设置图片预览的高度和宽度,取值同上。
    • setPreviewFrameRate(int fps):设置图片预览的帧速。

    在设置好Camera的参数后,可以通过函数void startPreview()开始预览图像、void stopPreview()结束预览,通过autoFocus(AutoFocusCallback cb)来自动对焦,最后可以通过takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)函数来拍照。该函数有三个参数,分别为快门回调接口、原生图像数据接口和压缩格式图片数据接口。如果数据格式不存在的话数据流为空,如果不需要实现这些接口则这些参数取值可以为null。

    以上就是关于OPhone Camera的基础知识和相关的API介绍,下面来具体看看如何在程序中拍照并使用照片。

    OPhone Camera 实战

    这个示例将显示预览图像,在图像上点击则触发拍照操作,拍照成功后显示所拍的照片,然后点击Start菜单可以继续拍照。

    首先通过OPhone开发工具(ODT)创建一个OPhone项目,填写基本信息后ODT会自动创建一个/src/org/goodev/camera/CameraActivity.java文件和res/layout/main.xml文件。

    把main.xml文件内容修改为如下:

    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:orientation="vertical"  
    4.     android:layout_width="fill_parent"  
    5.     android:layout_height="fill_parent"  
    6.     >  
    7.     <SurfaceView android:id="@+id/camera"  
    8.         android:layout_width="fill_parent"  
    9.         android:layout_height="fill_parent"/>  
    10.     <ImageView android:id="@+id/image"  
    11.         android:layout_width="fill_parent"  
    12.         android:layout_height="fill_parent"/>  
    13. </LinearLayout>  

    SurfaceView 用来预览图像,ImageView 用来显示所拍的照片。这里也需读者会问,为什么要使用SurfaceView 来预览图像?使用其他的View不可以吗?要回答这个问题,需要了解下SurfaceView 的作用,关于SurfaceView 的详细介绍已超出了本教程的范围,我们会在后续教程中来详细介绍SurfaceView ,这里只做简要介绍。

    在通常情况下,OPhone程序中的View都是在同一个GUI线程中绘制的,该线程也是接收用户交互事件的线程(例如:按钮点击事件)。从另外的线程修改GUI元素是不可以的,如果要迅速的更新UI显示该如何办?显然在主线程中还需要处理其他事件,不适合做这件事情,所以OPhone提供了SurfaceView 来满足这种需求。一个SurfaceView 包装一个Surface对象(通过SurfaceHolder操作该对象)而不是Canvas对象,这就是关键所在,Surface可以在其他线程中绘制,这对于周期性更新和要求高帧率的场景来说是很有用的,特别是在游戏开发中。Surface中包含了当前UI的原生数据(raw data),在不同的软件和硬件条件下对这些数据的处理是不一样的,这就可以通过一些设置来加速图形的绘制,可以通过SurfaceHolder的setType函数来设置,目前接收如下的参数:

    • SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
    • SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
    • SURFACE_TYPE_GPU:适用于GPU加速的Surface
    • SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果在这里设置了上面三种类型则可以发现不会出现预览图像,在和Camera底层的预览机制实现有关,如果对预览有特殊要求的可以现实PreviewCallback 接口来自己处理。

    关于SurfaceView先简单介绍到这里,下面来继续看看如何在代码中实现。

    修改CameraActivity类使其实现如下接口:

    1. android.view.SurfaceHolder.Callback  
    2. android.view.View.OnClickListener  

     在CameraActivity的onCreate函数中初始化相关资源:

    1. public void onCreate(Bundle savedInstanceState) {  
    2.         super.onCreate(savedInstanceState);  
    3.   
    4.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
    5.         getWindow().setFormat(PixelFormat.TRANSLUCENT);  
    6.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
    7.         WindowManager.LayoutParams.FLAG_FULLSCREEN);  
    8.         setContentView(R.layout.main);  
    9.         mSurfaceView = (SurfaceView) findViewById(R.id.camera);  
    10.         mImageView = (ImageView) findViewById(R.id.image);  
    11.         mImageView.setVisibility(View.GONE);  
    12.   
    13.         mSurfaceView.setOnClickListener(this);  
    14.         mSurfaceHolder = mSurfaceView.getHolder();  
    15.         mSurfaceHolder.addCallback(this);  
    16.         mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  

    上面的代码首先设置窗口为全屏幕无标题的窗口,然后取得SurfaceView和ImageView对象并设置mSurfaceView的OnClickListener和mSurfaceHolder 的回调函数,最后设置mSurfaceHolder的类型为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS

    当surface创建后初始化Camera对象,代码如下:

    1. public void surfaceCreated(SurfaceHolder holder) {  
    2.         mCamera = Camera.open();  
    3.     }  

    当surface摧毁的时候释放Camera对象,代码如下:

    1. public void surfaceDestroyed(SurfaceHolder holder) {  
    2.         mCamera.stopPreview();  
    3.         mPreviewRunning = false;  
    4.         mCamera.release();  
    5.         mCamera = null;  
    6.     }  

    当surface状态改变的时候,重置Camera的状态,代码如下:

    1. public void surfaceChanged(SurfaceHolder holder, int format, int width,  
    2.             int height) {  
    3.         if (mPreviewRunning) {  
    4.             mCamera.stopPreview();  
    5.         }  
    6.         Parameters params = mCamera.getParameters();  
    7.         params.setPreviewSize(width, height);  
    8.         mCamera.setParameters(params);  
    9.   
    10.         try {  
    11.             mCamera.setPreviewDisplay(holder);  
    12.         } catch (IOException e) {  
    13.             e.printStackTrace();  
    14.         }  
    15.         mCamera.startPreview();  
    16.         mPreviewRunning = true;  
    17.     }  

    当在surface上点击的时候拍照,代码如下:

    1. public void onClick(View v) {  
    2.     mCamera.takePicture(mShutterCallback, null, mPictureCallback);  
    3. }  

    在mPictureCallback中读取所拍的照片并显示:

    1. PictureCallback mPictureCallback = new PictureCallback() {  
    2.   
    3.         public void onPictureTaken(byte[] data, Camera camera) {  
    4.             Log.d("PictureCallback""...onPictureTaken...");  
    5.             if (data != null) {  
    6.             Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,  
    7.                         data.length);  
    8.                 mImageView.setImageBitmap(bitmap);  
    9.                 mImageView.setVisibility(View.VISIBLE);  
    10.                 mSurfaceView.setVisibility(View.GONE);  
    11.                 if (mPreviewRunning) {  
    12.                     mCamera.stopPreview();  
    13.                     mPreviewRunning = false;  
    14.                 }  
    15.             }  
    16.         }  
    17.   
    18. };  

    最后不要忘记使用Camera是需要权限的,在AndroidManifest.xml文件中添加如下设置:

    1. <uses-permission android:name="android.permission.CAMERA"/>  

    总结:通过以上示例程序可以看出在OPhone中使用设备的Camera是相当简单的,现在你就可以通过Camera来实现各种新奇的应用了,是否已经想跃跃欲试了?那就开始吧!

    附录:CameraActivity完整代码
    1. package org.goodev.camera;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. import android.app.Activity;  
    6. import android.graphics.Bitmap;  
    7. import android.graphics.BitmapFactory;  
    8. import android.graphics.PixelFormat;  
    9. import android.hardware.Camera;  
    10. import android.hardware.Camera.Parameters;  
    11. import android.hardware.Camera.PictureCallback;  
    12. import android.hardware.Camera.ShutterCallback;  
    13. import android.os.Bundle;  
    14. import android.util.Log;  
    15. import android.view.Menu;  
    16. import android.view.MenuItem;  
    17. import android.view.SurfaceHolder;  
    18. import android.view.SurfaceView;  
    19. import android.view.View;  
    20. import android.view.Window;  
    21. import android.view.WindowManager;  
    22. import android.view.SurfaceHolder.Callback;  
    23. import android.view.View.OnClickListener;  
    24. import android.widget.ImageView;  
    25.   
    26. public class CameraActivity extends Activity   
    27.     implements Callback, OnClickListener {  
    28.   
    29.     private static final int MENU_START = 1;  
    30.     private SurfaceView mSurfaceView;  
    31.     private SurfaceHolder mSurfaceHolder;  
    32.     private Camera mCamera;  
    33.     private boolean mPreviewRunning;  
    34.   
    35.     private ImageView mImageView;  
    36.   
    37.     /** 
    38.      * 拍照的回调接口 
    39.      */  
    40.     PictureCallback mPictureCallback = new PictureCallback() {  
    41.   
    42.         public void onPictureTaken(byte[] data, Camera camera) {  
    43.             Log.d("PictureCallback""...onPictureTaken...");  
    44.             if (data != null) {  
    45.                 Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,  
    46.                         data.length);  
    47.                 mImageView.setImageBitmap(bitmap);  
    48.                 mImageView.setVisibility(View.VISIBLE);  
    49.                 mSurfaceView.setVisibility(View.GONE);  
    50.                 if (mPreviewRunning) {  
    51.                     mCamera.stopPreview();  
    52.                     mPreviewRunning = false;  
    53.                 }  
    54.             }  
    55.         }  
    56.   
    57.     };  
    58.     /** 
    59.      * 在相机快门关闭时候的回调接口,通过这个接口来通知用户快门关闭的事件, 
    60.      * 普通相机在快门关闭的时候都会发出响声,根据需要可以在该回调接口中定义各种动作, 
    61.      * 例如:使设备震动 
    62.      */  
    63.     ShutterCallback mShutterCallback = new ShutterCallback() {  
    64.   
    65.         public void onShutter() {  
    66.             //just log ,do nothing  
    67.             Log.d("ShutterCallback""...onShutter...");  
    68.         }  
    69.   
    70.     };  
    71.   
    72.     /** Called when the activity is first created. */  
    73.     @Override  
    74.     public void onCreate(Bundle savedInstanceState) {  
    75.         super.onCreate(savedInstanceState);  
    76.   
    77.         requestWindowFeature(Window.FEATURE_NO_TITLE);  
    78.         getWindow().setFormat(PixelFormat.TRANSLUCENT);  
    79.         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,  
    80.         WindowManager.LayoutParams.FLAG_FULLSCREEN);  
    81.         setContentView(R.layout.main);  
    82.         mSurfaceView = (SurfaceView) findViewById(R.id.camera);  
    83.         mImageView = (ImageView) findViewById(R.id.image);  
    84.         mImageView.setVisibility(View.GONE);  
    85.   
    86.         mSurfaceView.setOnClickListener(this);  
    87.         mSurfaceHolder = mSurfaceView.getHolder();  
    88.         mSurfaceHolder.addCallback(this);  
    89.         mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
    90.   
    91.     }  
    92.   
    93.     @Override  
    94.     public boolean onCreateOptionsMenu(Menu menu) {  
    95.         super.onCreateOptionsMenu(menu);  
    96.         menu.add(0, MENU_START, 0, R.string.menu_start);  
    97.         return true;  
    98.     }  
    99.   
    100.     @Override  
    101.     public boolean onOptionsItemSelected(MenuItem item) {  
    102.         if (item.getItemId() == MENU_START) {  
    103.             mImageView.setVisibility(View.GONE);  
    104.             mSurfaceView.setVisibility(View.VISIBLE);  
    105.             if (mPreviewRunning) {  
    106.                 mCamera.stopPreview();  
    107.             }  
    108.             mCamera.startPreview();  
    109.             mPreviewRunning = true;  
    110.             return true;  
    111.         }  
    112.         return super.onOptionsItemSelected(item);  
    113.     }  
    114.   
    115.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
    116.             int height) {  
    117.         if (mPreviewRunning) {  
    118.             mCamera.stopPreview();  
    119.         }  
    120.         Parameters params = mCamera.getParameters();  
    121.         params.setPreviewSize(width, height);  
    122.         mCamera.setParameters(params);  
    123.   
    124.         try {  
    125.             mCamera.setPreviewDisplay(holder);  
    126.         } catch (IOException e) {  
    127.             e.printStackTrace();  
    128.         }  
    129.         mCamera.startPreview();  
    130.         mPreviewRunning = true;  
    131.     }  
    132.   
    133.     public void surfaceCreated(SurfaceHolder holder) {  
    134.         mCamera = Camera.open();  
    135.     }  
    136.   
    137.     public void surfaceDestroyed(SurfaceHolder holder) {  
    138.         mCamera.stopPreview();  
    139.         mPreviewRunning = false;  
    140.         mCamera.release();  
    141.         mCamera = null;  
    142.     }  
    143.   
    144.     public void onClick(View v) {  
    145.         mCamera.takePicture(mShutterCallback, null, mPictureCallback);  
    146.     }  
    147. }  

  • 相关阅读:
    在数值中加入千位分隔符的方法
    用 Javascript 验证表单(form)中的单选(radio)值
    用 Javascript 验证表单(form)中多选框(checkbox)值
    用 CSS 实现图片替换文字(Image replacement)
    计算机技术分类
    最近好乱acm与数模时间重复了
    memcached Telnet Interface
    event_new
    event_base_loop
    event_base_loop
  • 原文地址:https://www.cnblogs.com/xyzlmn/p/3168232.html
Copyright © 2020-2023  润新知