Skip to content

Commit 2d36bf0

Browse files
committed
add info to how to contribute new features
1 parent cbafaa0 commit 2d36bf0

File tree

7 files changed

+330
-0
lines changed

7 files changed

+330
-0
lines changed

CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ generate_dynamic_reconfigure_options(
6565
cfg/HLSColorFilter.cfg
6666
cfg/HSVColorFilter.cfg
6767
cfg/WatershedSegmentation.cfg
68+
#
69+
cfg/Sample.cfg
6870
)
6971

7072
## Generate messages in the 'msg' folder
@@ -342,6 +344,9 @@ endif()
342344
# https://github.com/opencv/opencv/blob/2.4/samples/cpp/video_homography.cpp
343345
# https://github.com/opencv/opencv/blob/2.4/samples/cpp/videocapture_pvapi.cpp
344346

347+
# SAMPLE
348+
opencv_apps_add_nodelet(sample src/nodelet/sample_nodelet.cpp)
349+
345350
add_library(${PROJECT_NAME} SHARED
346351
src/nodelet/nodelet.cpp
347352
${_opencv_apps_nodelet_cppfiles}

CONTRIBUTING.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
Contributing to opencv_apps
2+
===========================
3+
4+
Thanks for getting involved! We always welcome your contributions. The `opencv_apps` is the collection of image processing ROS nodes based on [OpenCV(Open Source Computer Vision Library)](https://github.com/opencv/opencv)
5+
6+
How to contribute
7+
=================
8+
9+
If you find a missing feature, please find corresponding OpenCV sample program. For example, if you willing to add histogram examples, find [tutorial_code/Histograms_Matching](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching).
10+
Then look for [CMakeLists.txt](https://github.com/ros-perception/opencv_apps/blob/cbafaa05dc32495b9aa6d487cbd411a405ad14bc/CMakeLists.txt#L167) file.
11+
12+
Then add source and cfg file. See [sample_nodelet](https://github.com/ros-perception/opencv_apps/blob/contrib/src/nodelet/sample_nodelet.cpp) and [Sample.cfg](https://github.com/ros-perception/opencv_apps/blob/contrib/cfg/Sample.cfg) for example.
13+
Please see @TODO section and modify to your contributed node.
14+
Note that all C++ code is validated by `clang-format` on [TravisCI](https://travis-ci.org/ros-perception/opencv_apps). So run following command before you commit source code.
15+
```
16+
find . -name '*.h' -or -name '*.hpp' -or -name '*.cpp' | xargs clang-format-3.9 -i -style=file
17+
```
18+
19+
Then use `opencv_apps_add_nodelet` macro to add your source code. This magic macro will generate nodelet as well as a standalone executable.
20+
```
21+
opencv_apps_add_nodelet(equalize_histogram src/nodelet/equalize_histogram_nodelet.cpp) # ./tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp
22+
```
23+
24+
Nodelet also requires to add your contributed code to [nodelet_plugins.xml](https://github.com/ros-perception/opencv_apps/blob/contrib/nodelet_plugins.xml#L118-L120).
25+
26+
We also require sample launch file and test launch file. See [sample.launch](https://github.com/ros-perception/opencv_apps/blob/contrib/launch/sample.launch) and [Sample.cfg](https://github.com/ros-perception/opencv_apps/blob/contrib/test/test-sample.test) for example. Please see @TODO section and modify to your contributed node.
27+
28+

cfg/Sample.cfg

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env python
2+
3+
PACKAGE = "opencv_apps"
4+
5+
from dynamic_reconfigure.parameter_generator_catkin import *
6+
7+
gen = ParameterGenerator()
8+
9+
gen.add("use_camera_info", bool_t, 0, "Indicates that the camera_info topic should be subscribed to to get the default input_frame_id. Otherwise the frame from the image message will be used.", False)
10+
11+
exit(gen.generate(PACKAGE, "sample", "Sample"))

launch/sample.launch

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<launch>
2+
<arg name="node_name" default="sample" /> <!-- @TODO change node name -->
3+
4+
<arg name="image" default="image" doc="The image topic. Should be remapped to the name of the real image topic." />
5+
6+
<arg name="use_camera_info" default="false" doc="Indicates that the camera_info topic should be subscribed to to get the default input_frame_id. Otherwise the frame from the image message will be used." />
7+
<arg name="debug_view" default="true" doc="Specify whether the node displays a window to show edge image" />
8+
<arg name="queue_size" default="3" doc="Specigy queue_size of input image subscribers" />
9+
<!-- @TODO add your parameters here -->
10+
11+
<!-- sample.cpp -->
12+
<node name="$(arg node_name)" pkg="opencv_apps" type="sample" > <!-- @TODO change type name -->
13+
<remap from="image" to="$(arg image)" />
14+
<param name="use_camera_info" value="$(arg use_camera_info)" />
15+
<param name="debug_view" value="$(arg debug_view)" />
16+
<param name="queue_size" value="$(arg queue_size)" />
17+
<!-- @TODO add your parameters here -->
18+
</node>
19+
</launch>

nodelet_plugins.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@
115115
<description>Nodelet to demonstrate the famous watershed segmentation algorithm in OpenCV: watershed()</description>
116116
</class>
117117

118+
<class name="opencv_apps/sample" type="opencv_apps::SampleNodelet" base_class_type="nodelet::Nodelet">
119+
<description>Nodelet to demonstrate the simple image processing</description>
120+
</class>
121+
118122
<!--
119123
for backward compatibility, can be removed in M-turtle
120124
-->

src/nodelet/sample_nodelet.cpp

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/*********************************************************************
2+
* Software License Agreement (BSD License)
3+
*
4+
* Copyright (c) @TODO Please fill your name here
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions
9+
* are met:
10+
*
11+
* * Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* * Redistributions in binary form must reproduce the above
14+
* copyright notice, this list of conditions and the following
15+
* disclaimer in the documentation and/or other materials provided
16+
* with the distribution.
17+
* * Neither the name of the Kei Okada nor the names of its
18+
* contributors may be used to endorse or promote products derived
19+
* from this software without specific prior written permission.
20+
*
21+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25+
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32+
* POSSIBILITY OF SUCH DAMAGE.
33+
*********************************************************************/
34+
35+
// @TODO Please add link to original sample program
36+
/**
37+
* This is a demo of @TODO
38+
*/
39+
40+
#include <ros/ros.h>
41+
#include "opencv_apps/nodelet.h"
42+
#include <image_transport/image_transport.h>
43+
#include <sensor_msgs/image_encodings.h>
44+
#include <cv_bridge/cv_bridge.h>
45+
#include <sensor_msgs/image_encodings.h>
46+
47+
#include <opencv2/highgui/highgui.hpp>
48+
#include <opencv2/imgproc/imgproc.hpp>
49+
50+
// @TODO Fill more header files hHere
51+
#include <dynamic_reconfigure/server.h>
52+
53+
// @TODO Note that please try to use existing opencv_apps/msg. They refrect opencv data classes.
54+
#include "opencv_apps/Point2DStamped.h"
55+
56+
//
57+
#include "opencv_apps/SampleConfig.h"
58+
#include "opencv_apps/nodelet.h"
59+
60+
namespace opencv_apps
61+
{
62+
class SampleNodelet : public opencv_apps::Nodelet
63+
{
64+
image_transport::Publisher img_pub_;
65+
image_transport::Subscriber img_sub_;
66+
image_transport::CameraSubscriber cam_sub_;
67+
ros::Publisher msg_pub_;
68+
69+
boost::shared_ptr<image_transport::ImageTransport> it_;
70+
71+
typedef opencv_apps::SampleConfig Config;
72+
typedef dynamic_reconfigure::Server<Config> ReconfigureServer;
73+
Config config_;
74+
boost::shared_ptr<ReconfigureServer> reconfigure_server_;
75+
76+
int queue_size_;
77+
bool debug_view_;
78+
ros::Time prev_stamp_;
79+
80+
std::string window_name_;
81+
static bool need_config_update_;
82+
83+
bool needToInit;
84+
85+
// @TODO Fill more vairables here
86+
static cv::Point2f point_;
87+
88+
// @TODO Define callback functions as static
89+
static void onMouse(int event, int x, int y, int /*flags*/, void* /*param*/)
90+
{
91+
ROS_INFO("onMouse %d %d %d", event, x, y); // @TODO static funcion needs ROS_INFO, but others can use NODELET_INFO
92+
if (event == CV_EVENT_LBUTTONDOWN)
93+
{
94+
point_ = cv::Point2f((float)x, (float)y);
95+
}
96+
}
97+
98+
void reconfigureCallback(Config& new_config, uint32_t level)
99+
{
100+
config_ = new_config;
101+
// @TODO Fill your code here
102+
}
103+
104+
void imageCallbackWithInfo(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& cam_info)
105+
{
106+
doWork(msg, cam_info->header.frame_id);
107+
}
108+
109+
void imageCallback(const sensor_msgs::ImageConstPtr& msg)
110+
{
111+
doWork(msg, msg->header.frame_id);
112+
}
113+
114+
void doWork(const sensor_msgs::ImageConstPtr& msg, const std::string& input_frame_from_msg)
115+
{
116+
// Work on the image.
117+
try
118+
{
119+
// Convert the image into something opencv can handle.
120+
cv::Mat image = cv_bridge::toCvShare(msg, sensor_msgs::image_encodings::BGR8)->image;
121+
122+
// Messages
123+
opencv_apps::Point2DStamped output_msg;
124+
output_msg.header = msg->header;
125+
126+
if (debug_view_)
127+
{
128+
// Create windows
129+
cv::namedWindow(window_name_, cv::WINDOW_AUTOSIZE);
130+
131+
// @TODO Create other GUI tools
132+
cv::setMouseCallback(window_name_, onMouse, 0);
133+
134+
if (need_config_update_)
135+
{
136+
reconfigure_server_->updateConfig(config_);
137+
// @TODO Update parameters
138+
need_config_update_ = false;
139+
}
140+
}
141+
142+
// Do the work
143+
if (needToInit)
144+
{
145+
// @TODO Do initial process
146+
}
147+
148+
// @TODO Do the work
149+
output_msg.point.x = point_.x;
150+
output_msg.point.y = point_.y;
151+
152+
needToInit = false;
153+
if (debug_view_)
154+
{
155+
cv::imshow(window_name_, image);
156+
157+
char c = (char)cv::waitKey(1);
158+
// if( c == 27 )
159+
// break;
160+
switch (c)
161+
{
162+
case 'r':
163+
needToInit = true;
164+
break;
165+
}
166+
}
167+
168+
// Publish the image.
169+
sensor_msgs::Image::Ptr out_img = cv_bridge::CvImage(msg->header, msg->encoding, image).toImageMsg();
170+
img_pub_.publish(out_img);
171+
msg_pub_.publish(output_msg);
172+
}
173+
catch (cv::Exception& e)
174+
{
175+
NODELET_ERROR("Image processing error: %s %s %s %i", e.err.c_str(), e.func.c_str(), e.file.c_str(), e.line);
176+
}
177+
178+
prev_stamp_ = msg->header.stamp;
179+
}
180+
181+
void subscribe() // NOLINT(modernize-use-override)
182+
{
183+
NODELET_DEBUG("Subscribing to image topic.");
184+
if (config_.use_camera_info)
185+
cam_sub_ = it_->subscribeCamera("image", queue_size_, &SampleNodelet::imageCallbackWithInfo, this);
186+
else
187+
img_sub_ = it_->subscribe("image", queue_size_, &SampleNodelet::imageCallback, this);
188+
}
189+
190+
void unsubscribe() // NOLINT(modernize-use-override)
191+
{
192+
NODELET_DEBUG("Unsubscribing from image topic.");
193+
img_sub_.shutdown();
194+
cam_sub_.shutdown();
195+
}
196+
197+
public:
198+
virtual void onInit() // NOLINT(modernize-use-override)
199+
{
200+
Nodelet::onInit();
201+
it_ = boost::shared_ptr<image_transport::ImageTransport>(new image_transport::ImageTransport(*nh_));
202+
203+
pnh_->param("queue_size", queue_size_, 3);
204+
pnh_->param("debug_view", debug_view_, false);
205+
if (debug_view_)
206+
{
207+
always_subscribe_ = true;
208+
}
209+
prev_stamp_ = ros::Time(0, 0);
210+
211+
window_name_ = "Sample"; // @TODO Add program name
212+
needToInit = true;
213+
214+
reconfigure_server_ = boost::make_shared<dynamic_reconfigure::Server<Config> >(*pnh_);
215+
dynamic_reconfigure::Server<Config>::CallbackType f =
216+
boost::bind(&SampleNodelet::reconfigureCallback, this, _1, _2);
217+
reconfigure_server_->setCallback(f);
218+
219+
img_pub_ = advertiseImage(*pnh_, "image", 1);
220+
msg_pub_ = advertise<opencv_apps::Point2DStamped>(*pnh_, "output", 1);
221+
// @TODO add more advertise/services
222+
223+
NODELET_INFO("Hot keys: ");
224+
NODELET_INFO("\tESC - quit the program");
225+
NODELET_INFO("\tr - auto-initialize tracking");
226+
// @ TODO Add more messages
227+
228+
onInitPostProcess();
229+
}
230+
};
231+
bool SampleNodelet::need_config_update_ = false;
232+
// @TODO static variable must initialized here
233+
cv::Point2f SampleNodelet::point_ = cv::Point2f(0, 0);
234+
} // namespace opencv_apps
235+
236+
#include <pluginlib/class_list_macros.h>
237+
PLUGINLIB_EXPORT_CLASS(opencv_apps::SampleNodelet, nodelet::Nodelet);

test/test-sample.test

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<launch>
2+
<arg name="gui" default="true" />
3+
<node name="play_face_bag" pkg="rosbag" type="play" args="-l $(find opencv_apps)/test/face_detector_withface_test_diamondback.bag" />
4+
5+
<group ns="wide_stereo/left" >
6+
<node name="image_proc" pkg="image_proc" type="image_proc" />
7+
<node name="image_view" pkg="image_view" type="image_view" args="image:=image_rect_color" if="$(arg gui)" />
8+
9+
<!-- sample.cpp -->
10+
<include file="$(find opencv_apps)/launch/sample.launch" > <!-- @TODO include your launch file -->
11+
<arg name="debug_view" value="$(arg gui)" />
12+
<arg name="image" value="image_rect_color" />
13+
</include>
14+
15+
<!-- Test Codes -->
16+
<node name="sample_saver_result" pkg="image_view" type="image_saver" args="image:=sample/image" > <!-- @TODO change node name -->
17+
<param name="filename_format" value="$(find opencv_apps)/test/sample_result.png"/> <!-- @TODO change file name -->
18+
</node>
19+
<param name="sample_test/topic" value="sample/output" /> <!-- @TODO topic name to check -->
20+
<test test-name="sample_test" pkg="rostest" type="hztest" name="sample_test" > <!-- @TODO change test name -->
21+
<param name="hz" value="20" />
22+
<param name="hzerror" value="15" />
23+
<param name="test_duration" value="5.0" />
24+
</test>
25+
</group>
26+
</launch>

0 commit comments

Comments
 (0)