diff --git a/modules/features2d/src/descriptors.cpp b/modules/features2d/src/descriptors.cpp index d18c13bb5c..4d35983738 100644 --- a/modules/features2d/src/descriptors.cpp +++ b/modules/features2d/src/descriptors.cpp @@ -350,21 +350,79 @@ void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, vector& oppo } } +struct KP_LessThan +{ + KP_LessThan(const vector& _kp) : kp(&_kp) {} + bool operator()(int i, int j) const + { + return (*kp)[i].class_id < (*kp)[j].class_id; + } + const vector* kp; +}; + void OpponentColorDescriptorExtractor::computeImpl( const Mat& bgrImage, vector& keypoints, Mat& descriptors ) const { vector opponentChannels; convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels ); - // Compute descriptors three times, once for each Opponent channel - // and concatenate into a single color surf descriptor + const int N = 3; // channels count + vector channelKeypoints[N]; + Mat channelDescriptors[N]; + vector idxs[N]; + + // Compute descriptors three times, once for each Opponent channel to concatenate into a single color descriptor + for( int ci = 0; ci < N; ci++ ) + { + channelKeypoints[ci].insert( channelKeypoints[ci].begin(), keypoints.begin(), keypoints.end() ); + // Use class_id member to get indices into initial keypoints vector + for( size_t ki = 0; ki < channelKeypoints[ci].size(); ki++ ) + channelKeypoints[ci][ki].class_id = ki; + + descriptorExtractor->compute( opponentChannels[ci], channelKeypoints[ci], channelDescriptors[ci] ); + idxs[ci].resize( channelKeypoints[ci].size() ); + for( size_t ki = 0; ki < channelKeypoints[ci].size(); ki++ ) + { + idxs[ci][ki] = ki; + } + std::sort( idxs[ci].begin(), idxs[ci].end(), KP_LessThan(channelKeypoints[ci]) ); + } + + vector outKeypoints; + outKeypoints.reserve( keypoints.size() ); + int descriptorSize = descriptorExtractor->descriptorSize(); - descriptors.create( static_cast(keypoints.size()), 3*descriptorSize, descriptorExtractor->descriptorType() ); - for( int i = 0; i < 3/*channel count*/; i++ ) + Mat mergedDescriptors( (int)keypoints.size(), 3*descriptorSize, descriptorExtractor->descriptorType() ); + int mergedCount = 0; + // cp - current channel position + for( size_t cp[] = {0, 0, 0}; cp[0] < channelKeypoints[0].size() && cp[1] < channelKeypoints[1].size() && cp[2] < channelKeypoints[2].size(); ) { - CV_Assert( opponentChannels[i].type() == CV_8UC1 ); - Mat opponentDescriptors = descriptors.colRange( i*descriptorSize, (i+1)*descriptorSize ); - descriptorExtractor->compute( opponentChannels[i], keypoints, opponentDescriptors ); + const int maxInitIdx = std::max( channelKeypoints[0][idxs[0][cp[0]]].class_id, + std::max( channelKeypoints[1][idxs[1][cp[1]]].class_id, + channelKeypoints[2][idxs[2][cp[2]]].class_id ) ); + + while( channelKeypoints[0][idxs[0][cp[0]]].class_id < maxInitIdx && cp[0] < channelKeypoints[0].size() ) { cp[0]++; } + while( channelKeypoints[1][idxs[1][cp[1]]].class_id < maxInitIdx && cp[1] < channelKeypoints[1].size() ) { cp[1]++; } + while( channelKeypoints[2][idxs[2][cp[2]]].class_id < maxInitIdx && cp[2] < channelKeypoints[2].size() ) { cp[2]++; } + if( cp[0] >= channelKeypoints[0].size() || cp[1] >= channelKeypoints[1].size() || cp[2] >= channelKeypoints[2].size() ) + break; + + if( channelKeypoints[0][idxs[0][cp[0]]].class_id == maxInitIdx && + channelKeypoints[1][idxs[1][cp[1]]].class_id == maxInitIdx && + channelKeypoints[2][idxs[2][cp[2]]].class_id == maxInitIdx ) + { + outKeypoints.push_back( keypoints[maxInitIdx] ); + // merge descriptors + for( int ci = 0; ci < N; ci++ ) + { + Mat dst = mergedDescriptors(Range(mergedCount, mergedCount+1), Range(ci*descriptorSize, (ci+1)*descriptorSize)); + channelDescriptors[ci].row( idxs[ci][cp[ci]] ).copyTo( dst ); + cp[ci]++; + } + mergedCount++; + } } + mergedDescriptors.rowRange(0, mergedCount).copyTo( descriptors ); + std::swap( outKeypoints, keypoints ); } void OpponentColorDescriptorExtractor::read( const FileNode& fn )