1. 程式人生 > >2013新春奉送:Android攝像頭開發完美demo---(迴圈聚焦,縮放大小,旋轉picture,查詢支援的picturesize, ImageButton按鍵效果)

2013新春奉送:Android攝像頭開發完美demo---(迴圈聚焦,縮放大小,旋轉picture,查詢支援的picturesize, ImageButton按鍵效果)

補充:我已在對此程式碼進行了全面的升級,升級後代碼結構更加利於維護擴充套件,全面適配所有手機,參見博文。此文中的資源也不要再下載了,請下載升級後的程式碼,如有問題請留言反饋,謝謝。---------------------------2014-6-23】  

【後注:】下載程式碼的注意,我的手機是4.3寸的屏,華為U9200.如果不能執行的請修改引數。看本篇的第四條。

     這個程式碼幾乎涉及到了攝像頭開發的所有方面,(除了PreviewCallback,這塊東西我會結合android攝像頭自動識別人臉/火災來談),且力求精簡,是雜家的心血阿!相對之前改進之處有:

1,精簡。只有一個ImageButton用來實現按下拍照。拍照後自動儲存,進入預覽介面。 不像原來的要三個按鍵:預覽/拍照/儲存。

2,聚焦方面實現不間斷迴圈聚焦。 不像之前的,要按一下按鍵聚焦一次。

3,ImageButton增加了按下的效果。按之前示例如下:,點選後背景變暗,有種風車旋轉的感覺。

4,增加了查詢攝像頭PictureSizes和PreviewSize的程式碼,除錯程式時應先查詢出自己的引數然後配置。不同的手機引數不同。另外,預覽surfaceView的高我設為800px,如果手機螢幕太小,這個引數要改。

5,改進了之前的按back返回按鍵退出程式後,再次進入程式camera沒有釋放,致使程式掛掉的問題。

6,改進了預覽時手機橫豎屏切換時,程式掛掉的毛病。但這裡的佈局還是採用預設的豎屏。

7,在實現迴圈聚焦的同時,保留了autoFocus()介面。可以測試出,在使用

FOCUS_MODE_CONTINUOUS_VIDEO聚焦模式下,autoFocus不發揮作用。如果不支援不間斷聚焦,setFocusMode就改成FOCUS_MODE_AUTO!!!

8,註釋更加良好。

廢話不說了請看原始碼:

第一部分:Manifinest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="yan.guoqi.rectphoto"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />
    <!-- 增加檔案儲存和訪問攝像頭的許可權 -->
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".RectPhoto"
            android:label="@string/title_activity_rect_photo" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
第二部分:佈局檔案
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/BestWish"
        tools:context=".RectPhoto" />

    <FrameLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <SurfaceView
            android:id="@+id/previewSV"
            android:layout_width="fill_parent"
            android:layout_height="800px" />
    </FrameLayout>

    <ImageButton
        android:id="@+id/photoImgBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/photo_img_btn"
        android:layout_gravity="center" />

</LinearLayout>
第三部分:RectPhoto.java主程式
 package yan.guoqi.rectphoto;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;

public class RectPhoto extends Activity implements SurfaceHolder.Callback{
	private static final String tag="yan";
	private boolean isPreview = false;
	private SurfaceView mPreviewSV = null; //預覽SurfaceView
	private SurfaceHolder mySurfaceHolder = null;
	private ImageButton mPhotoImgBtn = null;
	private Camera myCamera = null;
	private Bitmap mBitmap = null;
	private AutoFocusCallback myAutoFocusCallback = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//設定全屏無標題
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
		Window myWindow = this.getWindow();
		myWindow.setFlags(flag, flag);

		setContentView(R.layout.activity_rect_photo);

		//初始化SurfaceView
		mPreviewSV = (SurfaceView)findViewById(R.id.previewSV);
		mySurfaceHolder = mPreviewSV.getHolder();
		mySurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);//translucent半透明 transparent透明
		mySurfaceHolder.addCallback(this);
		mySurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

		//自動聚焦變量回調
		myAutoFocusCallback = new AutoFocusCallback() {

			public void onAutoFocus(boolean success, Camera camera) {
				// TODO Auto-generated method stub
				if(success)//success表示對焦成功
				{
					Log.i(tag, "myAutoFocusCallback: success...");
					//myCamera.setOneShotPreviewCallback(null);

				}
				else
				{
					//未對焦成功
					Log.i(tag, "myAutoFocusCallback: 失敗了...");

				}


			}
		};

		mPhotoImgBtn = (ImageButton)findViewById(R.id.photoImgBtn);
		//手動設定拍照ImageButton的大小為120×120,原圖片大小是64×64
		LayoutParams lp = mPhotoImgBtn.getLayoutParams();
		lp.width = 120;
		lp.height = 120;		
		mPhotoImgBtn.setLayoutParams(lp);				
		mPhotoImgBtn.setOnClickListener(new PhotoOnClickListener());
		mPhotoImgBtn.setOnTouchListener(new MyOnTouchListener());


	}


	/*下面三個是SurfaceHolder.Callback建立的回撥函式*/
	public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) 
	// 當SurfaceView/預覽介面的格式和大小發生改變時,該方法被呼叫
	{
		// TODO Auto-generated method stub		
		Log.i(tag, "SurfaceHolder.Callback:surfaceChanged!");
		initCamera();

	}


	public void surfaceCreated(SurfaceHolder holder) 
	// SurfaceView啟動時/初次例項化,預覽介面被建立時,該方法被呼叫。
	{
		// TODO Auto-generated method stub		
		myCamera = Camera.open();
		try {
			myCamera.setPreviewDisplay(mySurfaceHolder);
			Log.i(tag, "SurfaceHolder.Callback: surfaceCreated!");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			if(null != myCamera){
				myCamera.release();
				myCamera = null;
			}
			e.printStackTrace();
		}



	}


	public void surfaceDestroyed(SurfaceHolder holder) 
	//銷燬時被呼叫
	{
		// TODO Auto-generated method stub
		Log.i(tag, "SurfaceHolder.Callback:Surface Destroyed");
		if(null != myCamera)
		{
			myCamera.setPreviewCallback(null); /*在啟動PreviewCallback時這個必須在前不然退出出錯。
			這裡實際上註釋掉也沒關係*/
			
			myCamera.stopPreview(); 
			isPreview = false; 
			myCamera.release();
			myCamera = null;     
		}

	}

	//初始化相機
	public void initCamera(){
		if(isPreview){
			myCamera.stopPreview();
		}
		if(null != myCamera){			
			Camera.Parameters myParam = myCamera.getParameters();
			//			//查詢螢幕的寬和高
			//			WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
			//			Display display = wm.getDefaultDisplay();
			//			Log.i(tag, "螢幕寬度:"+display.getWidth()+" 螢幕高度:"+display.getHeight());

			myParam.setPictureFormat(PixelFormat.JPEG);//設定拍照後儲存的圖片格式

			//			//查詢camera支援的picturesize和previewsize
			//			List<Size> pictureSizes = myParam.getSupportedPictureSizes();
			//			List<Size> previewSizes = myParam.getSupportedPreviewSizes();
			//			for(int i=0; i<pictureSizes.size(); i++){
			//				Size size = pictureSizes.get(i);
			//				Log.i(tag, "initCamera:攝像頭支援的pictureSizes: width = "+size.width+"height = "+size.height);
			//			}
			//			for(int i=0; i<previewSizes.size(); i++){
			//				Size size = previewSizes.get(i);
			//				Log.i(tag, "initCamera:攝像頭支援的previewSizes: width = "+size.width+"height = "+size.height);
			//
			//			}


			//設定大小和方向等引數
			myParam.setPictureSize(1280, 960);
			myParam.setPreviewSize(960, 720);			
			//myParam.set("rotation", 90);  			
			myCamera.setDisplayOrientation(90);  
			myParam.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
			myCamera.setParameters(myParam);			
			myCamera.startPreview();
			myCamera.autoFocus(myAutoFocusCallback);
			isPreview = true;
		}
	}

	/*為了實現拍照的快門聲音及拍照儲存照片需要下面三個回撥變數*/
	ShutterCallback myShutterCallback = new ShutterCallback() 
	//快門按下的回撥,在這裡我們可以設定類似播放“咔嚓”聲之類的操作。預設的就是咔嚓。
	{

		public void onShutter() {
			// TODO Auto-generated method stub
			Log.i(tag, "myShutterCallback:onShutter...");

		}
	};
	PictureCallback myRawCallback = new PictureCallback() 
	// 拍攝的未壓縮原資料的回撥,可以為null
	{

		public void onPictureTaken(byte[] data, Camera camera) {
			// TODO Auto-generated method stub
			Log.i(tag, "myRawCallback:onPictureTaken...");

		}
	};
	PictureCallback myJpegCallback = new PictureCallback() 
	//對jpeg影象資料的回撥,最重要的一個回撥
	{

		public void onPictureTaken(byte[] data, Camera camera) {
			// TODO Auto-generated method stub
			Log.i(tag, "myJpegCallback:onPictureTaken...");
			if(null != data){
				mBitmap = BitmapFactory.decodeByteArray(data, 0, data.length);//data是位元組資料,將其解析成點陣圖
				myCamera.stopPreview();
				isPreview = false;
			}
			//設定FOCUS_MODE_CONTINUOUS_VIDEO)之後,myParam.set("rotation", 90)失效。圖片竟然不能旋轉了,故這裡要旋轉下
			Matrix matrix = new Matrix();
			matrix.postRotate((float)90.0);
			Bitmap rotaBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap.getWidth(), mBitmap.getHeight(), matrix, false);
			//儲存圖片到sdcard
			if(null != rotaBitmap)
			{
				saveJpeg(rotaBitmap);
			}

			//再次進入預覽
			myCamera.startPreview();
			isPreview = true;
		}
	};
	//拍照按鍵的監聽
	public class PhotoOnClickListener implements OnClickListener{

		public void onClick(View v) {
			// TODO Auto-generated method stub
			if(isPreview && myCamera!=null){
				myCamera.takePicture(myShutterCallback, null, myJpegCallback);	
			}

		}

	}
	/*給定一個Bitmap,進行儲存*/
	public void saveJpeg(Bitmap bm){
		String savePath = "/mnt/sdcard/rectPhoto/";
		File folder = new File(savePath);
		if(!folder.exists()) //如果資料夾不存在則建立
		{
			folder.mkdir();
		}
		long dataTake = System.currentTimeMillis();
		String jpegName = savePath + dataTake +".jpg";
		Log.i(tag, "saveJpeg:jpegName--" + jpegName);
		//File jpegFile = new File(jpegName);
		try {
			FileOutputStream fout = new FileOutputStream(jpegName);
			BufferedOutputStream bos = new BufferedOutputStream(fout);

			//			//如果需要改變大小(預設的是寬960×高1280),如改成寬600×高800
			//			Bitmap newBM = bm.createScaledBitmap(bm, 600, 800, false);

			bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);
			bos.flush();
			bos.close();
			Log.i(tag, "saveJpeg:儲存完畢!");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			Log.i(tag, "saveJpeg:儲存失敗!");
			e.printStackTrace();
		}
	}

	/*為了使圖片按鈕按下和彈起狀態不同,採用過濾顏色的方法.按下的時候讓圖片顏色變淡*/
	public class MyOnTouchListener implements OnTouchListener{

		public final  float[] BT_SELECTED=new float[]
				{ 2, 0, 0, 0, 2,
			0, 2, 0, 0, 2,
			0, 0, 2, 0, 2,
			0, 0, 0, 1, 0 };			    

		public final float[] BT_NOT_SELECTED=new float[]
				{ 1, 0, 0, 0, 0,
			0, 1, 0, 0, 0,
			0, 0, 1, 0, 0,
			0, 0, 0, 1, 0 };
		public boolean onTouch(View v, MotionEvent event) {
			// TODO Auto-generated method stub
			if(event.getAction() == MotionEvent.ACTION_DOWN){
				v.getBackground().setColorFilter(new ColorMatrixColorFilter(BT_SELECTED));
				v.setBackgroundDrawable(v.getBackground());
			}
			else if(event.getAction() == MotionEvent.ACTION_UP){
				v.getBackground().setColorFilter(new ColorMatrixColorFilter(BT_NOT_SELECTED));
				v.setBackgroundDrawable(v.getBackground());
				
			}
			return false;
		}

	}
	
	@Override
	public void onBackPressed()
	//無意中按返回鍵時要釋放記憶體
	{
		// TODO Auto-generated method stub
		super.onBackPressed();
		RectPhoto.this.finish();
	}
}

歡迎android愛好者加群248217350,備註:yanzi

注:程式碼不能正常執行的請看上面第4條,修改相關引數。
----------------------------------------------------------------------------------------本文系原創,轉載請註明作者:yanzi1225627


相關推薦

2013新春奉送Android攝像頭開發完美demo---(迴圈聚焦,大小,旋轉picture,查詢支援picturesize, ImageButton按鍵效果

【補充:我已在對此程式碼進行了全面的升級,升級後代碼結構更加利於維護擴充套件,全面適配所有手機,參見博文。此文中的資源也不要再下載了,請下載升級後的程式碼,如有問題請留言反饋,謝謝。---------------------------2014-6-23】  【後注:】下載程

萬樹ITAndroid軟體開發必學習的0基礎內容

  如今安卓系統中國的前景市場是非常廣闊的,它主要針對的是移動裝置市場,而如今智慧手機已經佔據人們生活不能缺少的一部分。所以,很多行業投入到安卓軟體開發,進入到安卓開發的人才也越來越多。  安卓應用軟體開發必學習的5大基礎內容: 1、程式語言 2、基礎應用開

android進階4step4Android實戰開發——事件分發機制

Android事件分發機制 為什麼需要事件分發機制? 比如:上圖 Button(View)的ViewGroup是FrameLayout2 FragmeLayout2的ViewGroup是FragmeLayout1 當點選Button時,所觸發的事件到底是交給誰來

第一行程式碼——第十一章Android特色開發——基於位置的服務

目錄: 11.1 基於位置的服務簡介 11.2 申請API Key 11.3 使用百度定位 11.3.1 準備LBS SDK 11.3.2 確定自己位置的經緯度 11.3.3 選擇定位模式 11.3.4 看得懂的位置資訊 11.4 使用百度地圖 11.4.1

day1Android Wear開發入門--建立手錶模擬器及在as平臺上建立Android Wear工程

第一次接觸Android Wear開發,不知如何著手。首先研究了一下手錶,看了一下里面的應用,腦子浮現的第一個問題是:1.如何將應用部署到手錶上?2.在Android studio平臺上怎麼開發?在網上查找了一些資料,折騰了幾天終於手機連線上了手錶模擬器。

android攝像頭開發,將Camera.onPreviewFrame裡面的data轉換成bitmap

最近在做的幾個專案都和攝像頭有關,其中不乏影象識別的,但是拍照識別有時候感覺還是有些low,直接把畫面一對準自己就識別了多好,就像zxing掃描二維碼一樣,於是上網查了很多資料,找到了需要給camera物件設定一個 Camera.PreviewCallback,在這個回撥中實

CSDN博文精選Android系列開發部落格資源彙總

  CSDN部落格本期熱文推薦,為您介紹有關Android應用開發的10個部落格,分享他們的日積月累的寶貴經驗,希望這些文章對Android開發者們能有所啟發和幫助。 前面寫了十四篇關於介面的入門文章,大家都看完和跟著練習之後,對於常用的Layout和View都會有一定

Android開發——資料庫框架Suger遇到的大坑(依據列名查詢不到資料解決辦法

Android開發——資料庫框架Suger遇到的大坑(依據列名查詢不到資料解決辦法) JavaBean命名出現大寫,資料無法正常儲存(用的是Suger第二種操作方式,第一種沒有測試) 習慣中對Bean中變數的命名會出現大寫字母,但使用Suger操作這樣的資料會出現問題,比如我這樣命名

Android開發學習之ImageView手勢拖拽、旋轉

           在Android應用中,圖片隨手勢的拖拽、縮放、旋轉在很多場景中都會用到,今天我們要做的就是在ImageView的基礎上實現一個可以拖拽、縮放、轉轉的TouchView。              一、實現原理              OnTouc

Android手勢單指拖動、雙指圖片

手勢其實是一個比較複雜的東西,首先是因為處理的時機。Android中觸控式螢幕的事件其實只有ACTION_DOWN、ACTION_MOVE和 ACTION_UP這三種,當然我們實現手勢的邏輯時,一般會用到GestureDetector,它有許多封裝好的事件回撥介面,比如on

AE開發之默認滾輪功能反置(C#修改註冊表數據

arcgis closed wheel engine user 直接 clas for sem ArcMap默認的滾輪縮放是向下放大,向上縮小 如果想修改成向上放大,向下縮小,直接在ArcMap-Customize-ArcMap Options裏, 將最下面的Mouse W

Swift我的第二個Demo(textField實現一個登入介面,沒有完成點選空白鍵盤

檔名:AppDelegate.swift import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func

百度地圖開發(三)隱藏Logo/比例尺/控制元件/放大縮小方法

隱藏百度地圖的Logo: View child = mMapView.getChildAt(1); if (child != null && (child instanceof ImageView || child instanceof ZoomControls)) {

原生webgl學習(八 WebGL實現動畫平移、旋轉

筆者在前面的文章主要是針對二維的靜態圖形進行開發;但有時候我們需要模型動起來,就像真實世界中的一切運動變化一樣。場景如果不是動態的,那麼可想而知,我們的世界是多麼枯燥乏味。為了讓我們開發的圖形應用看上去更加高大上,這一節筆者將和大家一起做一個動畫的例子;本節的內容用到了前面文

html5學習筆記三canvas中平移,旋轉等影象變換問題

1,儲存與恢復問題 關鍵字:save / restore save指儲存save之前的canvas狀態,restore恢復save儲存的canvas狀態。舉個例子我想在canvas中隔一秒顯示一個圖片,那我可以先用save指令儲存空白的canvas,然後在顯示一張圖片之後r

Android單點觸控技術,對圖片進行平移,旋轉操作

相信大家使用多點對圖片進行縮放,平移的操作很熟悉了,大部分大圖的瀏覽都具有此功能,有些app還可以對圖片進行旋轉操作,QQ的大圖瀏覽就可以對圖片進行旋轉操作,大家都知道對圖片進行縮放,平移,旋轉等操作可以使用Matrix來實現,Matrix就是一個3X3的矩陣,對圖片的處理可

Android O 修改開發者選項中動畫的預設值

frameworks/base/core/res/res/values/config.xml <item name="config_appTransitionAnimationDurationScaleDefault" format="float" type="di

OpenCV學習第十二篇帶透明通道影象合成(旋轉,和ROI

第一步:獲取素材圖片 Mat src, dst; src = imread("F:/識圖/底圖.PNG", 1); dst = imread("logo", -1); 【ps:這裡需要注意的是透明度圖片獲取,後面的引數帶-1】 第二

iOS開發之UIImage等比

評論功能真不錯 評論開通後,果然有很多人吐槽。謝謝大家的支援和關愛,如果有做的不到的地方,還請海涵。畢竟我一個人的力量是有限的,我會盡自己最大的努力大家準備一些乾貨。 有些內容可能都是比較基礎的,記住:不積跬步無以至千里,不積小流無以成江海。我想這個道理大家都懂,在為大家準備文章的過程中,對我來說也是一次

Android對圖片進行平移,旋轉操作

package com.app.freestyle; import java.util.Arrays; import java.util.Collections; import java.util.List; import com.app.freestyle.R; i