2 #include <opencv2/opencv.hpp> 11 #include <boost/thread/mutex.hpp> 12 #include <dynamic_reconfigure/server.h> 14 #include <sensor_msgs/Image.h> 15 #include <sensor_msgs/CameraInfo.h> 16 #include <geometry_msgs/PolygonStamped.h> 17 #include <geometry_msgs/PointStamped.h> 18 #include <jsk_recognition_msgs/Rect.h> 19 #include <jsk_perception/ColorHistogramSlidingMatcherConfig.h> 20 #include <jsk_recognition_msgs/BoundingBoxArray.h> 46 std::vector< std::vector< std::vector<unsigned int> > >
hsv_integral;
56 inline double calc_coe(std::vector< unsigned int > &a, std::vector<unsigned int> &b){
57 unsigned long sum_a=0, sum_b=0;
59 for(
int k=0, size=a.size(); k<size; ++k){
60 sum_a += a[k]; sum_b+= b[k];
62 for(
int k=0; k<256; ++k){
63 coe +=std::min((
double)a[k]/sum_a, (
double)b[k]/sum_b);
70 BOX(
int _x,
int _y,
int _dx,
int _dy){
71 x=_x, y=_y, dx=_dx, dy=_dy;
73 BOX(
int _x,
int _y,
int _dx,
int _dy,
double _coefficient){
74 x=_x, y=_y, dx=_dx, dy=_dy, coefficient = _coefficient;
78 return a_box.
x <= x && a_box.
x+a_box.
dx >= x && a_box.
y <= y && a_box.
y+a_box.
dy >= y;
80 inline bool in_box(
int x,
int y,
int dx,
int dy,
box a_box){
81 return point_in_box(x, y, a_box) || point_in_box(x+dx, y, a_box) || point_in_box(x, y+dy, a_box) || point_in_box(x+dx, y+dy, a_box);
83 inline bool in_boxes(
int x,
int y,
int dx,
int dy, std::vector<box> boxes){
84 for (
int i=0; i<boxes.size(); ++i){
85 if(in_box(x, y, dx, dy, boxes[i])){
93 , _subImage( _it,
"image", 1)
94 , _subInfo(_node,
"camera_info", 1)
95 , sync( SyncPolicy(10), _subImage, _subInfo)
97 _pubBestRect = _node.
advertise< jsk_recognition_msgs::Rect >(
"best_rect", 1);
98 _pubBestPolygon = _node.
advertise< geometry_msgs::PolygonStamped >(
"best_polygon", 1);
99 _pubBestPoint = _node.
advertise< geometry_msgs::PointStamped >(
"rough_point", 1);
100 _pubBestBoundingBox = _node.
advertise< jsk_recognition_msgs::BoundingBoxArray >(
"best_box", 1);
101 _debug_pub = _it.
advertise(
"debug_image", 1);
108 std::string template_filename;
109 std::string default_template_file_name;
111 #ifdef ROSPACK_EXPORT 113 rospack::Package *
p = rp.get_pkg(
"jsk_perception");
114 if (p!=
NULL) default_template_file_name = p->path + std::string(
"/sample/opencv-logo2.png");
117 std::vector<std::string> search_path;
119 rp.
crawl(search_path, 1);
121 if (rp.
find(
"jsk_perception",path)==
true) default_template_file_name = path + std::string(
"/sample/opencv-logo2.png");
123 }
catch (std::runtime_error &e) {}
124 local_nh.
param(
"template_filename", template_filename, default_template_file_name);
125 local_nh.
param(
"standard_width", standard_width, 12);
126 local_nh.
param(
"standard_height", standard_height, 12);
127 local_nh.
param(
"best_window_estimation_method", best_window_estimation_method, 1);
128 local_nh.
param(
"coefficient_threshold", coefficient_thre, 0.5);
129 local_nh.
param(
"coefficient_threshold_for_best_window", coefficient_thre_for_best_window, 0.67);
130 local_nh.
param(
"sliding_factor", sliding_factor, 1.0);
131 local_nh.
param(
"show_result", show_result_,
true);
132 local_nh.
param(
"pub_debug_image", pub_debug_image_,
true);
133 local_nh.
param(
"object_width", template_width, 0.06);
134 local_nh.
param(
"object_height", template_height, 0.0739);
136 cv::Mat template_image=cv::imread(template_filename);
137 if(template_add(template_image))template_images.push_back(template_image);
140 if(template_image.cols==0){
144 cv::Mat template_hsv_image;
145 cv::cvtColor(template_image, template_hsv_image, CV_BGR2HSV);
146 std::vector<unsigned int> template_vec(256);
147 for (
int k=0; k<256; ++k){
150 for (
int i = 0; i<template_image.rows; ++i){
151 for (
int j = 0; j<template_image.cols; ++j) {
152 uchar
h=template_hsv_image.data[i*template_hsv_image.step+j*3+0];
153 uchar
s=template_hsv_image.data[i*template_hsv_image.step+j*3+1];
164 ++template_vec[index_h*16 + index_s];
167 template_vecs.push_back(template_vec);
168 ROS_INFO(
"template vec was set successfully");
172 void image_cb(
const sensor_msgs::ImageConstPtr& msg_ptr,
const sensor_msgs::CameraInfoConstPtr& info_ptr)
174 boost::mutex::scoped_lock
lock(_mutex);
175 if(template_vecs.size()==0){
184 ROS_ERROR(
"cv_bridge exception: %s", e.what());
187 cv::Mat image=cv_ptr->image.clone();
189 if(hsv_integral.size()==0||(image.cols!=hsv_integral.size() && image.rows!=hsv_integral[0].size())){
190 ROS_INFO(
"before memory size was changed");
191 hsv_integral.resize(image.cols);
192 for(
int i=0; i<image.cols; ++i){
193 hsv_integral[i].resize(image.rows);
194 for(
int j=0; j<image.rows; ++j){
195 hsv_integral[i][j].resize(255);
198 ROS_INFO(
"memory size was changed");
201 cv::cvtColor(image, hsv_image, CV_BGR2HSV);
202 unsigned char hsv_mat[image.cols][image.rows];
203 for (
size_t i = 0, image_rows=image.rows; i<image_rows; ++i){
204 for (
size_t j = 0, image_cols=image.cols; j<image_cols; ++j) {
205 uchar
h=hsv_image.data[i*hsv_image.step+j*3+0];
206 uchar
s=hsv_image.data[i*hsv_image.step+j*3+1];
217 hsv_mat[j][i] = index_h*16+index_s;
222 #pragma omp parallel for 224 for (
size_t k =0; k<16*16; ++k){
225 if (k == hsv_mat[0][0]){
226 hsv_integral[0][0][k]=1;
229 hsv_integral[0][0][k]=0;
231 for (
size_t j=1, image_cols=image.cols; j<image_cols; ++j){
232 if(k == hsv_mat[j][0]){
233 hsv_integral[j][0][k] = hsv_integral[j-1][0][k]+1;
236 hsv_integral[j][0][k] = hsv_integral[j-1][0][k];
239 for (
int i=1,image_rows=image.rows; i<image_rows; ++i){
241 for (
int j=0, image_cols=image.cols; j<image_cols; ++j){
242 if(k == hsv_mat[j][i]){
245 hsv_integral[j][i][k] = hsv_integral[j][i-1][k]+ s;
249 ROS_INFO(
"integral histogram made");
250 for(
size_t template_index=0; template_index<template_vecs.size(); ++template_index){
251 std::vector<unsigned int> template_vec = template_vecs[template_index];
253 int index_i=-1, index_j=-1 ,index_width_d, index_height_d;
256 std::vector<box> boxes;
257 for(
float scale=image.cols/32; scale > 1; scale/=1.2){
258 int dot = (
int)(scale*2*sliding_factor);
260 int width_d = (
int)(scale*standard_width);
261 int height_d = (
int)(scale*standard_height);
262 for(
size_t i=0, image_rows=image.rows; i+height_d < image_rows; i+=dot){
263 for(
size_t j=0, image_cols=image.cols; j+width_d < image_cols; j+=dot){
265 std::vector <unsigned int> vec(256);
266 for(
size_t k=0; k<256; ++k){
267 vec[k] = hsv_integral[j+width_d][i+height_d][k]
268 - hsv_integral[j][i+height_d][k]
269 - hsv_integral[j+width_d][i][k]
270 + hsv_integral[j][i][k];
272 double temp_coe =
calc_coe(template_vec, vec);
274 if(temp_coe > coefficient_thre){
275 boxes.push_back(
box(j, i, width_d, height_d, temp_coe));
277 if (temp_coe > max_coe){
279 index_i=i; index_j=j; max_scale = scale;
280 index_width_d=width_d; index_height_d=height_d;
286 ROS_INFO(
"max_coefficient:%f", max_coe);
287 if(boxes.size() == 0 || max_coe < coefficient_thre_for_best_window){
290 cv::imshow(
"result", image);
291 cv::imshow(
"template", template_images[template_index]);
294 if(pub_debug_image_){
296 out_msg.
header = msg_ptr->header;
298 out_msg.
image = image;
303 if(best_window_estimation_method==0){
306 if(best_window_estimation_method==1){
307 box best_large_box(index_j, index_i, index_width_d, index_height_d, 0);
310 bool large_found=
false;
311 for(
size_t i=0; i<boxes.size(); ++i){
312 if(temp_width!=boxes[i].dx){
313 if(large_found)
break;
314 temp_width = boxes[i].dx;
316 if(in_box(index_j, index_i, index_width_d, index_height_d, boxes[i])){
318 if(max_coe < boxes[i].coefficient){
319 best_large_box = boxes[i];
324 index_j = best_large_box.
x; index_i = best_large_box.
y;
325 max_scale = best_large_box.
dx/standard_width;
327 if(best_window_estimation_method==2){
329 std::vector<box> boxes_temp;
330 for(
size_t i=0; i<boxes.size(); ++i){
331 box box_temp = boxes[i];
332 if(in_boxes(box_temp.
x, box_temp.
y, box_temp.
dx, box_temp.
dy, boxes_temp)){
335 boxes_temp.push_back(box_temp);
338 index_j = box_temp.
x, index_j=box_temp.
y;
339 max_scale = box_temp.
dx/standard_width;
345 cv::rectangle(image, cv::Point(index_j, index_i), cv::Point(index_j+(max_scale*standard_width), index_i+(max_scale*standard_height)), cv::Scalar(0, 0, 200), 3, 4);
346 jsk_recognition_msgs::Rect rect;
347 rect.x=index_j, rect.y=index_i, rect.width=(
int)(max_scale*standard_width); rect.height=(
int)(max_scale*standard_height);
349 geometry_msgs::PolygonStamped polygon_msg;
350 polygon_msg.header = msg_ptr->header;
351 polygon_msg.polygon.points.resize(2);
352 polygon_msg.polygon.points[0].x=index_j;
353 polygon_msg.polygon.points[0].y=index_i;
354 polygon_msg.polygon.points[1].x=(
int)(max_scale*standard_width)+index_j;
355 polygon_msg.polygon.points[1].y=(
int)(max_scale*standard_height)+index_i;
356 _pubBestPolygon.
publish(polygon_msg);
360 cv::Point2f corners2d[4] = {cv::Point2f(index_j, index_i),
361 cv::Point2f((
int)(max_scale*standard_width)+index_j, index_i),
362 cv::Point2f((
int)(max_scale*standard_width)+index_j, (
int)(max_scale*standard_height)+index_i),
363 cv::Point2f(index_j, (
int)(max_scale*standard_height)+index_i)
365 cv::Mat corners2d_mat(cv::Size(4, 1), CV_32FC2, corners2d);
366 cv::Point3f corners3d[4] = {cv::Point3f(-template_height/2,-template_width/2,0),
367 cv::Point3f(-template_height/2,template_width/2,0),
368 cv::Point3f(template_height/2,template_width/2,0),
369 cv::Point3f(template_height/2,-template_width/2,0)
371 cv::Mat corners3d_mat (cv::Size(4, 1), CV_32FC3, corners3d);
372 double fR3[3], fT3[3];
373 cv::Mat rvec(3, 1, CV_64FC1, fR3);
374 cv::Mat tvec(3, 1, CV_64FC1, fT3);
375 cv::Mat zero_distortion_mat = cv::Mat::zeros(4, 1, CV_64FC1);
377 cv::solvePnP (corners3d_mat, corners2d_mat,
381 geometry_msgs::PointStamped best_point;
382 best_point.point.x = fT3[0];
383 best_point.point.y = fT3[1];
384 best_point.point.z = fT3[2];
385 best_point.header = msg_ptr->header;
386 _pubBestPoint.
publish(best_point);
387 jsk_recognition_msgs::BoundingBoxArray box_array_msg;
388 jsk_recognition_msgs::BoundingBox box_msg;
389 box_array_msg.header = box_msg.header = msg_ptr->header;
390 box_msg.pose.position = best_point.point;
391 box_msg.pose.orientation.x = box_msg.pose.orientation.y = box_msg.pose.orientation.z = 0;
392 box_msg.pose.orientation.w = 1;
393 box_msg.dimensions.x = box_msg.dimensions.z = template_width;
394 box_msg.dimensions.y = template_height;
395 box_array_msg.boxes.push_back(box_msg);
396 _pubBestBoundingBox.
publish(box_array_msg);
399 cv::imshow(
"result", image);
400 cv::imshow(
"template", template_images[template_index]);
403 if(pub_debug_image_){
405 out_msg.
header = msg_ptr->header;
407 out_msg.
image = image;
412 void dyn_conf_callback(jsk_perception::ColorHistogramSlidingMatcherConfig &config, uint32_t level){
413 boost::mutex::scoped_lock
lock(_mutex);
414 standard_height = config.standard_height;
415 standard_width = config.standard_width;
416 coefficient_thre = config.coefficient_threshold;
417 sliding_factor = config.sliding_factor;
418 coefficient_thre_for_best_window = config.coefficient_threshold_for_best_window;
419 best_window_estimation_method = config.best_window_estimation_method;
425 inline double calc_coe(
unsigned int * a,
unsigned int* b){
426 unsigned long sum_a=0, sum_b=0;
428 for(
int k=0; k<256; ++k){
429 sum_a += a[k]; sum_b+= b[k];
431 for(
int k=0; k<256; ++k){
432 coe +=std::min((
double)a[k]/sum_a, (
double)b[k]/sum_b);
438 int main(
int argc,
char **argv){
439 ros::init (argc, argv,
"ColorHistogramSlidingMatcher");
443 dynamic_reconfigure::Server<jsk_perception::ColorHistogramSlidingMatcherConfig>
server;
444 dynamic_reconfigure::Server<jsk_perception::ColorHistogramSlidingMatcherConfig>::CallbackType
f;
446 server.setCallback(f);
BOX(int _x, int _y, int _dx, int _dy)
const cv::Matx33d & intrinsicMatrix() const
BOX(int _x, int _y, int _dx, int _dy, double _coefficient)
message_filters::sync_policies::ExactTime< sensor_msgs::Image, sensor_msgs::CameraInfo > SyncPolicy
void publish(const boost::shared_ptr< M > &message) const
image_transport::Publisher _debug_pub
void image_cb(const sensor_msgs::ImageConstPtr &msg_ptr, const sensor_msgs::CameraInfoConstPtr &info_ptr)
double coefficient_thre_for_best_window
ros::Publisher _pubBestBoundingBox
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
Publisher advertise(const std::string &base_topic, uint32_t queue_size, bool latch=false)
message_filters::Subscriber< sensor_msgs::CameraInfo > _subInfo
image_transport::SubscriberFilter _subImage
int best_window_estimation_method
std::vector< std::vector< std::vector< unsigned int > > > hsv_integral
T dot(T *pf1, T *pf2, int length)
image_transport::ImageTransport _it
ROSCPP_DECL void spin(Spinner &spinner)
std::vector< std::vector< unsigned int > > template_vecs
Connection registerCallback(C &callback)
bool in_boxes(int x, int y, int dx, int dy, std::vector< box > boxes)
ros::Publisher _pubBestRect
void publish(const sensor_msgs::Image &message) const
bool fromCameraInfo(const sensor_msgs::CameraInfo &msg)
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
ros::Publisher _pubBestPoint
bool point_in_box(int x, int y, box a_box)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool getSearchPathFromEnv(std::vector< std::string > &sp)
bool template_add(cv::Mat template_image)
void dyn_conf_callback(jsk_perception::ColorHistogramSlidingMatcherConfig &config, uint32_t level)
ros::Publisher _pubBestPolygon
int main(int argc, char **argv)
message_filters::Synchronizer< SyncPolicy > sync
void crawl(std::vector< std::string > search_path, bool force)
bool in_box(int x, int y, int dx, int dy, box a_box)
std::vector< cv::Mat > template_images
bool find(const std::string &name, std::string &path)
double calc_coe(std::vector< unsigned int > &a, std::vector< unsigned int > &b)
double calc_coe(unsigned int *a, unsigned int *b)
sensor_msgs::ImagePtr toImageMsg() const