iT邦幫忙

2021 iThome 鐵人賽

DAY 28
0
Mobile Development

Kotlin Android 30天,從 0 到 ML (Machine Learning)系列 第 28

Kotlin Android 第28天,從 0 到 ML - TensorFlow Lite -姿態估計 (Pose estimation)

  • 分享至 

  • xImage
  •  

前言:

   常常看到特效電影幕後花絮,都有請演員在綠幕前在錄動作身上都有點點,在螢幕上變成火材人,姿態估計是使用 ML 模型通過估計身體關鍵關節(關鍵點)的空間位置,從圖像或影片中估計人的姿勢的任務。
    

大綱 :

來看一下的姿態估計codelab的實作吧

範例提供了兩個 TensorFlow Lite 姿態估計模型的參考實現:

MoveNet:最先進的姿勢估計模型有兩種版本:Lighting 和 Thunder。
PoseNet:2017 年發布的上一代姿態估計模型。

MoveNet 有兩種版本:
MoveNet.Lightning 比 Thunder 版本更小、更快但準確度較低。它可以在現代智能手機上實時運行。
MoveNet.Thunder 是更準確的版本,但也比 Lightning 更大更慢。它對於需要更高準確性的用例很有用。

MoveNet 在各種數據集上的表現都優於 PoseNet,尤其是在帶有健身動作圖像的圖像中。因此,我們建議在 PoseNet 上使用 MoveNet。

將 TensorFlow Lite 模型添加到assets文件夾

 movenet_lightning.tflite
 movenet_thunder.tflite
 posenet.tflite

build.gradle(app)

dependencies {
   implementation 'org.tensorflow:tensorflow-lite:2.5.0'
   implementation 'org.tensorflow:tensorflow-lite-gpu:2.5.0'
   implementation 'org.tensorflow:tensorflow-lite-support:0.2.0'
}

**姿態估計 (Pose estimation) 是顯示在 camrea 的預覽畫面,就看一下camrea + surfaceView 重點部份吧
**

camrea 的 imageReader

imageReader =
   ImageReader.newInstance(PREVIEW_WIDTH, PREVIEW_HEIGHT,ImageFormat.YUV_420_888, 3)
    imageReader?.setOnImageAvailableListener({ reader ->
        val image = reader.acquireLatestImage()
        if (image != null) {
            if (!::imageBitmap.isInitialized) {
                imageBitmap =
                    Bitmap.createBitmap(
                        PREVIEW_WIDTH,
                        PREVIEW_HEIGHT,
                        Bitmap.Config.ARGB_8888
                    )
            }
            yuvConverter.yuvToRgb(image, imageBitmap)
            // Create rotated version for portrait display
            val rotateMatrix = Matrix()
            rotateMatrix.postRotate(90.0f)

            val rotatedBitmap = Bitmap.createBitmap(
                imageBitmap, 0, 0, PREVIEW_WIDTH, PREVIEW_HEIGHT,
                rotateMatrix, false
            )
            processImage(rotatedBitmap)
            image.close()
        }
    }, imageReaderHandler)


// process image
private fun processImage(bitmap: Bitmap) {
    var person: Person? = null
    var classificationResult: List<Pair<String, Float>>? = null

   //姿態估計模組
    synchronized(lock) {
        detector?.estimateSinglePose(bitmap)?.let {
            person = it
            classifier?.run {
                classificationResult = classify(person)
            }
        }
    }
    frameProcessedInOneSecondInterval++
    if (frameProcessedInOneSecondInterval == 1) {
        // send fps to view
        listener?.onFPSListener(framesPerSecond)
    }

    //姿態估計模組結果
    listener?.onDetectedInfo(person?.score, classificationResult)
    person?.let {
        visualize(it, bitmap)
    }
}

//依姿態估計模組結果畫圖
private fun visualize(person: Person, bitmap: Bitmap) {
    var outputBitmap = bitmap

    if (person.score > MIN_CONFIDENCE) {
        outputBitmap = VisualizationUtils.drawBodyKeypoints(bitmap, person)
    }

    val holder = surfaceView.holder
    val surfaceCanvas = holder.lockCanvas()
    surfaceCanvas?.let { canvas ->
        val screenWidth: Int
        val screenHeight: Int
        val left: Int
        val top: Int

        if (canvas.height > canvas.width) {
            val ratio = outputBitmap.height.toFloat() / outputBitmap.width
            screenWidth = canvas.width
            left = 0
            screenHeight = (canvas.width * ratio).toInt()
            top = (canvas.height - screenHeight) / 2
        } else {
            val ratio = outputBitmap.width.toFloat() / outputBitmap.height
            screenHeight = canvas.height
            top = 0
            screenWidth = (canvas.height * ratio).toInt()
            left = (canvas.width - screenWidth) / 2
        }
        val right: Int = left + screenWidth
        val bottom: Int = top + screenHeight

        canvas.drawBitmap(
            outputBitmap, Rect(0, 0, outputBitmap.width, outputBitmap.height),
            Rect(left, top, right, bottom), null
        )
        surfaceView.holder.unlockCanvasAndPost(canvas)
    }
}

執行結果:

手機上是用CPU 使用Lightning 加 PoseNet 計算時間比較短,效果比較明顯。

https://ithelp.ithome.com.tw/upload/images/20211003/20121643JVHXfREs47.png

參考:

https://www.tensorflow.org/lite/examples/pose_estimation/overview
https://github.com/tensorflow/examples/tree/master/lite/examples/pose_estimation/android


上一篇
Kotlin Android 第27天,從 0 到 ML - TensorFlow Lite -物體檢測 (Object detection)
下一篇
Kotlin Android 第29天,從 0 到 ML - TensorFlow Lite - 藝術風格轉換(Style Transfer)
系列文
Kotlin Android 30天,從 0 到 ML (Machine Learning)30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言