Skip to content

Commit ab201f3

Browse files
improve image rendering performance by less waited locking
1 parent 201faad commit ab201f3

2 files changed

Lines changed: 31 additions & 61 deletions

File tree

image_view/include/image_view/image_view_node.hpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
#ifndef IMAGE_VIEW__IMAGE_VIEW_NODE_HPP_
1616
#define IMAGE_VIEW__IMAGE_VIEW_NODE_HPP_
1717

18-
#include <condition_variable>
1918
#include <memory>
2019
#include <mutex>
20+
#include <semaphore>
2121
#include <string>
2222
#include <thread>
2323
#include <vector>
@@ -31,18 +31,6 @@
3131
namespace image_view
3232
{
3333

34-
class ThreadSafeImage
35-
{
36-
std::mutex mutex_;
37-
std::condition_variable condition_;
38-
cv_bridge::CvImageConstPtr image_;
39-
40-
public:
41-
void set(cv_bridge::CvImageConstPtr image);
42-
cv_bridge::CvImageConstPtr get();
43-
cv_bridge::CvImageConstPtr pop();
44-
};
45-
4634
class ImageViewNode
4735
: public rclcpp::Node
4836
{
@@ -55,7 +43,7 @@ class ImageViewNode
5543
~ImageViewNode();
5644

5745
private:
58-
ThreadSafeImage queued_image_, shown_image_;
46+
cv_bridge::CvImageConstPtr queued_image_, shown_image_;
5947
bool autosize_;
6048
int window_height_, window_width_;
6149
bool g_gui;
@@ -75,6 +63,8 @@ class ImageViewNode
7563
void windowThread();
7664
rcl_interfaces::msg::SetParametersResult paramCallback(const std::vector<rclcpp::Parameter> &);
7765
std::mutex param_mutex_;
66+
std::mutex image_mutex_;
67+
std::binary_semaphore new_data_available_{0};
7868
};
7969

8070
} // namespace image_view

image_view/src/image_view_node.cpp

Lines changed: 27 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -70,38 +70,6 @@
7070
namespace image_view
7171
{
7272

73-
void ThreadSafeImage::set(cv_bridge::CvImageConstPtr image)
74-
{
75-
std::lock_guard<std::mutex> lock(mutex_);
76-
image_ = image;
77-
condition_.notify_one();
78-
}
79-
80-
cv_bridge::CvImageConstPtr ThreadSafeImage::get()
81-
{
82-
std::lock_guard<std::mutex> lock(mutex_);
83-
return image_;
84-
}
85-
86-
cv_bridge::CvImageConstPtr ThreadSafeImage::pop()
87-
{
88-
cv_bridge::CvImageConstPtr image;
89-
90-
{
91-
std::unique_lock<std::mutex> lock(mutex_);
92-
93-
condition_.wait_for(
94-
lock, std::chrono::milliseconds(100),
95-
[this] {
96-
return !image_;
97-
});
98-
99-
image = std::move(image_);
100-
}
101-
102-
return image;
103-
}
104-
10573
ImageViewNode::ImageViewNode(const rclcpp::NodeOptions & options)
10674
: rclcpp::Node("image_view_node", options)
10775
{
@@ -180,6 +148,9 @@ ImageViewNode::ImageViewNode(const rclcpp::NodeOptions & options)
180148

181149
ImageViewNode::~ImageViewNode()
182150
{
151+
image_mutex_.unlock();
152+
new_data_available_.release();
153+
183154
if (window_thread_.joinable()) {
184155
window_thread_.join();
185156
}
@@ -234,9 +205,10 @@ void ImageViewNode::imageCb(const sensor_msgs::msg::Image::ConstSharedPtr & msg)
234205
encoding = "bgr8";
235206
}
236207

237-
queued_image_.set(
238-
cv_bridge::cvtColorForDisplay(
239-
cv_bridge::toCvShare(msg), encoding, options));
208+
image_mutex_.lock();
209+
queued_image_ = cv_bridge::cvtColorForDisplay(cv_bridge::toCvShare(msg), encoding, options);
210+
image_mutex_.unlock();
211+
new_data_available_.release();
240212
} catch (cv_bridge::Exception & e) {
241213
RCLCPP_ERROR_EXPRESSION(
242214
this->get_logger(), (static_cast<int>(this->now().seconds()) % 30 == 0),
@@ -264,16 +236,23 @@ void ImageViewNode::mouseCb(int event, int /* x */, int /* y */, int /* flags */
264236
return;
265237
}
266238

267-
cv_bridge::CvImageConstPtr image(this_->shown_image_.get());
239+
const std::string filename = string_format(this_->filename_format_, this_->count_);
268240

269-
if (!image) {
241+
this_->image_mutex_.lock();
242+
243+
if (!this_->shown_image_) {
244+
this_->image_mutex_.unlock();
270245
RCLCPP_WARN(this_->get_logger(), "Couldn't save image, no data!");
271246
return;
272247
}
273248

274-
std::string filename = string_format(this_->filename_format_, this_->count_);
249+
const cv::Mat image = this_->shown_image_->image;
250+
251+
this_->image_mutex_.unlock();
252+
253+
const bool suc = cv::imwrite(filename, image);
275254

276-
if (cv::imwrite(filename, image->image)) {
255+
if (suc) {
277256
RCLCPP_INFO(this_->get_logger(), "Saved image %s", filename.c_str());
278257
this_->count_++;
279258
} else {
@@ -294,19 +273,20 @@ void ImageViewNode::windowThread()
294273
}
295274

296275
while (rclcpp::ok()) {
297-
cv_bridge::CvImageConstPtr image(queued_image_.pop());
298-
299276
if (cv::getWindowProperty(window_name_, 1) < 0) {
300277
break;
301278
}
302279

303-
if (image) {
304-
cv::imshow(window_name_, image->image);
305-
shown_image_.set(image);
306-
cv::waitKey(1);
307-
} else {
308-
rclcpp::sleep_for(std::chrono::milliseconds(20));
280+
// wait for new image data;
281+
new_data_available_.acquire();
282+
283+
image_mutex_.lock();
284+
if (queued_image_) {
285+
cv::imshow(window_name_, queued_image_->image);
286+
shown_image_ = queued_image_;
309287
}
288+
image_mutex_.unlock();
289+
cv::waitKey(1);
310290
}
311291

312292
cv::destroyAllWindows();

0 commit comments

Comments
 (0)