Windows的图像格式和Android移动设备上的图像格式存在差异,使得处理存在一些问题!简单来讲


Camera得到的数据是:YUV,而在移动端设备上显示的数据又是:RGBA, 但是C++程序中处理的数据又是RGB。因此需要做数据的转换。具体的操作示意图如下:

                                                           


0. 使用前的准备。


Camera的使用需要先在AndroidManifest.xml 文件当中加入camera的权限:

   
   
   

   

一些小Tips:

Android 2.3之后,可以使用Camera.open(int)来获取特定的相机。

API Level 9之后,可以使用 Camera.getCameraInfo()来查看相机是在设备前面还是后面,还可以得到图像的方向。

相机是设备资源,被所有应用共享,当应用不使用相机时应当及时释放,应当在Activity.onPause()中释放。

如果不及时释放,后续的相机请求(包括你自己的应用和其他的应用发出的)都将失败并且导致应用退出。

1. 数据的获得:

需要先打开摄像头:

Camera mCamera = Camera.open();Camera.Parameters p = mCamera.getParameters();p.setPreviewFormat(ImageFormat.NV21);/*这是唯一值,也可以不设置。*/
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)        {           //你的操作             }         });

在这个回调里我们就能够获取到当前帧的数据,我们可以对其进行预处理,比如压缩、加密、特效处理等,不过byte[]这个buffer里面的数据是YUV格式的,一般是YUV420SP,而Android提供的SurfaceView、GLSurfaceView、TextureView等控件只支持RGB格式的渲染,因此我们需要一个算法来解码。也就是做数据的转化。


2.数据的转换(+JNI 的方法  总共有三种):


第一种方式:

@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());        }    }

其实在获得数据流以后没必要压缩,会降低速度:

以320×240大小的视频传输为例

方案 压缩率 压缩/传输方式 实时性 平均流量消耗  传输距离
用camera的回调函数发送原始的yuv420数据 0 无压缩,按帧传输 高(20~30 fps) 很高(6.5 Mbps)太恐怖了O_O  近距离有线或无线
用MediaRecorder对yuv420进行H264硬编码后发送 高(95%) 帧间压缩,视频流传输 高(20 fps) 低(30~70 Kbps)  可以远距离
调用本地H264编码库(JNI)对一帧YUV420数据编码后发送 高(97%) 帧间压缩,按帧传输 低(2 fps) 低(20 Kbps)  可以远距离
对一帧数据用GZIP库压缩后发送(很奇葩的做法) 较高(70%~80%) 帧内压缩,按帧传输 低(5 fps) 较高(300 Kbps)  可以远距离
对一帧数据用JPEG方式压缩后传输 一般(60%左右) 帧内压缩,按帧传输 高(25 fps) 高(170 Kbps)  可以远距离(带宽允许的话)
BitmapFactory.decodeByteArray
据说也很慢!

其实可以用它获得数据:

byte[] tmp = stream.toByteArray();
再用其他的方法处理。


第二种:


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;    }

第三种:

JNIEXPORT void JNICALL Java_com_dvt_pedDetec_pedDetec_yuv2rgb( JNIEnv* env, jobject, jint width, jint height, jbyteArray yuv,jintArray bgr)//JNIEXPORT void JNICALL Java___( JNIEnv* env, jobject, ){    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。


更多相关文章

  1. “罗永浩抖音首秀”销售数据的可视化大屏是怎么做出来的呢?
  2. Nginx系列教程(三)| 一文带你读懂Nginx的负载均衡
  3. 不吹不黑!GitHub 上帮助人们学习编码的 12 个资源,错过血亏...
  4. Mac OS X 下部分Android手机无法连接adb问题之解决方案
  5. [Android(安卓)特效] Android(安卓)通过流播放声音(二)
  6. Android中使用GreenDao的坑整理
  7. PhoneGap入门经典——理解PhoneGap应用程序基础
  8. 我的android 第18天 - 选择菜单
  9. X-Library系列Android应用框架详解

随机推荐

  1. Android查询短信数据库 查询联系人数据库
  2. PopupWindow 动画显示与消失(逐惭缩放、逐
  3. 如何在Android设备中用NDK编译SQLite并且
  4. android namespace 、样式、主题 (一)
  5. android 封装好的BottomTabBar
  6. Android实现点击两次返回键退出
  7. Android之使用Android-query框架进行开发
  8. AndroidGPS定位详解 (4)
  9. android编译问题,如何控制make编译hdpi,mdp
  10. RelativeLayout的布局学习(部分知识点)