Skip to content

Commit ee918d6

Browse files
committed
add specialized subscriber for labels as colors
1 parent 1a204f6 commit ee918d6

2 files changed

Lines changed: 129 additions & 12 deletions

File tree

hydra_ros/include/hydra_ros/input/image_receiver.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
* purposes notwithstanding any copyright notation herein.
3434
* -------------------------------------------------------------------------- */
3535
#pragma once
36+
#include <hydra/common/semantic_color_map.h>
3637
#include <ianvs/node_handle.h>
3738
#include <message_filters/subscriber.h>
3839
#include <message_filters/sync_policies/approximate_time.h>
@@ -104,6 +105,24 @@ struct LabelSubscriber {
104105
std::shared_ptr<FilterSub<sensor_msgs::msg::Image>> impl_;
105106
};
106107

108+
struct ColormappedLabelSubscriber {
109+
public:
110+
using MsgType = sensor_msgs::msg::Image;
111+
using Filter = message_filters::SimpleFilter<MsgType>;
112+
113+
ColormappedLabelSubscriber();
114+
explicit ColormappedLabelSubscriber(ianvs::NodeHandle nh, uint32_t queue_size = 1);
115+
virtual ~ColormappedLabelSubscriber();
116+
117+
Filter& getFilter() const;
118+
void setColormap(const SemanticColorMap* colormap);
119+
void fillInput(const sensor_msgs::msg::Image& img, ImageInputPacket& packet) const;
120+
121+
private:
122+
const SemanticColorMap* colormap_;
123+
std::shared_ptr<FilterSub<sensor_msgs::msg::Image>> impl_;
124+
};
125+
107126
struct FeatureSubscriber {
108127
public:
109128
using MsgType = semantic_inference_msgs::msg::FeatureImage;
@@ -213,6 +232,8 @@ class ClosedSetImageReceiver : public ImageReceiverImpl<LabelSubscriber> {
213232
virtual ~ClosedSetImageReceiver() = default;
214233
};
215234

235+
void declare_config(ClosedSetImageReceiver::Config& config);
236+
216237
class OpenSetImageReceiver : public ImageReceiverImpl<FeatureSubscriber> {
217238
public:
218239
struct Config : RosDataReceiver::Config {};
@@ -222,4 +243,21 @@ class OpenSetImageReceiver : public ImageReceiverImpl<FeatureSubscriber> {
222243

223244
void declare_config(OpenSetImageReceiver::Config& config);
224245

246+
class ColormappedLabelImageReceiver
247+
: public ImageReceiverImpl<ColormappedLabelSubscriber> {
248+
public:
249+
struct Config : RosDataReceiver::Config {
250+
std::filesystem::path colormap_path;
251+
} const config;
252+
253+
ColormappedLabelImageReceiver(const Config& config, const std::string& sensor_name);
254+
virtual ~ColormappedLabelImageReceiver() = default;
255+
bool initImpl() override;
256+
257+
private:
258+
std::unique_ptr<SemanticColorMap> colormap_;
259+
};
260+
261+
void declare_config(ColormappedLabelImageReceiver::Config& config);
262+
225263
} // namespace hydra

hydra_ros/src/input/image_receiver.cpp

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
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+
123174
FeatureSubscriber::FeatureSubscriber() = default;
124175

125176
FeatureSubscriber::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-
157202
RGBDImageReceiver::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

189234
ClosedSetImageReceiver::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

199244
OpenSetImageReceiver::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+
203277
namespace {
204278

205279
static 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

Comments
 (0)