使用 Google Face Detection ML Kit 在现有照片周围绘制一个框

Posted

技术标签:

【中文标题】使用 Google Face Detection ML Kit 在现有照片周围绘制一个框【英文标题】:Drawing a Box Around Face To Existed Photos with Google Face Detection ML Kit 【发布时间】:2021-07-12 06:25:20 【问题描述】:

我们在 android 中实现了用于人脸检测的 Android ML Kit。它的作用就像魅力一样,可以检测人脸。

问题:当检测到多个人脸时,我们想在检测到的人脸周围绘制矩形

我们做了什么:

已实现

 implementation 'com.google.android.gms:play-services-mlkit-face-detection:16.1.5'

创建了一个自定义视图:

class FaceView(val theContext : Context, val bounds : Rect) : View(theContext) 

    override fun onDraw(canvas: Canvas?) 
        super.onDraw(canvas)

        val myPaint = Paint()

        myPaint.color = Color.BLACK
        myPaint.style = Paint.Style.STROKE
        myPaint.strokeWidth = 10f

        canvas?.drawRect(bounds, myPaint)
    

试图在我们从人脸对象 ML 套件创建的边界上绘制一个矩形

val result = detector.process(image).addOnSuccessListener  faces ->

for (face in faces) 
val bounds = face.boundingBox

val view = FaceView(requireContext(), bounds)
binding.actionRoot.addView(view)

val lp : ConstraintLayout.LayoutParams =
 ConstraintLayout.LayoutParams(bounds.width(),bounds.height())

lp.startToStart = binding.actionPhoto.id
lp.topToTop = binding.actionPhoto.id

lp.marginStart = bounds.right
lp.topMargin = bounds.bottom
        
view.layoutParams = lp

结果:

我们如何为我们从 URI(不是从 CameraX)生成的每个人脸绘制一个矩形并使其可点击?

【问题讨论】:

【参考方案1】:

这里可以参考项目,不过是java代码

https://github.com/kkdroidgit/FaceDetect

【讨论】:

感谢您的回复。我检查了它,我可以用这种方法在脸部周围画一个矩形。但我也需要是可点击的(选择要改变的脸),并且项目中提供的功能不包括它。我的目的不是创建绘制的位图,而是创建图像视图。【参考方案2】:

-- 虽然 ML 套件提供检测到的人脸的矩形。我认为 Google Developers 让我们更轻松,自动绘制矩形并将人脸作为独立的位图对象提供。

对于我的解决方案:

我使用@anonymous 建议的示例项目在脸部周围画线。

首先,我从提供的面部矩形中获得了起点、终点、底部和顶部。 (这个矩形是从原始位图创建的,而不是从图像视图中创建的。所以矩形点属于我使用的原始位图)。

由于 Rect 点不属于 ImageView 而属于位图本身,我们需要在 ImageView 上找到相关的 rect 点(或者创建一个缩放的位图并在其上检测人脸)。我们将这些点计算为原始位图中的百分比。

虽然我们在示例项目中使用原始点来绘制线条。我们实现了一个带有透明背景的视图,使用计算点来使面部矩形可点击。

-作为最后一件事,我们为每个面创建了位图。

    detector.process(theImage)
                    .addOnSuccessListener  faces ->
    
           val bounds = face.boundingBox
            val screenWidth = GetScreenWidth().execute()
    
            // val theImage = InputImage.fromBitmap(tempBitmap,0)
    
            val paint = Paint()
            paint.strokeWidth = 1f
            paint.color = Color.RED
            paint.style = Paint.Style.STROKE
    
            val theStartPoint = if(bounds.left < 0) 0 else bounds.left
            val theEndPoint = if(bounds.right > tempBitmap.width) tempBitmap.width else  bounds.right
            val theTopPoint = if(bounds.top < 0) 0 else  bounds.top 
            val theBottomPoint = if(bounds.bottom > tempBitmap.height) tempBitmap.height else  bounds.bottom 
    
            val faceWidth = theEndPoint - theStartPoint
            val faceHeight = theBottomPoint - theTopPoint
    
            Log.d(Statics.LOG_TAG, "Face width : $faceWidth Face Height $faceHeight")
    
            val startPointPercent = theStartPoint.toFloat() / tempBitmap.width.toFloat()
            val topPointPercent = theTopPoint.toFloat() / tempBitmap.height.toFloat()
    
            Log.d(Statics.LOG_TAG, "Face start point percent : $startPointPercent Face top percent $topPointPercent")
    
            val faceWidthPercent = faceWidth / tempBitmap.width.toFloat()
            val faceHeightPercent = faceHeight / tempBitmap.height.toFloat()
    
            Log.d(Statics.LOG_TAG, "Face width  percent: $faceWidthPercent Face Height Percent $faceHeightPercent")
    
            val faceImage = ConstraintLayout(requireContext())
            faceImage.setBackgroundColor(Color.TRANSPARENT)
            binding.actionRoot.addView(faceImage)
    
            val boxWidth = screenWidth.toFloat()*faceWidthPercent
            val boxHeight = screenWidth.toFloat()*faceHeightPercent
    
            Log.d(Statics.LOG_TAG, "Box width : $boxWidth Box Height $boxHeight")
    
            val lp : ConstraintLayout.LayoutParams =
                ConstraintLayout.LayoutParams(
                    boxWidth.toInt(),
                    boxHeight.toInt()
                )
    
    
            lp.startToStart = binding.actionPhoto.id
            lp.topToTop = binding.actionPhoto.id
    
            lp.marginStart = (screenWidth * startPointPercent).toInt()
            lp.topMargin = (screenWidth * topPointPercent).toInt()
    
            faceImage.layoutParams = lp
    
            val theFaceBitmap = Bitmap.createBitmap(
                tempBitmap,
                theStartPoint,
                theTopPoint,
                faceWidth,
                faceHeight)
    
    
            if (face.trackingId != null) 
                val id = face.trackingId
    
                faceImage.setOnClickListener 
                    
                
                    binding.actionPhoto.setImageBitmap(theFaceBitmap)
                    
                 
                
            

结果:

【讨论】:

以上是关于使用 Google Face Detection ML Kit 在现有照片周围绘制一个框的主要内容,如果未能解决你的问题,请参考以下文章

face detection,landmark, recognition with deeplearning

在 C++ 中反序列化 cnn_face_detection_model_v1

dlib:无法打开 face_landmark_detection_ex 进行阅读?

谁有关于如何使用 Face Detection Camera 2 API 的资料?

face detection[FaceBoxes]

姿态分析开源工具箱MMPose安装及使用示例(2d face landmark detection)