UpdateConsumer.h
Go to the documentation of this file.
1#pragma once
2
3#include <mutex>
4#include <optional>
5
11
13#include <VisionX/libraries/armem_human/aron/Person.aron.generated.h>
14#include <VisionX/libraries/armem_human/aron/PersonInstance.aron.generated.h>
16
18{
19 /**
20 * @brief Core logic for fusing face recognition and pose tracking into PersonInstance entities.
21 *
22 * This class handles the complex task of matching and linking face recognition data with
23 * body pose tracking data to maintain a unified representation of tracked people.
24 *
25 * Matching Strategy:
26 * - Face -> PersonInstance: Match by profile ID, then try to link with a nearby pose
27 * - Pose -> PersonInstance: Match by tracking ID or spatial proximity to a recognized face
28 * - Ensures tracking ID uniqueness: only one PersonInstance per tracking ID
29 *
30 * Key Operations:
31 * - consumeFaceRecognitionUpdate(): Process new face recognition data
32 * - consumePoseUpdate(): Process new pose tracking data
33 * - Uses spatial proximity (maxFaceHeadDistance) to match faces with pose head positions
34 */
36 {
37 public:
39 {
40 float maxFaceHeadDistance = 1000.0F; // in [mm]
41
42 /// If false, body tracking (pose) data is ignored entirely: PersonInstances
43 /// are updated based on face detections only and their poseID is left unset.
44 bool enableBodyTracking = true;
45 };
46
48
49 /**
50 * @brief Process a new face recognition result.
51 *
52 * Workflow:
53 * 1. Find existing PersonInstance by profile ID
54 * 2. If found: Update face data and validate pose link is still plausible
55 * 3. If not found: Create new PersonInstance
56 * 4. Try to match with a nearby pose (within maxFaceHeadDistance)
57 * 5. Ensure tracking ID uniqueness across all PersonInstances
58 */
59 void
61 const armarx::armem::MemoryID& faceRecognitionID);
62
63 /**
64 * @brief Process a new human pose update.
65 *
66 * Workflow:
67 * 1. Search for PersonInstance with matching tracking ID
68 * 2. If not found, try to match by spatial proximity to a recognized face
69 * 3. If matched: Update PersonInstance with new pose
70 * 4. If not matched: Create new PersonInstance based on pose alone
71 */
73 const armarx::armem::MemoryID& poseID);
74
75 /**
76 * @brief Process a profile update (not yet implemented).
77 */
78 void consumeProfileUpdate(const armarx::human::arondto::Person& profile,
79 const armarx::armem::MemoryID& profileID);
80
81 private:
82 /**
83 * @brief Checks whether a pose and face recognition instance can be plausibly matched.
84 *
85 * Compares the head position from the pose with the face position from face recognition.
86 * They must be within maxFaceHeadDistance to be considered plausible.
87 *
88 * @return true when plausible (distance within threshold).
89 * @return false when not plausible (too far apart or missing data).
90 */
91 bool checkForPlausability(const ::armarx::armem::human::HumanPose& pose,
92 const ::armarx::armem::human::FaceRecognition& face);
93
94 /**
95 * @brief Same as checkForPlausability (appears to be a duplicate).
96 */
97 bool checkHumanPoseForPlausability(const ::armarx::armem::human::HumanPose& pose,
98 const ::armarx::armem::human::FaceRecognition& face);
99
100 /**
101 * @brief Clears the pose ID from a PersonInstance.
102 *
103 * Used when a pose link is no longer valid (e.g., too far from face, outdated data).
104 */
105 void removePoseFromPersonInstance(const armarx::armem::MemoryID& personInstanceId,
107
108 /// Helper struct to bundle a pose with its memory ID
109 struct HumanPoseWithID
110 {
113 };
114
115 /**
116 * @brief Find the closest pose to a given face position.
117 *
118 * Searches all available poses and finds the one whose head position is closest
119 * to the given face position (within maxFaceHeadDistance threshold).
120 *
121 * @param facePos The 3D position of the detected face
122 * @return The closest pose with its ID, or std::nullopt if none within threshold
123 */
124 std::optional<HumanPoseWithID> getClosestPoseID(const Eigen::Vector3f& facePos);
125
126 /**
127 * @brief Find the closest face recognition to a given head position.
128 *
129 * Searches all available face recognitions and finds the one closest to the
130 * given head position (within maxFaceHeadDistance threshold).
131 *
132 * @param headPos The 3D position of the head from pose tracking
133 * @return The closest face recognition ID, or std::nullopt if none within threshold
134 */
135 std::optional<armarx::armem::MemoryID>
136 getClosestFaceID(const armarx::FramedPosition& headPos);
137
138 /// Query and retrieve a HumanPose from memory by its ID
139 std::optional<armarx::armem::human::HumanPose>
140 humanPoseFromMemId(const armarx::armem::MemoryID& memId);
141
142 /// Query and retrieve a FaceRecognition from memory by its ID
143 std::optional<armarx::armem::human::FaceRecognition>
144 faceRecognitionFromMemId(const armarx::armem::MemoryID& memId);
145
146 /**
147 * @brief Updates a PersonInstance with a new pose ID and position.
148 *
149 * Updates both the pose reference and the global position of the PersonInstance
150 * based on the head position from the new pose.
151 */
152 void updateInstanceWithNewPoseId(const armarx::armem::MemoryID& instanceId,
154 const armarx::armem::MemoryID& newPoseId,
155 const ::armarx::armem::human::HumanPose& pose);
156
157 /**
158 * @brief Creates a new PersonInstance based on a pose without face recognition.
159 *
160 * Tries to find a nearby face recognition to link with, otherwise creates
161 * an instance with only pose information.
162 */
163 void createNewInstanceBasedOnPose(const armarx::armem::MemoryID& poseId,
165
166 /// Adds a pose ID to an existing PersonInstance
167 void addPoseToInstance(const armarx::armem::MemoryID& memId,
168 const armarx::armem::MemoryID& poseId,
170
171 /**
172 * @brief Extracts the head position from a HumanPose.
173 *
174 * Supports different pose models (k4a, openpose, mmm) and extracts the
175 * head keypoint position in global coordinates.
176 *
177 * @return Head position if available, std::nullopt otherwise
178 */
179 static std::optional<armarx::FramedPosition>
180 getHeadPos(armarx::armem::human::HumanPose pose);
181
182 /// Calculate Euclidean distance between face and head positions
183 static float getDistance(const Eigen::Vector3f& facePos,
184 const armarx::FramedPosition& headPos);
185
186 /**
187 * @brief Ensure tracking ID uniqueness: clear a tracking ID from all other PersonInstances.
188 *
189 * When assigning a tracking ID to a PersonInstance, this ensures no other PersonInstance
190 * has the same tracking ID by clearing the pose link from any others using it.
191 *
192 * @param trackingId The tracking ID to make unique
193 * @param exceptProfileID The profile ID of the PersonInstance that should keep this tracking ID
194 */
195 void ensureTrackingIdUniqueness(const std::string& trackingId,
196 const armarx::armem::MemoryID& exceptProfileID);
197
198 /**
199 * @brief Logs the tracking state after processing a face recognition update.
200 */
201 void logFaceRecognitionUpdateDuration(const armarx::armem::Duration& duration);
202
203 /// Helper struct to bundle a PersonInstance with its memory ID
204 struct PersonInstanceWithID
205 {
206 armarx::human::arondto::PersonInstance personInstance;
208 };
209
210 /**
211 * @brief Finds a PersonInstance matching the given profile ID.
212 *
213 * @param queryResult The query result containing PersonInstances to search
214 * @param profileID The profile ID to match
215 * @return The matching PersonInstance with its ID, or std::nullopt if not found
216 */
217 std::optional<PersonInstanceWithID>
218 findMatchingPersonInstance(const armarx::armem::client::QueryResult& queryResult,
219 const armarx::armem::MemoryID& profileID);
220
221 /**
222 * @brief Clears the pose ID from a PersonInstance and commits the change.
223 *
224 * @param personInstanceMatched The PersonInstance with its ID
225 */
226 void clearPoseIdFromPersonInstance(const PersonInstanceWithID& personInstanceMatched);
227
228 /**
229 * @brief Sets a new pose ID for a PersonInstance and commits the change.
230 *
231 * @param personInstanceMatched The PersonInstance with its ID
232 * @param poseId The new pose ID to set
233 */
234 void setPoseIdForPersonInstance(const PersonInstanceWithID& personInstanceMatched,
235 const armarx::armem::MemoryID& poseId);
236
237 /**
238 * @brief Checks if a memory ID has all components specified.
239 *
240 * @param memoryId The memory ID to check
241 * @return true if all components are present, false otherwise
242 */
243 static bool isMemoryIdFullySpecified(const armarx::armem::MemoryID& memoryId);
244
245 // Memory readers and writers for accessing different data sources
246 armarx::armem::client::Reader faceRecognitionReader; ///< Read face recognition data
247 armarx::armem::client::Writer personInstanceWriter; ///< Write PersonInstance updates
248 armarx::armem::client::Reader personInstanceReader; ///< Read PersonInstance data
249 armarx::armem::client::Reader poseReader; ///< Read pose tracking data
250
251 /// Higher-level reader that can resolve linked data (faces, poses, profiles)
253
254 const Properties properties_; ///< Configuration (e.g., maxFaceHeadDistance threshold)
255
256 std::mutex consumeMtx; ///< Mutex to prevent concurrent processing of updates
257 };
258} // namespace VisionX::components::person_instance_updater
void consumePoseUpdate(const armarx::armem::human::HumanPose &humanPose, const armarx::armem::MemoryID &poseID)
Process a new human pose update.
UpdateConsumer(armarx::armem::client::MemoryNameSystem &mns, const Properties &properties)
void consumeFaceRecognitionUpdate(const armarx::armem::human::FaceRecognition &faceRecognition, const armarx::armem::MemoryID &faceRecognitionID)
Process a new face recognition result.
void consumeProfileUpdate(const armarx::human::arondto::Person &profile, const armarx::armem::MemoryID &profileID)
Process a profile update (not yet implemented).
The FramedPosition class.
Definition FramedPose.h:158
The memory name system (MNS) client.
Reads data from a memory server.
Definition Reader.h:25
Helps a memory client sending data to a memory.
Definition Writer.h:23
armarx::core::time::Duration Duration
bool enableBodyTracking
If false, body tracking (pose) data is ignored entirely: PersonInstances are updated based on face de...
Result of a QueryInput.
Definition Query.h:51