예제 #1
0
void callback(const sensor_msgs::ImageConstPtr &imgPtr){
    cvImageFromROS =cv_bridge::toCvCopy(imgPtr);
    diff =cv_bridge::toCvCopy(imgPtr);

    cvImageFromROS->image.copyTo(image);
    diff->image.copyTo(DiffImage);
    out_msg.header   = imgPtr->header;
    out_msg.encoding = "mono16";


    int cols=image.cols;
    int rows=image.rows;
    ushort v;
    cv::Point p;
    for(int i=0;i<cols;i++){
        for(int j=0;j<rows;j++){
            p.x=i;
            p.y=j;
            v=((float)image.at<ushort>(p));
            v*=multiplier->cell(p.y,p.x,v);
            image.at<ushort>(p)=(ushort)v;
        }
    }

    out_msg.image    =  image;
    pub.publish(out_msg.toImageMsg());
    out_msg.image    =  image-DiffImage;
    pub2.publish(out_msg.toImageMsg());
    //std::cout<<"global diff: "<< cv::sum(out_msg.image)/(out_msg.image.rows*out_msg.image.cols)<<std::endl;

}
예제 #2
0
void faceDetect(){
  //Detect faces
   cv::cvtColor( frame, frame_gray, CV_BGR2GRAY );
   cv::equalizeHist( frame_gray, frame_gray );
   face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, cv::Size(30, 30) );
  
   //for each face draws an ellipse arround and look for the red color at a distance from 
   for( i = 0; i < faces.size(); i++ )
    {
      cv::Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
      cv::ellipse( frame, center, cv::Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, cv::Scalar( 0, 255, 0 ), 2, 8, 0 );
      faceX = (float) faces[i].x;
      faceY = (float) faces[i].y;
     
      if( ((faceX + faceColorThresh) > (posX ) | (faceX - faceColorThresh) < (posX )) ) {
	face = true; 
	//publishing camera image
	out_msg.image    = frame; //frame
	out_msg.encoding = sensor_msgs::image_encodings::BGR8;
	msg = out_msg.toImageMsg();
	pub.publish(msg);
	ROS_FATAL("PERSON DETECTED");
	break;
      }
    }
}
예제 #3
0
	inline void publish(Mat img, imgColorType t, ros::Time now =
			ros::Time::now())
	{
		hasListener=(img_pub.getNumSubscribers() > 0);
		if (!enable || !hasListener)
			return;
		Mat res;
		switch (t)
		{
		case gray:
			msg.encoding = sensor_msgs::image_encodings::MONO8;
			res = img;
			break;
		case hsv:
			msg.encoding = sensor_msgs::image_encodings::BGR8;
			cvtColor(img, res, CV_HSV2BGR);
			break;
		case bgr:
		default:
			msg.encoding = sensor_msgs::image_encodings::BGR8;
			res = img;
			break;
		}
		msg.header.stamp = now;
		msg.image = res;
		img_pub.publish(msg.toImageMsg());
	}
예제 #4
0
void callback(const sensor_msgs::ImageConstPtr &imgPtr){
    cvImageFromROS =cv_bridge::toCvCopy(imgPtr);

    cvImageFromROS->image.copyTo(image);
    out_msg.header   = imgPtr->header;
    out_msg.encoding = "mono16";
    out_msg.image    = image;
    pub.publish(out_msg.toImageMsg());
}
예제 #5
0
/***********************************************************
* @fn main(int argc, char **argv)
* @brief starts the Pot_Nav node and publishises twist when 
* it gets a new image asuming 30 hz
***********************************************************/
int main(int argc, char **argv)
{
	ros::init(argc, argv, "Pot_Nav");
    ros::NodeHandle n;
    image_transport::ImageTransport it(n);
    
    
	dynamic_reconfigure::Server<MST_Potential_Navigation::Pot_Nav_ParamsConfig> srv;
    dynamic_reconfigure::Server<MST_Potential_Navigation::Pot_Nav_ParamsConfig>::CallbackType f;
    f = boost::bind(&setparamsCallback, _1, _2);
	srv.setCallback(f);

	//create subsctiptions
    image_sub_edges = it.subscribe( n.resolveName("image_edges") , 1, edgesCallback );

    //create publishers
    twist_pub = n.advertise<geometry_msgs::Twist>( "nav_twist" , 5 );
    map_pub = it.advertise( "map" , 5 );
    
    //set rate to 30 hz
    ros::Rate loop_rate(30);
    
    
    
    //run main loop
	while (ros::ok())
    {
		//check calbacks
		ros::spinOnce();
		
		//finds and publishes new twist
		if(map_changed)
		{
			geometry_msgs::Twist twist;
			
			twist = find_twist(); 
			
			//publish twist
			twist_pub.publish(twist);
			
			//publish map
			map_pub.publish(map_dis.toImageMsg());
			
			map_changed = 0;
		}
		
		loop_rate.sleep();
    }
    
    return 0;
}
void HiwrCameraControllerNodelet::publishFrame(Mat frame ) {
    out_msg_.encoding = sensor_msgs::image_encodings::MONO8;
    out_msg_.image    = frame;
    out_msg_.header.seq = published_frame_;


    char frame_id[20];
    sprintf(frame_id , "%d" , published_frame_);
    out_msg_.header.frame_id = frame_id;
    out_msg_.header.stamp = ros::Time::now();

    published_frame_++;
    image_publisher_.publish(out_msg_.toImageMsg() );
}
예제 #7
0
void mapSubCallback(const nav_msgs::OccupancyGrid map) {
  //================================================================MAP TO IMAGE
  MAP_X = map.info.width;
  MAP_Y = map.info.height;

  MAP_RESOLUTION = map.info.resolution;

  if ((MAP_X < 3) || (MAP_Y < 3) ) {
    ROS_INFO("Map size is only x: %ld,  y: %ld . Not running map to image conversion", MAP_X, MAP_Y);
    return;
  }

  cv::Mat *map_mat  = &cv_img.image;

  // resize cv image if it doesn't have the same dimensions as the map
  if ((map_mat->rows != MAP_Y) && (map_mat->cols != MAP_X)) {
    *map_mat = cv::Mat(MAP_Y, MAP_X, CV_8U);
  }

  // ROS_INFO("Fault_1");

  const std::vector<int8_t>&map_data(map.data);

  unsigned char *map_mat_data_p = (unsigned char *)map_mat->data;

  // ROS_INFO("Fault_2");

  //We have to flip around the y axis, y for image starts at the top and y for map at the bottom

  int MAP_Y_rev = MAP_Y - 1;

  // ROS_INFO_STREAM("Fault for :" << MAP_Y_rev);

  for (int y = MAP_Y_rev; y >= 0; --y) {
    int idx_map_y = MAP_X * (MAP_Y - y);
    int idx_img_y = MAP_X * y;

    // ROS_INFO_STREAM("Fault_3 :" << y);

    // if (y == 0) {
    //   ROS_INFO_STREAM("MAP_X :" << MAP_X);
    // }

    for (int x = 0; x < MAP_X; ++x) {
      int idx = idx_img_y + x;
      //
      // if (y == 0 && x > 1000) {
      //   ROS_INFO_STREAM("x :" << x);
      //   try {
      //     //ROS_INFO_STREAM("valid:" << isValidPtr(map_data, idx_map_y + x));
      //     ROS_INFO_STREAM("Map data :" << map_data[idx_map_y + x]);
      //   } catch (std::exception& e) {
      //     std::cout << e.what() << std::endl;
      //   }
      // }

      switch (map_data[idx_map_y + x]) {
        case -1:
          map_mat_data_p[idx] = 255; //grey color:unknown default value of 127
          break;

        case 0:
          map_mat_data_p[idx] = 255; // laser ray:default 255
          break;

        case 100:
          map_mat_data_p[idx] = 0; // obstacle:default 0
          break;
      }

      // if (y == 0 && x > 1000) {
      //   ROS_INFO_STREAM("x :" << x);
      // }
    }

    // ROS_INFO_STREAM("Fault_3 :" << y);
  }

  // ROS_INFO("Fault_4");


//======================================================================== DETECT TREES
  cv::Mat im, im_with_keypoints;

// Reduce the noise
  if (GaussianBlur_kernelSize > 1) {
    cv::GaussianBlur(cv_img.image, im, cv::Size(GaussianBlur_kernelSize, GaussianBlur_kernelSize), 0);
  } else {
    im = cv_img.image;
  }

// Setup SimpleBlobDetector parameters.
  cv::SimpleBlobDetector::Params params;

// Change thresholds
  params.minThreshold = minThreshold;
  params.maxThreshold = maxThreshold;

// Filter by Area.
  if (minArea < maxArea) {
    params.filterByArea = true;
    params.minArea = minArea;
    params.maxArea = maxArea;
  } else {
    params.filterByArea = false;
  }

// Filter by Circularity
  if (minCircularity < maxCircularity) {
    params.filterByCircularity = true;
    params.minCircularity = minCircularity;
    params.maxCircularity = maxCircularity;
  } else {
    params.filterByCircularity = false;
  }

// Filter by Convexity
  if (minConvexity < maxConvexity) {
    params.filterByConvexity = true;
    params.minConvexity = minConvexity;
    params.maxConvexity = maxConvexity;
  } else {
    params.filterByConvexity = false;
  }

// Filter by Inertia
// params.filterByInertia = true;
// params.minInertiaRatio = 0.01;

// Storage for blobs
  std::vector<cv::KeyPoint> keypoints;

// Set up detector with params
  cv::Ptr<cv::SimpleBlobDetector> detector = cv::SimpleBlobDetector::create(params);

// Detect blobs
  detector->detect(im, keypoints);

//================================================================ Publish Markers
  visualization_msgs::Marker marker;
  marker.header.frame_id = "map";
  marker.header.stamp = ros::Time();
  marker.ns = "agri_mapper";
  marker.id = 0;
  marker.type = visualization_msgs::Marker::SPHERE_LIST;
  marker.action = visualization_msgs::Marker::ADD;
  marker.pose.position.x = -(MAP_X * MAP_RESOLUTION / 2) - 0.2;
  marker.pose.position.y = -(MAP_Y * MAP_RESOLUTION / 2) - 0.2;
  marker.pose.position.z = 0;
  marker.pose.orientation.x = 0;
  marker.pose.orientation.y = 0;
  marker.pose.orientation.z = 0;
  marker.pose.orientation.w = 1;
  marker.scale.x = 0.1;
  marker.scale.y = 0.1;
  marker.scale.z = 0.1;
  marker.color.a = 1.0; // Don't forget to set the alpha!
  marker.color.r = 0.0;
  marker.color.g = 1.0;
  marker.color.b = 0.0;

  marker.points.resize(keypoints.size());

  std::vector<cv::KeyPoint>::iterator it = keypoints.begin();

  ROS_INFO_STREAM("making markers");
  ROS_INFO_STREAM("\n Size : " << keypoints.size() << "\n");

  for (int i = 0; it != keypoints.end(); ++it, i++) {
    marker.points[i].x = (it->pt.x) * MAP_RESOLUTION;
    marker.points[i].y = (MAP_Y - it->pt.y) * MAP_RESOLUTION;
    marker.points[i].z = 0;
  }

  ROS_INFO_STREAM("made markers");

  vis_pub.publish(marker);

//============================================================================PUBLISH IMAGE

// Draw detected blobs as red circles.
// DrawMatchesFlags::DRAW_RICH_KEYPOINTS flag ensures
// the size of the circle corresponds to the size of blob

  cv::drawKeypoints(im, keypoints, im_with_keypoints, cv::Scalar(255, 0, 0), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

  cv_detectionImg.image = im_with_keypoints;

  image_pub.publish(cv_img.toImageMsg());
  detected_pub.publish(cv_detectionImg.toImageMsg());
}
int main(int argc, char **argv)
{
    ros::init(argc, argv, "people_counting");
    ros::NodeHandle node;

    ros::param::param<std::string>(ros::this_node::getName() + "dataset", fileDataset_param, "haarcascade_upperbody.xml");
    ros::param::param<double>(ros::this_node::getName() + "scaleFactor", scaleFactor_param, 0.1);
    ros::param::param<int>(ros::this_node::getName() + "minNeighbors", minNeighbors_param, 0);
    // ros::param::param<double>("minSize", minSize_param, 0);
    ros::param::param<double>(ros::this_node::getName() + "maxSize", maxSize_param, 1.0);

    // argc--; argv++;
    // while( argc && *argv[0] == '-' )
    // {
    //     if( !strcmp(*argv, "-fps") && ( argc > 1 ) )
    //     {
    //         fps = atof(*(argv+1));
    //         printf("With %ffps\n",fps);
    //         argc--; argv++;
    //     }
    //     if( !strcmp(*argv, "-crowd_dataset") && ( argc > 1 ) )
    //     {
    //         file_dataset = *(argv+1);
    //         printf("Using dataset form %s\n",file_dataset.c_str());
    //         argc--; argv++;
    //     }
    //     argc--; argv++;
    // }

    std::vector<cv::Rect> objects;
    std::vector<cv::Scalar> colors;
    cv::RNG rng(12345);

    img_msg.encoding = "bgr8";

    if ( ! classifier.load(fileDataset_param))
        ROS_ERROR("Can't open %s", fileDataset_param.c_str());

    ros::Publisher img_pub = node.advertise<sensor_msgs::Image>("crowd/count_img", 100);
    ros::Publisher count_pub = node.advertise<std_msgs::UInt16>("crowd/people_count", 100);

    image_transport::ImageTransport it(node);
    image_transport::Subscriber img_sub = it.subscribe("image", 1, imageCallback);

    ros::Rate loop_rate(fps);

    while (ros::ok())
    {
        if (! img_msg.image.empty()) {
            classifier.detectMultiScale(img_msg.image, objects, 1.0+scaleFactor_param, minNeighbors_param+1, 0, cv::Size(), maxSize);
            for (int j = 0; j < objects.size(); ++j) {
                if ( j > max_detected) {
                    colors.push_back(cv::Scalar(rng.uniform(0,255),rng.uniform(0, 255),rng.uniform(0, 255)));
                    max_detected = j;
                }
                cv::rectangle(img_msg.image, objects[j], colors[j], 2);
            }
            people_count.data = (u_int16_t)objects.size();
        }
        img_pub.publish(img_msg.toImageMsg());
        count_pub.publish(people_count);

        ros::spinOnce();
        loop_rate.sleep();
    }

    return 0;
}
namespace hiwr_camera_controller
{

/** Segfault signal handler */
void sigsegvHandler(int sig)
{
    signal(SIGSEGV, SIG_DFL);
    fprintf(stderr, "Segmentation fault, catched by sigsegvHandler.\n");
    ROS_ERROR("Segmentation fault, catched by sigsegvHandler");
    ros::shutdown();                      // stop the main loop
}


void HiwrCameraControllerNodelet::onInit(){
    public_nh_ = getNodeHandle(); //Public namespace

    private_nh_ = getMTPrivateNodeHandle();

    //Retrieveing params from param/config__xx.yaml
    //Can be better with have_param() before getting ...
    private_nh_.getParam("absolute_exposure", config_.absolute_exposure);
    private_nh_.getParam("camera_info_url", config_.camera_info_url);
    private_nh_.getParam("camera_name", config_.camera_name);
    private_nh_.getParam("brightness", config_.brightness);
    private_nh_.getParam("contrast", config_.contrast);
    private_nh_.getParam("device_name", config_.device);
    private_nh_.getParam("exposure", config_.exposure);
    private_nh_.getParam("focus_absolute", config_.focus_absolute);
    private_nh_.getParam("focus_auto", config_.focus_auto);
    private_nh_.getParam("format_mode", config_.format_mode);
    private_nh_.getParam("frame_id", config_.frame_id);
    private_nh_.getParam("frame_rate", config_.frame_rate);
    private_nh_.getParam("gain", config_.gain);
    private_nh_.getParam("height", config_.height);
    private_nh_.getParam("power_line_frequency", config_.power_line_frequency);
    private_nh_.getParam("saturation", config_.saturation);
    private_nh_.getParam("sharpness", config_.sharpness);
    private_nh_.getParam("white_balance_temperature", config_.white_balance_temperature);
    private_nh_.getParam("width", config_.width);

    configureSpinning(private_nh_);

    it_ = new image_transport::ImageTransport(private_nh_);
    image_pub_ = it_->advertise("output_video", 1);

    running_ = true;
    device_thread_ = boost::shared_ptr< boost::thread >
       (new boost::thread(boost::bind(&HiwrCameraControllerNodelet::spin, this)));

    NODELET_INFO("[UVC Cam Nodelet] Loading OK");
}

HiwrCameraControllerNodelet::HiwrCameraControllerNodelet():
    private_nh_("~"),
    public_nh_(config_.camera_name)
{
    next_config_level_=0;
    next_config_update_ = false;
    next_config_count_=0;

    reconfig_number_=0;
    published_frame_=0;

    state_ = Driver::CLOSED;
    spining_state_ = true;
    calibration_matches_ = true;
    frame_= NULL;
}

void HiwrCameraControllerNodelet::loopGrabImage(){

    std::unique_lock<std::mutex> lk(mutex_);

    if(lk.owns_lock()){
        lk.unlock();
    }

    while(ros::ok()){
        int buf_idx;

        if(next_config_update_){
            printf("[%s] will apply nextconfig__ \n", config_.camera_name.c_str());
            applyNewConfig(next_config_ , next_config_level_);
            printf("[%s] Did apply nextconfig__ \n", config_.camera_name.c_str());
        }

        if(!spining_state_){
            usleep(1000);
            continue;
        }

        uint32_t tmp_bytes_used;
        try{
            buf_idx = cam_->grab(&next_frame_, &tmp_bytes_used);
        }catch (std::exception e) {
            printf("exception calling grab\n");
            usleep(1000);
            continue;
        }

        if (buf_idx < 0) {
            printf("Could not grab image\n");
            usleep(1000);
            continue;
        }

        if(!lk.try_lock()){
            cam_->release(buf_idx);
            continue;
        }
        if(frame_!=NULL){
            free(frame_);
        }
        frame_ = (unsigned char*)malloc(tmp_bytes_used);
        memcpy(frame_, next_frame_, tmp_bytes_used);
        bytes_used_ = tmp_bytes_used;
        new_frame_=true;
        lk.unlock();
        waiter_.notify_all();

        cam_->release(buf_idx);

    }

}

void HiwrCameraControllerNodelet::closeCamera(){
    if (state_ != Driver::CLOSED){

        ROS_INFO_STREAM("[" << camera_name_ << "] closing device");
        if(cam_) {
            delete cam_;
        }
        state_ = Driver::CLOSED;
    }
}


/** Open the camera device.
 *
 * @param newconfig_ config_uration parameters
 * @return true, if successful
 *
 * if successful:
 *   state_ is Driver::OPENED
 *   camera_name_ set to camera_name string
 */
bool HiwrCameraControllerNodelet::openCamera(Config &new_config){

    new_config.format_mode = uvc_cam::Cam::MODE_YUYV;
    uvc_cam::Cam::mode_t mode = uvc_cam::Cam::MODE_YUYV;
    bool success = true;
    final_=NULL;
    try
    {
        ROS_INFO("opening uvc_cam at %dx%d, %f fps - %s : %s", new_config.width, new_config.height, new_config.frame_rate , new_config.device.c_str() , findVideoDevice(new_config.device.c_str()));
        printf("before cam creating, cam is at %p\n", cam_);
        ROS_INFO("[Uvc Cam Nodelet] video device is {%s}", new_config.device.c_str() );
        char * video_device = findVideoDevice(new_config.device.c_str());
        NODELET_INFO("Video DEVICE IS %s",video_device);
        cam_ = new uvc_cam::Cam(video_device, mode, new_config.width, new_config.height, new_config.frame_rate);
        printf("after cam creating, cam is at %p\n", cam_);

        camera_name_ = config_.camera_name ;
        NODELET_INFO("[%s] camera_name_=%s",config_.camera_name.c_str(), camera_name_.c_str()  );
        if (camera_name_ != camera_name_)
        {
            camera_name_ = camera_name_;
        }
        state_ = Driver::OPENED;
        calibration_matches_ = true;

    }
    catch (uvc_cam::Exception& e)
    {
        ROS_FATAL_STREAM("[" << camera_name_
                         << "] exception opening device: " << e.what());
        success = false;
    }
    catch(std::runtime_error& ex){
        success = false;
        NODELET_WARN("[UVC Cam Node] runtime_error ex : %s",ex.what());
    }

    return success;
}


void HiwrCameraControllerNodelet::dealMemory(){
    if(final_!=NULL){
        free(final_);
    };
    final_ = (unsigned char *) malloc( sizeof( char) * config_width_ * config_height_ );
    if(final_ == NULL){
        printf("############# MALLOC FAILED !! ##########\n");
    }
}

bool HiwrCameraControllerNodelet::copyRead(){
    std::unique_lock<std::mutex> lk(mutex_);

    if(!lk.owns_lock()){
        try {
            lk.lock();
        } catch(const std::system_error& e) {
            std::cout << "coin2 Caught system_error with code " << e.code()
                      << " meaning " << e.what() << '\n';
        }
    }

    if(!new_frame_){
        waiter_.wait(lk);
    }
    image_ipl_ = cvCreateImageHeader(cvSize(config_width_ ,config_height_), 8, 1);
    dealMemory();
    const int total = config_width_*config_height_*2;

    if(total!=bytes_used_)
        return false;

    int j=0;
    for(int i=0; i< total; j++){
        final_[j]=frame_[i];
        i+=2;
    };
    new_frame_=false;
    lk.unlock();

    return true;
}

std::unique_lock<std::mutex> HiwrCameraControllerNodelet::getLock(){
    std::unique_lock<std::mutex> lk(mutex_);
    if(!lk.owns_lock()){
        printf(" dont get the lock \n");
        try {
            lk.lock();
        } catch(const std::system_error& e) {
            std::cout << "coin2 Caught system_error with code " << e.code()
                      << " meaning " << e.what() << '\n';
        }
    }
    printf(" do get the lock \n");
    return lk;
}

/** Read camera data.
 *
 * @return true if successful
 */
bool HiwrCameraControllerNodelet::read() {
    bool success = true;
    if(config_width_ < 1 || config_height_ < 1 )
        return false;

    try
    {
        bool copy_worked = copyRead();
        if(!copy_worked)
            return false;

        image_ipl_->imageData = (char *)final_;
    }
    catch (uvc_cam::Exception& e)
    {
        printf("exception readind data %s", e.what());
        success = false;
    }
    return success;
}

/** Dynamic reconfig_ure callback
 *
 *  Called immediately when callback first defined. Called again
 *  when dynamic reconfig_ure starts or changes a parameter value.
 *
 *  @param newconfig_ new Config values
 *  @param level bit-wise OR of reconfig_uration levels for all
 *               changed parameters (0xffffffff on initial call)
 **/

void HiwrCameraControllerNodelet::reconfig(Config &new_config, uint32_t level)
{

    next_config_= new_config;
    next_config_.device = config_.device;
    next_config_level_ = level;
    printf("################################## reconfig_ call with level %u \n" , level);
    next_config_update_ = true;
    next_config_count_ ++;

}


void HiwrCameraControllerNodelet::changeSize(int width, int height){

    printf("############## changing size called %d %d %d \n", width, height, next_config_update_);
    if(next_config_update_ == true){
        printf("change sizze called, but already called before \n");
        return;
    }
    next_config_ = Config(config_);
    next_config_.width = width;
    next_config_.height = height;
    next_config_update_ = true;

}

void HiwrCameraControllerNodelet::applyNewConfig(Config &new_config, uint32_t level)
{
    printf("### dynamic reconfig_ure level 0x%x \n", level);
    ROS_DEBUG("dynamic reconfig_ure level 0x%x", level);
    reconfig_number_++;
    // resolve frame ID using tf_prefix parameter
    if (new_config.frame_id == "")
        new_config.frame_id = "camera";

    ROS_DEBUG("dynamic reconfig_ure level 0x%x", level);
    std::string tf_prefix = tf::getPrefixParam(private_nh_);
    ROS_DEBUG_STREAM("tf_prefix: " << tf_prefix);
    new_config.frame_id = tf::resolve(tf_prefix, new_config.frame_id);

    if (state_ != Driver::CLOSED && (level & Levels::RECONFIGURE_CLOSE))
    {
        // must close the device before updating these parameters
        closeCamera();                  // state_ --> CLOSED
    }
    if (state_ == Driver::CLOSED)
    {
        // open with new values
        if (openCamera(new_config))
        {
            // update camera name string
            new_config.camera_name = camera_name_;
        }
    }


    if(reconfig_number_ == 1 || config_.focus_auto != new_config.focus_auto){
        try {
            NODELET_INFO("will try to set autofocus to %d \n " , new_config.focus_auto);
            cam_->set_control( 0x009A090C , new_config.focus_auto);
        } catch (uvc_cam::Exception& e) {
            ROS_ERROR_STREAM("Problem setting focus_auto. Exception was " << e.what());
        }
    }


    if(reconfig_number_ == 1 || config_.focus_absolute != new_config.focus_absolute){
        try {
            NODELET_INFO("will try to set focus_absolute to %d \n " , new_config.focus_absolute);
            cam_->set_control( 0x009A090A  , new_config.focus_absolute);
        } catch (uvc_cam::Exception& e) {
            ROS_ERROR_STREAM("Problem setting focus_absolute. Exception was " << e.what() << "value was" << new_config.focus_absolute ) ;
        }
    }

    config_ = new_config;

    config_width_ = new_config.width;
    config_height_ = new_config.height;

    next_config_update_ = false;
    printf("### dynamic reconfig_ure will unlock\n");

}


void HiwrCameraControllerNodelet::setSpinningState(bool p_spinning_state){
    spining_state_ = p_spinning_state;
}

bool HiwrCameraControllerNodelet::getSpinningState(){
    return spining_state_;
}

cv_bridge::CvImage out_msg_;

void HiwrCameraControllerNodelet::publishFrame(Mat frame ) {
    out_msg_.encoding = sensor_msgs::image_encodings::MONO8;
    out_msg_.image    = frame;
    out_msg_.header.seq = published_frame_;


    char frame_id[20];
    sprintf(frame_id , "%d" , published_frame_);
    out_msg_.header.frame_id = frame_id;
    out_msg_.header.stamp = ros::Time::now();

    published_frame_++;
    image_publisher_.publish(out_msg_.toImageMsg() );
}


/** driver main spin loop */\
void HiwrCameraControllerNodelet::spin() {
    NODELET_INFO("[UVC Cam Nodelet] Main Loop...");
    printf("inside spinOnce loop \n");
    dynamic_reconfigure::Server<Config> srv;
    dynamic_reconfigure::Server<Config>::CallbackType f
            = boost::bind(&HiwrCameraControllerNodelet::reconfig, this, _1, _2);
    srv.setCallback(f);

    reconfig(config_, 0xffffffff);
    applyNewConfig(config_ , 0xffffffff);




   spinning_thread_ = boost::shared_ptr< boost::thread >
      (new boost::thread(boost::bind(&HiwrCameraControllerNodelet::loopGrabImage, this)));

    while (ros::ok())
    {
        if (state_ != Driver::CLOSED)
        {
            //Check nb subscribers
            if(image_pub_.getNumSubscribers() > 0 && !next_config_update_)
            {
                if (spining_state_ == true  && next_config_count_ > 0 && read() )
                {

                    cv_bridge::CvImagePtr cv_ptr(new cv_bridge::CvImage);
                    cv_ptr->header.stamp = ros::Time::now();
                    cv_ptr->header.frame_id = config_.frame_id;
                    cv_ptr->encoding = sensor_msgs::image_encodings::MONO8; //"mono8";//"bgr8";
                    cv_ptr->image = Mat( image_ipl_ );


                    image_pub_.publish(cv_ptr->toImageMsg());

                }else{
                    usleep(1000);//1ms sleep
                }
            }else{
                usleep(1000);
            }
        }
        ros::spinOnce();
    }
}

bool HiwrCameraControllerNodelet::serviceSetSpinningState( hiwr_msg::SetState::Request &req ,hiwr_msg::SetState::Response  &res  ){
    res.state = req.state;
    setSpinningState(req.state);
    return true;
}

bool HiwrCameraControllerNodelet::serviceGetSpinningState( hiwr_msg::GetState::Request &req ,hiwr_msg::GetState::Response  &res  ){
    res.state =getSpinningState();
    return true;
}

void HiwrCameraControllerNodelet::configureSpinning(ros::NodeHandle& nh){
    NODELET_INFO("[UVCCam Nodelet] START config_uring spinning state");
    ros::NodeHandle& ph = getMTPrivateNodeHandle();
    service_spinning_state_setter_ = ph.advertiseService("setSpinningState", &HiwrCameraControllerNodelet::serviceSetSpinningState, this);
    service_spinning_state_getter_ = ph.advertiseService("getSpinningState", &HiwrCameraControllerNodelet::serviceGetSpinningState, this);

    NODELET_INFO("[UVCCam Nodelet] DONE");
}

PLUGINLIB_DECLARE_CLASS(hiwr_camera_controller,HiwrCameraControllerNodelet, hiwr_camera_controller::HiwrCameraControllerNodelet, nodelet::Nodelet);
}
void BallDetector::imageCb(const sensor_msgs::ImageConstPtr& msg){
  static cv_bridge::CvImageConstPtr cv_const_ptr;

#ifdef BALLDETECTOR_DEBUG
  static cv_bridge::CvImage cv_img;
  cv_img.header.stamp = ros::Time::now();

  if(debugLevel.sendDebugTimes){
    debugTimeInit();
    debugTimeStart();
  }
#endif

  try{
    cv_const_ptr = cv_bridge::toCvShare(msg, enc::BGR8);
  }catch (cv_bridge::Exception& e){
    ROS_ERROR("cv_bridge exception: %s", e.what());
    return;
  }

#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugTimes){
    debugTimeRecordAndReStart("cvconvert");
  }
#endif

#ifdef BALLDETECTOR_DEBUG
  //Get a the image just as a Mat
  static cv::Mat colorImg;
  if(debugLevel.sendDebugImages){
    colorImg = cv_const_ptr->image.clone();
    //cv_const_ptr->image.copyTo(colorImg);
  }else{
    colorImg = cv_const_ptr->image;
  }
#else 
  static cv::Mat colorImg;
  colorImg = cv_const_ptr->image;
#endif

  //Create the hsv image
  static cv::Mat hsvImg;
#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugTimes){
    debugTimeRecordAndReStart("allocate");
  }
#endif
  
  //colorImg is type CV_8U
  cv::cvtColor(colorImg,hsvImg,CV_RGB2HSV);
  //cv::cvtColor(colorImg,hsvImg,CV_RGB2HLS);
  //cv::cvtColor(colorImg,hsvImg,CV_RGB2Lab); //faster but not on gumstix?

#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugTimes){
    debugTimeRecordAndReStart("hsv");
  }
#endif

  //Perform thresholding
  static cv::Mat threshImg;
  cv::inRange(hsvImg,lowThresh,highThresh,threshImg);


#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugTimes){
    debugTimeRecordAndReStart("threshold");
  }
#endif

#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugImages){
    //Send some images out
    cv_img.image = threshImg;
    cv_img.encoding = enc::MONO8; // TYPE_8UC1;
    debugImg2_pub_.publish(cv_img.toImageMsg());

    cv_img.image = hsvImg;
    cv_img.encoding = enc::BGR8;
    debugImg3_pub_.publish(cv_img.toImageMsg());

  }
#endif /** BALLDETECTOR_DEBUG **/

#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugTimes){
    debugTimeStart();
  }
#endif
  //Contours
  static vector<vector<cv::Point> > contours;
  contours.clear();
  static vector<cv::Vec4i> hierarchy;
  hierarchy.clear();

  //Some quick testing indicates CV_RETR_* doesn't make too much
  //difference in performance.  The CV_CHAIN_APPROX_* also doesn't
  //seem to make much difference, but the "NONE" draws the full
  //outline with debug mode (taking more time), but is easier to look
  //at the output.
  cv::findContours( threshImg, contours, hierarchy,
  CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
  //cv::findContours( threshImg, contours, hierarchy,
  //CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );


#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugTimes){
    debugTimeRecordAndReStart("findcontours");
  }
#endif

  // iterate through all the top-level contours,
  // draw each connected component with its own random color
  int idxMax = -1;
  unsigned int idxMaxValue = 0;
  int idx = 0;
  if(hierarchy.size() > 0){
    for( ; idx >= 0; idx = hierarchy[idx][0] ){
      //If it is large enough, fit an ellipse to it
      if(contours.at(idx).size() > 15){
        //Slower than the below methods
        //cv::RotatedRect r = cv::fitEllipse(cv::Mat(contours.at(idx)));
        //cv::Rect rect = r.boundingRect();

        //Find the min/max pixel locatiosn of x and y
        int maxX = 0, maxY = 0;
        unsigned int maxXidx = 0, maxYidx = 0;
        //Just needs to be bigger than max image width/height
        int minX = 999999999, minY = 999999999;
        unsigned int minXidx = 0, minYidx = 0;
        for(unsigned int i = 0; i < contours.at(idx).size(); i++){
          cv::Point p = contours.at(idx).at(i);
          if(p.x > maxX){
            maxXidx = i;
            maxX = p.x;
          }
          else if(p.x < minX){
            minXidx = i;
            minX = p.x;
          }
          if(p.y > maxY){
            maxYidx = i;
            maxY = p.y;
          }
          else if(p.y < minY){
            minYidx = i;
            minY = p.y;
          }
        }

        //Keep the ellipse if it is mostly round
          //if((rect.width/(1.0*rect.height) > 0.75) && (rect.height/(1.0*rect.width) > 0.75)){

        if(((1.0*(contours.at(idx).at(maxXidx).x-contours.at(idx).at(minXidx).x)/
             (contours.at(idx).at(maxYidx).y-contours.at(idx).at(minYidx).y))) > 0.75
           &&
           ((1.0*(contours.at(idx).at(maxYidx).y-contours.at(idx).at(minYidx).y)/
             (contours.at(idx).at(maxXidx).x-contours.at(idx).at(minXidx).x)) > 0.75)){
#ifdef BALLDETECTOR_DEBUG
          if(debugLevel.sendDebugImages){
            //cv::ellipse(colorImg,r,cv::Scalar(255,0,0,0),3);

            //Color all the points white (it isn't all points, but a lot on the boarders)
            for(unsigned int i = 0; i < contours.at(idx).size(); i++){
              cv::Point p = contours.at(idx).at(i);
              //Get a pointer to the row, then access the pixel elements
              colorImg.ptr<uchar>(p.y)[3*p.x] = 255;
              colorImg.ptr<uchar>(p.y)[3*p.x+1] = 255;
              colorImg.ptr<uchar>(p.y)[3*p.x+2] = 255;
            }

            //draw max/min points
            /*
            cv::rectangle(colorImg,
                          cv::Point(contours.at(idx).at(maxXidx).x - 1, 
                                    contours.at(idx).at(maxXidx).y- 1),
                          cv::Point(contours.at(idx).at(maxXidx).x + 1, 
                                    contours.at(idx).at(maxXidx).y+ 1),
                          cv::Scalar(255,0,0,0),2);
            cv::rectangle(colorImg,
                          cv::Point(contours.at(idx).at(maxYidx).x - 1, 
                                    contours.at(idx).at(maxYidx).y- 1),
                          cv::Point(contours.at(idx).at(maxYidx).x + 1, 
                                    contours.at(idx).at(maxYidx).y+ 1),
                          cv::Scalar(255,0,0,0),2);
            cv::rectangle(colorImg,
                          cv::Point(contours.at(idx).at(minXidx).x - 1, 
                                    contours.at(idx).at(minXidx).y- 1),
                          cv::Point(contours.at(idx).at(minXidx).x + 1, 
                                    contours.at(idx).at(minXidx).y+ 1),
                          cv::Scalar(255,0,0,0),2);
            cv::rectangle(colorImg,
                          cv::Point(contours.at(idx).at(minYidx).x - 1, 
                              contours.at(idx).at(minYidx).y- 1),
                          cv::Point(contours.at(idx).at(minYidx).x + 1, 
                                    contours.at(idx).at(minYidx).y+ 1),
                          cv::Scalar(255,0,0,0),2);
            */
          }
#endif /** BALLDETECTOR_DEBUG **/
          //If there are more points in it than our previous max, then record it
          //N.B. contours.at(idx).size() isn't all points, rather a
          //representation of them...but it seems to map fairly well.
          if(idxMaxValue < contours.at(idx).size()){
            idxMaxValue = contours.at(idx).size();
            idxMax = idx;
          }
        }
      }
    }  
  }


#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugTimes){
    debugTimeRecordAndReStart("iteratecontours");
  }
#endif

  //Make sure we found a good one
  if(idxMax >= 0){

    //Now publish and draw the best
    cv::RotatedRect ellipse = cv::fitEllipse(cv::Mat(contours.at(idxMax)));
    cv::Rect rect = ellipse.boundingRect();
    //Publish the message for the best
    ballDetector::ballLocation circ;
    circ.header.stamp = ros::Time::now();
    //Use the average of the height and width as the radius
    double radius = (rect.height/2.0 + rect.width/2.0)/2.0;
    circ.imageWidth = colorImg.cols;
    circ.imageHeight = colorImg.rows;
    //Make it relative to the center of the image
    circ.x = rect.x + radius - threshImg.cols/2;
    circ.y = -1*(rect.y + radius - threshImg.rows/2);
    circ.radius = radius;
    circle_pub_.publish(circ);
#ifdef BALLDETECTOR_DEBUG
    if(debugLevel.sendDebugImages){
      //Draw the best one bold
      cv::ellipse(colorImg,ellipse,cv::Scalar(0,255,0,0),4);
      //And the center point
      cv::rectangle(colorImg,
                    cv::Point(rect.x + radius-2,rect.y + radius-2),
                    cv::Point(rect.x + radius+2,rect.y + radius+2),
                    cv::Scalar(0,255,0,0),4);

      //Find min/max x,y pixel locations to draw them
      //cout << "---------------------\n";
      int maxX = 0, maxY = 0;
      unsigned int maxXidx = 0, maxYidx = 0;
      //Just needs to be bigger than max image width/height
      int minX = 999999999, minY = 999999999;
      unsigned int minXidx = 0, minYidx = 0;
      for(unsigned int i = 0; i < contours.at(idxMax).size(); i++){
        cv::Point p = contours.at(idxMax).at(i);
        //printf("%d: [%d,%d] ",i,p.x,p.y);
        if(p.x > maxX){
          maxXidx = i;
          maxX = p.x;
        }
        else if(p.x < minX){
          minXidx = i;
          minX = p.x;
        }
        if(p.y > maxY){
          maxYidx = i;
          maxY = p.y;
        }
        else if(p.y < minY){
          minYidx = i;
          minY = p.y;
        }
      }


      /*
      printf("\nminX: %d, %d, %d, %d\n",minX,minXidx,
             contours.at(idxMax).at(minXidx).x,contours.at(idxMax).at(minXidx).y);
      printf("maxX: %d, %d, %d, %d\n",maxX,maxXidx,
             contours.at(idxMax).at(maxXidx).x,contours.at(idxMax).at(maxXidx).y);
      printf("minY: %d, %d, %d, %d\n",minY,minYidx,
             contours.at(idxMax).at(minYidx).x,contours.at(idxMax).at(minYidx).y);
      printf("maxY: %d, %d, %d, %d\n",maxY,maxYidx,
             contours.at(idxMax).at(maxYidx).x,contours.at(idxMax).at(maxYidx).y);
      printf("diffX: %d\n",contours.at(idxMax).at(maxXidx).x-contours.at(idxMax).at(minXidx).x);
      printf("diffY: %d\n",contours.at(idxMax).at(maxYidx).y-contours.at(idxMax).at(minYidx).y);
      printf("ratio: %f %f\n",
             1.0*(contours.at(idxMax).at(maxXidx).x-contours.at(idxMax).at(minXidx).x)/
             (contours.at(idxMax).at(maxYidx).y-contours.at(idxMax).at(minYidx).y),
             1.0*(contours.at(idxMax).at(maxYidx).y-contours.at(idxMax).at(minYidx).y)/
             (contours.at(idxMax).at(maxXidx).x-contours.at(idxMax).at(minXidx).x));
      */

      //draw max/min points
      cv::rectangle(colorImg,
                    cv::Point(contours.at(idxMax).at(maxXidx).x - 1, 
                              contours.at(idxMax).at(maxXidx).y - 1),
                    cv::Point(contours.at(idxMax).at(maxXidx).x + 1, 
                              contours.at(idxMax).at(maxXidx).y + 1),
                    cv::Scalar(0,0,255,0),2);
      cv::rectangle(colorImg,
                    cv::Point(contours.at(idxMax).at(maxYidx).x - 1, 
                              contours.at(idxMax).at(maxYidx).y - 1),
                    cv::Point(contours.at(idxMax).at(maxYidx).x + 1, 
                              contours.at(idxMax).at(maxYidx).y + 1),
                    cv::Scalar(0,0,255,0),2);
      cv::rectangle(colorImg,
                    cv::Point(contours.at(idxMax).at(minXidx).x - 1, 
                              contours.at(idxMax).at(minXidx).y - 1),
                    cv::Point(contours.at(idxMax).at(minXidx).x + 1, 
                              contours.at(idxMax).at(minXidx).y + 1),
                    cv::Scalar(0,0,255,0),2);
      cv::rectangle(colorImg,
                    cv::Point(contours.at(idxMax).at(minYidx).x - 1, 
                              contours.at(idxMax).at(minYidx).y - 1),
                    cv::Point(contours.at(idxMax).at(minYidx).x + 1, 
                              contours.at(idxMax).at(minYidx).y + 1),
                    cv::Scalar(0,0,255,0),2);
    }
#endif /** BALLDETECTOR_DEBUG **/
  }


#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugTimes){
    debugTimeRecordAndReStart("publish");
  }
#endif

#ifdef BALLDETECTOR_DEBUG
  if(debugLevel.sendDebugImages){
    cv_img.image = colorImg;
    cv_img.encoding = enc::BGR8;
    debugImg1_pub_.publish(cv_img.toImageMsg());

  }

  if(debugLevel.sendDebugTimes){
    debugTimeSend();
  }
#endif /** BALLDETECTOR_DEBUG **/

}
예제 #11
0
void imageDataHandler(const sensor_msgs::Image::ConstPtr& imageData) 
{
  timeLast = timeCur;
  timeCur = imageData->header.stamp.toSec() - 0.1163;

  cv_bridge::CvImageConstPtr imageDataCv = cv_bridge::toCvShare(imageData, "mono8");

  if (!systemInited) {
    remap(imageDataCv->image, image0, mapx, mapy, CV_INTER_LINEAR);
    oclImage0 = oclMat(image0);
    systemInited = true;

    return;
  }

  Mat imageLast, imageCur;
  oclMat oclImageLast, oclImageCur;
  if (isOddFrame) {
    remap(imageDataCv->image, image1, mapx, mapy, CV_INTER_LINEAR);
    oclImage1 = oclMat(image1);

    imageLast = image0;
    imageCur = image1;

    oclImageLast = oclImage0;
    oclImageCur = oclImage1;
  } else {
    remap(imageDataCv->image, image0, mapx, mapy, CV_INTER_LINEAR);
    oclImage0 = oclMat(image0);

    imageLast = image1;
    imageCur = image0;

    oclImageLast = oclImage1;
    oclImageCur = oclImage0;
  }
  isOddFrame = !isOddFrame;

  resize(oclImageLast, oclImageShow, showSize);
  oclImageShow.download(imageShow);
  cornerHarris(oclImageShow, oclHarrisLast, 2, 3, 0.04);
  oclHarrisLast.download(harrisLast);

  vector<Point2f> *featuresTemp = featuresLast;
  featuresLast = featuresCur;
  featuresCur = featuresTemp;

  pcl::PointCloud<ImagePoint>::Ptr imagePointsTemp = imagePointsLast;
  imagePointsLast = imagePointsCur;
  imagePointsCur = imagePointsTemp;
  imagePointsCur->clear();

  int recordFeatureNum = totalFeatureNum;
  detectionCount = (detectionCount + 1) % (detectionSkipNum + 1);
  if (detectionCount == detectionSkipNum) {
    oclMat oclFeaturesSub;
    for (int i = 0; i < ySubregionNum; i++) {
      for (int j = 0; j < xSubregionNum; j++) {
        int ind = xSubregionNum * i + j;
        int numToFind = maxFeatureNumPerSubregion - subregionFeatureNum[ind];

        if (numToFind > maxFeatureNumPerSubregion / 5.0) {
          int subregionLeft = xBoundary + (int)(subregionWidth * j);
          int subregionTop = yBoundary + (int)(subregionHeight * i);
          Rect subregion = Rect(subregionLeft, subregionTop, (int)subregionWidth, (int)subregionHeight);

          oclFeatureDetector.maxCorners = numToFind;
          oclFeatureDetector(oclImageLast(subregion), oclFeaturesSub);
          if (oclFeaturesSub.cols > 0) {
            oclFeatureDetector.downloadPoints(oclFeaturesSub, featuresSub);
            numToFind = featuresSub.size();
          } else {
            numToFind = 0;
          }

          int numFound = 0;
          for(int k = 0; k < numToFind; k++) {
            featuresSub[k].x += subregionLeft;
            featuresSub[k].y += subregionTop;

            int xInd = (featuresSub[k].x + 0.5) / showDSRate;
            int yInd = (featuresSub[k].y + 0.5) / showDSRate;

            if (harrisLast.at<float>(yInd, xInd) > 1e-7) {
              featuresLast->push_back(featuresSub[k]);
              featuresInd.push_back(featuresIndFromStart);

              numFound++;
              featuresIndFromStart++;
            }
          }
          totalFeatureNum += numFound;
          subregionFeatureNum[ind] += numFound;
        }
      }
    }
  }

  if (totalFeatureNum > 0) {
    Mat featuresLastMat(1, totalFeatureNum, CV_32FC2, (void*)&(*featuresLast)[0]);
    oclMat oclFeaturesLast(featuresLastMat);
    oclMat oclFeaturesCur, oclFeaturesStatus;

    oclOpticalFlow.sparse(oclImageLast, oclImageCur, oclFeaturesLast, oclFeaturesCur, oclFeaturesStatus);
    if (oclFeaturesCur.cols > 0 && oclFeaturesCur.cols == oclFeaturesStatus.cols) {
      download(oclFeaturesCur, *featuresCur);
      download(oclFeaturesStatus, featuresStatus);
      totalFeatureNum = featuresCur->size();
    } else {
      totalFeatureNum = 0;
    }
  }

  for (int i = 0; i < totalSubregionNum; i++) {
    subregionFeatureNum[i] = 0;
  }

  ImagePoint point;
  int featureCount = 0;
  for (int i = 0; i < totalFeatureNum; i++) {
    double trackDis = sqrt(((*featuresLast)[i].x - (*featuresCur)[i].x) 
                    * ((*featuresLast)[i].x - (*featuresCur)[i].x)
                    + ((*featuresLast)[i].y - (*featuresCur)[i].y) 
                    * ((*featuresLast)[i].y - (*featuresCur)[i].y));

    if (!(trackDis > maxTrackDis || (*featuresCur)[i].x < xBoundary || 
      (*featuresCur)[i].x > imageWidth - xBoundary || (*featuresCur)[i].y < yBoundary || 
      (*featuresCur)[i].y > imageHeight - yBoundary) && featuresStatus[i]) {

      int xInd = (int)(((*featuresLast)[i].x - xBoundary) / subregionWidth);
      int yInd = (int)(((*featuresLast)[i].y - yBoundary) / subregionHeight);
      int ind = xSubregionNum * yInd + xInd;

      if (subregionFeatureNum[ind] < maxFeatureNumPerSubregion) {
        (*featuresCur)[featureCount] = (*featuresCur)[i];
        (*featuresLast)[featureCount] = (*featuresLast)[i];
        featuresInd[featureCount] = featuresInd[i];

        point.u = -((*featuresCur)[featureCount].x - kImage[2]) / kImage[0];
        point.v = -((*featuresCur)[featureCount].y - kImage[5]) / kImage[4];
        point.ind = featuresInd[featureCount];
        imagePointsCur->push_back(point);

        if (i >= recordFeatureNum) {
          point.u = -((*featuresLast)[featureCount].x - kImage[2]) / kImage[0];
          point.v = -((*featuresLast)[featureCount].y - kImage[5]) / kImage[4];
          imagePointsLast->push_back(point);
        }

        featureCount++;
        subregionFeatureNum[ind]++;
      }
    }
  }
  totalFeatureNum = featureCount;
  featuresCur->resize(totalFeatureNum);
  featuresLast->resize(totalFeatureNum);
  featuresInd.resize(totalFeatureNum);

  sensor_msgs::PointCloud2 imagePointsLast2;
  pcl::toROSMsg(*imagePointsLast, imagePointsLast2);
  imagePointsLast2.header.stamp = ros::Time().fromSec(timeLast);
  imagePointsLastPubPointer->publish(imagePointsLast2);

  showCount = (showCount + 1) % (showSkipNum + 1);
  if (showCount == showSkipNum) {
    bridge.image = imageShow;
    bridge.encoding = "mono8";
    sensor_msgs::Image::Ptr imageShowPointer = bridge.toImageMsg();
    imageShowPubPointer->publish(imageShowPointer);
  }
}