ImageProcessingNodelet.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <ros/package.h>
00003 #include <nodelet/nodelet.h>
00004 #include <cv_bridge/cv_bridge.h>
00005 #include <opencv2/core/core.hpp>
00006 #include <opencv2/imgproc/imgproc.hpp>
00007 #include <dynamic_reconfigure/server.h>
00008 #include <sensor_msgs/image_encodings.h>
00009 #include <pluginlib/class_list_macros.h>
00010 #include <image_transport/image_transport.h>
00011 #include <nifti_image_proc/ProcessingConfig.h>
00012 
00013 //#define USE_MT_NODE_HANDLE
00014 #define MIN_INTENSITY 0
00015 #define MAX_INTENSITY 255
00016 #define LOOKUP_SIZE 256
00017 
00018 namespace nifti_image_proc {
00019 
00023 class ImageProcessingNodelet: public nodelet::Nodelet {
00024 private:
00026   int min_intensity;
00028   int max_intensity;
00030   double gamma;
00032   double percent_saturated;
00033   boost::shared_ptr<image_transport::ImageTransport> it;
00034   image_transport::Publisher cameraPub;
00035   image_transport::Subscriber cameraSub;
00036   nifti_image_proc::ProcessingConfig processingConfig;
00037   boost::shared_ptr<dynamic_reconfigure::Server<nifti_image_proc::ProcessingConfig> > server;
00038   dynamic_reconfigure::Server<nifti_image_proc::ProcessingConfig>::CallbackType f;
00039 public:
00040   ImageProcessingNodelet();
00041   void onInit();
00042   void processingCallback(nifti_image_proc::ProcessingConfig &config, uint32_t level);
00043   void cameraCallback(const sensor_msgs::ImageConstPtr& msg);
00044   cv::Mat cumulativeHist(cv::Mat hist);
00045 };
00046 
00047 ImageProcessingNodelet::ImageProcessingNodelet():
00048     min_intensity(MIN_INTENSITY),
00049     max_intensity(MAX_INTENSITY),
00050     gamma(1.0),
00051     percent_saturated(5.0) {
00052 }
00053 
00054 void ImageProcessingNodelet::onInit() {
00055   NODELET_INFO("Initializing ImageProcessingNodelet...");
00056 #ifdef USE_MT_NODE_HANDLE
00057   ros::NodeHandle &nh = getMTNodeHandle();
00058   ros::NodeHandle &pnh = getMTPrivateNodeHandle();
00059 #else
00060   ros::NodeHandle &nh = getNodeHandle();
00061   ros::NodeHandle &pnh = getPrivateNodeHandle();
00062 #endif
00063 
00064   pnh.param("min_intensity", min_intensity, min_intensity);
00065   pnh.param("max_intensity", max_intensity, max_intensity);
00066   pnh.param("gamma", gamma, gamma);
00067   pnh.param("percent_saturated", percent_saturated, percent_saturated);
00068 
00069   f = boost::bind(&ImageProcessingNodelet::processingCallback, this, _1, _2);
00070   server.reset(new dynamic_reconfigure::Server<nifti_image_proc::ProcessingConfig>(pnh));
00071   server->setCallback(f);
00072 
00073   it.reset(new image_transport::ImageTransport(nh));
00074   cameraSub = it->subscribe("image", 5, &ImageProcessingNodelet::cameraCallback, this);
00075   cameraPub = it->advertise("processed_image", 5);
00076   NODELET_INFO("ImageProcessingNodelet initialized.");
00077 }
00078 
00079 void ImageProcessingNodelet::processingCallback(nifti_image_proc::ProcessingConfig &config, uint32_t level) {
00080   processingConfig = config;
00081 }
00082 
00087 void ImageProcessingNodelet::cameraCallback(const sensor_msgs::ImageConstPtr& msg) {
00088   // Avoid processing the image if there is no subscribers.
00089   if (cameraPub.getNumSubscribers() <= 0) {
00090     return;
00091   }
00092 
00093   cv_bridge::CvImagePtr cv_ptr;
00094   try {
00095     cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
00096   } catch (cv_bridge::Exception& e) {
00097     ROS_ERROR("cv_bridge exception: %s", e.what());
00098     return;
00099   }
00100 
00101   gamma = processingConfig.gamma;
00102   percent_saturated = processingConfig.percent_saturated;
00103   double width = cv_ptr->image.cols, height = cv_ptr->image.rows;
00104 
00105   if (percent_saturated != 0.0) {
00106     cv::Mat grey;
00107     cv::cvtColor(cv_ptr->image, grey, CV_BGR2GRAY);
00108     cv::Mat hist;
00109 
00110     int histSize = 256;
00111     float range[] = { 0, 256 };
00112     const float* histRange = { range };
00113     calcHist(&grey, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange, true, false);
00114 
00115     hist /= width * height;
00116     hist *= 100;
00117     hist = cumulativeHist(hist);
00118 
00119     int l_min = 255, l_max = 0, sum_min = 0.0, sum_max = 0.0;
00120     for (; l_min >= 0; l_min--) {
00121       if (hist.at<float>(l_min) <= percent_saturated / 2.0) {
00122         break;
00123       }
00124     }
00125     for (; l_max < 256; l_max++) {
00126       if (100 - hist.at<float>(l_max) <= percent_saturated / 2.0) {
00127         break;
00128       }
00129     }
00130     min_intensity = l_min;
00131     max_intensity = l_max;
00132   } else {
00133     min_intensity = processingConfig.min_intensity;
00134     max_intensity = processingConfig.max_intensity;
00135   }
00136 
00137   cv::Mat lookup(1, LOOKUP_SIZE, CV_8U);
00138   for (int i = 0; i < LOOKUP_SIZE; i++) {
00139     if (i < min_intensity) {
00140       lookup.at<uchar>(i) = MIN_INTENSITY;
00141     } else if (i > max_intensity) {
00142       lookup.at<uchar>(i) = MAX_INTENSITY;
00143     } else {
00144       lookup.at<uchar>(i) = static_cast<uchar>(255.0
00145           * pow(((double) (i - min_intensity) / (double) (max_intensity - min_intensity)), 1 / gamma) + 0.5);
00146     }
00147   }
00148 
00149   cv::Mat result;
00150   cv::LUT(cv_ptr->image, lookup, result);
00151 
00152   cv_bridge::CvImagePtr image_ptr(new cv_bridge::CvImage);
00153   image_ptr->header = msg->header;
00154 //  image_ptr->header.stamp = ros::Time::now();
00155 //  image_ptr->header.frame_id = "processed_image";
00156   image_ptr->encoding = sensor_msgs::image_encodings::BGR8;
00157   image_ptr->image = result;
00158 
00159   cameraPub.publish(image_ptr->toImageMsg());
00160 }
00161 
00167 cv::Mat ImageProcessingNodelet::cumulativeHist(cv::Mat hist) {
00168   cv::Mat cumulative(hist.size(), hist.type());
00169   float sum = 0.0;
00170   for (int i = 0; i < 256; i++) {
00171     sum += hist.at<float>(i);
00172     cumulative.at<float>(i) = sum;
00173   }
00174   return cumulative;
00175 }
00176 
00177 }
00178 
00179 PLUGINLIB_DECLARE_CLASS(nifti_image_proc, image_processing_nodelet,
00180     nifti_image_proc::ImageProcessingNodelet, nodelet::Nodelet)
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines


nifti_image_proc
Author(s): Ilina Stoilkovska, Tomas Petricek / petrito1@cmp.felk.cvut.cz
autogenerated on Fri Nov 29 2013 14:34:22