Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions apps/computer-vision/app/pose_estimation/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import Spinner from '../../components/Spinner';
import { BottomBar } from '../../components/BottomBar';
import { ModelPicker, ModelOption } from '../../components/ModelPicker';
import { getImage } from '../../utils';
import {
models,
usePoseEstimation,
PoseDetections,
PoseEstimationModelSources,
RnExecutorchError,
RnExecutorchErrorCode,
} from 'react-native-executorch';
Expand All @@ -17,6 +19,16 @@ import Svg, { Circle, Line } from 'react-native-svg';
import ErrorBanner from '../../components/ErrorBanner';
import { COCO_SKELETON_CONNECTIONS } from '../../components/utils/cocoSkeleton';

const poseEstimation = models.pose_estimation;

const MODELS: ModelOption<PoseEstimationModelSources>[] = [
{ label: 'YOLO26N Pose', value: poseEstimation.yolo26n() },
{
label: 'RF-DETR Keypoint (beta)',
value: poseEstimation.rfdetr_keypoint_preview(),
},
];

// Colors for different people
const PERSON_COLORS = ['lime', 'cyan', 'magenta', 'yellow', 'orange', 'pink'];

Expand All @@ -30,8 +42,10 @@ export default function PoseEstimationScreen() {
}>();
const [inferenceTime, setInferenceTime] = useState<number | null>(null);
const [layout, setLayout] = useState({ width: 0, height: 0 });
const [selectedModel, setSelectedModel] =
useState<PoseEstimationModelSources>(poseEstimation.yolo26n());

const model = usePoseEstimation({ model: models.pose_estimation.yolo26n() });
const model = usePoseEstimation({ model: selectedModel });
const { setGlobalGenerating } = useContext(GeneratingContext);

useEffect(() => {
Expand Down Expand Up @@ -60,7 +74,7 @@ export default function PoseEstimationScreen() {
if (imageUri) {
try {
const start = Date.now();
const output = await model.forward(imageUri, { inputSize: 384 });
const output = await model.forward(imageUri);
setInferenceTime(Date.now() - start);
setResults(output);
} catch (e) {
Expand Down Expand Up @@ -206,6 +220,16 @@ export default function PoseEstimationScreen() {
</View>
)}
</View>
<ModelPicker
models={MODELS}
selectedModel={selectedModel}
disabled={model.isGenerating}
onSelect={(m) => {
setSelectedModel(m);
setResults([]);
setInferenceTime(null);
}}
/>
<StatsBar
inferenceTime={inferenceTime}
detectionCount={results.length > 0 ? results.length : null}
Expand Down
11 changes: 8 additions & 3 deletions docs/docs/03-hooks/02-computer-vision/usePoseEstimation.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,15 @@ See the full guide: [VisionCamera Integration](./visioncamera-integration.md).

## Supported models

| Model | Number of keypoints | Keypoint list | Multi-size Support |
| ------------------------------------------------------------------------------------------- | ------------------- | ----------------------------------------------------------- | ------------------ |
| [YOLO26N-Pose](https://huggingface.co/software-mansion/react-native-executorch-yolo26-pose) | 17 | [COCO](../../06-api-reference/enumerations/CocoKeypoint.md) | Yes (384/512/640) |
| Model | Number of keypoints | Keypoint list | Multi-size Support |
| ------------------------------------------------------------------------------------------------------------- | ------------------- | ----------------------------------------------------------- | ------------------ |
| [YOLO26N-Pose](https://huggingface.co/software-mansion/react-native-executorch-yolo26-pose) | 17 | [COCO](../../06-api-reference/enumerations/CocoKeypoint.md) | Yes (384/512/640) |
| [RF-DETR Keypoint (preview)](https://huggingface.co/software-mansion/react-native-executorch-rfdetr-keypoint) | 17 | [COCO](../../06-api-reference/enumerations/CocoKeypoint.md) | No |

:::tip
YOLO models support multiple input sizes (384px, 512px, 640px). Smaller sizes are faster but less accurate, while larger sizes are more accurate but slower. Choose based on your speed/accuracy requirements.
:::

:::warning
`rfdetr_keypoint_preview` is a **preview weights** export and may be re-exported under a different constant once a stable version ships. It is a single-input-size model (no `inputSize` option) and ships `xnnpack`, `coreml`, and `mlx` backends — pass `{ backend }` to override the platform default, e.g. `models.pose_estimation.rfdetr_keypoint_preview({ backend: 'mlx' })`.
:::
2 changes: 1 addition & 1 deletion docs/docs/05-utilities/model-registry.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Each leaf is a **function**. Call it (optionally with `{ quant, backend }`) to g
| `classification` | `efficientnet_v2_s` |
| `privacy_filter` | `openai`, `nemotron` |
| `object_detection` | `ssdlite_320_mobilenet_v3_large`, `yolo26n` … `yolo26x`, `rf_detr_nano` |
| `pose_estimation` | `yolo26n` |
| `pose_estimation` | `yolo26n`, `rfdetr_keypoint_preview` _(beta)_ |
| `semantic_segmentation` | `deeplab_v3_resnet50`, `lraspp_mobilenet_v3_large`, `fcn_resnet101`, `selfie_segmentation`, … |
| `instance_segmentation` | `yolo26n` … `yolo26x`, `rf_detr_nano`, `fastsam_s`, `fastsam_x` |
| `style_transfer` | `candy`, `mosaic`, `rain_princess`, `udnie` |
Expand Down
28 changes: 28 additions & 0 deletions packages/react-native-executorch/src/constants/modelRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,31 @@ const RF_DETR_NANO_SEG_VARIANTS = {
},
};

// RF-DETR Keypoint (pose estimation) — BETA preview. Configs mirror the
// All three backends ship fp32
// (non-quantized); this entry may be re-exported under a different constant
// once more RF-DETR keypoint weights are released.
const RF_DETR_KEYPOINT_PREVIEW_VARIANTS = {
xnnpack: {
base: {
modelName: 'rfdetr-keypoint-preview' as const,
modelSource: M.RF_DETR_KEYPOINT_PREVIEW_XNNPACK_FP32_MODEL,
},
},
coreml: {
base: {
modelName: 'rfdetr-keypoint-preview' as const,
modelSource: M.RF_DETR_KEYPOINT_PREVIEW_COREML_FP32_MODEL,
},
},
mlx: {
base: {
modelName: 'rfdetr-keypoint-preview' as const,
modelSource: M.RF_DETR_KEYPOINT_PREVIEW_MLX_FP32_MODEL,
},
},
};

const FASTSAM_S_VARIANTS = {
xnnpack: {
base: {
Expand Down Expand Up @@ -608,6 +633,9 @@ export const models = {
},
pose_estimation: {
yolo26n: base(M.YOLO26N_POSE),
// BETA preview — may be re-exported under a different constant once a
// stable RF-DETR keypoint model ships.
rfdetr_keypoint_preview: variant(RF_DETR_KEYPOINT_PREVIEW_VARIANTS),
},
semantic_segmentation: {
deeplab_v3_resnet50: pair(
Expand Down
22 changes: 22 additions & 0 deletions packages/react-native-executorch/src/constants/modelUrls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,28 @@ export const YOLO26N_POSE = {
modelSource: YOLO26N_POSE_MODEL,
} as const;

// RF-DETR Keypoint (pose estimation) — BETA preview.
// NOTE: served from the `preview/` path under PREVIOUS_VERSION_TAG (shipping as
// part of a patch release). This export is a preview and may be re-exported
// under a different constant once a stable version ships.
export const RF_DETR_KEYPOINT_PREVIEW_XNNPACK_FP32_MODEL = `${URL_PREFIX}-rfdetr-keypoint/${PREVIOUS_VERSION_TAG}/preview/xnnpack/rfdetr_keypoint_preview_xnnpack_fp32.pte`;
export const RF_DETR_KEYPOINT_PREVIEW_COREML_FP32_MODEL = `${URL_PREFIX}-rfdetr-keypoint/${PREVIOUS_VERSION_TAG}/preview/coreml/rfdetr_keypoint_preview_coreml_fp32.pte`;
export const RF_DETR_KEYPOINT_PREVIEW_MLX_FP32_MODEL = `${URL_PREFIX}-rfdetr-keypoint/${PREVIOUS_VERSION_TAG}/preview/mlx/rfdetr_keypoint_preview_mlx_fp32.pte`;
const RF_DETR_KEYPOINT_PREVIEW_MODEL =
Platform.OS === 'ios'
? RF_DETR_KEYPOINT_PREVIEW_COREML_FP32_MODEL
: RF_DETR_KEYPOINT_PREVIEW_XNNPACK_FP32_MODEL;

/**
* @category Models - Pose Estimation
* @beta Preview export — may be re-exported under a different constant once a
* stable RF-DETR keypoint model ships.
*/
export const RF_DETR_KEYPOINT_PREVIEW = {
modelName: 'rfdetr-keypoint-preview',
modelSource: RF_DETR_KEYPOINT_PREVIEW_MODEL,
} as const;

// Style transfer
/**
* Builds the four `(backend, precision)` URLs for a single style-transfer style.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,20 @@ const YOLO_POSE_CONFIG = {
defaultKeypointThreshold: 0.5,
} satisfies PoseEstimationConfig<typeof CocoKeypoint>;

// RF-DETR keypoint preview (BETA). Unlike yolo26n-pose's multi-method
// `forward_<size>` export, this ships a single `forward` method — omitting
// availableInputSizes/defaultInputSize makes forward() dispatch to plain
// `forward`. May be renamed once a stable model ships.
const RFDETR_KEYPOINT_CONFIG = {
keypointMap: CocoKeypoint,
preprocessorConfig: undefined,
defaultDetectionThreshold: 0.5,
defaultKeypointThreshold: 0.5,
} satisfies PoseEstimationConfig<typeof CocoKeypoint>;

const ModelConfigs = {
'yolo26n-pose': YOLO_POSE_CONFIG,
'rfdetr-keypoint-preview': RFDETR_KEYPOINT_CONFIG,
} as const satisfies Record<
PoseEstimationModelName,
PoseEstimationConfig<LabelEnum>
Expand Down
14 changes: 10 additions & 4 deletions packages/react-native-executorch/src/types/poseEstimation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,16 @@ export type PoseEstimationConfig<K extends LabelEnum> = {
* Each model name maps to its required fields.
* @category Types
*/
export type PoseEstimationModelSources = {
modelName: 'yolo26n-pose';
modelSource: ResourceSource;
};
export type PoseEstimationModelSources =
| {
modelName: 'yolo26n-pose';
modelSource: ResourceSource;
}
// RF-DETR keypoint preview (BETA) — may be renamed once a stable model ships.
| {
modelName: 'rfdetr-keypoint-preview';
modelSource: ResourceSource;
};

/**
* Union of all built-in pose estimation model names.
Expand Down
Loading