Initial commit
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
package com.example.jnicpp.bowling
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.Paint
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.example.jnicpp.R
|
||||
import com.google.mlkit.vision.pose.Pose
|
||||
|
||||
/**
|
||||
* Draws the 33 ML Kit pose landmarks and connecting skeleton lines on top of
|
||||
* the camera preview. The landmark topology and the coordinate mapping math
|
||||
* (analysis-image pixels -> view pixels, replicating `PreviewView`'s
|
||||
* `FILL_CENTER` scaling) live in [PoseSkeletonRenderer], shared with
|
||||
* [CameraXController]'s baked-into-the-recorded-video overlay so both paths
|
||||
* can't drift apart.
|
||||
*/
|
||||
class PoseOverlayView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : View(context, attrs) {
|
||||
|
||||
private val jointPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
color = ContextCompat.getColor(context, R.color.skeleton_joint)
|
||||
style = Paint.Style.FILL
|
||||
}
|
||||
private val bonePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
|
||||
color = ContextCompat.getColor(context, R.color.skeleton_bone)
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = PoseSkeletonRenderer.STROKE_WIDTH
|
||||
}
|
||||
|
||||
private var pose: Pose? = null
|
||||
private var isFrontCamera = false
|
||||
|
||||
// Source image size and rotation, as last reported by the analyzer --
|
||||
// fed straight into PoseSkeletonRenderer.computeTransform on every
|
||||
// size/frame change.
|
||||
private var sourceWidth = 0
|
||||
private var sourceHeight = 0
|
||||
private var sourceRotationDegrees = 0
|
||||
|
||||
private var transform = Matrix()
|
||||
|
||||
/** Called from the main thread with the latest analyzer result, or null to clear. */
|
||||
fun update(frame: PoseAnalyzer.PoseFrameResult?) {
|
||||
pose = frame?.pose
|
||||
if (frame != null) {
|
||||
isFrontCamera = frame.isFrontCamera
|
||||
sourceWidth = frame.imageWidth
|
||||
sourceHeight = frame.imageHeight
|
||||
sourceRotationDegrees = frame.rotationDegrees
|
||||
}
|
||||
recomputeTransform()
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
pose = null
|
||||
invalidate()
|
||||
}
|
||||
|
||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||
super.onSizeChanged(w, h, oldw, oldh)
|
||||
recomputeTransform()
|
||||
}
|
||||
|
||||
private fun recomputeTransform() {
|
||||
transform = PoseSkeletonRenderer.computeTransform(
|
||||
sourceWidth = sourceWidth,
|
||||
sourceHeight = sourceHeight,
|
||||
sourceRotationDegrees = sourceRotationDegrees,
|
||||
targetWidth = width,
|
||||
targetHeight = height,
|
||||
// Front camera preview is mirrored; flip the x axis about the
|
||||
// view's center so the overlay matches what's on screen.
|
||||
mirror = isFrontCamera
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
val currentPose = pose ?: return
|
||||
PoseSkeletonRenderer.draw(canvas, currentPose, transform, bonePaint, jointPaint)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user