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

0. 使用前的準備。
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)來獲得特定的相機。
API Level 9以后,可使用 Camera.getCameraInfo()
來查看相機是在裝備前面還是后面,還可以得到圖象的方向。
相機是裝備資源,被所有利用同享,當(dāng)利用不使用相機時應(yīng)當(dāng)及時釋放,應(yīng)當(dāng)在Activity.onPause()中釋放。
如果不及時釋放,后續(xù)的相機要求(包括你自己的利用和其他的利用發(fā)出的)都將失敗并且致使利用退出。
1. 數(shù)據(jù)的取得:
需要先打開攝像頭:
Camera mCamera = Camera.open();
Camera.Parameters p = mCamera.getParameters();
p.setPreviewFormat(ImageFormat.NV21);
/*這是唯1值,也能夠不設(shè)置。*/
mCamera.setParameters(p);
mCamera.startPreview();
Camera提供了這個接口,用法以下:( take care of the function format here):
mCamera.setPreviewCallback(new PreviewCallback(){
@Override
public void onPreviewFrame(byte[] data, Camera camera)
{
//你的操作
}
});
在這個回調(diào)里我們就可以夠獲得到當(dāng)前幀的數(shù)據(jù),我們可以對其進行預(yù)處理,比如緊縮、加密、殊效處理等,不過byte[]這個buffer里面的數(shù)據(jù)是YUV格式的,1般是YUV420SP,而Android提供的SurfaceView、GLSurfaceView、TextureView等控件只支持RGB格式的渲染,因此我們需要1個算法來解碼。也就是做數(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ù)據(jù)流以后沒必要緊縮,會下降速度:
以320×240大小的視頻傳輸為例
方案 |
緊縮率 |
緊縮/傳輸方式 |
實時性 |
平均流量消耗 |
傳輸距離 |
用camera的回調(diào)函數(shù)發(fā)送原始的yuv420數(shù)據(jù) |
0 |
無緊縮,按幀傳輸 |
高(20~30 fps) |
很高(6.5 Mbps)太恐怖了O_O |
近距離有線或無線 |
用MediaRecorder對yuv420進行H264硬編碼后發(fā)送 |
高(95%) |
幀間緊縮,視頻流傳輸 |
高(20 fps) |
低(30~70 Kbps) |
可以遠距離 |
調(diào)用本地H264編碼庫(JNI)對1幀YUV420數(shù)據(jù)編碼后發(fā)送 |
高(97%) |
幀間緊縮,按幀傳輸 |
低(2 fps) |
低(20 Kbps) |
可以遠距離 |
對1幀數(shù)據(jù)用GZIP庫緊縮后發(fā)送(很奇葩的做法) |
較高(70%~80%) |
幀內(nèi)緊縮,按幀傳輸 |
低(5 fps) |
較高(300 Kbps) |
可以遠距離 |
對1幀數(shù)據(jù)用JPEG方式緊縮后傳輸 |
1般(60%左右) |
幀內(nèi)緊縮,按幀傳輸 |
高(25 fps) |
高(170 Kbps) |
可以遠距離(帶寬允許的話) |
<span style="background-color: rgb(255, 255, 255);">BitmapFactory.decodeByteArray</span>
聽說也很慢!
其實可以用它取得數(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)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機掃描二維碼進行捐贈