博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
「OpenGL」未来视觉1-Android摄像头采集基础
阅读量:7084 次
发布时间:2019-06-28

本文共 5885 字,大约阅读时间需要 19 分钟。

相信很多人都用过相机功能,也开发过简单调度相机功能,但是相机采集功能。是图像信号输入的重要来源。

SurfaceView和View的不同之处:

 

SurfaceView和View对比

相机图像采样,需要维持一个比较稳定的帧数来维持图像实时性,需要频繁刷新,创建一个子线程来进行画面更新,会被占用主线程效率好很多,而且双缓冲机制可以在画面从前台刷新到后台时才占用主线程操作,所以选用SurfaceView作绘制是最好的。

而GLSurfaceView是SurfaceView的一个子类,专用于openGL绘制,其运行效率远高于SurfaceView是因为使用了GPU参与绘制。
这一节介绍Android摄像头采样,还是采用了SurfaceView来做采样
1.需要申请相机权限。

2.打开摄像头,先检查摄像和前置摄像头,然后通过摄像头Id,来返回摄像头对象。

fun openCamera(cameraId:Int):Camera?{        if (!haveFeature(PackageManager.FEATURE_CAMERA)){            Log.e(TAG,"no camera!")            return null        }        if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT && !haveFeature(PackageManager.FEATURE_CAMERA_FRONT)){            Log.e(TAG,"no front camera!")            return null        }        val camera = Camera.open(cameraId)        if (camera == null){            Log.e(TAG, "openCamera failed")            return null        }        return camera    }

3.设置画面比例

/**     * 获取最大的图片大小     */    fun getLargePictureSize(camera: Camera?): Camera.Size? {        if (camera != null) {            //获取可选比例            val sizes = camera.parameters.supportedPictureSizes            var temp: Camera.Size = sizes[0]            for (i in 1 until sizes.size) {                val scale = sizes[i].height.toFloat() / sizes[i].width                if (temp.width < sizes[i].width && scale < 0.6f && scale > 0.5f)                    temp = sizes[i]            }            return temp        }        return null    }    /**     * 获取最大的预览大小     */    fun getLargePreviewSize(camera: Camera?): Camera.Size? {        if (camera != null) {            //获取可选比例            val sizes = camera.parameters.supportedPreviewSizes            var temp: Camera.Size = sizes[0]            for (i in 1 until sizes.size) {                if (temp.width < sizes[i].width)                    temp = sizes[i]            }            return temp        }        return null    } /**     * 相机采样参数大小     */    fun setOptimalSize(camera:Camera,aspectRatio:Float,maxWidth:Int,maxHeight:Int){        val parameters= camera.parameters        //使用自动对焦        if (parameters.supportedFocusModes.contains(                        Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {            parameters.focusMode = Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE        }        val size = getLargePreviewSize(camera)        size?.let {            //设置相机预览大小            parameters.setPreviewSize(it.width,it.height)            Log.d(TAG, "input max: (" + maxWidth + ", " + maxHeight + "), output size: ("                    + it.width + ", " + it.height + ")")        }        val pictureSize = getLargePictureSize(camera)        pictureSize?.let {            //图片参数            parameters.setPictureSize(it.width,it.height)            Log.d(TAG, "picture max: (" + maxWidth + ", " + maxHeight + "), output size: ("                    + it.width + ", " + it.height + ")")        }        camera.parameters = parameters    }

3.设置相机图像角度

fun setDisplayOritation(activity: Activity, camera: Camera, cameraId: Int) {        //获取window的角度        val rotation = activity.windowManager.defaultDisplay.rotation        var degress = 0        when (rotation) {            Surface.ROTATION_0 -> degress = 0            Surface.ROTATION_90 -> degress = 90            Surface.ROTATION_180 -> degress = 180            Surface.ROTATION_270 -> degress = 270        }        val info = Camera.CameraInfo()        Camera.getCameraInfo(cameraId, info)        var result: Int        //前置摄像头        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {            result = (info.orientation + degress) % 360            result = (360 - result) % 360  // compensate the mirror        } else {//后置摄像头            result = (info.orientation - degress + 360) % 360 // back-facing        }        Log.d(TAG, "window rotation: $degress, camera oritation: $result")        camera.setDisplayOrientation(result)    }

4.设置完摄像头参数后,需要设置一个SurfaceHolder.CallBack。

有三个必须的方法

//创建时调用   override fun surfaceCreated(holder: SurfaceHolder?) { }   //当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用。   override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) { }   //被移除时调用   override fun surfaceDestroyed(holder: SurfaceHolder?) {}

这里创建相机的调用surfaceCreated,之后会立刻调用一次surfaceChanged

这里在surfaceChanged上调用openGL的init操作

fun initOpenGL(surface: Surface, width: Int, height: Int){        //新开一个之后一个线程的线程池        mExecutor.execute {            //获取纹理id            val textureId = OpenGLJniLib.magicBaseInit(surface,width,height,BaseApplication.context.assets)                       if (textureId < 0){                Log.e(TAG, "surfaceCreated init OpenGL ES failed!")                return@execute            }            //需要使用surfaceTexture来做纹理装载            mSurfaceTexture = SurfaceTexture(textureId)            //添加纹理变化回调            mSurfaceTexture?.setOnFrameAvailableListener { drawOpenGL() }            try {                //把摄像头采样关联到纹理                mCamera?.setPreviewTexture(mSurfaceTexture)                //开始摄像头采样                doStartPreview()            }catch (e:IOException){                Log.e(TAG,e.localizedMessage)                releaseOpenGL()            }        }    }

5.开始预览,并开始自动对焦。

fun doStartPreview(){        mCamera?.startPreview()        cameraFocus(width/2.0f,height/2.0f)    }

6.opengl绘制,先要强制更新纹理图像,再更新获取纹理矩阵,然后让opengl绘制

fun drawOpenGL(){        mExecutor.execute {            mSurfaceTexture?.updateTexImage()            mSurfaceTexture?.getTransformMatrix(mMatrix)            OpenGLJniLib.magicBaseDraw(mMatrix)        }    }

7.在destroySurfaceView的是否释放资源

fun releaseOpenGL(){        mExecutor.execute {            mSurfaceTexture?.release()            mSurfaceTexture=null            OpenGLJniLib.magicBaseRelease()        }    }

介绍了Camera采样配置和,surfaceTexture纹理获取了和加载,下一节,将会介绍native层的opengl绘制代码。

Android摄像头采集基础介绍就到这。这里做一个小小推广。有需要Android系统技术进阶资料可加群;964557053 免费领取

「OpenGL」未来视觉1-Android摄像头采集基础

转载地址:http://simml.baihongyu.com/

你可能感兴趣的文章
阿拉伯数字转中文大写(整数)
查看>>
【3次握手4次挥手】-转
查看>>
使用traefik作为kubernetes的ingress
查看>>
char nvarchar varchar
查看>>
Lucene 源码分析之倒排索引(二)
查看>>
.net web端导出Excel个人的看法
查看>>
12.29.作业
查看>>
项目管理初探
查看>>
keras入门--Mnist手写体识别
查看>>
服务器开发中的多进程,多线程及多协程
查看>>
1139 观光公交
查看>>
poj3159
查看>>
[Python爬虫] 之二十一:Selenium +phantomjs 利用 pyquery抓取36氪网站数据
查看>>
java 把json对象中转成map键值对
查看>>
extjs grid行插入进度条
查看>>
Extjs 页面布局以及dataview的使用
查看>>
滴滴研发笔记题,亮灯问题
查看>>
装饰模式(Decorator)
查看>>
几何画板二次函数系的制作
查看>>
[设计模式]PHP设计模式之单例模式
查看>>