Skip to content

Commit 7e08063

Browse files
improve image rendering performance by less waited locking
1 parent ec232a0 commit 7e08063

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
{
@@ -177,6 +145,9 @@ ImageViewNode::ImageViewNode(const rclcpp::NodeOptions & options)
177145

178146
ImageViewNode::~ImageViewNode()
179147
{
148+
image_mutex_.unlock();
149+
new_data_available_.release();
150+
180151
if (window_thread_.joinable()) {
181152
window_thread_.join();
182153
}
@@ -231,9 +202,10 @@ void ImageViewNode::imageCb(const sensor_msgs::msg::Image::ConstSharedPtr & msg)
231202
encoding = "bgr8";
232203
}
233204

234-
queued_image_.set(
235-
cv_bridge::cvtColorForDisplay(
236-
cv_bridge::toCvShare(msg), encoding, options));
205+
image_mutex_.lock();
206+
queued_image_ = cv_bridge::cvtColorForDisplay(cv_bridge::toCvShare(msg), encoding, options);
207+
image_mutex_.unlock();
208+
new_data_available_.release();
237209
} catch (cv_bridge::Exception & e) {
238210
RCLCPP_ERROR_EXPRESSION(
239211
this->get_logger(), (static_cast<int>(this->now().seconds()) % 30 == 0),
@@ -261,16 +233,23 @@ void ImageViewNode::mouseCb(int event, int /* x */, int /* y */, int /* flags */
261233
return;
262234
}
263235

264-
cv_bridge::CvImageConstPtr image(this_->shown_image_.get());
236+
const std::string filename = string_format(this_->filename_format_, this_->count_);
265237

266-
if (!image) {
238+
this_->image_mutex_.lock();
239+
240+
if (!this_->shown_image_) {
241+
this_->image_mutex_.unlock();
267242
RCLCPP_WARN(this_->get_logger(), "Couldn't save image, no data!");
268243
return;
269244
}
270245

271-
std::string filename = string_format(this_->filename_format_, this_->count_);
246+
const cv::Mat image = this_->shown_image_->image;
247+
248+
this_->image_mutex_.unlock();
249+
250+
const bool suc = cv::imwrite(filename, image);
272251

273-
if (cv::imwrite(filename, image->image)) {
252+
if (suc) {
274253
RCLCPP_INFO(this_->get_logger(), "Saved image %s", filename.c_str());
275254
this_->count_++;
276255
} else {
@@ -291,19 +270,20 @@ void ImageViewNode::windowThread()
291270
}
292271

293272
while (rclcpp::ok()) {
294-
cv_bridge::CvImageConstPtr image(queued_image_.pop());
295-
296273
if (cv::getWindowProperty(window_name_, 1) < 0) {
297274
break;
298275
}
299276

300-
if (image) {
301-
cv::imshow(window_name_, image->image);
302-
shown_image_.set(image);
303-
cv::waitKey(1);
304-
} else {
305-
rclcpp::sleep_for(std::chrono::milliseconds(20));
277+
// wait for new image data;
278+
new_data_available_.acquire();
279+
280+
image_mutex_.lock();
281+
if (queued_image_) {
282+
cv::imshow(window_name_, queued_image_->image);
283+
shown_image_ = queued_image_;
306284
}
285+
image_mutex_.unlock();
286+
cv::waitKey(1);
307287
}
308288

309289
cv::destroyAllWindows();

0 commit comments

Comments
 (0)