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
44
45 /**
46 * @brief Process a new face recognition result.
47 *
48 * Workflow:
49 * 1. Find existing PersonInstance by profile ID
50 * 2. If found: Update face data and validate pose link is still plausible
51 * 3. If not found: Create new PersonInstance
52 * 4. Try to match with a nearby pose (within maxFaceHeadDistance)
53 * 5. Ensure tracking ID uniqueness across all PersonInstances
54 */
55 void
57 const armarx::armem::MemoryID& faceRecognitionID);
58
59 /**
60 * @brief Process a new human pose update.
61 *
62 * Workflow:
63 * 1. Search for PersonInstance with matching tracking ID
64 * 2. If not found, try to match by spatial proximity to a recognized face
65 * 3. If matched: Update PersonInstance with new pose
66 * 4. If not matched: Create new PersonInstance based on pose alone
67 */
69 const armarx::armem::MemoryID& poseID);
70
71 /**
72 * @brief Process a profile update (not yet implemented).
73 */
74 void consumeProfileUpdate(const armarx::human::arondto::Person& profile,
75 const armarx::armem::MemoryID& profileID);
76
77 /**
78 * @brief Check if the consumer is currently processing an update.
79 * @return true if busy (mutex locked), false otherwise.
80 */
81 bool isBusy();
82
83 private:
84 /**
85 * @brief Checks whether a pose and face recognition instance can be plausibly matched.
86 *
87 * Compares the head position from the pose with the face position from face recognition.
88 * They must be within maxFaceHeadDistance to be considered plausible.
89 *
90 * @return true when plausible (distance within threshold).
91 * @return false when not plausible (too far apart or missing data).
92 */
93 bool checkForPlausability(const ::armarx::armem::human::HumanPose& pose,
94 const ::armarx::armem::human::FaceRecognition& face);
95
96 /**
97 * @brief Same as checkForPlausability (appears to be a duplicate).
98 */
99 bool checkHumanPoseForPlausability(const ::armarx::armem::human::HumanPose& pose,
100 const ::armarx::armem::human::FaceRecognition& face);
101
102 /**
103 * @brief Clears the pose ID from a PersonInstance.
104 *
105 * Used when a pose link is no longer valid (e.g., too far from face, outdated data).
106 */
107 void removePoseFromPersonInstance(const armarx::armem::MemoryID& personInstanceId,
109
110 /// Helper struct to bundle a pose with its memory ID
111 struct HumanPoseWithID
112 {
115 };
116
117 /**
118 * @brief Find the closest pose to a given face position.
119 *
120 * Searches all available poses and finds the one whose head position is closest
121 * to the given face position (within maxFaceHeadDistance threshold).
122 *
123 * @param facePos The 3D position of the detected face
124 * @return The closest pose with its ID, or std::nullopt if none within threshold
125 */
126 std::optional<HumanPoseWithID> getClosestPoseID(const Eigen::Vector3f& facePos);
127
128 /**
129 * @brief Find the closest face recognition to a given head position.
130 *
131 * Searches all available face recognitions and finds the one closest to the
132 * given head position (within maxFaceHeadDistance threshold).
133 *
134 * @param headPos The 3D position of the head from pose tracking
135 * @return The closest face recognition ID, or std::nullopt if none within threshold
136 */
137 std::optional<armarx::armem::MemoryID>
138 getClosestFaceID(const armarx::FramedPosition& headPos);
139
140 /// Query and retrieve a HumanPose from memory by its ID
141 std::optional<armarx::armem::human::HumanPose>
142 humanPoseFromMemId(const armarx::armem::MemoryID& memId);
143
144 /// Query and retrieve a FaceRecognition from memory by its ID
145 std::optional<armarx::armem::human::FaceRecognition>
146 faceRecognitionFromMemId(const armarx::armem::MemoryID& memId);
147
148 /**
149 * @brief Updates a PersonInstance with a new pose ID and position.
150 *
151 * Updates both the pose reference and the global position of the PersonInstance
152 * based on the head position from the new pose.
153 */
154 void updateInstanceWithNewPoseId(const armarx::armem::MemoryID& instanceId,
156 const armarx::armem::MemoryID& newPoseId,
157 const ::armarx::armem::human::HumanPose& pose);
158
159 /**
160 * @brief Creates a new PersonInstance based on a pose without face recognition.
161 *
162 * Tries to find a nearby face recognition to link with, otherwise creates
163 * an instance with only pose information.
164 */
165 void createNewInstanceBasedOnPose(const armarx::armem::MemoryID& poseId,
167
168 /// Adds a pose ID to an existing PersonInstance
169 void addPoseToInstance(const armarx::armem::MemoryID& memId,
170 const armarx::armem::MemoryID& poseId,
172
173 /**
174 * @brief Extracts the head position from a HumanPose.
175 *
176 * Supports different pose models (k4a, openpose, mmm) and extracts the
177 * head keypoint position in global coordinates.
178 *
179 * @return Head position if available, std::nullopt otherwise
180 */
181 static std::optional<armarx::FramedPosition>
182 getHeadPos(armarx::armem::human::HumanPose pose);
183
184 /// Calculate Euclidean distance between face and head positions
185 static float getDistance(const Eigen::Vector3f& facePos,
186 const armarx::FramedPosition& headPos);
187
188 /**
189 * @brief Ensure tracking ID uniqueness: clear a tracking ID from all other PersonInstances.
190 *
191 * When assigning a tracking ID to a PersonInstance, this ensures no other PersonInstance
192 * has the same tracking ID by clearing the pose link from any others using it.
193 *
194 * @param trackingId The tracking ID to make unique
195 * @param exceptProfileID The profile ID of the PersonInstance that should keep this tracking ID
196 */
197 void ensureTrackingIdUniqueness(const std::string& trackingId,
198 const armarx::armem::MemoryID& exceptProfileID);
199
200 /**
201 * @brief Logs the tracking state after processing a face recognition update.
202 */
203 void logFaceRecognitionUpdateDuration(const armarx::armem::Duration& duration);
204
205 /// Helper struct to bundle a PersonInstance with its memory ID
206 struct PersonInstanceWithID
207 {
208 armarx::human::arondto::PersonInstance personInstance;
210 };
211
212 /**
213 * @brief Finds a PersonInstance matching the given profile ID.
214 *
215 * @param queryResult The query result containing PersonInstances to search
216 * @param profileID The profile ID to match
217 * @return The matching PersonInstance with its ID, or std::nullopt if not found
218 */
219 std::optional<PersonInstanceWithID>
220 findMatchingPersonInstance(const armarx::armem::client::QueryResult& queryResult,
221 const armarx::armem::MemoryID& profileID);
222
223 /**
224 * @brief Clears the pose ID from a PersonInstance and commits the change.
225 *
226 * @param personInstanceMatched The PersonInstance with its ID
227 */
228 void clearPoseIdFromPersonInstance(const PersonInstanceWithID& personInstanceMatched);
229
230 /**
231 * @brief Sets a new pose ID for a PersonInstance and commits the change.
232 *
233 * @param personInstanceMatched The PersonInstance with its ID
234 * @param poseId The new pose ID to set
235 */
236 void setPoseIdForPersonInstance(const PersonInstanceWithID& personInstanceMatched,
237 const armarx::armem::MemoryID& poseId);
238
239 /**
240 * @brief Checks if a memory ID has all components specified.
241 *
242 * @param memoryId The memory ID to check
243 * @return true if all components are present, false otherwise
244 */
245 static bool isMemoryIdFullySpecified(const armarx::armem::MemoryID& memoryId);
246
247 // Memory readers and writers for accessing different data sources
248 armarx::armem::client::Reader faceRecognitionReader; ///< Read face recognition data
249 armarx::armem::client::Writer personInstanceWriter; ///< Write PersonInstance updates
250 armarx::armem::client::Reader personInstanceReader; ///< Read PersonInstance data
251 armarx::armem::client::Reader poseReader; ///< Read pose tracking data
252
253 /// Higher-level reader that can resolve linked data (faces, poses, profiles)
255
256 const Properties properties_; ///< Configuration (e.g., maxFaceHeadDistance threshold)
257
258 std::mutex consumeMtx; ///< Mutex to prevent concurrent processing of updates
259 };
260} // namespace VisionX::components::person_instance_updater
bool isBusy()
Check if the consumer is currently processing an update.
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
Result of a QueryInput.
Definition Query.h:51