前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android利用SurfaceView显示Camera图像爬坑记(二)

Android利用SurfaceView显示Camera图像爬坑记(二)

作者头像
Vaccae
发布2019-07-25 11:45:28
1.7K0
发布2019-07-25 11:45:28
举报
文章被收录于专栏:微卡智享

前言

前一章《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的方法绘制图片即可。

回调函数的代码

代码语言:javascript
复制
    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

代码语言:javascript
复制
    //输出图像
    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

代码语言:javascript
复制
    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;
    }

我们重新运行程序的视频效果

上面视频可以看到,我们的图像已经正常了,但是图像显示出来的大小和我们的界面布局不一致,我们下一篇就针对这个问题来看看怎么处理。

-END-

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微卡智享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图像处理
图像处理基于腾讯云深度学习等人工智能技术,提供综合性的图像优化处理服务,包括图像质量评估、图像清晰度增强、图像智能裁剪等。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档