有没有办法裁剪Image / ImageProxy在传递给MLKit的分析器之前?

如何解决有没有办法裁剪Image / ImageProxy在传递给MLKit的分析器之前?

我正在将CameraX的Analyzer用例与MLKit的BarcodeScanner一起使用。我想裁剪从相机接收到的部分图像,然后再将其传递给扫描仪。

我现在正在做的是将ImageProxy(我在分析器中收到的)转换为Bitmap,将其裁剪然后传递给BarcodeScanner。缺点是这不是一个非常快速和有效的过程。

运行此代码时,我还注意到我在Logcat中收到警告:

ML Kit检测到您似乎将相机镜框传递给了 检测器作为位图对象。这是低效的。请用 用于camera2 API的YUV_420_888格式(用于(旧版)相机的NV21格式) API,然后直接将字节数组传递给ML Kit。

最好不要进行ImageProxy转换,但是如何裁剪要分析的矩形?

我已经尝试过的是设置cropRect(imageProxy.image.cropRect)类的Image字段,但这似乎并不影响最终结果。

解决方法

是的,如果您使用 ViewPort 并将视口设置为您的 UseCases(imageCapture or imageAnalysis as here https://developer.android.com/training/camerax/configuration),您只能获得有关裁剪矩形的信息,特别是如果您使用 ImageAnalysis(因为如果您使用 imageCapture,对于磁盘上的图像在保存之前被裁剪,它不适用于 ImageAnalysis,如果您使用 imageCapture 而不保存在磁盘上)和这里的解决方案我是如何解决这个问题的:

  1. 首先为用例设置视口,如下所示:https://developer.android.com/training/camerax/configuration

  2. 获取裁剪位图进行分析

    override fun analyze(imageProxy: ImageProxy) {
         val mediaImage = imageProxy.image
         if (mediaImage != null && mediaImage.format == ImageFormat.YUV_420_888) {
             croppedBitmap(mediaImage,imageProxy.cropRect).let { bitmap ->
                 requestDetectInImage(InputImage.fromBitmap(bitmap,rotation))
                     .addOnCompleteListener { imageProxy.close() }
             }
         } else {
             imageProxy.close()
         }
     }
    
     private fun croppedBitmap(mediaImage: Image,cropRect: Rect): Bitmap {
         val yBuffer = mediaImage.planes[0].buffer // Y
         val vuBuffer = mediaImage.planes[2].buffer // VU
    
         val ySize = yBuffer.remaining()
         val vuSize = vuBuffer.remaining()
    
         val nv21 = ByteArray(ySize + vuSize)
    
         yBuffer.get(nv21,ySize)
         vuBuffer.get(nv21,ySize,vuSize)
    
         val yuvImage = YuvImage(nv21,ImageFormat.NV21,mediaImage.width,mediaImage.height,null)
         val outputStream = ByteArrayOutputStream()
         yuvImage.compressToJpeg(cropRect,100,outputStream)
         val imageBytes = outputStream.toByteArray()
    
         return BitmapFactory.decodeByteArray(imageBytes,imageBytes.size)
     }
    

可能会降低转换速度,但在我的设备上我没有注意到差异。我在compressToJpeg方法中设置了100的质量,但是mb如果设置的质量低可以提高速度,需要测试。

更新:21 年 5 月 2 日:

我找到了另一种方法,无需先转换为 jpeg,然后再转换为位图。这应该是一种更快的方式。

  1. 将视口设置为以前的。

  2. 将 YUV_420_888 转换为 NV21,然后进行裁剪和分析。

     override fun analyze(imageProxy: ImageProxy) {
         val mediaImage = imageProxy.image
         if (mediaImage != null && mediaImage.format == ImageFormat.YUV_420_888) {
             croppedNV21(mediaImage,imageProxy.cropRect).let { byteArray ->
                 requestDetectInImage(
                     InputImage.fromByteArray(
                         byteArray,imageProxy.cropRect.width(),imageProxy.cropRect.height(),rotation,IMAGE_FORMAT_NV21,)
                 )
                     .addOnCompleteListener { imageProxy.close() }
             }
         } else {
             imageProxy.close()
         }
     }
    
     private fun croppedNV21(mediaImage: Image,cropRect: Rect): ByteArray {
         val yBuffer = mediaImage.planes[0].buffer // Y
         val vuBuffer = mediaImage.planes[2].buffer // VU
    
         val ySize = yBuffer.remaining()
         val vuSize = vuBuffer.remaining()
    
         val nv21 = ByteArray(ySize + vuSize)
    
         yBuffer.get(nv21,vuSize)
    
         return cropByteArray(nv21,cropRect)
     }
    
     private fun cropByteArray(array: ByteArray,imageWidth: Int,cropRect: Rect): ByteArray {
         val croppedArray = ByteArray(cropRect.width() * cropRect.height())
         var i = 0
         array.forEachIndexed { index,byte ->
             val x = index % imageWidth
             val y = index / imageWidth
    
             if (cropRect.left <= x && x < cropRect.right && cropRect.top <= y && y < cropRect.bottom) {
                 croppedArray[i] = byte
                 i++
             }
         }
    
         return croppedArray
     }
    

我从这里获得的第一个作物乐趣: Android: How to crop images using CameraX?

而且我还发现了另一种作物乐趣,似乎更复杂:

private fun cropByteArray(src: ByteArray,width: Int,height: Int,cropRect: Rect,): ByteArray {
    val x = cropRect.left * 2 / 2
    val y = cropRect.top * 2 / 2
    val w = cropRect.width() * 2 / 2
    val h = cropRect.height() * 2 / 2
    val yUnit = w * h
    val uv = yUnit / 2
    val nData = ByteArray(yUnit + uv)
    val uvIndexDst = w * h - y / 2 * w
    val uvIndexSrc = width * height + x
    var srcPos0 = y * width
    var destPos0 = 0
    var uvSrcPos0 = uvIndexSrc
    var uvDestPos0 = uvIndexDst
    for (i in y until y + h) {
        System.arraycopy(src,srcPos0 + x,nData,destPos0,w) //y memory block copy
        srcPos0 += width
        destPos0 += w
        if (i and 1 == 0) {
            System.arraycopy(src,uvSrcPos0,uvDestPos0,w) //uv memory block copy
            uvSrcPos0 += width
            uvDestPos0 += w
        }
    }
    return nData
}

我从这里获得的第二次收获乐趣: https://www.programmersought.com/article/75461140907/

如果有人能帮助改进代码,我会很高兴。

,

您将使用 ImageProxy.SetCroprect 获取矩形,然后使用 CropRect 设置它。 例如,如果你有 imageProxy,你会做: ImageProxy.setCropRect(Rect) 然后你会做 ImageProxy.CropRect。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-