Example #1
0
  // suggest new feature point for tracking (count point are kept)
  bool detect
  (
    const image::Image<unsigned char> & ima,
    std::vector<features::PointFeature> & pt_to_track,
    const size_t count
  ) const override
  {
    cv::Mat current_img;
    cv::eigen2cv(ima.GetMat(), current_img);
    std::vector<cv::KeyPoint> m_nextKeypoints;

    cv::Ptr<cv::FeatureDetector> m_detector = cv::GFTTDetector::create(count);
    if (m_detector == NULL)
      return false;

    m_detector->detect(current_img, m_nextKeypoints);

    if (m_nextKeypoints.size() >= count)
    {
      // shuffle to avoid to sample only in one bucket
      std::mt19937 gen(std::mt19937::default_seed);
      std::shuffle(m_nextKeypoints.begin(), m_nextKeypoints.end(), gen);
    }
    const size_t kept_kp_count =  std::min(m_nextKeypoints.size(), count);
    m_nextKeypoints.resize(kept_kp_count);

    pt_to_track.resize(kept_kp_count);
    for (size_t i = 0; i  < kept_kp_count; ++i)
      pt_to_track[i] = features::PointFeature(m_nextKeypoints[i].pt.x, m_nextKeypoints[i].pt.y);

    return kept_kp_count != 0;
    // Return false if no point can be added
  }
Example #2
0
  /// Try to track current point set in the provided image
  /// return false when tracking failed (=> to send frame to relocalization)
  bool track
  (
    const image::Image<unsigned char> & ima,
    const std::vector<features::PointFeature> & pt_to_track,
    std::vector<features::PointFeature> & pt_tracked,
    std::vector<bool> & status
  ) override
  {
    cv::eigen2cv(ima.GetMat(), current_img_);
    if (!pt_to_track.empty())
    {
      prevPts_.resize(pt_to_track.size());
      nextPts_.resize(pt_to_track.size());

      for (size_t i=0; i < pt_to_track.size(); ++i)
      {
        prevPts_[i].x = pt_to_track[i].x();
        prevPts_[i].y = pt_to_track[i].y();
      }

      std::vector<unsigned char> status_uchar;
      cv::calcOpticalFlowPyrLK(prev_img_, current_img_, prevPts_, nextPts_, status_uchar, error_);
      status.assign(status_uchar.begin(), status_uchar.end());

      for (size_t i=0; i < nextPts_.size(); ++i)
      {
        pt_tracked[i].coords() << nextPts_[i].x, nextPts_[i].y;
      }
    }
    // swap frame for next tracking iteration
    current_img_.copyTo(prev_img_);

    const size_t tracked_point_count = std::accumulate(status.begin(), status.end(), 0);
    return (tracked_point_count != 0);
  }
  /**
  @brief Detect regions on the image and compute their attributes (description)
  @param image Image.
  @param regions The detected regions and attributes (the caller must delete the allocated data)
  @param mask 8-bit gray image for keypoint filtering (optional).
     Non-zero values depict the region of interest.
  */
  bool Describe(const image::Image<unsigned char>& image,
    std::unique_ptr<Regions> &regions,
    const image::Image<unsigned char> * mask = nullptr)
  {
    // Convert for opencv
    cv::Mat img;
    cv::eigen2cv(image.GetMat(), img);

    // Convert mask image into cv::Mat
    cv::Mat m_mask;
    if(mask != nullptr) {
      cv::eigen2cv(mask->GetMat(), m_mask);
    }

    // Create a SIFT detector
    std::vector< cv::KeyPoint > v_keypoints;
    cv::Mat m_desc;
    cv::Ptr<cv::Feature2D> siftdetector = cv::xfeatures2d::SIFT::create();

    // Process SIFT computation
    siftdetector->detectAndCompute(img, m_mask, v_keypoints, m_desc);

    Allocate(regions);

    // Build alias to cached data
    SIFT_Regions * regionsCasted = dynamic_cast<SIFT_Regions*>(regions.get());
    // reserve some memory for faster keypoint saving
    regionsCasted->Features().reserve(v_keypoints.size());
    regionsCasted->Descriptors().reserve(v_keypoints.size());

    // Prepare a column vector with the sum of each descriptor
    cv::Mat m_siftsum;
    cv::reduce(m_desc, m_siftsum, 1, cv::REDUCE_SUM);

    // Copy keypoints and descriptors in the regions
    int cpt = 0;
    for(std::vector< cv::KeyPoint >::const_iterator i_kp = v_keypoints.begin();
        i_kp != v_keypoints.end();
        ++i_kp, ++cpt)
    {
      SIOPointFeature feat((*i_kp).pt.x, (*i_kp).pt.y, (*i_kp).size, (*i_kp).angle);
      regionsCasted->Features().push_back(feat);

      Descriptor<unsigned char, 128> desc;
      for(int j = 0; j < 128; j++)
      {
        desc[j] = static_cast<unsigned char>(512.0*sqrt(m_desc.at<float>(cpt, j)/m_siftsum.at<float>(cpt, 0)));
      }
      regionsCasted->Descriptors().push_back(desc);
    }

    return true;
  };
  /**
  @brief Detect regions on the image and compute their attributes (description)
  @param image Image.
  @param regions The detected regions and attributes (the caller must delete the allocated data)
  @param mask 8-bit gray image for keypoint filtering (optional).
     Non-zero values depict the region of interest.
  */
  bool Describe
  (
    const image::Image<unsigned char>& image,
    std::unique_ptr<Regions> &regions,
    const image::Image<unsigned char> * mask = nullptr
  ) override
  {
    const int w = image.Width(), h = image.Height();
    // Convert to float in range [0;1]
    const image::Image<float> If(image.GetMat().cast<float>()/255.0f);

    // compute sift keypoints
    Allocate(regions);

    // Build alias to cached data
    SIFT_Regions * regionsCasted = dynamic_cast<SIFT_Regions*>(regions.get());
    {
      using namespace openMVG::features::sift;
      const int supplementary_images = 3;
      // => in order to ensure each gaussian slice is used in the process 3 extra images are required:
      // +1 for dog computation
      // +2 for 3d discrete extrema definition

      HierarchicalGaussianScaleSpace octave_gen(
        params_.num_octaves_,
        params_.num_scales_,
        (params_.first_octave_ == -1)
        ? GaussianScaleSpaceParams(1.6f/2.0f, 1.0f/2.0f, 0.5f, supplementary_images)
        : GaussianScaleSpaceParams(1.6f, 1.0f, 0.5f, supplementary_images));
      octave_gen.SetImage( If );

      std::vector<Keypoint> keypoints;
      keypoints.reserve(5000);
      Octave octave;
      while ( octave_gen.NextOctave( octave ) )
      {
        std::vector< Keypoint > keys;
        // Find Keypoints
        SIFT_KeypointExtractor keypointDetector(
          params_.peak_threshold_ / octave_gen.NbSlice(),
          params_.edge_threshold_);
        keypointDetector(octave, keys);
        // Find Keypoints orientation and compute their description
        Sift_DescriptorExtractor descriptorExtractor;
        descriptorExtractor(octave, keys);

        // Concatenate the found keypoints
        std::move(keys.begin(), keys.end(), std::back_inserter(keypoints));
      }
      for (const auto & k : keypoints)
      {
        // Feature masking
        if (mask)
        {
          const image::Image<unsigned char> & maskIma = *mask;
          if (maskIma(k.y, k.x) == 0)
            continue;
        }

        Descriptor<unsigned char, 128> descriptor;
        descriptor << (k.descr.cast<unsigned char>());
        {
          regionsCasted->Descriptors().emplace_back(descriptor);
          regionsCasted->Features().emplace_back(k.x, k.y, k.sigma, k.theta);
        }
      }
    }
    return true;
  };
Example #5
0
    /**
    @brief Detect regions on the image and compute their attributes (description)
    @param image Image.
    @param regions The detected regions and attributes (the caller must delete the allocated data)
    @param mask 8-bit gray image for keypoint filtering (optional).
       Non-zero values depict the region of interest.
    */
    bool Describe(const image::Image<unsigned char>& image,
                  std::unique_ptr<Regions> &regions,
                  const image::Image<unsigned char> * mask = NULL)
    {
        const int w = image.Width(), h = image.Height();
        //Convert to float
        const image::Image<float> If(image.GetMat().cast<float>());

        VlSiftFilt *filt = vl_sift_new(w, h,
                                       _params._num_octaves, _params._num_scales, _params._first_octave);
        if (_params._edge_threshold >= 0)
            vl_sift_set_edge_thresh(filt, _params._edge_threshold);
        if (_params._peak_threshold >= 0)
            vl_sift_set_peak_thresh(filt, 255*_params._peak_threshold/_params._num_scales);

        Descriptor<vl_sift_pix, 128> descr;
        Descriptor<unsigned char, 128> descriptor;

        // Process SIFT computation
        vl_sift_process_first_octave(filt, If.data());

        Allocate(regions);

        // Build alias to cached data
        SIFT_Regions * regionsCasted = dynamic_cast<SIFT_Regions*>(regions.get());
        // reserve some memory for faster keypoint saving
        regionsCasted->Features().reserve(2000);
        regionsCasted->Descriptors().reserve(2000);

        while (true) {
            vl_sift_detect(filt);

            VlSiftKeypoint const *keys  = vl_sift_get_keypoints(filt);
            const int nkeys = vl_sift_get_nkeypoints(filt);

            // Update gradient before launching parallel extraction
            vl_sift_update_gradient(filt);

#ifdef OPENMVG_USE_OPENMP
            #pragma omp parallel for private(descr, descriptor)
#endif
            for (int i = 0; i < nkeys; ++i) {

                // Feature masking
                if (mask)
                {
                    const image::Image<unsigned char> & maskIma = *mask;
                    if (maskIma(keys[i].y, keys[i].x) == 0)
                        continue;
                }

                double angles [4] = {0.0, 0.0, 0.0, 0.0};
                int nangles = 1; // by default (1 upright feature)
                if (_bOrientation)
                {   // compute from 1 to 4 orientations
                    nangles = vl_sift_calc_keypoint_orientations(filt, angles, keys+i);
                }

                for (int q=0 ; q < nangles ; ++q) {
                    vl_sift_calc_keypoint_descriptor(filt, &descr[0], keys+i, angles[q]);
                    const SIOPointFeature fp(keys[i].x, keys[i].y,
                                             keys[i].sigma, static_cast<float>(angles[q]));

                    siftDescToUChar(&descr[0], descriptor, _params._root_sift);
#ifdef OPENMVG_USE_OPENMP
                    #pragma omp critical
#endif
                    {
                        regionsCasted->Descriptors().push_back(descriptor);
                        regionsCasted->Features().push_back(fp);
                    }
                }
            }
            if (vl_sift_process_next_octave(filt))
                break; // Last octave
        }
        vl_sift_delete(filt);

        return true;
    };