/** @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> ®ions, 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> ®ions, 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; };
/** @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> ®ions, 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; };