Android平臺Camera實時濾鏡實現方法探討(一)--JNI操作Bitmap
眾所周知,通過setPreviewHolder可以將預覽資料顯示在一個SurfaceView上,即可實現相機拍照時的預覽功能,通過新增各個控制元件和介面即可實現簡單相機應用,但如果需要對預覽畫面進行處理,例如類似美圖秀秀等相機APP的實時濾鏡功能,此種方案無法達到目的,需要另外需找辦法,本系列旨在探討Android平臺相機開發,結合影象處理,UI設計,實現類似於美圖秀秀,Instagram,aillias等優秀相機APP的效果。
目前Android平臺優質的預覽資料實時處理開原始碼不多,例如android-gpuimage,採用將YUV資料在NDK層轉化為RGB資料,由OpenGL渲染到螢幕中,濾鏡演算法由Shader實現
其他方面,經過研究,目前主要有以下思路實現
1.不轉換,直接由OpenGL繪製,採用Shader實現影象處理(因處理演算法和渲染圖片大部分採用RGB格式,此方案暫不考慮,僅提出可能性);
2.通過C/C++實現YUV->RGB和影象處理,合成Bitmap,由CPU繪製在Canvas上;
3.通過C/C++實現YUV->RGB和影象處理,在NDK層直接繪製在SurfaceView上;
4.通過C/C++實現YUV->RGB,採用Shader實現影象處理,採用OpenGL繪製(android-gpuimage);
5.通過Shader實現YUV->RGB和影象處理,採用OpenGL繪製。(最終採用方案)
由於方案1暫不考慮,首先從方案2探討,Android平臺的Camera控制很多部落格說過了,直接跳過,在onPreviewFrame(byte[] data, Camera camera)中,我們可以獲得相機預覽,格式為YUV格式,通過C++方案轉換成RGB,通過BitmapFactory合成Bitmap,通過getHolder().lockCanvas()獲得canvas,再通過canvas.drawBitmap將bitmap繪製在螢幕當中。
通過BitmapFactory建立bitmap是一個很耗時的過程,如果每一幀都建立一個bitmap,將出現嚴重卡頓,所以我們只需要建立一個Bitmap,將該Bitmap傳遞給C++層,通過JNI操作Bitmap的畫素資料,即通過AndroidBitmap_lockPixels獲得指標,將YUV資料轉換後填充到該指標中(具體轉換演算法見android-gpuimage)來修改該Bitmap,避免了Bitmap的建立,經過華為Mate7試驗,ARGB_8888格式1280X720大小的Bitmap每次繪製耗時6ms左右,每幀間隔50ms~60ms左右,若將影象處理演算法控制在40ms~50ms內(例如YUV轉換RGB演算法),該方案基本可行。
另外,可以通過方案2的思路,放棄建立Bitmap,將SurfaceView格式設定為RGB,通過JNI操作Surface,直接將資料顯示在SurfaceView中,該方案僅理論思考,由於上述6ms基本達到理論要求,因此方案2並未實踐驗證,若有錯誤或者驗證的同學,歡迎交流。
關鍵程式碼示例:
jbyte* yuv = (jbyte*) (*env)->GetPrimitiveArrayCritical(env, yuv420sp, 0);//獲取Java層傳遞的YUV
int* rgbData = NULL;//Bitmap畫素資料
if(AndroidBitmap_lockPixels(env,bitmap,(void**)&rgbData))
return -1;
for(j = 0; j < h; j++) {//YUV轉RGB演算法,在此新增自己的影象處理
pixPtr = j * w;
jDiv2 = j >> 1;
for(i = 0; i < w; i++) {
Y = yuv[pixPtr];
if(Y < 0) Y += 255;
if((i & 0x1) != 1) {
cOff = sz + jDiv2 * w + (i >> 1) * 2;
Cb = yuv[cOff];
if(Cb < 0) Cb += 127; else Cb -= 128;
Cr = yuv[cOff + 1];
if(Cr < 0) Cr += 127; else Cr -= 128;
}
Y = Y + (Y >> 3) + (Y >> 5) + (Y >> 7);
R = Y + (Cr << 1) + (Cr >> 6);
if(R < 0) R = 0; else if(R > 255) R = 255;
G = Y - Cb + (Cb >> 3) + (Cb >> 4) - (Cr >> 1) + (Cr >> 3);
if(G < 0) G = 0; else if(G > 255) G = 255;
B = Y + Cb + (Cb >> 1) + (Cb >> 4) + (Cb >> 5);
if(B < 0) B = 0; else if(B > 255) B = 255;
rgbData[pixPtr++] = 0xff000000 + (R << 16) + (G << 8) + B;//填充Bitmap
}
}
AndroidBitmap_unlockPixels(env,bitmap);//釋放鎖
(*env)->ReleasePrimitiveArrayCritical(env, yuv420sp, yuv, 0);
相關文章
- Android JNI 之 Bitmap 操作Android
- Android平臺Camera開發實踐指南Android
- Android平臺Airplay的實現方法AndroidAI
- Redis 叢集實現原理探討Redis
- spring IOC容器實現探討Spring
- android實現app通過jni呼叫C/C++方法AndroidAPPC++
- 非技術探討:文章定時釋出功能如何實現
- Windows平臺RTMP多例項推送探討Windows
- Android camera實時預覽 實時處理,面部認證。Android
- 用Canvas+Javascript FileAPI 實現一個跨平臺的圖片剪下、濾鏡處理、上傳下載工具CanvasJavaScriptAPI
- Android camera2實現預覽Android
- Android 通過JNI實現守護程式Android
- Android平臺實現https信任所有證書的方法AndroidHTTP
- 如何用華為影像服務快速實現濾鏡功能
- 短影片美顏sdk濾鏡功能的實現流程
- Android Studio 呼叫Camera實現拍照功能Android
- 用程式碼探討KVC/KVO的實現原理
- 用程式碼探討 KVC/KVO 的實現原理
- Android技術棧(三)依賴注入技術的探討與實現Android依賴注入
- Android Bitmap實戰技巧Android
- 利用 Redis 的 bitmap 實現簡單的布隆過濾器Redis過濾器
- 神奇的濾鏡!巧妙實現內凹的平滑圓角
- DarkMode(4):css濾鏡 顏色反轉實現深色模式CSS模式
- with as探討時小插曲
- 探討把一個元素從它所在的div 拖動到另一個div內的實現方法
- 開源低程式碼平臺開發實踐一:低程式碼開發探討與技術選型
- 基於Android平臺實現人臉識別Android
- 《蜘蛛俠:平行宇宙》的視覺解析與濾鏡實現視覺
- VANTIQ—實時協作平臺
- 一次分表踩坑實踐的探討
- [貝聊科技]有關Android應用桌面角標(BadgeNumber)實現的探討Android
- 總部資訊平臺與企業資訊平臺的設計協調探討
- 關於多型實現Singleton模式的探討 (轉)多型模式
- 愛奇藝統一實時計算平臺建設
- 實現簡單的BitMap
- Android 濾鏡效果和顏色通道過濾Android
- 實現在安卓平臺下的即時通訊安卓
- ERP專案實施風險分析與控制方法探討(轉)