android环境下摄像头数据采集及显示

来源:互联网 发布:sql 数据库链接 编辑:程序博客网 时间:2024/05/01 23:23

       以前项目涉及些摄像头预览及数据处理操作,当时的需求是除了做摄像头预览外,还要显示文字、个性图像等,当初在查找资料实现相关模块时,发现很多资料讲的比较繁琐,不够简洁,这里将自己的实现方式分享出来,希望能够为正在做相关工作的同学提供些思路。不过这里先顺便提一下,如果单纯的做摄像头预览,不在预览数据时做添加文字、图像等额外操作,可以用surfaceview方式,性能上会更好些。

       这里将摄像头采集及视频图像绘制放在一个模块中,比较便于管理及维护,同时在使用时,因为该类继承自view类,所以可以向操作很多view类一样,将其添加到任何布局中,在与采集的数据宽高比例保持一致的前提下,在页面显示上可以非常灵活的控制视图尺寸大小。不过使用这种方式实现摄像头预览,最大的瓶颈是在旋转yuv数据及将其转为rgb数据时,计算比较耗时,一般情况下采集640*480数据还好,但对于960*720数据来说,手机性能一般的话,就会显得比较卡了。解决方式在做数据旋转时,可以尝试采用ndk c的方式,以提高运行效率,在做yuv转rgb时,也可以尝试用ndk c的方式,但是最好的方式是采用gpu shader方式,直接渲染yuv数据,即将采集的yuv数据以纹理的方式上传至gpu,然后由gpu完成yuv转rgb并显示。下面是相关代码:

public class CameraView extends View implements PreviewCallback{// 源视频帧宽/高private int srcFrameWidth  = 640;private int srcFrameHeight = 480;private int frameSize = srcFrameWidth * srcFrameHeight;private int qtrFrameSize = srcFrameWidth * srcFrameHeight >> 2;// 帧预览贴图private Bitmap previewBmp = null;private Rect previewRect = null;private Camera camera = null;// 图层private BaseLayer[] layers = null;// 数据采集private int[] rgb_data = null;private byte[] yuvdata = null;// 摄像头前置/后置public static final int CAMERA_BACK  = 0;public static final int CAMERA_FRONT = 1;private int curCameraIndex = CAMERA_BACK;public CameraView(Context _context){super(_context);}public CameraView(Context _context, AttributeSet _attrs){super(_context, _attrs);}public CameraView(Context context, int previewWidth, int previewHeight, int cameraIndex){super(context);curCameraIndex = cameraIndex;rgb_data = new int[frameSize];yuvdata = new byte[frameSize * 3 / 2];previewBmp = Bitmap.createBitmap(srcFrameHeight, srcFrameWidth, Config.ARGB_8888);previewRect = new Rect(0, 0, previewWidth, previewHeight);// 定义图层layers = new BaseLayer[2];layers[0]  = new TextLayer(context, 0, false);layers[1] = new ImageLayer(context, 1, false);// 文字((TextLayer)layers[0]).setFontParams(32, Color.CYAN);((TextLayer)layers[0]).setTextPos(100, 300);((TextLayer)layers[0]).setContent("天气还不错....");layers[0].setVisible(true);// 图像((ImageLayer)layers[1]).setImagePos(100, 150);layers[1].setVisible(true);// 初始化并打开摄像头startCamera(cameraIndex);this.setBackgroundColor(Color.parseColor("#82858b"));}// 根据索引初始化摄像头public void startCamera(int cameraIndex){// 先停止摄像头stopCamera();// 再初始化并打开摄像头if (camera == null){camera = Camera.open(cameraIndex);Camera.Parameters params = camera.getParameters();params.setPreviewSize(srcFrameWidth, srcFrameHeight);params.setPreviewFormat(ImageFormat.NV21);camera.setParameters(params);camera.setPreviewCallback(this);camera.startPreview();}}// 停止并释放摄像头public void stopCamera(){if (camera != null){camera.setPreviewCallback(null);camera.stopPreview();camera.release();camera = null;}}// 绘制@Overrideprotected void onDraw(Canvas canvas){super.onDraw(canvas);// 填充数据(因为数据已经旋转过,此时宽与高需要互换)previewBmp.setPixels(rgb_data, 0, srcFrameHeight, 0, 0, srcFrameHeight, srcFrameWidth);// 绘制图层for (BaseLayer layer : layers){if (layer.isVisible()){layer.drawLayer(previewBmp);}}// 贴图canvas.drawBitmap(previewBmp, null, previewRect, null);}// 获取摄像头视频数据@Overridepublic void onPreviewFrame(byte[] data, Camera camera){int i = 0, j = 0, k = 0;int uvHeight = srcFrameHeight >> 1;// 旋转yuv数据if (curCameraIndex == CAMERA_BACK){// 旋转yfor (i = 0; i < srcFrameWidth; i++){for (j = srcFrameHeight - 1; j >= 0; j--){yuvdata[k] = data[srcFrameWidth * j + i];k++;}}// 旋转uvfor (i = 0; i < srcFrameWidth; i += 2){   for (j = uvHeight - 1; j >= 0; j--)   {   yuvdata[k] = data[frameSize + srcFrameWidth * j + i + 1];// cb/u   yuvdata[k + qtrFrameSize] = data[frameSize + srcFrameWidth * j + i];// cr/v   k++;   }}}else{// 旋转yfor (i = srcFrameWidth - 1; i >= 0; i--){for (j = srcFrameHeight - 1; j >= 0; j--){yuvdata[k] = data[srcFrameWidth * j + i];k++;}}// 旋转uvfor (i = srcFrameWidth - 2; i >= 0; i -= 2){   for (j = uvHeight - 1; j >= 0; j--)   {   yuvdata[k] = data[frameSize + srcFrameWidth * j + i + 1];// cb/u   yuvdata[k + qtrFrameSize] = data[frameSize + srcFrameWidth * j + i];// cr/v   k++;   }}}// yuv转rgb(因为数据已经旋转过,此时宽与高需要互换)int yp = 0;for (i = 0, yp = 0; i < srcFrameWidth; i++){int uvp = frameSize + (i >> 1) * uvHeight, u = 0, v = 0;for (j = 0; j < srcFrameHeight; j++, yp++){int y = (0xff & yuvdata[yp]) - 16;if ((j & 1) == 0){u = (0xff & yuvdata[uvp + (j>>1)]) - 128;v = (0xff & yuvdata[uvp + qtrFrameSize + (j>>1)]) - 128;}int y1192 = 1192 * y;int r = (y1192 + 1634 * v);int g = (y1192 - 833 * v - 400 * u);int b = (y1192 + 2066 * u);if (r < 0) r = 0; else if (r > 262143) r = 262143;if (g < 0) g = 0; else if (g > 262143) g = 262143;if (b < 0) b = 0; else if (b > 262143) b = 262143;rgb_data[i*srcFrameHeight + j] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) & 0xff00) | ((b >> 10) & 0xff);}// for}// forinvalidate();}}
工程下载链接:http://download.csdn.net/detail/u013085897/8652979




0 0
原创粉丝点击