完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
前一章《Android利用SurfaceView显示Camera图像爬坑记(一)》我们已经实现了利用SurfaceView将Camera中的实时帧图像显示出来了,我们做这个的主要目录是想把每一帧的数据取出后通过OpenCV图像处理后,再实时显示出处理后的图像。
要实现这个情况,我们首先要把Camera的实时数据存成Bitbmp的图像然后通过自己的处理显示出来,接下来我们就看看怎么样把Camera的实时图像都通过Bitbmp的方式显示出来。 代码实现 我们还是接上一篇的代码接着开始,还记得上一篇中我们的VaccaeSurfaceView类中定义了Camera的回调方法吗? 我们在程序运行后的LogCat里面可以查看到日志,输入的Log里面会不停的发送good字符串,如下图 上面就说明了我们的回调方法已经成功了,想到我们自己把图像处理显示出来,就可以在这个回调的方法中进行图片的处理。 这里简单介绍一下代码中的synchronized(this),当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。 简单的说就是我们获取的每一帧图像都会在这个代码里面处理完成了才处理下一帧图像。当然这里也可以用AnsycTask来进行实现。 实现原理及核心代码 我们在图像上按获取到的图片Bitbmp通过我们创建的SurfaceHolder来生成Canavas,然后在这个Canavas中能过drawBitbmp的方法绘制图片即可。 回调函数的代码 private Camera.PreviewCallback previewCallback=new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] bytes, Camera camera) { synchronized (this) { Log.i(“frame”, “good”); int width=camera.getParameters().getPreviewSize().width; int height=camera.getParameters().getPreviewSize().height; Canvas canvas=holder.lockCanvas(); if (canvas != null) { canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR); Bitmap cacheBitmap=nv21ToBitmap(bytes, width, height); canvas.drawBitmap(cacheBitmap, 0, 0, null); holder.unlockCanvasAndPost(canvas); } } } }; 上图中对图像有一个nv21toBitmap的方法,就是用来生成图像的,我们看一下这个方法。 nv21ToBitmap //输出图像 private static Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { Bitmap bitmap=null; try { YuvImage image=new YuvImage(nv21, ImageFormat.NV21, width, height, null); ByteArrayOutputStream stream=new ByteArrayOutputStream(); image.compressToJpeg(new Rect(0, 0, width, height), 80, stream); //将rawImage转换成bitmap BitmapFactory.Options options=new BitmapFactory.Options(); options.inPreferredConfig=Bitmap.Config.ARGB_8888; bitmap=BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size(), options); stream.close(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } 到目前为止看来我们已经完成了,接下来我们运行程序,程序中倒是一直在正常运行,不过我们看了一下LogCat中的记录,发现一直报错 在网上查找了一下原因,可能是camera.setPreviewDisplay(holder)这句有问题,相机一直在用这个holder像surfaceview输出图像,后面程序中再使用surfaceholder来绘制新的图片,就会冲突,然后报错。 找了找解决办法,发现可以用SurfaceTexture来代替实现这个图像的绘制,那我们按这个方法来试试 首先定义一个SurfaceTexture 然后在VaccaeSurfaceView构造函数中实例化这个SurfaceTexture 最后在StartCamera的方法加加入setPreviewTexture,并且屏蔽原来的seetPreviewDisplay的方法 接下来我们运行程序后,发现每一帧也都显示出来了,不过图像的方向不对,如下图 解决这个问题也比较简单,我们把我们的nv21ToBitmap处理图片的方法改造一下,让其直接也旋转90度即可。 nv21ToBitmap private static Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { Bitmap bitmap=null; try { YuvImage image=new YuvImage(nv21, ImageFormat.NV21, width, height, null); ByteArrayOutputStream stream=new ByteArrayOutputStream(); image.compressToJpeg(new Rect(0, 0, width, height), 80, stream); //将rawImage转换成bitmap BitmapFactory.Options options=new BitmapFactory.Options(); options.inPreferredConfig=Bitmap.Config.ARGB_8888; bitmap=BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size(), options); //加入图像旋转 Matrix m=new Matrix(); m.postRotate(90); bitmap=Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, true); stream.close(); } catch (IOException e) { e.printStackTrace(); } return bitmap; } 我们重新运行程序的视频效果 上面视频可以看到,我们的图像已经正常了,但是图像显示出来的大小和我们的界面布局不一致,我们下一篇就针对这个问题来看看怎么处理。 |
|
|
|
只有小组成员才能发言,加入小组>>
930浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-24 07:29 , Processed in 0.468178 second(s), Total 48, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号