Android設(shè)備上opencv開(kāi)發(fā)圖像格式
來(lái)源:程序員人生 發(fā)布時(shí)間:2015-03-30 08:26:24 閱讀次數(shù):5749次
Windows的圖象格式和Android移動(dòng)裝備上的圖象格式存在差異,使得處理存在1些問(wèn)題!簡(jiǎn)單來(lái)說(shuō)
Camera得到的數(shù)據(jù)是:YUV,而在移動(dòng)端裝備上顯示的數(shù)據(jù)又是:RGBA, 但是C++程序中處理的數(shù)據(jù)又是RGB。因此需要做數(shù)據(jù)的轉(zhuǎn)換。具體的操作示意圖以下:

0. 使用前的準(zhǔn)備。
Camera的使用需要先在AndroidManifest.xml 文件當(dāng)中加入camera的權(quán)限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
1些小Tips:
Android 2.3以后,可使用Camera.open(int)來(lái)獲得特定的相機(jī)。
API Level 9以后,可使用 Camera.getCameraInfo()
來(lái)查看相機(jī)是在裝備前面還是后面,還可以得到圖象的方向。
相機(jī)是裝備資源,被所有利用同享,當(dāng)利用不使用相機(jī)時(shí)應(yīng)當(dāng)及時(shí)釋放,應(yīng)當(dāng)在Activity.onPause()中釋放。
如果不及時(shí)釋放,后續(xù)的相機(jī)要求(包括你自己的利用和其他的利用發(fā)出的)都將失敗并且致使利用退出。
1. 數(shù)據(jù)的取得:
需要先打開(kāi)攝像頭:
Camera mCamera = Camera.open();
Camera.Parameters p = mCamera.getParameters();
p.setPreviewFormat(ImageFormat.NV21);
/*這是唯1值,也能夠不設(shè)置。*/
mCamera.setParameters(p);
mCamera.startPreview();
Camera提供了這個(gè)接口,用法以下:( take care of the function format here):
mCamera.setPreviewCallback(new PreviewCallback(){
@Override
public void onPreviewFrame(byte[] data, Camera camera)
{
//你的操作
}
});
在這個(gè)回調(diào)里我們就可以夠獲得到當(dāng)前幀的數(shù)據(jù),我們可以對(duì)其進(jìn)行預(yù)處理,比如緊縮、加密、殊效處理等,不過(guò)byte[]這個(gè)buffer里面的數(shù)據(jù)是YUV格式的,1般是YUV420SP,而Android提供的SurfaceView、GLSurfaceView、TextureView等控件只支持RGB格式的渲染,因此我們需要1個(gè)算法來(lái)解碼。也就是做數(shù)據(jù)的轉(zhuǎn)化。
2.數(shù)據(jù)的轉(zhuǎn)換(+JNI 的方法 總共有3種):
第1種方式:
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
Size size = camera.getParameters().getPreviewSize();
try{
YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
if(image!=null){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);
Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
stream.close();
}
}catch(Exception ex){
Log.e("Sys","Error:"+ex.getMessage());
}
}
其實(shí)在取得數(shù)據(jù)流以后沒(méi)必要緊縮,會(huì)下降速度:
以320×240大小的視頻傳輸為例
方案 |
緊縮率 |
緊縮/傳輸方式 |
實(shí)時(shí)性 |
平均流量消耗 |
傳輸距離 |
用camera的回調(diào)函數(shù)發(fā)送原始的yuv420數(shù)據(jù) |
0 |
無(wú)緊縮,按幀傳輸 |
高(20~30 fps) |
很高(6.5 Mbps)太恐怖了O_O |
近距離有線或無(wú)線 |
用MediaRecorder對(duì)yuv420進(jìn)行H264硬編碼后發(fā)送 |
高(95%) |
幀間緊縮,視頻流傳輸 |
高(20 fps) |
低(30~70 Kbps) |
可以遠(yuǎn)距離 |
調(diào)用本地H264編碼庫(kù)(JNI)對(duì)1幀YUV420數(shù)據(jù)編碼后發(fā)送 |
高(97%) |
幀間緊縮,按幀傳輸 |
低(2 fps) |
低(20 Kbps) |
可以遠(yuǎn)距離 |
對(duì)1幀數(shù)據(jù)用GZIP庫(kù)緊縮后發(fā)送(很奇葩的做法) |
較高(70%~80%) |
幀內(nèi)緊縮,按幀傳輸 |
低(5 fps) |
較高(300 Kbps) |
可以遠(yuǎn)距離 |
對(duì)1幀數(shù)據(jù)用JPEG方式緊縮后傳輸 |
1般(60%左右) |
幀內(nèi)緊縮,按幀傳輸 |
高(25 fps) |
高(170 Kbps) |
可以遠(yuǎn)距離(帶寬允許的話) |
<span style="background-color: rgb(255, 255, 255);">BitmapFactory.decodeByteArray</span>
聽(tīng)說(shuō)也很慢!
其實(shí)可以用它取得數(shù)據(jù):
byte[] tmp = stream.toByteArray();
再用其他的方法處理。
第2種:
public Bitmap rawByteArray2RGBABitmap2(byte[] data, int width, int height) {
int frameSize = width * height;
int[] rgba = new int[frameSize];
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++) {
int y = (0xff & ((int) data[i * width + j]));
int u = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 0]));
int v = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 1]));
y = y < 16 ? 16 : y;
int r = Math.round(1.164f * (y - 16) + 1.596f * (v - 128));
int g = Math.round(1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128));
int b = Math.round(1.164f * (y - 16) + 2.018f * (u - 128));
r = r < 0 ? 0 : (r > 255 ? 255 : r);
g = g < 0 ? 0 : (g > 255 ? 255 : g);
b = b < 0 ? 0 : (b > 255 ? 255 : b);
rgba[i * width + j] = 0xff000000 + (b << 16) + (g << 8) + r;
}
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bmp.setPixels(rgba, 0 , width, 0, 0, width, height);
return bmp;
}
第3種:
JNIEXPORT void JNICALL Java_com_dvt_pedDetec_pedDetec_yuv2rgb( JNIEnv* env, jobject, jint width, jint height, jbyteArray yuv,jintArray bgr)
//JNIEXPORT void JNICALL Java_<package>_<class>_<function>( JNIEnv* env, jobject, <Args>)
{
jbyte* _yuv =env->GetByteArrayElements(yuv,0);
jint* _bgr =env->GetIntArrayElements(bgr,0);
Mat myuv(height+height/2, width, CV_8UC1, (uchar *)_yuv);
Mat mbgr(height, width, CV_8UC3, (uchar *)_bgr);
cvtColor(myuv, mbgr, CV_yuv420sp2BGR);
//cvtColor(mbgr, mbgra,CV_BGR2BGRA); for display
}
更正:
cvtColor(myuv, mbgr, CV_yuv420sp2BGR)
里面的更正為:CV_YUV420sp2BGR。
生活不易,碼農(nóng)辛苦
如果您覺(jué)得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)