android环境下摄像头数据采集及显示
作者:网络 软件教程库 2020-05-12
以前项目涉及些摄像头预览及数据处理操作,当时的需求是除了做摄像头预览外,还要显示文字、个性图像等,当初在查找资料实现相关模块时,发现很多资料讲的比较繁琐,不够简洁,这里将自己的实现方式分享出来,希望能够为正在做相关工作的同学提供些思路。不过这里先顺便提一下,如果单纯的做摄像头预览,不在预览数据时做添加文字、图像等额外操作,可以用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; } } // 绘制 @override protected 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); } // 获取摄像头视频数据 @override public void onpreviewframe(byte[] data, camera camera) { int i = 0, j = 0, k = 0; int uvheight = srcframeheight 1; // 旋转yuv数据 if (curcameraindex == camera_back) { // 旋转y for (i = 0; i srcframewidth; i++) { for (j = srcframeheight - 1; j = 0; j--) { yuvdata[k] = data[srcframewidth * j + i]; k++; } } // 旋转uv for (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 { // 旋转y for (i = srcframewidth - 1; i = 0; i--) { for (j = srcframeheight - 1; j = 0; j--) { yuvdata[k] = data[srcframewidth * j + i]; k++; } } // 旋转uv for (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 + (j1)]) - 128; v = (0xff yuvdata[uvp + qtrframesize + (j1)]) - 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 }// for invalidate(); } }工程下载链接:http://download.csdn.net/detail/u013085897/8652979
android环境下摄像头数据采集及显示
原文地址:http://blog.csdn.net/grafx/article/details/45422945
这篇内容就是由软件教程库 小编为各位整理 原文链接:https://www.itjcku.com/9999/1091354.html
推荐内容