iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 25
1

FaceRecognizer

  • 從相簿選取一張圖片
  • 通過人臉識別找到人臉,並在圖片上畫一個方塊

Face Recognizer

這一個臉部識別的流程是

  • 從 Album 中取出一張照片
  • 放到 FaceView 的 Canvas 上
  • 通過 FaceDetector 偵測人臉
  • 偵測到人臉以後,在人臉上畫一個黃色的方塊

FaceView

初始化我們的 Canvas 以及 Paint

注意:官方文件有標註 bitmap must be in 565 format.

class FaceView(context: Context, attrs: AttributeSet): View(context, attrs) {
    private var paint: Paint
    private var bitmap: Bitmap
    private var canvas: Canvas

    private val maxFaceNumbers = 25
    private var numberOfFaceDetected = 0
    private var faces = arrayOfNulls<FaceDetector.Face>(25)

    init {
        // bitmap
        val width = Resources.getSystem().displayMetrics.widthPixels
        bitmap = Bitmap.createBitmap(width, 800, Bitmap.Config.RGB_565)

        // Canvas
        canvas = Canvas(bitmap)
        canvas.drawColor(Color.GRAY)

        // Paint
        paint = Paint()
        paint.color = Color.YELLOW
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = 4f
        paint.textSize = 50f

    }
}

setupWithImage 方法

提供一個來放入圖片的 Uri 的方法,將圖片的大小轉成和 FaceView 相同。

    fun setupWithImage(uri: Uri) {
        Log.e("FaceView","Setup With Uri $uri")

        try {
            val resolver = context.contentResolver

            // must be RGB_565
            val options = BitmapFactory.Options()
            options.inPreferredConfig = Bitmap.Config.RGB_565

            val image = BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options)

            // scale the bitmap
            bitmap = ThumbnailUtils.extractThumbnail(image, width, height)

        } catch (e: Exception) {
            Log.e("setup with image","failed")
        }
    }

DetectFace 方法

通過 FaceDetector 來進行人臉偵測,偵測結束後通過 invalidate() 來呼叫 onDraw 方法

override onDraw 方法

當觸發 onDraw 方法的時候,會去看有幾張臉被識別出來,

根據雙眼的距離來計算整張臉的位置,然後在臉上畫黃色的方塊。
https://ithelp.ithome.com.tw/upload/images/20171228/201073299QOwt5HdgL.png


MainActivity

通過 Intent 讓使用者選取圖片

private fun takeImageFromAlbum() {
    val intent = Intent()
    intent.type = "image/*"
    intent.action = Intent.ACTION_GET_CONTENT
    startActivityForResult(intent, OPEN_PHOTO_FOLDER_REQUEST_CODE)

}

onActivityResult

通過 intent 來接收圖片的 Uri 然後丟給 FaceView 呈現在畫面上。

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    println("onActivityResult requestCode is $requestCode")

    when(requestCode){
        OPEN_PHOTO_FOLDER_REQUEST_CODE -> {
            val imageUri = data?.data
            println("imageUri is $imageUri")
            if(imageUri != null){
                faceView.setupWithImage(imageUri)
            } else {
                Toast.makeText(this,"get image Uri failed", Toast.LENGTH_SHORT).show()
            }
        }

        else -> {
            println("no handler on ActivityResult, resultcode is $resultCode")
        }
    }

}

detectFace 方法

在通過剛才 FaceView 提供的 detectFace 方法進行臉部識別和畫方塊的功能。

faceView.detectFace()

筆記

  • 研究:原本無法識別的臉部圖片,我通過工具轉成 jpg 就可以識別了,這是為什麼?

參考


上一篇
Kotlin 開發第 24 天 Painter (Canvas)
下一篇
Kotlin 開發第 26 天 ActionSend ( Intent-Filter )
系列文
Kotlin 30 天,通過每天一個小 demo 學習 Android 開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言