PersonInstanceUpdater.cpp
Go to the documentation of this file.
1/**
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package VisionX::ArmarXObjects::person_instance_updater
17 * @author Philipp Seidel ( uyhvq at student dot kit dot edu )
18 * @author Fabian Reister ( fabian dot reister at kit dot edu )
19 * @date 2023
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
24
26
27#include <memory>
28#include <string>
29#include <vector>
30
36
42
44#include <VisionX/libraries/armem_human/aron/FaceRecognition.aron.generated.h>
45#include <VisionX/libraries/armem_human/aron/HumanPose.aron.generated.h>
46#include <VisionX/libraries/armem_human/aron/Person.aron.generated.h>
50
52{
53
54 const std::string PersonInstanceUpdater::provider_name = "person_instance_updater";
55
58 {
61
62 def->optional(properties.updateConsumer.maxFaceHeadDistance, "maxFaceHeadDistance");
63
64 return def;
65 }
66
67 void
71
72 void
74 {
75 this->updateConsumer =
76 std::make_unique<UpdateConsumer>(memoryNameSystem(), properties.updateConsumer);
77
78 registerMemorySubscriptions();
79 }
80
81 void
83 {
84 // unsubscribe from all memory subscriptions
85 for (auto& handle : subscriptionHandles)
86 {
88 }
89
90 this->updateConsumer.reset();
91 }
92
93 void
97
98 void
99 PersonInstanceUpdater::registerMemorySubscriptions()
100 {
101 ARMARX_CHECK_NOT_NULL(updateConsumer);
102 namespace armem = armarx::armem;
103
104 // ========== Subscribe to FaceRecognition updates ==========
105 // When a face is recognized (with identity information), we need to either:
106 // 1. Update an existing PersonInstance with the new face data, or
107 // 2. Create a new PersonInstance if this is a newly recognized person
108 {
109 armem::client::Reader faceRecognitionReader =
111
112 auto faceRecognitionCallback =
113 [this,
114 faceRecognitionReader](const std::vector<armem::MemoryID>& updatedSnapshotIDs)
115 {
116 // Callback triggered when new face recognition results arrive
117 //ARMARX_INFO << "Updated faces with IDs: " << updatedSnapshotIDs;
118
119 // Query the actual face recognition data for the updated IDs
121 faceRecognitionReader.queryMemoryIDs(updatedSnapshotIDs);
122
123 if (result.success)
124 {
125 // Process each face recognition instance
128 armarx::human::arondto::FaceRecognition>& instance)
129 {
130 // Convert from ARON DTO to internal representation
132 fromAron(instance.data(), faceRecognition);
133
134 // Delegate to UpdateConsumer to match with poses and update PersonInstances
135 updateConsumer->consumeFaceRecognitionUpdate(faceRecognition,
136 instance.id());
137 });
138 }
139 };
140
141 subscriptionHandles.push_back(
143 faceRecognitionCallback));
144 }
145
146 // ========== Subscribe to Pose updates ==========
147 // When a human pose is tracked (body skeleton with tracking ID), we need to either:
148 // 1. Update an existing PersonInstance that has a matching tracking ID, or
149 // 2. Try to match it with a recognized face based on spatial proximity, or
150 // 3. Create a new PersonInstance for this tracked pose
151 {
152 armem::client::Reader poseReader =
154
155 auto poseCallback =
156 [this, poseReader](const std::vector<armem::MemoryID>& updatedSnapshotIDs)
157 {
158 // Skip if UpdateConsumer is busy to prevent data accumulation
159 // (pose updates come at high frequency)
160 if (updateConsumer->isBusy())
161 {
162 ARMARX_DEBUG << "Update consumer is currently processing data. To prevent data "
163 "accumulation, we skip this update.";
164 return;
165 }
166
167 // Query the actual pose data for the updated IDs
168 //ARMARX_INFO << "Updated poses with IDs: " << updatedSnapshotIDs;
169 armem::client::QueryResult result = poseReader.queryMemoryIDs(updatedSnapshotIDs);
170 if (result.success)
171 {
172 // Process each pose instance
174 [this](
176 instance)
177 {
178 // Convert from ARON DTO to internal representation
179 armarx::armem::human::HumanPose humanPose;
180 fromAron(instance.data(), humanPose);
181
182 // Delegate to UpdateConsumer to match with faces and update PersonInstances
183 updateConsumer->consumePoseUpdate(humanPose, instance.id());
184 });
185 }
186 };
187
188 subscriptionHandles.push_back(
189 memoryNameSystem().subscribe(armarx::human::PoseCoreSegmentID, poseCallback));
190 }
191
192 // ========== Subscribe to Profile updates (currently disabled) ==========
193 // Profile updates would contain person information like name, ID, etc.
194 // Currently disabled with if(false) - would update PersonInstance profile data when enabled
195 if (false)
196 {
197 armem::client::Reader profileReader =
199
200 auto profileCallback =
201 [this, profileReader](const std::vector<armem::MemoryID>& updatedSnapshotIDs)
202 {
203 //ARMARX_INFO << "Updated profiles with IDs: " << updatedSnapshotIDs;
204 armem::client::QueryResult result =
205 profileReader.queryMemoryIDs(updatedSnapshotIDs);
206 if (result.success)
207 {
210 instance)
211 { updateConsumer->consumeProfileUpdate(instance.data(), instance.id()); });
212 }
213 };
214
215 subscriptionHandles.push_back(
216 memoryNameSystem().subscribe(armarx::human::ProfileCoreSegmentID, profileCallback));
217 }
218 }
219
220 std::string
225
226 std::string
231
232 // ARMARX_REGISTER_COMPONENT_EXECUTABLE(PersonInstanceUpdater,
233 // PersonInstanceUpdater::GetDefaultName());
234
235} // namespace VisionX::components::person_instance_updater
static std::string GetDefaultName()
Get the component's default name.
Default component property definition container.
Definition Component.h:70
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:90
Reader useReader(const MemoryID &memoryID)
Use a memory server and get a reader for it.
Reads data from a memory server.
Definition Reader.h:25
QueryResult queryMemoryIDs(const std::vector< MemoryID > &ids, armem::query::DataMode dataMode=armem::query::DataMode::WithData) const
Query a specific set of memory IDs.
Definition Reader.cpp:374
void unsubscribe(SubscriptionHandle &subscriptionHandle)
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
Definition Logging.h:184
base::EntityInstanceBase< AronDtoT, EntityInstanceMetadata > EntityInstanceBase
Entity instance with a concrete ARON DTO type as data.
const armem::MemoryID ProfileCoreSegmentID
const armem::MemoryID FaceRecognitionCoreSegmentID
const armem::MemoryID PoseCoreSegmentID
void fromAron(const arondto::PackagePath &dto, PackageFileLocation &bo)
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
bool forEachInstanceWithDataAs(EntityInstanceBaseAronDtoFunctionT &&func) const
Call func on each instance with its data converted to Aron DTO class.
Result of a QueryInput.
Definition Query.h:51
wm::Memory memory
The slice of the memory that matched the query.
Definition Query.h:58