Skip to content

Commit 8152008

Browse files
authored
Merge pull request #38 from iory/harris
Add corner-harris
2 parents 68ecb24 + b5fd405 commit 8152008

File tree

7 files changed

+280
-1
lines changed

7 files changed

+280
-1
lines changed

CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ generate_dynamic_reconfigure_options(
2424
cfg/FindContours.cfg cfg/ConvexHull.cfg cfg/GeneralContours.cfg cfg/ContourMoments.cfg
2525
cfg/FaceDetection.cfg
2626
cfg/GoodfeatureTrack.cfg
27+
cfg/CornerHarris.cfg
2728
#
2829
cfg/CamShift.cfg
2930
cfg/FBackFlow.cfg
@@ -202,7 +203,7 @@ opencv_apps_add_nodelet(contour_moments contour_moments/contour_moments src/node
202203
# TrackingMotion
203204
opencv_apps_add_nodelet(goodfeature_track goodfeature_track/goodfeature_track src/nodelet/goodfeature_track_nodelet.cpp) # ./tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp
204205
# ./tutorial_code/TrackingMotion/cornerDetector_Demo.cpp
205-
# ./tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
206+
opencv_apps_add_nodelet(corner_harris corner_harris/corner_harris src/nodelet/corner_harris_nodelet.cpp) # ./tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
206207
# ./tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
207208

208209
# videoio

cfg/CornerHarris.cfg

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env python
2+
3+
PACKAGE='corner_harris'
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.", True)
10+
gen.add("threshold", int_t, 0, "Threshold of corner.", 200, 0, 255)
11+
12+
exit(gen.generate(PACKAGE, "corner_harris", "CornerHarris"))

launch/corner_harris.launch

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<launch>
2+
<arg name="node_name" default="corner_harris" />
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 image" />
8+
9+
<arg name="threshold" default="200" doc="Threshold value of a circle around corners's norm" />
10+
11+
<!-- corner_harris.cpp -->
12+
<node name="$(arg node_name)" pkg="opencv_apps" type="corner_harris" >
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+
</node>
17+
</launch>

nodelet_plugins.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@
4747
<description>Nodelet for detecting corners using Shi-Tomasi method</description>
4848
</class>
4949

50+
<class name="corner_harris/corner_harris" type="corner_harris::CornerHarrisNodelet" base_class_type="nodelet::Nodelet">
51+
<description>Nodelet for detecting corners using Harris method</description>
52+
</class>
53+
5054
<class name="camshift/camshift" type="camshift::CamShiftNodelet" base_class_type="nodelet::Nodelet">
5155
<description>Nodelet to show mean-shift based tracking</description>
5256
</class>
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
// -*- coding:utf-8-unix; mode: c++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2+
/*********************************************************************
3+
* Software License Agreement (BSD License)
4+
*
5+
* Copyright (c) 2016, JSK Lab.
6+
* All rights reserved.
7+
*
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions
10+
* are met:
11+
*
12+
* * Redistributions of source code must retain the above copyright
13+
* notice, this list of conditions and the following disclaimer.
14+
* * Redistributions in binary form must reproduce the above
15+
* copyright notice, this list of conditions and the following
16+
* disclaimer in the documentation and/or other materials provided
17+
* with the distribution.
18+
* * Neither the name of the Kei Okada nor the names of its
19+
* contributors may be used to endorse or promote products derived
20+
* from this software without specific prior written permission.
21+
*
22+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25+
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26+
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31+
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33+
* POSSIBILITY OF SUCH DAMAGE.
34+
*********************************************************************/
35+
#include <ros/ros.h>
36+
#include "opencv_apps/nodelet.h"
37+
#include <image_transport/image_transport.h>
38+
#include <sensor_msgs/image_encodings.h>
39+
#include <cv_bridge/cv_bridge.h>
40+
41+
#include <opencv2/highgui/highgui.hpp>
42+
#include <opencv2/imgproc/imgproc.hpp>
43+
44+
#include <dynamic_reconfigure/server.h>
45+
#include "opencv_apps/CornerHarrisConfig.h"
46+
47+
// https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
48+
/**
49+
* @function cornerHarris_Demo.cpp
50+
* @brief Demo code for detecting corners using Harris-Stephens method
51+
* @author OpenCV team
52+
*/
53+
54+
namespace corner_harris {
55+
class CornerHarrisNodelet : public opencv_apps::Nodelet
56+
{
57+
image_transport::Publisher img_pub_;
58+
image_transport::Subscriber img_sub_;
59+
image_transport::CameraSubscriber cam_sub_;
60+
ros::Publisher msg_pub_;
61+
62+
boost::shared_ptr<image_transport::ImageTransport> it_;
63+
64+
typedef corner_harris::CornerHarrisConfig Config;
65+
typedef dynamic_reconfigure::Server<Config> ReconfigureServer;
66+
Config config_;
67+
boost::shared_ptr<ReconfigureServer> reconfigure_server_;
68+
69+
bool debug_view_;
70+
71+
std::string window_name_;
72+
static bool need_config_update_;
73+
74+
int threshold_;
75+
76+
void reconfigureCallback(Config &new_config, uint32_t level)
77+
{
78+
config_ = new_config;
79+
threshold_ = config_.threshold;
80+
}
81+
82+
const std::string &frameWithDefault(const std::string &frame, const std::string &image_frame)
83+
{
84+
if (frame.empty())
85+
return image_frame;
86+
return frame;
87+
}
88+
89+
void imageCallbackWithInfo(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& cam_info)
90+
{
91+
do_work(msg, cam_info->header.frame_id);
92+
}
93+
94+
void imageCallback(const sensor_msgs::ImageConstPtr& msg)
95+
{
96+
do_work(msg, msg->header.frame_id);
97+
}
98+
99+
static void trackbarCallback( int, void* )
100+
{
101+
need_config_update_ = true;
102+
}
103+
104+
void do_work(const sensor_msgs::ImageConstPtr& image_msg, const std::string input_frame_from_msg)
105+
{
106+
// Work on the image.
107+
try
108+
{
109+
// Convert the image into something opencv can handle.
110+
cv::Mat frame = cv_bridge::toCvShare(image_msg, sensor_msgs::image_encodings::BGR8)->image;
111+
112+
// Do the work
113+
cv::Mat dst, dst_norm, dst_norm_scaled;
114+
dst = cv::Mat::zeros( frame.size(), CV_32FC1 );
115+
116+
cv::Mat src_gray;
117+
118+
if ( frame.channels() > 1 ) {
119+
cv::cvtColor( frame, src_gray, cv::COLOR_BGR2GRAY );
120+
} else {
121+
src_gray = frame;
122+
cv::cvtColor( src_gray, frame, cv::COLOR_GRAY2BGR );
123+
}
124+
125+
/// Detector parameters
126+
int blockSize = 2;
127+
int apertureSize = 3;
128+
double k = 0.04;
129+
130+
/// Detecting corners
131+
cv::cornerHarris( src_gray, dst, blockSize, apertureSize, k, cv::BORDER_DEFAULT );
132+
133+
/// Normalizing
134+
cv::normalize( dst, dst_norm, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat() );
135+
cv::convertScaleAbs( dst_norm, dst_norm_scaled );
136+
137+
/// Drawing a circle around corners
138+
for( int j = 0; j < dst_norm.rows ; j++ ) {
139+
for( int i = 0; i < dst_norm.cols; i++ ) {
140+
if( (int) dst_norm.at<float>(j,i) > threshold_ ) {
141+
cv::circle( frame, cv::Point(i, j), 5, cv::Scalar(0), 2, 8, 0 );
142+
}
143+
}
144+
}
145+
146+
/// Create window
147+
if( debug_view_) {
148+
cv::namedWindow( window_name_, cv::WINDOW_AUTOSIZE );
149+
const int max_threshold = 255;
150+
if (need_config_update_) {
151+
config_.threshold = threshold_;
152+
reconfigure_server_->updateConfig(config_);
153+
need_config_update_ = false;
154+
}
155+
cv::createTrackbar( "Threshold:", window_name_, &threshold_, max_threshold, trackbarCallback);
156+
}
157+
158+
if( debug_view_) {
159+
cv::imshow( window_name_, frame );
160+
int c = cv::waitKey(1);
161+
}
162+
163+
// Publish the image.
164+
sensor_msgs::Image::Ptr out_img = cv_bridge::CvImage(image_msg->header, sensor_msgs::image_encodings::BGR8, frame).toImageMsg();
165+
img_pub_.publish(out_img);
166+
}
167+
catch (cv::Exception &e)
168+
{
169+
NODELET_ERROR("Image processing error: %s %s %s %i", e.err.c_str(), e.func.c_str(), e.file.c_str(), e.line);
170+
}
171+
}
172+
173+
void subscribe()
174+
{
175+
NODELET_DEBUG("Subscribing to image topic.");
176+
if (config_.use_camera_info)
177+
cam_sub_ = it_->subscribeCamera("image", 3, &CornerHarrisNodelet::imageCallbackWithInfo, this);
178+
else
179+
img_sub_ = it_->subscribe("image", 3, &CornerHarrisNodelet::imageCallback, this);
180+
}
181+
182+
void unsubscribe()
183+
{
184+
NODELET_DEBUG("Unsubscribing from image topic.");
185+
img_sub_.shutdown();
186+
cam_sub_.shutdown();
187+
}
188+
189+
public:
190+
virtual void onInit()
191+
{
192+
Nodelet::onInit();
193+
it_ = boost::shared_ptr<image_transport::ImageTransport>(new image_transport::ImageTransport(*nh_));
194+
195+
pnh_->param("debug_view", debug_view_, false);
196+
197+
if (debug_view_) {
198+
always_subscribe_ = true;
199+
}
200+
201+
window_name_ = "CornerHarris Demo";
202+
203+
reconfigure_server_ = boost::make_shared<dynamic_reconfigure::Server<Config> >(*pnh_);
204+
dynamic_reconfigure::Server<Config>::CallbackType f =
205+
boost::bind(&CornerHarrisNodelet::reconfigureCallback, this, _1, _2);
206+
reconfigure_server_->setCallback(f);
207+
208+
img_pub_ = advertiseImage(*pnh_, "image", 1);
209+
210+
onInitPostProcess();
211+
}
212+
};
213+
bool CornerHarrisNodelet::need_config_update_ = false;
214+
}
215+
216+
#include <pluginlib/class_list_macros.h>
217+
PLUGINLIB_EXPORT_CLASS(corner_harris::CornerHarrisNodelet, nodelet::Nodelet);

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ else()
3737
add_rostest(test-face_detection.test ARGS gui:=false use_opencv3:=true)
3838
endif()
3939
add_rostest(test-goodfeature_track.test ARGS gui:=false)
40+
add_rostest(test-corner_harris.test ARGS gui:=false)
4041
add_rostest(test-camshift.test ARGS gui:=false)
4142
add_rostest(test-fback_flow.test ARGS gui:=false)
4243
add_rostest(test-lk_flow.test ARGS gui:=false)

test/test-corner_harris.test

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
<!-- corner_harris.cpp -->
10+
<include file="$(find opencv_apps)/launch/corner_harris.launch" >
11+
<arg name="debug_view" value="$(arg gui)" />
12+
<arg name="image" value="image_rect" />
13+
<arg name="threshold" value="200" />
14+
</include>
15+
16+
<!-- Test Codes -->
17+
<node name="corner_harris_saver" pkg="image_view" type="image_saver" args="image:=corner_harris/image" >
18+
<param name="filename_format" value="$(find opencv_apps)/test/corner_harris.png"/>
19+
</node>
20+
<param name="corner_harris_test/topic" value="corner_harris/image" />
21+
<test test-name="corner_harris_test" pkg="rostest" type="hztest" name="corner_harris_test" >
22+
<param name="hz" value="20" />
23+
<param name="hzerror" value="15" />
24+
<param name="test_duration" value="5.0" />
25+
</test>
26+
</group>
27+
</launch>

0 commit comments

Comments
 (0)