motion_detection.cpp
Go to the documentation of this file.
00001 #include "motion_detection.h"
00002 
00003 MotionDetection::MotionDetection()
00004 {
00005     ros::NodeHandle n;
00006     ros::NodeHandle p_n("~"); //private nh
00007 
00008     img_prev_ptr_.reset();
00009     img_current_ptr_.reset();
00010 
00011     image_transport::ImageTransport it(n);
00012     image_transport::ImageTransport image_motion_it(p_n);
00013     image_transport::ImageTransport image_detected_it(p_n);
00014 
00015     //camera_sub_ = it.subscribeCamera("opstation/rgb/image_color", 1, &MotionDetection::imageCallback, this);
00016 
00017     image_sub_ = it.subscribe("opstation/rgb/image_color", 1 , &MotionDetection::imageCallback, this);
00018 
00019     dyn_rec_server_.setCallback(boost::bind(&MotionDetection::dynRecParamCallback, this, _1, _2));
00020 
00021     image_percept_pub_ = n.advertise<hector_worldmodel_msgs::ImagePercept>("image_percept", 20);
00022     image_motion_pub_ = image_motion_it.advertiseCamera("image_motion", 10);
00023     image_detected_pub_ = image_detected_it.advertiseCamera("image_detected", 10);
00024 }
00025 
00026 MotionDetection::~MotionDetection() {}
00027 
00028 void MotionDetection::imageCallback(const sensor_msgs::ImageConstPtr& img) //, const sensor_msgs::CameraInfoConstPtr& info)
00029 {
00030   // get image
00031   cv_bridge::CvImageConstPtr img_next_ptr(cv_bridge::toCvShare(img, sensor_msgs::image_encodings::MONO8));
00032 
00033   if (img_prev_ptr_)
00034   {
00035     // Calc differences between the images and do AND-operation
00036     // threshold image, low differences are ignored (ex. contrast change due to sunlight)
00037     cv::Mat diff1;
00038     cv::Mat diff2;
00039     cv::Mat img_motion;
00040     cv::absdiff(img_prev_ptr_->image, img_next_ptr->image, diff1);
00041     cv::absdiff(img_current_ptr_->image, img_next_ptr->image, diff2);
00042     cv::bitwise_and(diff1, diff2, img_motion);
00043     cv::threshold(img_motion, img_motion, motion_detect_threshold_, 255, CV_THRESH_BINARY);
00044     cv::Mat kernel_ero = getStructuringElement(cv::MORPH_RECT, cv::Size(5,5));
00045     cv::erode(img_motion, img_motion, kernel_ero);
00046 
00047     unsigned int number_of_changes = 0;
00048     int min_x = img_motion.cols, max_x = 0;
00049     int min_y = img_motion.rows, max_y = 0;
00050     // loop over image and detect changes
00051     for(int j = 0; j < img_motion.rows; j++) { // height
00052       for(int i = 0; i < img_motion.cols; i++) { // width
00053         // check if at pixel (j,i) intensity is equal to 255
00054         // this means that the pixel is different in the sequence
00055         // of images (prev_frame, current_frame, next_frame)
00056         if(static_cast<int>(img_motion.at<uchar>(j,i)) == 255) {
00057           number_of_changes++;
00058           if (min_x > i) min_x = i;
00059           if (max_x < i) max_x = i;
00060           if (min_y > j) min_y = j;
00061           if (max_y < j) max_y = j;
00062         }
00063       }
00064     }
00065 
00066     cv::Mat img_detected;
00067     img_current_col_ptr_->image.copyTo(img_detected);
00068 
00069     double percept_size = std::max(std::abs(max_x-min_x), std::abs(max_y-min_y));
00070     double area = std::abs(max_x-min_x) * std::abs(max_y-min_y);
00071     double density = area > 0.0 ? number_of_changes/area : 0.0;
00072 
00073     if (number_of_changes && max_percept_size > percept_size && percept_size > min_percept_size && density > min_density)
00074     {
00075       cv::rectangle(img_detected, cv::Rect(cv::Point(min_x, min_y), cv::Point(max_x, max_y)), CV_RGB(255,0,0), 5);
00076     }
00077 
00078     //cv::imshow("view", img_current_ptr_->image);
00079     sensor_msgs::CameraInfo::Ptr info;
00080     info.reset(new sensor_msgs::CameraInfo());
00081     info->header = img->header;
00082 
00083     if(image_motion_pub_.getNumSubscribers() > 0)
00084     {
00085       cv_bridge::CvImage cvImg;
00086       img_motion.copyTo(cvImg.image);
00087       cvImg.header = img->header;
00088       cvImg.encoding = sensor_msgs::image_encodings::MONO8;
00089       image_motion_pub_.publish(cvImg.toImageMsg(), info);
00090     }
00091 
00092     if(image_detected_pub_.getNumSubscribers() > 0)
00093     {
00094       cv_bridge::CvImage cvImg;
00095       img_detected.copyTo(cvImg.image);
00096       cvImg.header = img->header;
00097       cvImg.encoding = sensor_msgs::image_encodings::BGR8;
00098       image_detected_pub_.publish(cvImg.toImageMsg(), info);
00099     }
00100   }
00101 
00102   // shift image buffers
00103   img_prev_ptr_= img_current_ptr_;
00104   img_current_ptr_ = img_next_ptr;
00105 
00106   img_current_col_ptr_ = cv_bridge::toCvShare(img, sensor_msgs::image_encodings::BGR8);
00107 
00108 
00109 //  // calculate the standard deviation
00110 //  Scalar mean, stddev;
00111 //  meanStdDev(motion, mean, stddev);
00112 
00113 //  // if not to much changes then the motion is real (neglect agressive snow, temporary sunlight)
00114 //  if(stddev[0] < max_deviation)
00115 //  {
00116 //    int number_of_changes = 0;
00117 //    int min_x = motion.cols, max_x = 0;
00118 //    int min_y = motion.rows, max_y = 0;
00119 //    // loop over image and detect changes
00120 //    for(int j = y_start; j < y_stop; j+=2) { // height
00121 //      for(int i = x_start; i < x_stop; i+=2) { // width
00122 //        // check if at pixel (j,i) intensity is equal to 255
00123 //        // this means that the pixel is different in the sequence
00124 //        // of images (prev_frame, current_frame, next_frame)
00125 //        if(static_cast<int>(motion.at<uchar>(j,i)) == 255) {
00126 //          number_of_changes++;
00127 //          if(min_x>i) min_x = i;
00128 //          if(max_x<i) max_x = i;
00129 //          if(min_y>j) min_y = j;
00130 //          if(max_y<j) max_y = j;
00131 //        }
00132 //      }
00133 //    }
00134 
00135 //    if(number_of_changes) {
00136 //      //check if not out of bounds
00137 //      if(min_x-10 > 0) min_x -= 10;
00138 //      if(min_y-10 > 0) min_y -= 10;
00139 //      if(max_x+10 < result.cols-1) max_x += 10;
00140 //      if(max_y+10 < result.rows-1) max_y += 10;
00141 //      // draw rectangle round the changed pixel
00142 //      Point x(min_x,min_y);
00143 //      Point y(max_x,max_y);
00144 //      Rect rect(x,y);
00145 //      Mat cropped = result(rect);
00146 //      cropped.copyTo(result_cropped);
00147 //      rectangle(result,rect,color,1);
00148 //    }
00149 //    //return number_of_changes;
00150 //  }
00151   //return 0;
00152 }
00153 
00154 //void MotionDetection::mappingCallback(const thermaleye_msgs::Mapping& mapping)
00155 //{
00156 //   mapping_ = mapping;
00157 //   mappingDefined_ = true;
00158 //   ROS_INFO("Mapping received");
00159 //}
00160 
00161 void MotionDetection::dynRecParamCallback(MotionDetectionConfig &config, uint32_t level)
00162 {
00163   motion_detect_threshold_ = config.motion_detect_threshold;
00164   min_percept_size = config.motion_detect_min_percept_size;
00165   max_percept_size = config.motion_detect_max_percept_size;
00166   min_density = config.motion_detect_min_density;
00167   percept_class_id_ = config.percept_class_id;
00168 }
00169 
00170 int main(int argc, char **argv)
00171 {
00172   //cv::namedWindow("view");
00173   //cv::startWindowThread();
00174 
00175   ros::init(argc, argv, "motion_detection");
00176   MotionDetection md;
00177   ros::spin();
00178 
00179   //cv::destroyWindow("view");
00180 
00181   return 0;
00182 }
00183 


hector_motion_detection
Author(s): Alexander Stumpf
autogenerated on Mon Oct 6 2014 10:37:00