3535#include " hydra_ros/input/image_receiver.h"
3636
3737#include < config_utilities/config.h>
38+ #include < config_utilities/types/path.h>
39+ #include < config_utilities/validation.h>
3840#include < glog/logging.h>
3941
4042#include < cv_bridge/cv_bridge.hpp>
@@ -120,6 +122,58 @@ void LabelSubscriber::fillInput(const Image& img, ImageInputPacket& packet) cons
120122 }
121123}
122124
125+ ColormappedLabelSubscriber::ColormappedLabelSubscriber ()
126+ : default_label_(-1 ), colormap_(nullptr ) {}
127+
128+ ColormappedLabelSubscriber::ColormappedLabelSubscriber (ianvs::NodeHandle nh,
129+ uint32_t queue_size)
130+ : default_label_(-1 ),
131+ colormap_ (nullptr ),
132+ impl_(std::make_shared<FilterSub<Image>>(nh, " semantic/image_raw" , queue_size)) {}
133+
134+ ColormappedLabelSubscriber::~ColormappedLabelSubscriber () = default ;
135+
136+ ColormappedLabelSubscriber::Filter& ColormappedLabelSubscriber::getFilter () const {
137+ return *CHECK_NOTNULL (impl_);
138+ }
139+
140+ void ColormappedLabelSubscriber::setColormap (const SemanticColorMap* colormap,
141+ int32_t default_label) {
142+ colormap_ = colormap;
143+ default_label_ = default_label;
144+ }
145+
146+ void ColormappedLabelSubscriber::fillInput (const Image& img,
147+ ImageInputPacket& packet) const {
148+ if (!colormap_) {
149+ LOG (ERROR ) << " Colormap not set for subscriber!" ;
150+ return ;
151+ }
152+
153+ cv::Mat colors;
154+ try {
155+ colors = cv_bridge::toCvCopy (img)->image ;
156+ } catch (const cv_bridge::Exception& e) {
157+ LOG (ERROR ) << " Failed to convert label image: " << e.what ();
158+ return ;
159+ }
160+
161+ if (colors.empty () || colors.channels () != 3 ) {
162+ LOG (ERROR ) << " Failed to decode color image to semantics!" ;
163+ return ;
164+ }
165+
166+ packet.labels = cv::Mat (colors.size (), CV_32SC1 );
167+ for (int r = 0 ; r < colors.rows ; ++r) {
168+ for (int c = 0 ; c < colors.cols ; ++c) {
169+ const auto & pixel = colors.at <cv::Vec3b>(r, c);
170+ const spark_dsg::Color color (pixel[0 ], pixel[1 ], pixel[2 ]);
171+ packet.labels .at <int32_t >(r, c) =
172+ colormap_->getLabelFromColor (color).value_or (default_label_);
173+ }
174+ }
175+ }
176+
123177FeatureSubscriber::FeatureSubscriber () = default;
124178
125179FeatureSubscriber::FeatureSubscriber (ianvs::NodeHandle nh, uint32_t queue_size)
@@ -148,12 +202,6 @@ void FeatureSubscriber::fillInput(const MsgType& msg, ImageInputPacket& packet)
148202 }
149203}
150204
151- void declare_config (RGBDImageReceiver::Config& config) {
152- using namespace config ;
153- name (" RGBDImageReceiver::Config" );
154- base<RosDataReceiver::Config>(config);
155- }
156-
157205RGBDImageReceiver::RGBDImageReceiver (const Config& config,
158206 const std::string& sensor_name)
159207 : RosDataReceiver(config, sensor_name) {}
@@ -180,26 +228,56 @@ void RGBDImageReceiver::callback(const sensor_msgs::msg::Image::ConstSharedPtr&
180228 queue.push (packet);
181229}
182230
183- void declare_config (ClosedSetImageReceiver ::Config& config) {
231+ void declare_config (RGBDImageReceiver ::Config& config) {
184232 using namespace config ;
185- name (" ClosedSetImageReceiver ::Config" );
233+ name (" RGBDImageReceiver ::Config" );
186234 base<RosDataReceiver::Config>(config);
187235}
188236
189237ClosedSetImageReceiver::ClosedSetImageReceiver (const Config& config,
190238 const std::string& sensor_name)
191239 : ImageReceiverImpl<LabelSubscriber>(config, sensor_name) {}
192240
193- void declare_config (OpenSetImageReceiver ::Config& config) {
241+ void declare_config (ClosedSetImageReceiver ::Config& config) {
194242 using namespace config ;
195- name (" OpenSetImageReceiver ::Config" );
196- base<hydra:: RosDataReceiver::Config>(config);
243+ name (" ClosedSetImageReceiver ::Config" );
244+ base<RosDataReceiver::Config>(config);
197245}
198246
199247OpenSetImageReceiver::OpenSetImageReceiver (const Config& config,
200248 const std::string& sensor_name)
201249 : ImageReceiverImpl<FeatureSubscriber>(config, sensor_name) {}
202250
251+ void declare_config (OpenSetImageReceiver::Config& config) {
252+ using namespace config ;
253+ name (" OpenSetImageReceiver::Config" );
254+ base<hydra::RosDataReceiver::Config>(config);
255+ }
256+
257+ ColormappedLabelImageReceiver::ColormappedLabelImageReceiver (const Config& config,
258+ const std::string& name)
259+ : ImageReceiverImpl<ColormappedLabelSubscriber>(config, name),
260+ config(config::checkValid(config)),
261+ colormap_(SemanticColorMap::fromCsv(config.colormap_path)) {
262+ CHECK (colormap_) << " Colormap required!" ;
263+ }
264+
265+ bool ColormappedLabelImageReceiver::initImpl () {
266+ using Base = ImageReceiverImpl<ColormappedLabelSubscriber>;
267+ const auto ret = Base::initImpl ();
268+ semantic_sub_.setColormap (colormap_.get (), config.default_label );
269+ return ret;
270+ }
271+
272+ void declare_config (ColormappedLabelImageReceiver::Config& config) {
273+ using namespace config ;
274+ name (" ColormappedLabelImageReceiver::Config" );
275+ base<hydra::RosDataReceiver::Config>(config);
276+ field<Path::Absolute>(config.colormap_path , " colormap_path" );
277+ field (config.default_label , " default_label" );
278+ check<Path::Exists>(config.colormap_path , " colormap_path" );
279+ }
280+
203281namespace {
204282
205283static const auto no_semantic_registration =
@@ -220,6 +298,11 @@ static const auto open_registration =
220298 OpenSetImageReceiver::Config,
221299 std::string>(" OpenSetImageReceiver" );
222300
223- } // namespace
301+ static const auto color_registration =
302+ config::RegistrationWithConfig<hydra::DataReceiver,
303+ ColormappedLabelImageReceiver,
304+ ColormappedLabelImageReceiver::Config,
305+ std::string>(" ColormappedLabelImageReceiver" );
224306
307+ } // namespace
225308} // namespace hydra
0 commit comments