现在的位置: 首页 > 综合 > 正文

本讲内容:Android手机摄像头编程入门

2018年04月18日 ⁄ 综合 ⁄ 共 7479字 ⁄ 字号 评论关闭

本讲内容:Android手机摄像头编程入门

智能手机中的摄像头和普通手机中的摄像头最大的区别在于,智能机上的摄像头可以由程序员写程序控制,做一些有趣的应用譬如,画中画,做一些有用的应用譬如二维码识别,等等。本讲打算通过一个实例,来介绍一下摄像头编程,相关解释都写在代码中了,请注意看代码注释。

实例:窈窈照相机,功能很简单,就是点击程序弹出照相预览界面,点击相机按钮完成照相功能,所照相片会存储在手机存储卡根目录。

1、创建一个项目 Lesson36_Camera ,主程序文件为 MainActivity.java

2、AndroidManifest.xml 中设置屏幕为横屏,并且声明摄像头和存储卡的使用权限,具体代码如下:

01 <?xml
version=
"1.0" encoding="utf-8"?>
02 <manifest package="basic.android.lesson36"xmlns:android="http://schemas.android.com/apk/res/android"android:versioncode="1" android:versionname="1.0">
03     <application
android:label=
"@string/app_name"android:icon="@drawable/icon">
04         <activity
android:label=
"@string/app_name"android:name=".MainActivity" android:screenorientation="landscape"android:configchanges="orientation|keyboardHidden|keyboard">
05             <intent
-filter=
"">
06                 <action
android:name=
"android.intent.action.MAIN">
07                 <category
android:name=
"android.intent.category.LAUNCHER">
08             </category></action></intent>
09         </activity>
10  
11     </application>
12     <uses
-sdk=
"" android:minsdkversion="8">
13     <uses
-permission=
"" android:name="android.permission.CAMERA"></uses>
14     <uses
-permission=
""android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses>
15     <uses
-feature=
"" android:name="android.hardware.camera">
16     <uses
-feature=
"" android:name="android.hardware.camera.autofocus">
17 </uses></uses></uses></manifest>

3、本例中不需要布局文件main.xml,因为本例中的UI组建都是动态添加上去的。

4、最后MainActivity.java的代码如下:

001 package basic.android.lesson36;
002  
003 import java.io.BufferedOutputStream;
004 import java.io.File;
005 import java.io.FileOutputStream;
006 import java.io.IOException;
007 import java.util.Calendar;
008 import java.util.Locale;
009  
010 import android.app.Activity;
011 import android.content.Context;
012 import android.graphics.Bitmap;
013 import android.graphics.BitmapFactory;
014 import android.graphics.PixelFormat;
015 import android.hardware.Camera;
016 import android.os.Bundle;
017 import android.text.format.DateFormat;
018 import android.util.Log;
019 import android.view.KeyEvent;
020 import android.view.SurfaceHolder;
021 import android.view.SurfaceView;
022 import android.view.Window;
023 import android.view.WindowManager;
024 import android.widget.FrameLayout;
025 import android.widget.TextView;
026 import android.widget.Toast;
027  
028 public class MainActivity extends Activity
{
029  
030     private CameraView
cv;
031     //准备一个相机对象
032     private Camera
mCamera = 
null;
033     //准备一个Bitmap对象
034     private Bitmap
mBitmap = 
null
035  
036     //准备一个保存图片的PictureCallback对象
037     public Camera.PictureCallback
pictureCallback = 
newCamera.PictureCallback()
{
038  
039         public void onPictureTaken(byte[]
data, Camera camera) {
040             Log.i("yao","onPictureTaken");
041             Toast.makeText(getApplicationContext(), "正在保存……",
Toast.LENGTH_LONG).show();
042             //用BitmapFactory.decodeByteArray()方法可以把相机传回的裸数据转换成Bitmap对象
043             mBitmap
= BitmapFactory.decodeByteArray(data, 
0,
data.length);
044             //接下来的工作就是把Bitmap保存成一个存储卡中的文件
045             File
file = 
new File("/sdcard/YY"newDateFormat().format("yyyyMMdd_hhmmss",
Calendar.getInstance(Locale.CHINA)) +
".jpg");
046             try {
047                 file.createNewFile();
048                 BufferedOutputStream
os = 
new BufferedOutputStream(newFileOutputStream(file));
049                 mBitmap.compress(Bitmap.CompressFormat.PNG, 100,
os);
050                 os.flush();
051                 os.close();
052                 Toast.makeText(getApplicationContext(), "图片保存完毕,在存储卡的根目录",
Toast.LENGTH_LONG).show();
053             catch (IOException
e) {
054                 e.printStackTrace();
055             }
056         }
057  
058     };
059  
060     //Activity的创建方法
061     @Override
062     public void onCreate(Bundle
savedInstanceState) {
063         super.onCreate(savedInstanceState);
064  
065         //窗口去掉标题
066         requestWindowFeature(Window.FEATURE_NO_TITLE);
067         //窗口设置为全屏
068         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);
069         //设置窗口为半透明
070         getWindow().setFormat(PixelFormat.TRANSLUCENT);
071  
072         //提供一个帧布局
073         FrameLayout 
fl = 
new FrameLayout(this);     
074  
075         //创建一个照相预览用的SurfaceView子类,并放在帧布局的底层
076         cv
new CameraView(this);
077         fl.addView(cv);
078  
079         //创建一个文本框添加在帧布局中,我们可以看到,文字自动出现在了SurfaceView的前面,由此你可以在预览窗口做出各种特殊效果
080         TextView
tv = 
new TextView(this);
081         tv.setText("请按\"相机\"按钮拍摄");
082         fl.addView(tv);
083  
084         //设置Activity的根内容视图
085         setContentView(fl);
086  
087     }
088  
089     //相机按键按下的事件处理方法
090     public boolean onKeyDown(int keyCode,
KeyEvent event) {
091         Log.i("yao","MainActivity.onKeyDown");
092         if (keyCode
== KeyEvent.KEYCODE_CAMERA) {
093             if (mCamera
!= 
null)
{
094                 Log.i("yao","mCamera.takePicture");
095                 //当按下相机按钮时,执行相机对象的takePicture()方法,该方法有三个回调对象做入参,不需要的时候可以设null
096                 mCamera.takePicture(nullnull,
pictureCallback);
097             }
098         }
099         return cv.onKeyDown(keyCode,
event);
100     }
101  
102     //
照相视图
103     class CameraView extends SurfaceView
{
104  
105         private SurfaceHolder
holder = 
null;
106  
107         //构造函数
108         public CameraView(Context
context) {
109             super(context);
110             Log.i("yao","CameraView");
111  
112             //
操作surface的holder
113             holder
this.getHolder();
114             //
创建SurfaceHolder.Callback对象
115             holder.addCallback(new SurfaceHolder.Callback()
{
116  
117                 @Override
118                 public void surfaceDestroyed(SurfaceHolder
holder) {
119                     //
停止预览
120                     mCamera.stopPreview();
121                     //
释放相机资源并置空
122                     mCamera.release();
123                     mCamera
null;
124                 }
125  
126                 @Override
127                 public void surfaceCreated(SurfaceHolder
holder) {
128                     //当预览视图创建的时候开启相机
129                     mCamera
= Camera.open();
130                     try {
131                         //设置预览
132                         mCamera.setPreviewDisplay(holder);
133                     catch (IOException
e) {
134                         //
释放相机资源并置空
135                         mCamera.release();
136                         mCamera
null;
137                     }
138  
139                 }
140  
141                 //当surface视图数据发生变化时,处理预览信息
142                 @Override
143                 public void surfaceChanged(SurfaceHolder
holder, 
int format,int width, int height)
{
144  
145                     //获得相机参数对象
146                     Camera.Parameters
parameters = mCamera.getParameters();
147                     //设置格式
148                     parameters.setPictureFormat(PixelFormat.JPEG);
149                     //设置预览大小,这里我的测试机是Milsstone所以设置的是854x480
150                     parameters.setPreviewSize(854480);
151                     //设置自动对焦
152                     parameters.setFocusMode("auto");
153                     //设置图片保存时的分辨率大小
154                     parameters.setPictureSize(25921456);
155                     //给相机对象设置刚才设定的参数
156                     mCamera.setParameters(parameters);
157                     //开始预览
158                     mCamera.startPreview();
159                 }
160             });
161             //
设置Push缓冲类型,说明surface数据由其他来源提供,而不是用自己的Canvas来绘图,在这里是由摄像头来提供数据
162             holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
163         }
164  
165     }
166  
167 }

5、连接Milestone,编译并运行程序:悲剧的是,截图只能看到黑黑的一片,无法截取到摄像头传输过来SurfaceView信息,而在真机中是能看到预览效果的。

device

还是上一张照好的图片给大家吧,(用了好多年的小黑……)

YY20101208_030141

好了,本讲就到这里,谢谢大家的支持和鼓励,下次再见。

 

抱歉!评论已关闭.