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,55 @@ void LabelSubscriber::fillInput(const Image& img, ImageInputPacket& packet) cons
120122 }
121123}
122124
125+ ColormappedLabelSubscriber::ColormappedLabelSubscriber () : colormap_(nullptr ) {}
126+
127+ ColormappedLabelSubscriber::ColormappedLabelSubscriber (ianvs::NodeHandle nh,
128+ uint32_t queue_size)
129+ : colormap_(nullptr ),
130+ impl_ (std::make_shared<FilterSub<Image>>(nh, " semantic/image_raw" , queue_size)) {}
131+
132+ ColormappedLabelSubscriber::~ColormappedLabelSubscriber () = default ;
133+
134+ ColormappedLabelSubscriber::Filter& ColormappedLabelSubscriber::getFilter () const {
135+ return *CHECK_NOTNULL (impl_);
136+ }
137+
138+ void ColormappedLabelSubscriber::setColormap (const SemanticColorMap* colormap) {
139+ colormap_ = colormap;
140+ }
141+
142+ void ColormappedLabelSubscriber::fillInput (const Image& img,
143+ ImageInputPacket& packet) const {
144+ if (!colormap_) {
145+ LOG (ERROR ) << " Colormap not set for subscriber!" ;
146+ return ;
147+ }
148+
149+ cv::Mat colors;
150+ try {
151+ colors = cv_bridge::toCvCopy (img)->image ;
152+ } catch (const cv_bridge::Exception& e) {
153+ LOG (ERROR ) << " Failed to convert label image: " << e.what ();
154+ return ;
155+ }
156+
157+ if (colors.empty () || colors.channels () != 3 ) {
158+ LOG (ERROR ) << " Failed to decode color image to semantics!" ;
159+ return ;
160+ }
161+
162+ packet.labels = cv::Mat (colors.size (), CV_32SC1 );
163+ for (int r = 0 ; r < colors.rows ; ++r) {
164+ for (int c = 0 ; c < colors.cols ; ++c) {
165+ const auto & pixel = colors.at <cv::Vec3b>(r, c);
166+ const spark_dsg::Color color (pixel[0 ], pixel[1 ], pixel[2 ]);
167+ // this is lazy, but works out to the same invalid label we normally use
168+ packet.labels .at <int32_t >(r, c) =
169+ colormap_->getLabelFromColor (color).value_or (-1 );
170+ }
171+ }
172+ }
173+
123174FeatureSubscriber::FeatureSubscriber () = default;
124175
125176FeatureSubscriber::FeatureSubscriber (ianvs::NodeHandle nh, uint32_t queue_size)
@@ -148,12 +199,6 @@ void FeatureSubscriber::fillInput(const MsgType& msg, ImageInputPacket& packet)
148199 }
149200}
150201
151- void declare_config (RGBDImageReceiver::Config& config) {
152- using namespace config ;
153- name (" RGBDImageReceiver::Config" );
154- base<RosDataReceiver::Config>(config);
155- }
156-
157202RGBDImageReceiver::RGBDImageReceiver (const Config& config,
158203 const std::string& sensor_name)
159204 : RosDataReceiver(config, sensor_name) {}
@@ -180,26 +225,55 @@ void RGBDImageReceiver::callback(const sensor_msgs::msg::Image::ConstSharedPtr&
180225 queue.push (packet);
181226}
182227
183- void declare_config (ClosedSetImageReceiver ::Config& config) {
228+ void declare_config (RGBDImageReceiver ::Config& config) {
184229 using namespace config ;
185- name (" ClosedSetImageReceiver ::Config" );
230+ name (" RGBDImageReceiver ::Config" );
186231 base<RosDataReceiver::Config>(config);
187232}
188233
189234ClosedSetImageReceiver::ClosedSetImageReceiver (const Config& config,
190235 const std::string& sensor_name)
191236 : ImageReceiverImpl<LabelSubscriber>(config, sensor_name) {}
192237
193- void declare_config (OpenSetImageReceiver ::Config& config) {
238+ void declare_config (ClosedSetImageReceiver ::Config& config) {
194239 using namespace config ;
195- name (" OpenSetImageReceiver ::Config" );
196- base<hydra:: RosDataReceiver::Config>(config);
240+ name (" ClosedSetImageReceiver ::Config" );
241+ base<RosDataReceiver::Config>(config);
197242}
198243
199244OpenSetImageReceiver::OpenSetImageReceiver (const Config& config,
200245 const std::string& sensor_name)
201246 : ImageReceiverImpl<FeatureSubscriber>(config, sensor_name) {}
202247
248+ void declare_config (OpenSetImageReceiver::Config& config) {
249+ using namespace config ;
250+ name (" OpenSetImageReceiver::Config" );
251+ base<hydra::RosDataReceiver::Config>(config);
252+ }
253+
254+ ColormappedLabelImageReceiver::ColormappedLabelImageReceiver (const Config& config,
255+ const std::string& name)
256+ : ImageReceiverImpl<ColormappedLabelSubscriber>(config, name),
257+ config(config::checkValid(config)),
258+ colormap_(SemanticColorMap::fromCsv(config.colormap_path)) {
259+ CHECK (colormap_) << " Colormap required!" ;
260+ }
261+
262+ bool ColormappedLabelImageReceiver::initImpl () {
263+ using Base = ImageReceiverImpl<ColormappedLabelSubscriber>;
264+ const auto ret = Base::initImpl ();
265+ semantic_sub_.setColormap (colormap_.get ());
266+ return ret;
267+ }
268+
269+ void declare_config (ColormappedLabelImageReceiver::Config& config) {
270+ using namespace config ;
271+ name (" ColormappedLabelImageReceiver::Config" );
272+ base<hydra::RosDataReceiver::Config>(config);
273+ field<Path::Absolute>(config.colormap_path , " colormap_path" );
274+ check<Path::Exists>(config.colormap_path , " colormap_path" );
275+ }
276+
203277namespace {
204278
205279static const auto no_semantic_registration =
@@ -220,6 +294,11 @@ static const auto open_registration =
220294 OpenSetImageReceiver::Config,
221295 std::string>(" OpenSetImageReceiver" );
222296
223- } // namespace
297+ static const auto color_registration =
298+ config::RegistrationWithConfig<hydra::DataReceiver,
299+ ColormappedLabelImageReceiver,
300+ ColormappedLabelImageReceiver::Config,
301+ std::string>(" ColormappedLabelImageReceiver" );
224302
303+ } // namespace
225304} // namespace hydra
0 commit comments