|
|
@ -350,21 +350,79 @@ void convertBGRImageToOpponentColorSpace( const Mat& bgrImage, vector<Mat>& oppo |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct KP_LessThan |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
KP_LessThan(const vector<KeyPoint>& _kp) : kp(&_kp) {} |
|
|
|
|
|
|
|
bool operator()(int i, int j) const |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return (*kp)[i].class_id < (*kp)[j].class_id; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
const vector<KeyPoint>* kp; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
void OpponentColorDescriptorExtractor::computeImpl( const Mat& bgrImage, vector<KeyPoint>& keypoints, Mat& descriptors ) const |
|
|
|
void OpponentColorDescriptorExtractor::computeImpl( const Mat& bgrImage, vector<KeyPoint>& keypoints, Mat& descriptors ) const |
|
|
|
{ |
|
|
|
{ |
|
|
|
vector<Mat> opponentChannels; |
|
|
|
vector<Mat> opponentChannels; |
|
|
|
convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels ); |
|
|
|
convertBGRImageToOpponentColorSpace( bgrImage, opponentChannels ); |
|
|
|
|
|
|
|
|
|
|
|
// Compute descriptors three times, once for each Opponent channel
|
|
|
|
const int N = 3; // channels count
|
|
|
|
// and concatenate into a single color surf descriptor
|
|
|
|
vector<KeyPoint> channelKeypoints[N]; |
|
|
|
|
|
|
|
Mat channelDescriptors[N]; |
|
|
|
|
|
|
|
vector<int> 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<KeyPoint> outKeypoints; |
|
|
|
|
|
|
|
outKeypoints.reserve( keypoints.size() ); |
|
|
|
|
|
|
|
|
|
|
|
int descriptorSize = descriptorExtractor->descriptorSize(); |
|
|
|
int descriptorSize = descriptorExtractor->descriptorSize(); |
|
|
|
descriptors.create( static_cast<int>(keypoints.size()), 3*descriptorSize, descriptorExtractor->descriptorType() ); |
|
|
|
Mat mergedDescriptors( (int)keypoints.size(), 3*descriptorSize, descriptorExtractor->descriptorType() ); |
|
|
|
for( int i = 0; i < 3/*channel count*/; i++ ) |
|
|
|
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 ); |
|
|
|
const int maxInitIdx = std::max( channelKeypoints[0][idxs[0][cp[0]]].class_id, |
|
|
|
Mat opponentDescriptors = descriptors.colRange( i*descriptorSize, (i+1)*descriptorSize ); |
|
|
|
std::max( channelKeypoints[1][idxs[1][cp[1]]].class_id, |
|
|
|
descriptorExtractor->compute( opponentChannels[i], keypoints, opponentDescriptors ); |
|
|
|
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 ) |
|
|
|
void OpponentColorDescriptorExtractor::read( const FileNode& fn ) |
|
|
|