Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbaa7bb04f | ||
|
|
1c6ced2dce |
Generated
+4
@@ -2,6 +2,10 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="deploymentTargetSelector">
|
<component name="deploymentTargetSelector">
|
||||||
<selectionStates>
|
<selectionStates>
|
||||||
|
<SelectionState runConfigName="Unnamed">
|
||||||
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
|
<DialogSelection />
|
||||||
|
</SelectionState>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
<DropdownSelection timestamp="2026-09-05T10:57:53.251732600Z">
|
<DropdownSelection timestamp="2026-09-05T10:57:53.251732600Z">
|
||||||
|
|||||||
Generated
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="temurin-21" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ import androidx.lifecycle.LifecycleOwner
|
|||||||
import com.example.jnicpp.R
|
import com.example.jnicpp.R
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
import com.google.mlkit.vision.pose.PoseLandmark // for testing
|
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -325,10 +323,6 @@ class CameraXController(
|
|||||||
PoseSkeletonRenderer.draw(canvas, poseFrame.landmarks, transform, overlayBonePaint, overlayJointPaint)
|
PoseSkeletonRenderer.draw(canvas, poseFrame.landmarks, transform, overlayBonePaint, overlayJointPaint)
|
||||||
PoseSkeletonRenderer.drawAngleLabels(canvas, poseFrame.landmarks, poseFrame.angles, transform, overlayAnglePaint)
|
PoseSkeletonRenderer.drawAngleLabels(canvas, poseFrame.landmarks, poseFrame.angles, transform, overlayAnglePaint)
|
||||||
|
|
||||||
val leftWrist = poseFrame.landmarks[PoseLandmark.LEFT_WRIST]
|
|
||||||
val singleLandmark = if (leftWrist != null) mapOf(PoseLandmark.LEFT_WRIST to leftWrist) else emptyMap()
|
|
||||||
feedbackUI?.drawCircles(canvas, singleLandmark, transform, forRecord = true)
|
|
||||||
|
|
||||||
val state = recordingOverlayStateProvider?.invoke()
|
val state = recordingOverlayStateProvider?.invoke()
|
||||||
val scale = feedbackUI?.computeCamScale(canvas) ?: (minOf(targetWidth, targetHeight) / 1080f)
|
val scale = feedbackUI?.computeCamScale(canvas) ?: (minOf(targetWidth, targetHeight) / 1080f)
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import androidx.camera.core.ImageProxy
|
|||||||
import com.google.mlkit.vision.common.InputImage
|
import com.google.mlkit.vision.common.InputImage
|
||||||
import com.google.mlkit.vision.pose.PoseDetection
|
import com.google.mlkit.vision.pose.PoseDetection
|
||||||
import com.google.mlkit.vision.pose.PoseDetector
|
import com.google.mlkit.vision.pose.PoseDetector
|
||||||
import com.google.mlkit.vision.pose.defaults.PoseDetectorOptions
|
import com.google.mlkit.vision.pose.accurate.AccuratePoseDetectorOptions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Bridges CameraX's [ImageAnalysis] frame stream into ML Kit's
|
* @brief Bridges CameraX's [ImageAnalysis] frame stream into ML Kit's
|
||||||
@@ -84,8 +84,8 @@ class PoseAnalyzer(
|
|||||||
// if later angle-based form analysis needs the extra precision and a
|
// if later angle-based form analysis needs the extra precision and a
|
||||||
// real device's frame rate can keep up with it.
|
// real device's frame rate can keep up with it.
|
||||||
private val detector: PoseDetector = PoseDetection.getClient(
|
private val detector: PoseDetector = PoseDetection.getClient(
|
||||||
PoseDetectorOptions.Builder()
|
AccuratePoseDetectorOptions.Builder()
|
||||||
.setDetectorMode(PoseDetectorOptions.STREAM_MODE)
|
.setDetectorMode(AccuratePoseDetectorOptions.STREAM_MODE)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ class PoseLandmarkSmoother(
|
|||||||
SmoothedLandmark(
|
SmoothedLandmark(
|
||||||
x = prev.x + (smoothingFactor * (landmark.position.x - prev.x)),
|
x = prev.x + (smoothingFactor * (landmark.position.x - prev.x)),
|
||||||
y = prev.y + (smoothingFactor * (landmark.position.y - prev.y)),
|
y = prev.y + (smoothingFactor * (landmark.position.y - prev.y)),
|
||||||
inFrameLikelihood = prev.inFrameLikelihood +
|
inFrameLikelihood = landmark.inFrameLikelihood,
|
||||||
(smoothingFactor * (landmark.inFrameLikelihood - prev.inFrameLikelihood)),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
previous[landmark.landmarkType] = next
|
previous[landmark.landmarkType] = next
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import android.util.AttributeSet
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.example.jnicpp.R
|
import com.example.jnicpp.R
|
||||||
import com.google.mlkit.vision.pose.PoseLandmark // for testing
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Draws the 33 ML Kit pose landmarks and connecting skeleton lines
|
* @brief Draws the 33 ML Kit pose landmarks and connecting skeleton lines
|
||||||
@@ -126,19 +125,6 @@ class PoseOverlayView @JvmOverloads constructor(
|
|||||||
val currentLandmarks = landmarks ?: return
|
val currentLandmarks = landmarks ?: return
|
||||||
PoseSkeletonRenderer.draw(canvas, currentLandmarks, transform, bonePaint, jointPaint)
|
PoseSkeletonRenderer.draw(canvas, currentLandmarks, transform, bonePaint, jointPaint)
|
||||||
angles?.let { PoseSkeletonRenderer.drawAngleLabels(canvas, currentLandmarks, it, transform, anglePaint) }
|
angles?.let { PoseSkeletonRenderer.drawAngleLabels(canvas, currentLandmarks, it, transform, anglePaint) }
|
||||||
|
|
||||||
// currentLandmarks to change to landmarks that require highlighting
|
|
||||||
// test code to contain only left wrist in currentLandmarks to not clutter the screen
|
|
||||||
val leftWrist = currentLandmarks[PoseLandmark.LEFT_WRIST]
|
|
||||||
|
|
||||||
// Build a single‑item map if it exists
|
|
||||||
val singleLandmark = if (leftWrist != null) {
|
|
||||||
mapOf(PoseLandmark.LEFT_WRIST to leftWrist)
|
|
||||||
} else {
|
|
||||||
emptyMap()
|
|
||||||
}
|
|
||||||
// end test code
|
|
||||||
feedbackUI?.drawCircles(canvas, singleLandmark, transform)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import com.google.mlkit.vision.pose.PoseLandmark
|
|||||||
object PoseSkeletonRenderer {
|
object PoseSkeletonRenderer {
|
||||||
|
|
||||||
/** @brief Minimum `inFrameLikelihood` a landmark needs to be considered reliable enough to draw or use. */
|
/** @brief Minimum `inFrameLikelihood` a landmark needs to be considered reliable enough to draw or use. */
|
||||||
const val MIN_LIKELIHOOD = 0.5f
|
const val MIN_LIKELIHOOD = 0.35f
|
||||||
/** @brief Radius, in target/view pixels, of each drawn joint dot. */
|
/** @brief Radius, in target/view pixels, of each drawn joint dot. */
|
||||||
const val DOT_RADIUS = 8f
|
const val DOT_RADIUS = 8f
|
||||||
/** @brief Stroke width, in target/view pixels, of each drawn bone line. */
|
/** @brief Stroke width, in target/view pixels, of each drawn bone line. */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "9.1.1"
|
agp = "9.4.0"
|
||||||
coreKtx = "1.18.0"
|
coreKtx = "1.18.0"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.3.0"
|
junitVersion = "1.3.0"
|
||||||
@@ -30,9 +30,10 @@ androidx-camera-effects = { group = "androidx.camera", name = "camera-effects",
|
|||||||
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
|
androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle" }
|
||||||
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
|
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" }
|
||||||
androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityKtx" }
|
androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityKtx" }
|
||||||
mlkit-pose-detection = { group = "com.google.mlkit", name = "pose-detection", version.ref = "mlkitPoseDetection" }
|
|
||||||
mlkit-pose-detection-accurate = { group = "com.google.mlkit", name = "pose-detection-accurate", version.ref = "mlkitPoseDetection" }
|
mlkit-pose-detection-accurate = { group = "com.google.mlkit", name = "pose-detection-accurate", version.ref = "mlkitPoseDetection" }
|
||||||
|
mlkit-pose-detection = { group = "com.google.mlkit", name = "pose-detection", version.ref = "mlkitPoseDetection" }
|
||||||
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" }
|
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=b266d5ff6b90eada6dc3b20cb090e3731302e553a27c5d3e4df1f0d76beaff06
|
distributionSha256Sum=b266d5ff6b90eada6dc3b20cb090e3731302e553a27c5d3e4df1f0d76beaff06
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.0-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
Reference in New Issue
Block a user