[分享] 取得攝影機預覽資料並回饋到螢幕上
原本不想寫的..因為架構上需要用到三個class 另外有些細節部分我也不很熟
怕寫出來有誤導大眾之嫌 不過最近還是會有人問類似的問題 所以我乾脆抽點時間
開個新專案把主要機制 重新整理出來 大家也比較方便了解
在一切起頭前 這邊首先介紹會用到的class 一共有三個
ViewToDraw class
從View繼承而來 功能就是提供畫布功能讓你畫東西
Camera preview class
很一般的攝影機預覽class 唯一不同的地方是它會有個變數來存ViewToDraw
這樣每次預覽更新 就可以丟圖像資料直接到畫布上 順便提醒它更新畫面
main class
功能不多 主要就是鎖住螢幕的旋轉方向在lanscape(因為2.2以前不支援potrait)
還有取得全畫面(如果你想要的話) 並建立起主要的layout
好了 這邊了解後接下來就開始動工了 首先你會需要修改AndroidManifest.xml
這應該寫過攝影機功能的人都知道 要加入下面兩行
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
這邊就不多談了
再來就是改layout 不過由於你的layout會用到custom view而你還沒實作 所以會有錯誤
訊息...先不管它吧 anyway, 整個xml如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<FrameLayout android:id="@+id/FrameLayout01"
android:layout_height="fill_parent" android:layout_width="fill_parent">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/preview">
</FrameLayout>
<com.maya.mcp.ViewToDraw
android:id="@+id/vtd"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
</com.maya.mcp.ViewToDraw>
</FrameLayout>
</LinearLayout>
ID為preview的FrameLayout之後會加上攝影機預覽的surfaceView
ID為vtd的cutsom View就是等會要拿來畫畫的畫布
搞定了layout後接下來開始實作class 首先從畫布開始...
在這邊 你會需要幾個變數 首先是輸入圖像的長跟寬 由於它不一定跟螢幕解析度相同
所以你等會需要它做長寬比縮放
另外 你當然也需要一個byte的陣列去存preview callback時丟過來的圖像資料
還有 你也要一個變數確定Camera已經架好運作 資料已經丟來的旗標 不然甚麼圖像都沒
讀到時就讓程式傻傻跑onDraw 結果一定是會crash的
ok..變數搞定了 接下來是method... 變數設定存取的那些就不管了 相信你都會寫
這邊你還會需要一個把YUV420SP資料轉存的method 由於在我的範例中我只來簡單判斷
亮度 所以程式相當簡單如下
private boolean getBoolean(int x, int y){
int l;
l = (0xff & ((int) image[x+y*imgWidth])) - 16;
if (l > 128){
return true;
}else{
return false;
}
}
如果你要轉成RGB 我也有附在檔案裡 不過是從網路上挖來的..請自行研究
至於onDraw()要做甚麼呢? 以我的範例是要把讀到的圖二元化後塗回畫布去
所以是用二層迴圈把圖像資料解讀出來 然後再丟白或黑點上去
@Override
protected void onDraw(Canvas canvas){
int i, j;
//將預覽圖資料與畫布做長寬縮放比運算
float hscale = (float)canvas.getHeight()/imgHeight;
float wscale = (float)canvas.getWidth()/imgWidth;
if(isCameraSet){
for(i=0;i<imgWidth;i+=8){
for(j=0;j<imgHeight;j+=8){
if(getBoolean(i,j)){
canvas.drawPoint(i*wscale, j*hscale,
whitePaint);
}else{
canvas.drawPoint(i*wscale, j*hscale,
blackPaint);
}
}
}
}
}
接下來是cameraView class 大部分都跟一般開相機功能的範例一樣 主要不同點在於
使用了setPreViewCallbackWithBuffer 設定callback來處理相機預覽畫面的資料更新
這是一個2.2新增的method 在2.1以前請用setPreViewCallback 兩者差別只在於前者
要先產生多個buffer給callback預備使用 讓傳回效率可以進一步提升 程式如下
//產生 buffer
PixelFormat p = new PixelFormat();
PixelFormat.getPixelFormatInfo(parameters.getPreviewFormat(),p);
int bufSize = (pickedW*pickedH*p.bitsPerPixel)/8;
//把buffer給preview callback備用
byte[] buffer = new byte[bufSize];
mycamera.addCallbackBuffer(buffer);
buffer = new byte[bufSize];
mycamera.addCallbackBuffer(buffer);
buffer = new byte[bufSize];
mycamera.addCallbackBuffer(buffer);
//設定預覽畫面更新時的callback
mycamera.setPreviewCallbackWithBuffer(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
vtd.putImage(data);
vtd.CameraSet();
//更新畫布 (call onDraw())
vtd.invalidate();
//把buffer丟回給callback重新利用
mycamera.addCallbackBuffer(data);
}
});
最後是處理main class 這部分就很簡單 主要有三
1.把畫面鎖在landscape
2.取得ViewToDraw
3.產生攝影機預覽的surfaceView 並把ViewToDraw pass過去
4.把上面的surfaceView加到FrameLayout
程式如下
// 取得全螢幕
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
setContentView(R.layout.main);
//鎖住螢幕方向
setRequestedOrientation(0);
//取得畫圖的View
ViewToDraw dtw = (ViewToDraw) findViewById(R.id.vtd);
//產生攝影機預覽surfaceView
CameraView cameraView = new CameraView(this, dtw, this.getApplicationContext());
//把預覽的surfaceView加到名為preview的FrameLayout
((FrameLayout) findViewById(R.id.preview)).addView(cameraView);
整個範例程式碼可以到下面下載 不保證跑在每台手機上都能很順就是了XD
http://www.megaupload.com/?d=S0U489LO
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 71.109.152.84
※ 編輯: mamaya3 來自: 71.109.152.84 (04/26 11:23)
推
04/26 12:04, , 1F
04/26 12:04, 1F
推
04/26 12:17, , 2F
04/26 12:17, 2F
推
04/26 14:29, , 3F
04/26 14:29, 3F
推
04/26 17:18, , 4F
04/26 17:18, 4F
推
04/26 17:31, , 5F
04/26 17:31, 5F
推
04/26 17:41, , 6F
04/26 17:41, 6F
推
04/26 19:21, , 7F
04/26 19:21, 7F
推
04/26 20:24, , 8F
04/26 20:24, 8F
推
04/26 21:38, , 9F
04/26 21:38, 9F
推
04/26 22:11, , 10F
04/26 22:11, 10F
推
04/26 23:16, , 11F
04/26 23:16, 11F
推
04/27 15:50, , 12F
04/27 15:50, 12F
推
04/28 15:31, , 13F
04/28 15:31, 13F
推
04/29 17:01, , 14F
04/29 17:01, 14F
→
04/30 13:47, , 15F
04/30 13:47, 15F
→
04/30 13:48, , 16F
04/30 13:48, 16F
→
04/30 13:49, , 17F
04/30 13:49, 17F
推
04/30 13:53, , 18F
04/30 13:53, 18F
推
04/30 14:03, , 19F
04/30 14:03, 19F
→
04/30 17:55, , 20F
04/30 17:55, 20F
→
04/30 17:56, , 21F
04/30 17:56, 21F
→
04/30 17:56, , 22F
04/30 17:56, 22F
推
07/26 17:37, , 23F
07/26 17:37, 23F
討論串 (同標題文章)
AndroidDev 近期熱門文章
PTT數位生活區 即時熱門文章