Skip to main content

oxihuman_export/
openpose_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5pub struct OpenPoseKeypoint {
6    pub x: f32,
7    pub y: f32,
8    pub confidence: f32,
9}
10
11pub struct OpenPoseBody {
12    pub keypoints: Vec<OpenPoseKeypoint>,
13}
14
15pub fn new_openpose_keypoint(x: f32, y: f32, conf: f32) -> OpenPoseKeypoint {
16    OpenPoseKeypoint {
17        x,
18        y,
19        confidence: conf,
20    }
21}
22
23pub fn new_openpose_body() -> OpenPoseBody {
24    OpenPoseBody {
25        keypoints: Vec::new(),
26    }
27}
28
29pub fn body_push_keypoint(b: &mut OpenPoseBody, kp: OpenPoseKeypoint) {
30    b.keypoints.push(kp);
31}
32
33pub fn body_to_json(b: &OpenPoseBody) -> String {
34    let inner: Vec<_> = b
35        .keypoints
36        .iter()
37        .map(|kp| format!(r#"[{},{},{}]"#, kp.x, kp.y, kp.confidence))
38        .collect();
39    format!(r#"{{"keypoints":[{}]}}"#, inner.join(","))
40}
41
42static COCO_NAMES: &[&str] = &[
43    "nose",
44    "neck",
45    "right_shoulder",
46    "right_elbow",
47    "right_wrist",
48    "left_shoulder",
49    "left_elbow",
50    "left_wrist",
51    "right_hip",
52    "right_knee",
53    "right_ankle",
54    "left_hip",
55    "left_knee",
56    "left_ankle",
57    "right_eye",
58    "left_eye",
59    "right_ear",
60    "left_ear",
61];
62
63pub fn keypoint_name_coco(idx: usize) -> &'static str {
64    COCO_NAMES.get(idx).copied().unwrap_or("unknown")
65}
66
67pub fn body_is_valid_coco(b: &OpenPoseBody) -> bool {
68    b.keypoints.len() == 18
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_new_openpose_body_empty() {
77        /* starts empty */
78        let b = new_openpose_body();
79        assert_eq!(b.keypoints.len(), 0);
80    }
81
82    #[test]
83    fn test_body_push_keypoint() {
84        /* push increases count */
85        let mut b = new_openpose_body();
86        body_push_keypoint(&mut b, new_openpose_keypoint(0.5, 0.3, 0.9));
87        assert_eq!(b.keypoints.len(), 1);
88    }
89
90    #[test]
91    fn test_keypoint_name_coco_nose() {
92        /* idx 0 = nose */
93        assert_eq!(keypoint_name_coco(0), "nose");
94    }
95
96    #[test]
97    fn test_body_is_valid_coco_false() {
98        /* not 18 = invalid */
99        let b = new_openpose_body();
100        assert!(!body_is_valid_coco(&b));
101    }
102
103    #[test]
104    fn test_body_to_json_not_empty() {
105        /* json not empty */
106        let mut b = new_openpose_body();
107        body_push_keypoint(&mut b, new_openpose_keypoint(0.0, 0.0, 1.0));
108        let j = body_to_json(&b);
109        assert!(!j.is_empty());
110    }
111}