当前位置:   article > 正文

NO.2 CameraX_android camerax imageanalysis.analyzer 图不正常

android camerax imageanalysis.analyzer 图不正常

零蚀
[camerax 官方文档(翻墙)](这是一个高能网站,很多相关的google教程都在这)
配置 ->动态权限 ->预览->文件->YUV_420_888转bitmap


step 1 (依赖)

alpha06 的camerax 版本

// Use the most recent version of CameraX, currently that is alpha06.
ext {
        amerax_version = '1.0.0-alpha06'
}
implementation "androidx.camera:camera-core:${camerax_version}"
implementation "androidx.camera:camera-camera2:${camerax_version}"


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

还需要jdk1.8的支持

// android 下
compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}   
  • 1
  • 2
  • 3
  • 4
  • 5

camera显示控件TextureView

<TextureView
        android:id="@+id/view_finder"
        android:layout_width="640px"
        android:layout_height="640px"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

step 2(权限)

权限(动态权限)

<uses-permission android:name="android.permission.CAMERA" />
  • 1
 // 获取权限
if(ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
        !=PERMISSION_GRANTED){
    ActivityCompat.requestPermissions(this, arrayOf(
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA
    ),10001)
}else{
    LogUtil.d("已经申请了权限")
    normalInit()
}

// 权限返回值
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if(requestCode==10001){

        permissions.forEachIndexed { index, it ->
            if(grantResults[index]==0) {
                LogUtil.d("权限: $it 申请成功")
            }else{
                LogUtil.d("权限: $it 申请失败")
            }
        }
        // 初始化摄像头等操作
        normalInit()
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

step 3(最简demo)

添加监听

object CameraBaseUtil{

    .....

    fun initCameraListener(view:TextureView){
        view.addOnLayoutChangeListener { v,
                                         left, top, right, bottom,
                                         oldLeft, oldTop, oldRight, oldBottom ->
            LogUtil.d("camera的监听发生改变")
        }
    }
    
    ....
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

构建camera,启动,变化,结束的demo

object CameraWorkUtil {

    private var preview:Preview?=null
    
    enum class CameraStatus {
        START,
        UPDATE,
        FINISH
    }


    fun initCameraListener(view: TextureView) {
        view.addOnLayoutChangeListener { v,
                                         left, top, right, bottom,
                                         oldLeft, oldTop, oldRight, oldBottom ->

            //action(this,view,CameraStatus.UPDATE)
            LogUtil.d("camera的监听发生改变")
        }
    }

    fun action(owner: LifecycleOwner, view: TextureView, status: CameraStatus) {
        when (status) {
            CameraStatus.START -> startCamera(owner, view)
            CameraStatus.UPDATE -> upDataCamera()
            CameraStatus.FINISH -> finishCamera()
        }
    }

    private fun finishCamera() {
        if (preview!=null) {
            CameraX.unbind(preview)
        }
    }

    private fun upDataCamera() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
    }


    private fun startCamera(owner: LifecycleOwner, viewFinder: TextureView) {
        // 创建配置对象,供给TextureView使用
        val previewConfig = PreviewConfig.Builder().apply {
            setTargetResolution(Size(640, 480))
        }.build()

        // 构建使用场景
        preview = Preview(previewConfig)

        // 每当发生变化都会使得,重新计算&布局
        preview.setOnPreviewOutputUpdateListener {
            val parent = viewFinder.parent as ViewGroup
            parent.removeView(viewFinder)
            parent.addView(viewFinder, 0)

            viewFinder.surfaceTexture = it.surfaceTexture
            //upDataCamera()
        }

        CameraX.bindToLifecycle(owner,preview)
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9LakJeqp-1585648545745)(media/15855483514011/15856133146946.jpg)]


step 4(生成文件)

获取图像的文件操作

private fun startCamera(owner: LifecycleOwner, viewFinder: TextureView) {


    val previewConfig = PreviewConfig.Builder().apply {
        setTargetResolution(Size(640,640))
    }.build()

    val preview=Preview(previewConfig)

    // 每当发生变化都会使得,重新计算&布局
    preview.setOnPreviewOutputUpdateListener {
        val parent = viewFinder.parent as ViewGroup
        parent.removeView(viewFinder)
        parent.addView(viewFinder, 0)

        viewFinder.surfaceTexture = it.surfaceTexture
        //upDataCamera()
    }

    // 捕获图像(它自己氛围低质和高质两种图像,差异在于获取的时间)
    // 这里不在设置分辨率,而是相位定量
    val imageCaptureConfig = ImageCaptureConfig.Builder()
            .apply {
                    setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
            }.build()

    // 将图像捕捉的场景依附于点击监听上。
    imageCapture = ImageCapture(imageCaptureConfig)

    CameraX.bindToLifecycle(owner, preview , imageCapture)
}




fun getPictureConfig(file:File,listener:OnCameraCaptureInter){

    imageCapture?.takePicture(file, Executors.newCachedThreadPool(),
             object :ImageCapture.OnImageSavedListener{
                override fun onImageSaved(file: File) {
                    listener.success(file)

                }

                override fun onError(imageCaptureError: ImageCapture.ImageCaptureError, message: String, cause: Throwable?) {
                    listener.error(message)

                }
            })

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6mu4URJ3-1585648545747)(media/15855483514011/15856186604700.jpg)]

ivCaptureButton.setOnClickListener {


    val file=File(Environment.getExternalStorageDirectory().absolutePath+
                    File.separator+
                    Environment.DIRECTORY_PICTURES,
                    "${System.currentTimeMillis()}.jpg")

    LogUtil.e(file.absolutePath)
    CameraBaseUtil.getPictureConfig(file,object:OnCameraCaptureInter{
    	override fun success(file: File) {

        	toast("the file's path is ${file.path}")
    	}

    	override fun error(message: String) {
        	toast(message)
    	}
  	})
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vkeTF1Ug-1585648545747)(media/15855483514011/15856187867860.jpg)]


step 5(YUV_420_888)

获取图像像素矩阵,并转为bitmap(划重点,官网没有)

首先我们要知道camerax默认的iamgeFormat是YUV_420_888,而一般我们转为图片的格式只有NV21和YUY2所以采用YuvImage来转图片的byteArray是行不通的。(我们从camera直接拿到的byteArray是不能进行直接的Bitmap的,可以了解一下YUV),所以为了转换计算方便需要用到NDK来处理这些byte转换问题

具体转化方法可以看**[

推荐阅读
相关标签