00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 #include <ros/ros.h>
00032 #include <ros/node_handle.h>
00033 #include "sensor_msgs/Image.h"
00034 #include "image_transport/image_transport.h"
00035 #include "cv_bridge/CvBridge.h"
00036 #include <opencv/cv.h>
00037 #include <opencv/highgui.h>
00038 #include "cvaux.h"
00039 #include "cxmisc.h"
00040 #include "highgui.h"
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <ctype.h>
00044 #include <string.h>
00045 #include "ias_projected_light/cp.h"
00046 
00047 
00048 
00049 class BGFGCodeBook
00050 {
00051 
00052 public:
00053   BGFGCodeBook(ros::NodeHandle &n) :
00054     nh_(n), it_(nh_)
00055   {
00056     n.param("input_image_topic", input_image_topic_, std::string("/stereo/left/image_rect"));
00057     n.param("output_topic_", output_topic_, std::string("/stereo/left/roi"));
00058     n.param("modMin", modMin_, 75);
00059     n.param("modMax", modMax_, 75);
00060     n.param("cbBounds_", cbBounds_, 10);
00061     n.param("nframesToLearnBG", nframesToLearnBG_, 10);
00062     n.param("nChannels", nChannels_, 3);
00063     image_sub_ = it_.subscribe(input_image_topic_, 1, &BGFGCodeBook::imageCallback, this);
00064     cl = n.serviceClient<ias_projected_light::cp> ("change_pattern");
00065     pub = n.advertise<sensor_msgs::RegionOfInterest> (output_topic_, 1);
00066 
00067     
00068     model_ = 0;
00069     ch_ =
00070     { true,true,true}; 
00071         rawImage_ = 0;
00072         yuvImage_ = 0; 
00073         ImaskCodeBook_ = 0;
00074         ImaskCodeBookCC_ = 0;
00075         c_ = n_ = nframes_ = 0;
00076         model_ = cvCreateBGCodeBookModel();
00077 
00078         
00079         model_->modMin[0] = modMin_;
00080         model_->modMin[1] = model_->modMin[2] = modMin_;
00081         model_->modMax[0] = modMax_;
00082         model_->modMax[1] = model_->modMax[2] = modMax_;
00083         model_->cbBounds[0] = model_->cbBounds[1] = model_->cbBounds[2] = cbBounds_;
00084 
00085         pause_ = false;
00086         singlestep_ = false;
00087 
00088         first_image = true;
00089       }
00090 
00091       ~BGFGCodeBook()
00092       {
00093         cvDestroyWindow( "Raw" );
00094         cvDestroyWindow( "ForegroundCodeBook");
00095         cvDestroyWindow( "CodeBook_ConnectComp");
00096       }
00097 
00098       void help(void)
00099       {
00100         printf("\nLearn background and find foreground using simple average and average difference learning method:\n"
00101             "\nUSAGE:\nbgfg_codebook_node _input_image_topic:=/image_topic\n"
00102             "***Keep the focus on the video windows, NOT the console***\n\n"
00103             "INTERACTIVE PARAMETERS:\n"
00104             "\tESC,q,Q  - quit the program\n"
00105             "\th    - print this help\n"
00106             "\tp    - pause toggle\n"
00107             "\ts    - single step\n"
00108             "\tr    - run mode (single step off)\n"
00109             "=== AVG PARAMS ===\n"
00110             "\t-    - bump high threshold UP by 0.25\n"
00111             "\t=    - bump high threshold DOWN by 0.25\n"
00112             "\t[    - bump low threshold UP by 0.25\n"
00113             "\t]    - bump low threshold DOWN by 0.25\n"
00114             "=== CODEBOOK PARAMS ===\n"
00115             "\ty,u,v- only adjust channel 0(y) or 1(u) or 2(v) respectively\n"
00116             "\ta    - adjust all 3 channels at once\n"
00117             "\tb    - adjust both 2 and 3 at once\n"
00118             "\ti,o  - bump upper threshold up,down by 1\n"
00119             "\tk,l  - bump lower threshold up,down by 1\n"
00120             "\tSPACE - reset the model\n"
00121         );
00122       }
00123 
00124       void imageCallback(const sensor_msgs::ImageConstPtr& msg_ptr)
00125       {
00126 
00127         if(first_image) 
00128 
00129         {
00130           ias_projected_light::cp srv;
00131           srv.request.pattern = 0;
00132           srv.request.block_size = 1;
00133           while (ros::ok() && !cl.call(srv))
00134           {
00135             ROS_INFO("Failed to show black pattern!");
00136             cvWaitKey(50);
00137           }
00138           first_image = false;
00139           cvWaitKey(500);
00140           return;
00141         }
00142 
00143         IplImage *cv_image = NULL;
00144         try
00145         {
00146           cv_image = bridge_.imgMsgToCv(msg_ptr, "bgr8");
00147         }
00148         catch (sensor_msgs::CvBridgeException error)
00149         {
00150           ROS_ERROR("error");
00151         }
00152 
00153         if( !pause_ )
00154         {
00155           
00156           rawImage_ = cv_image;
00157           ++nframes_;
00158           if(!rawImage_)
00159           {
00160             ROS_WARN("[BGFGCodeBook:] No image received");
00161             return;
00162           }
00163         }
00164         if( singlestep_ )
00165         pause_ = true;
00166 
00167         
00168         if( nframes_ == 1 && rawImage_ )
00169         {
00170           ROS_DEBUG("[BGFGCodeBook:] First image received");
00171           
00172           yuvImage_ = cvCloneImage(rawImage_);
00173           ImaskCodeBook_ = cvCreateImage( cvGetSize(rawImage_), IPL_DEPTH_8U, 1 );
00174           ImaskCodeBookCC_ = cvCreateImage( cvGetSize(rawImage_), IPL_DEPTH_8U, 1 );
00175           cvSet(ImaskCodeBook_,cvScalar(255));
00176 #ifdef IMAGES
00177           cvNamedWindow( "Raw", 1 );
00178           cvNamedWindow( "ForegroundCodeBook",1);
00179           cvNamedWindow( "CodeBook_ConnectComp",1);
00180 #endif
00181         }
00182 
00183         
00184         if( rawImage_ )
00185         {
00186           cvCvtColor( rawImage_, yuvImage_, CV_BGR2YCrCb );
00187           
00188           if( !pause_ && nframes_-1 < nframesToLearnBG_ )
00189           {
00190             cvBGCodeBookUpdate( model_, yuvImage_ );
00191             ROS_DEBUG("[BGFGCodeBook:] Learning BG, nframes: %d", nframes_);
00192           }
00193           if( nframes_-1 == nframesToLearnBG_ )
00194           cvBGCodeBookClearStale( model_, model_->t/2 );
00195 
00196           if(nframes_-1 == nframesToLearnBG_) 
00197 
00198           {
00199             ias_projected_light::cp srv;
00200             srv.request.pattern = 1;
00201             srv.request.block_size = 1;
00202             while (ros::ok() && !cl.call(srv))
00203             {
00204               ROS_INFO("Failed to show white pattern!");
00205               cvWaitKey(50);
00206             }
00207           }
00208 
00209           
00210           if( nframes_-1 >= nframesToLearnBG_ )
00211           {
00212             ROS_DEBUG("[BGFGCodeBook:] Finding FG (modMin: %d , modMax: %d)",model_->modMin[0],model_->modMax[0]);
00213             
00214             cvBGCodeBookDiff( model_, yuvImage_, ImaskCodeBook_ );
00215             
00216             cvCopy(ImaskCodeBook_,ImaskCodeBookCC_);
00217             cvSegmentFGMask( ImaskCodeBookCC_ );
00218           }
00219 
00220           CvMemStorage* stor = cvCreateMemStorage(0);
00221           CvSeq* seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), stor);
00222 
00223           
00224           for (int i = 0; i < ImaskCodeBookCC_->width; i++)
00225           {
00226             for (int j = 0; j < ImaskCodeBookCC_->height; j++)
00227             {
00228               if(cvGet2D(ImaskCodeBookCC_, j, i).val[0] != 0)
00229               {
00230                 CvPoint p;
00231                 p.x = i;
00232                 p.y = j;
00233                 cvSeqPush(seq, &p);
00234               }
00235             }
00236           }
00237 
00238           if(seq->total > 0)
00239           {
00240             CvRect roi = cvBoundingRect(seq);
00241             cvRectangle(ImaskCodeBookCC_, cvPoint(roi.x,roi.y), cvPoint(roi.x+roi.width, roi.y + roi.height), cvScalar(255), 5);
00242             sensor_msgs::RegionOfInterest r;
00243             r.x_offset = roi.x;
00244             r.y_offset = roi.y;
00245             r.height = roi.height;
00246             r.width = roi.width;
00247 
00248             pub.publish(r);
00249 
00250           }
00251 #ifdef IMAGES
00252           
00253           cvShowImage( "Raw", rawImage_ );
00254           cvShowImage( "ForegroundCodeBook",ImaskCodeBook_);
00255           cvShowImage( "CodeBook_ConnectComp",ImaskCodeBookCC_);
00256 #endif
00257 
00258         }
00259 #ifdef IMAGES
00260         
00261         c_ = cvWaitKey(10)&0xFF;
00262         c_ = tolower(c_);
00263 
00264         if(c_ == 27 || c_ == 'q')
00265         {
00266           ros::shutdown();
00267           return;
00268         }
00269         
00270         switch( c_ )
00271         {
00272           case 'h':
00273           help();
00274           break;
00275           case 'p':
00276           pause_ = !pause_;
00277           break;
00278           case 's':
00279           singlestep_ = !singlestep_;
00280           pause_ = false;
00281           break;
00282           case 'r':
00283           pause_ = false;
00284           singlestep_ = false;
00285           break;
00286           case ' ':
00287           cvBGCodeBookClearStale( model_, 0 );
00288           nframes_ = 0;
00289           break;
00290           
00291           case 'y': case '0':
00292           case 'u': case '1':
00293           case 'v': case '2':
00294           case 'a': case '3':
00295           case 'b':
00296           ch_[0] = c_ == 'y' || c_ == '0' || c_ == 'a' || c_ == '3';
00297           ch_[1] = c_ == 'u' || c_ == '1' || c_ == 'a' || c_ == '3' || c_ == 'b';
00298           ch_[2] = c_ == 'v' || c_ == '2' || c_ == 'a' || c_ == '3' || c_ == 'b';
00299           printf("CodeBook YUV Channels active: %d, %d, %d\n", ch_[0], ch_[1], ch_[2] );
00300           break;
00301           case 'i': 
00302           case 'o': 
00303           case 'k': 
00304           case 'l': 
00305 
00306           {
00307             uchar* ptr = c_ == 'i' || c_ == 'o' ? model_->modMax : model_->modMin;
00308             for(n_=0; n_<nChannels_; n_++)
00309             {
00310               if( ch_[n_] )
00311               {
00312                 int v = ptr[n_] + (c_ == 'i' || c_ == 'l' ? 1 : -1);
00313                 ptr[n_] = CV_CAST_8U(v);
00314               }
00315               
00316             }
00317             
00318             ROS_INFO("modMax: %d, modMin: %d", model_->modMax[0], model_->modMin[0]);
00319           }
00320           break;
00321         }
00322 #endif
00323 
00324       }
00325 
00326     protected:
00327 
00328       ros::NodeHandle nh_;
00329       image_transport::ImageTransport it_;
00330       image_transport::Subscriber image_sub_;
00331       ros::Publisher pub;
00332       ros::ServiceClient cl;
00333       sensor_msgs::CvBridge bridge_;
00334       std::string input_image_topic_;
00335       std::string output_topic_;
00336 
00337       
00338       CvBGCodeBookModel* model_;
00339       int modMin_, modMax_, cbBounds_;
00340       
00341       bool ch_[3]; 
00342       IplImage* rawImage_, *yuvImage_; 
00343       IplImage *ImaskCodeBook_, *ImaskCodeBookCC_;
00344       int c_, n_, nframes_, nChannels_;
00345       int nframesToLearnBG_;
00346       bool pause_;
00347       bool singlestep_;
00348       bool first_image;
00349     };
00350 
00351 int main(int argc, char** argv)
00352 {
00353   ros::init(argc, argv, "bgfg_codebook");
00354   ros::NodeHandle n;
00355   BGFGCodeBook bg(n);
00356   ros::spin();
00357   return 0;
00358 }