react-native-nitro-pose-exercises 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/margelo/nitro/nitroposeexercises/NitroPoseExercises.kt +49 -43
- package/nitrogen/generated/android/nitroposeexercises+autolinking.cmake +0 -1
- package/package.json +1 -1
- package/nitrogen/generated/shared/c++/HybridWorkletQueueFactorySpec.cpp +0 -22
- package/nitrogen/generated/shared/c++/HybridWorkletQueueFactorySpec.hpp +0 -66
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
package com.margelo.nitro.nitroposeexercises
|
|
2
2
|
|
|
3
3
|
import android.graphics.Bitmap
|
|
4
|
-
import android.graphics.Matrix
|
|
5
4
|
import androidx.annotation.Keep
|
|
6
5
|
import com.facebook.proguard.annotations.DoNotStrip
|
|
7
|
-
import com.google.mediapipe.framework.image.
|
|
6
|
+
import com.google.mediapipe.framework.image.MediaImageBuilder
|
|
8
7
|
import com.google.mediapipe.tasks.core.BaseOptions
|
|
9
8
|
import com.google.mediapipe.tasks.vision.core.RunningMode
|
|
10
9
|
import com.google.mediapipe.tasks.vision.poselandmarker.PoseLandmarker
|
|
@@ -12,7 +11,7 @@ import com.google.mediapipe.tasks.vision.poselandmarker.PoseLandmarkerOptions
|
|
|
12
11
|
import com.margelo.nitro.NitroModules
|
|
13
12
|
import com.margelo.nitro.core.Promise
|
|
14
13
|
import com.margelo.nitro.camera.HybridFrameSpec
|
|
15
|
-
import com.margelo.nitro.camera
|
|
14
|
+
import com.margelo.nitro.camera.`public`.NativeFrame
|
|
16
15
|
import kotlin.math.acos
|
|
17
16
|
import kotlin.math.max
|
|
18
17
|
import kotlin.math.min
|
|
@@ -156,59 +155,66 @@ class HybridPoseExercise : HybridNitroPoseExercisesSpec() {
|
|
|
156
155
|
// Frame Processing
|
|
157
156
|
// ═══════════════════════════════════════════════════════════
|
|
158
157
|
|
|
159
|
-
|
|
158
|
+
override fun processFrame(frame: HybridFrameSpec) {
|
|
160
159
|
if (_status != SessionStatus.ACTIVE && _status != SessionStatus.COUNTDOWN) return
|
|
161
160
|
if (!isInitialized || poseLandmarker == null) return
|
|
162
161
|
|
|
163
|
-
// Cast to NativeFrame to get the ImageProxy
|
|
164
|
-
val nativeFrame = frame as? NativeFrame ?: return
|
|
165
|
-
val imageProxy = nativeFrame.image ?: return
|
|
166
|
-
|
|
167
162
|
frameCount++
|
|
168
163
|
if (frameCount % processEveryNFrames != 0) return
|
|
169
164
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
val bitmap = imageProxyToBitmap(imageProxy)
|
|
173
|
-
val mpImage = BitmapImageBuilder(bitmap).build()
|
|
174
|
-
|
|
175
|
-
val result = poseLandmarker!!.detect(mpImage)
|
|
176
|
-
|
|
177
|
-
if (result.landmarks().isNotEmpty()) {
|
|
178
|
-
val poseLandmarks = result.landmarks()[0]
|
|
179
|
-
|
|
180
|
-
if (poseWasLost) {
|
|
181
|
-
poseWasLost = false
|
|
182
|
-
onPoseRegained?.invoke()
|
|
183
|
-
}
|
|
165
|
+
val nativeFrame = frame as? NativeFrame ?: return
|
|
166
|
+
val imageProxy = nativeFrame.image ?: return
|
|
184
167
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
)
|
|
192
|
-
}.toTypedArray()
|
|
193
|
-
|
|
194
|
-
if (_status == SessionStatus.ACTIVE) {
|
|
195
|
-
processExerciseLogic()
|
|
196
|
-
}
|
|
168
|
+
try {
|
|
169
|
+
val bitmapBuffer = Bitmap.createBitmap(
|
|
170
|
+
imageProxy.width,
|
|
171
|
+
imageProxy.height,
|
|
172
|
+
Bitmap.Config.ARGB_8888
|
|
173
|
+
)
|
|
197
174
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
175
|
+
// Use MediaPipe's BitmapImageBuilder
|
|
176
|
+
imageProxy.use {
|
|
177
|
+
val mpImage = com.google.mediapipe.framework.image.MediaImageBuilder(
|
|
178
|
+
imageProxy.image!!
|
|
179
|
+
).build()
|
|
180
|
+
|
|
181
|
+
val result = poseLandmarker!!.detect(mpImage)
|
|
182
|
+
|
|
183
|
+
if (result.landmarks().isNotEmpty()) {
|
|
184
|
+
val poseLandmarks = result.landmarks()[0]
|
|
185
|
+
|
|
186
|
+
if (poseWasLost) {
|
|
187
|
+
poseWasLost = false
|
|
188
|
+
onPoseRegained?.invoke()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
_landmarks = poseLandmarks.map { lm ->
|
|
192
|
+
Landmark(
|
|
193
|
+
x = lm.x().toDouble(),
|
|
194
|
+
y = lm.y().toDouble(),
|
|
195
|
+
z = lm.z().toDouble(),
|
|
196
|
+
visibility = (lm.visibility().orElse(0f)).toDouble()
|
|
197
|
+
)
|
|
198
|
+
}.toTypedArray()
|
|
199
|
+
|
|
200
|
+
if (_status == SessionStatus.ACTIVE) {
|
|
201
|
+
processExerciseLogic()
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
if (!poseWasLost) {
|
|
205
|
+
poseWasLost = true
|
|
206
|
+
onPoseLost?.invoke()
|
|
207
|
+
}
|
|
208
|
+
_landmarks = emptyArray()
|
|
209
|
+
}
|
|
202
210
|
}
|
|
203
|
-
_landmarks = emptyArray()
|
|
204
|
-
}
|
|
205
211
|
|
|
206
|
-
|
|
212
|
+
bitmapBuffer.recycle()
|
|
207
213
|
|
|
208
214
|
} catch (e: Exception) {
|
|
209
|
-
|
|
215
|
+
// MediaPipe detection failed — skip this frame
|
|
210
216
|
}
|
|
211
|
-
|
|
217
|
+
}
|
|
212
218
|
|
|
213
219
|
// ═══════════════════════════════════════════════════════════
|
|
214
220
|
// ImageProxy to Bitmap conversion
|
|
@@ -34,7 +34,6 @@ target_sources(
|
|
|
34
34
|
../nitrogen/generated/android/nitroposeexercisesOnLoad.cpp
|
|
35
35
|
# Shared Nitrogen C++ sources
|
|
36
36
|
../nitrogen/generated/shared/c++/HybridNitroPoseExercisesSpec.cpp
|
|
37
|
-
../nitrogen/generated/shared/c++/HybridWorkletQueueFactorySpec.cpp
|
|
38
37
|
# Android-specific Nitrogen C++ sources
|
|
39
38
|
../nitrogen/generated/android/c++/JHybridNitroPoseExercisesSpec.cpp
|
|
40
39
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nitro-pose-exercises",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Real-time on-device exercise tracking for React Native. Rep counting, form validation, and skeleton overlay powered by MediaPipe Pose Landmarker and VisionCamera v5 via Nitro Modules.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
///
|
|
2
|
-
/// HybridWorkletQueueFactorySpec.cpp
|
|
3
|
-
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
-
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright © Marc Rousavy @ Margelo
|
|
6
|
-
///
|
|
7
|
-
|
|
8
|
-
#include "HybridWorkletQueueFactorySpec.hpp"
|
|
9
|
-
|
|
10
|
-
namespace margelo::nitro::camera::worklets {
|
|
11
|
-
|
|
12
|
-
void HybridWorkletQueueFactorySpec::loadHybridMethods() {
|
|
13
|
-
// load base methods/properties
|
|
14
|
-
HybridObject::loadHybridMethods();
|
|
15
|
-
// load custom methods/properties
|
|
16
|
-
registerHybrids(this, [](Prototype& prototype) {
|
|
17
|
-
prototype.registerHybridMethod("wrapThreadInQueue", &HybridWorkletQueueFactorySpec::wrapThreadInQueue);
|
|
18
|
-
prototype.registerHybridMethod("getCurrentThreadMarker", &HybridWorkletQueueFactorySpec::getCurrentThreadMarker);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
} // namespace margelo::nitro::camera::worklets
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
///
|
|
2
|
-
/// HybridWorkletQueueFactorySpec.hpp
|
|
3
|
-
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
-
/// https://github.com/mrousavy/nitro
|
|
5
|
-
/// Copyright © Marc Rousavy @ Margelo
|
|
6
|
-
///
|
|
7
|
-
|
|
8
|
-
#pragma once
|
|
9
|
-
|
|
10
|
-
#if __has_include(<NitroModules/HybridObject.hpp>)
|
|
11
|
-
#include <NitroModules/HybridObject.hpp>
|
|
12
|
-
#else
|
|
13
|
-
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
14
|
-
#endif
|
|
15
|
-
|
|
16
|
-
// Forward declaration of `HybridNativeThreadSpec` to properly resolve imports.
|
|
17
|
-
namespace margelo::nitro::camera { class HybridNativeThreadSpec; }
|
|
18
|
-
|
|
19
|
-
#include "JSIConverter+AsyncQueue.hpp"
|
|
20
|
-
#include <memory>
|
|
21
|
-
#include <VisionCamera/HybridNativeThreadSpec.hpp>
|
|
22
|
-
|
|
23
|
-
namespace margelo::nitro::camera::worklets {
|
|
24
|
-
|
|
25
|
-
using namespace margelo::nitro;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* An abstract base class for `WorkletQueueFactory`
|
|
29
|
-
* Inherit this class to create instances of `HybridWorkletQueueFactorySpec` in C++.
|
|
30
|
-
* You must explicitly call `HybridObject`'s constructor yourself, because it is virtual.
|
|
31
|
-
* @example
|
|
32
|
-
* ```cpp
|
|
33
|
-
* class HybridWorkletQueueFactory: public HybridWorkletQueueFactorySpec {
|
|
34
|
-
* public:
|
|
35
|
-
* HybridWorkletQueueFactory(...): HybridObject(TAG) { ... }
|
|
36
|
-
* // ...
|
|
37
|
-
* };
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
class HybridWorkletQueueFactorySpec: public virtual HybridObject {
|
|
41
|
-
public:
|
|
42
|
-
// Constructor
|
|
43
|
-
explicit HybridWorkletQueueFactorySpec(): HybridObject(TAG) { }
|
|
44
|
-
|
|
45
|
-
// Destructor
|
|
46
|
-
~HybridWorkletQueueFactorySpec() override = default;
|
|
47
|
-
|
|
48
|
-
public:
|
|
49
|
-
// Properties
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
public:
|
|
53
|
-
// Methods
|
|
54
|
-
virtual std::shared_ptr<::worklets::AsyncQueue> wrapThreadInQueue(const std::shared_ptr<margelo::nitro::camera::HybridNativeThreadSpec>& thread) = 0;
|
|
55
|
-
virtual double getCurrentThreadMarker() = 0;
|
|
56
|
-
|
|
57
|
-
protected:
|
|
58
|
-
// Hybrid Setup
|
|
59
|
-
void loadHybridMethods() override;
|
|
60
|
-
|
|
61
|
-
protected:
|
|
62
|
-
// Tag for logging
|
|
63
|
-
static constexpr auto TAG = "WorkletQueueFactory";
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
} // namespace margelo::nitro::camera::worklets
|