void ComputeMSURFDescriptor( const ImageT & Lx , const ImageT & Ly , const int id_octave , const SIOPointFeature & ipt , Descriptor< unsigned char , 64 > & desc ) { Descriptor< float , 64 > descFloat; ComputeMSURFDescriptor( Lx , Ly , id_octave , ipt , descFloat); }
/** @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, OPENMVG_UNIQUE_PTR<Regions> ®ions, const image::Image<unsigned char> * mask = NULL) { _params._options.fDesc_factor = (_params._eAkazeDescriptor == AKAZE_MSURF || _params._eAkazeDescriptor == AKAZE_LIOP) ? 10.f*sqrtf(2.f) : 11.f*sqrtf(2.f); // MLDB AKAZE akaze(image, _params._options); akaze.Compute_AKAZEScaleSpace(); std::vector<AKAZEKeypoint> kpts; kpts.reserve(5000); akaze.Feature_Detection(kpts); akaze.Do_Subpixel_Refinement(kpts); Allocate(regions); switch(_params._eAkazeDescriptor) { case AKAZE_MSURF: { // Build alias to cached data AKAZE_Float_Regions * regionsCasted = dynamic_cast<AKAZE_Float_Regions*>(regions.get()); regionsCasted->Features().resize(kpts.size()); regionsCasted->Descriptors().resize(kpts.size()); #ifdef OPENMVG_USE_OPENMP #pragma omp parallel for #endif for (int i = 0; i < static_cast<int>(kpts.size()); ++i) { AKAZEKeypoint ptAkaze = kpts[i]; // Feature masking if (mask) { const image::Image<unsigned char> & maskIma = *mask; if (maskIma(ptAkaze.y, ptAkaze.x) > 0) continue; } const TEvolution & cur_slice = akaze.getSlices()[ptAkaze.class_id]; if (_bOrientation) akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly); else ptAkaze.angle = 0.0f; regionsCasted->Features()[i] = SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle); ComputeMSURFDescriptor(cur_slice.Lx, cur_slice.Ly, ptAkaze.octave, regionsCasted->Features()[i], regionsCasted->Descriptors()[i]); } } break; case AKAZE_LIOP: { // Build alias to cached data AKAZE_Liop_Regions * regionsCasted = dynamic_cast<AKAZE_Liop_Regions*>(regions.get()); regionsCasted->Features().resize(kpts.size()); regionsCasted->Descriptors().resize(kpts.size()); // Init LIOP extractor LIOP::Liop_Descriptor_Extractor liop_extractor; #ifdef OPENMVG_USE_OPENMP #pragma omp parallel for #endif for (int i = 0; i < static_cast<int>(kpts.size()); ++i) { AKAZEKeypoint ptAkaze = kpts[i]; // Feature masking if (mask) { const image::Image<unsigned char> & maskIma = *mask; if (maskIma(ptAkaze.y, ptAkaze.x) > 0) continue; } const TEvolution & cur_slice = akaze.getSlices()[ptAkaze.class_id]; if (_bOrientation) akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly); else ptAkaze.angle = 0.0f; regionsCasted->Features()[i] = SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle); // Compute LIOP descriptor (do not need rotation computation, since // LIOP descriptor is rotation invariant). // Rescale for LIOP patch extraction const SIOPointFeature fp = SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size/2.0, ptAkaze.angle); float desc[144]; liop_extractor.extract(image, fp, desc); for(int j=0; j < 144; ++j) regionsCasted->Descriptors()[i][j] = static_cast<unsigned char>(desc[j] * 255.f +.5f); } } break; case AKAZE_MLDB: { // Build alias to cached data AKAZE_Binary_Regions * regionsCasted = dynamic_cast<AKAZE_Binary_Regions*>(regions.get()); regionsCasted->Features().resize(kpts.size()); regionsCasted->Descriptors().resize(kpts.size()); #ifdef OPENMVG_USE_OPENMP #pragma omp parallel for #endif for (int i = 0; i < static_cast<int>(kpts.size()); ++i) { AKAZEKeypoint ptAkaze = kpts[i]; // Feature masking if (mask) { const image::Image<unsigned char> & maskIma = *mask; if (maskIma(ptAkaze.y, ptAkaze.x) > 0) continue; } const TEvolution & cur_slice = akaze.getSlices()[ptAkaze.class_id]; if (_bOrientation) akaze.Compute_Main_Orientation(ptAkaze, cur_slice.Lx, cur_slice.Ly); else ptAkaze.angle = 0.0f; regionsCasted->Features()[i] = SIOPointFeature(ptAkaze.x, ptAkaze.y, ptAkaze.size, ptAkaze.angle); // Compute MLDB descriptor Descriptor<bool,486> desc; ComputeMLDBDescriptor(cur_slice.cur, cur_slice.Lx, cur_slice.Ly, ptAkaze.octave, regionsCasted->Features()[i], desc); // convert the bool vector to the binary unsigned char array unsigned char * ptr = reinterpret_cast<unsigned char*>(®ionsCasted->Descriptors()[i]); memset(ptr, 0, regionsCasted->DescriptorLength()*sizeof(unsigned char)); // For each byte for (int j = 0; j < std::ceil(486./8.); ++j, ++ptr) { // set the corresponding 8bits to the good values for (int iBit = 0; iBit < 8 && j*8+iBit < 486; ++iBit) { *ptr |= desc[j*8+iBit] << iBit; } } } } break; } return true; };