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()介面。可以測試出,在使用
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】 【後注:】下載程
萬樹IT:Android軟體開發必學習的0基礎內容
如今安卓系統中國的前景市場是非常廣闊的,它主要針對的是移動裝置市場,而如今智慧手機已經佔據人們生活不能缺少的一部分。所以,很多行業投入到安卓軟體開發,進入到安卓開發的人才也越來越多。 安卓應用軟體開發必學習的5大基礎內容: 1、程式語言 2、基礎應用開
android進階4step4:Android實戰開發——事件分發機制
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
day1:Android 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