Commit 6be2945a authored by Woody Chow's avatar Woody Chow

Multithreading findScaleSpaceExtremaComputer. Sort the keypoints afterwards to…

Multithreading findScaleSpaceExtremaComputer. Sort the keypoints afterwards to make the output stable
parent 27f6d4e7
...@@ -569,85 +569,109 @@ static bool adjustLocalExtrema( const std::vector<Mat>& dog_pyr, KeyPoint& kpt, ...@@ -569,85 +569,109 @@ static bool adjustLocalExtrema( const std::vector<Mat>& dog_pyr, KeyPoint& kpt,
} }
// class findScaleSpaceExtremaComputer : public ParallelLoopBody
// Detects features at extrema in DoG scale space. Bad features are discarded
// based on contrast and ratio of principal curvatures.
void SIFT_Impl::findScaleSpaceExtrema( const std::vector<Mat>& gauss_pyr, const std::vector<Mat>& dog_pyr,
std::vector<KeyPoint>& keypoints ) const
{ {
int nOctaves = (int)gauss_pyr.size()/(nOctaveLayers + 3); public:
int threshold = cvFloor(0.5 * contrastThreshold / nOctaveLayers * 255 * SIFT_FIXPT_SCALE); findScaleSpaceExtremaComputer(
const int n = SIFT_ORI_HIST_BINS; int _o,
float hist[n]; int _i,
KeyPoint kpt; int _threshold,
int _idx,
int _step,
int _cols,
int _nOctaveLayers,
double _contrastThreshold,
double _edgeThreshold,
double _sigma,
const std::vector<Mat>& _gauss_pyr,
const std::vector<Mat>& _dog_pyr,
std::vector<KeyPoint>& _keypoints,
Mutex &_mutex)
: o(_o),
i(_i),
threshold(_threshold),
idx(_idx),
step(_step),
cols(_cols),
nOctaveLayers(_nOctaveLayers),
contrastThreshold(_contrastThreshold),
edgeThreshold(_edgeThreshold),
sigma(_sigma),
gauss_pyr(_gauss_pyr),
dog_pyr(_dog_pyr),
keypoints(_keypoints),
mutex(_mutex) { }
void operator()( const cv::Range& range ) const
{
const int begin = range.start;
const int end = range.end;
keypoints.clear(); static const int n = SIFT_ORI_HIST_BINS;
float hist[n];
for( int o = 0; o < nOctaves; o++ ) const Mat& img = dog_pyr[idx];
for( int i = 1; i <= nOctaveLayers; i++ ) const Mat& prev = dog_pyr[idx-1];
const Mat& next = dog_pyr[idx+1];
KeyPoint kpt;
for( int r = begin; r < end; r++)
{ {
int idx = o*(nOctaveLayers+2)+i; const sift_wt* currptr = img.ptr<sift_wt>(r);
const Mat& img = dog_pyr[idx]; const sift_wt* prevptr = prev.ptr<sift_wt>(r);
const Mat& prev = dog_pyr[idx-1]; const sift_wt* nextptr = next.ptr<sift_wt>(r);
const Mat& next = dog_pyr[idx+1];
int step = (int)img.step1();
int rows = img.rows, cols = img.cols;
for( int r = SIFT_IMG_BORDER; r < rows-SIFT_IMG_BORDER; r++) for( int c = SIFT_IMG_BORDER; c < cols-SIFT_IMG_BORDER; c++)
{ {
const sift_wt* currptr = img.ptr<sift_wt>(r); sift_wt val = currptr[c];
const sift_wt* prevptr = prev.ptr<sift_wt>(r);
const sift_wt* nextptr = next.ptr<sift_wt>(r); // find local extrema with pixel accuracy
if( std::abs(val) > threshold &&
for( int c = SIFT_IMG_BORDER; c < cols-SIFT_IMG_BORDER; c++) ((val > 0 && val >= currptr[c-1] && val >= currptr[c+1] &&
val >= currptr[c-step-1] && val >= currptr[c-step] && val >= currptr[c-step+1] &&
val >= currptr[c+step-1] && val >= currptr[c+step] && val >= currptr[c+step+1] &&
val >= nextptr[c] && val >= nextptr[c-1] && val >= nextptr[c+1] &&
val >= nextptr[c-step-1] && val >= nextptr[c-step] && val >= nextptr[c-step+1] &&
val >= nextptr[c+step-1] && val >= nextptr[c+step] && val >= nextptr[c+step+1] &&
val >= prevptr[c] && val >= prevptr[c-1] && val >= prevptr[c+1] &&
val >= prevptr[c-step-1] && val >= prevptr[c-step] && val >= prevptr[c-step+1] &&
val >= prevptr[c+step-1] && val >= prevptr[c+step] && val >= prevptr[c+step+1]) ||
(val < 0 && val <= currptr[c-1] && val <= currptr[c+1] &&
val <= currptr[c-step-1] && val <= currptr[c-step] && val <= currptr[c-step+1] &&
val <= currptr[c+step-1] && val <= currptr[c+step] && val <= currptr[c+step+1] &&
val <= nextptr[c] && val <= nextptr[c-1] && val <= nextptr[c+1] &&
val <= nextptr[c-step-1] && val <= nextptr[c-step] && val <= nextptr[c-step+1] &&
val <= nextptr[c+step-1] && val <= nextptr[c+step] && val <= nextptr[c+step+1] &&
val <= prevptr[c] && val <= prevptr[c-1] && val <= prevptr[c+1] &&
val <= prevptr[c-step-1] && val <= prevptr[c-step] && val <= prevptr[c-step+1] &&
val <= prevptr[c+step-1] && val <= prevptr[c+step] && val <= prevptr[c+step+1])))
{ {
sift_wt val = currptr[c]; int r1 = r, c1 = c, layer = i;
if( !adjustLocalExtrema(dog_pyr, kpt, o, layer, r1, c1,
// find local extrema with pixel accuracy nOctaveLayers, (float)contrastThreshold,
if( std::abs(val) > threshold && (float)edgeThreshold, (float)sigma) )
((val > 0 && val >= currptr[c-1] && val >= currptr[c+1] && continue;
val >= currptr[c-step-1] && val >= currptr[c-step] && val >= currptr[c-step+1] && float scl_octv = kpt.size*0.5f/(1 << o);
val >= currptr[c+step-1] && val >= currptr[c+step] && val >= currptr[c+step+1] && float omax = calcOrientationHist(gauss_pyr[o*(nOctaveLayers+3) + layer],
val >= nextptr[c] && val >= nextptr[c-1] && val >= nextptr[c+1] && Point(c1, r1),
val >= nextptr[c-step-1] && val >= nextptr[c-step] && val >= nextptr[c-step+1] && cvRound(SIFT_ORI_RADIUS * scl_octv),
val >= nextptr[c+step-1] && val >= nextptr[c+step] && val >= nextptr[c+step+1] && SIFT_ORI_SIG_FCTR * scl_octv,
val >= prevptr[c] && val >= prevptr[c-1] && val >= prevptr[c+1] && hist, n);
val >= prevptr[c-step-1] && val >= prevptr[c-step] && val >= prevptr[c-step+1] && float mag_thr = (float)(omax * SIFT_ORI_PEAK_RATIO);
val >= prevptr[c+step-1] && val >= prevptr[c+step] && val >= prevptr[c+step+1]) || for( int j = 0; j < n; j++ )
(val < 0 && val <= currptr[c-1] && val <= currptr[c+1] &&
val <= currptr[c-step-1] && val <= currptr[c-step] && val <= currptr[c-step+1] &&
val <= currptr[c+step-1] && val <= currptr[c+step] && val <= currptr[c+step+1] &&
val <= nextptr[c] && val <= nextptr[c-1] && val <= nextptr[c+1] &&
val <= nextptr[c-step-1] && val <= nextptr[c-step] && val <= nextptr[c-step+1] &&
val <= nextptr[c+step-1] && val <= nextptr[c+step] && val <= nextptr[c+step+1] &&
val <= prevptr[c] && val <= prevptr[c-1] && val <= prevptr[c+1] &&
val <= prevptr[c-step-1] && val <= prevptr[c-step] && val <= prevptr[c-step+1] &&
val <= prevptr[c+step-1] && val <= prevptr[c+step] && val <= prevptr[c+step+1])))
{ {
int r1 = r, c1 = c, layer = i; int l = j > 0 ? j - 1 : n - 1;
if( !adjustLocalExtrema(dog_pyr, kpt, o, layer, r1, c1, int r2 = j < n-1 ? j + 1 : 0;
nOctaveLayers, (float)contrastThreshold,
(float)edgeThreshold, (float)sigma) )
continue;
float scl_octv = kpt.size*0.5f/(1 << o);
float omax = calcOrientationHist(gauss_pyr[o*(nOctaveLayers+3) + layer],
Point(c1, r1),
cvRound(SIFT_ORI_RADIUS * scl_octv),
SIFT_ORI_SIG_FCTR * scl_octv,
hist, n);
float mag_thr = (float)(omax * SIFT_ORI_PEAK_RATIO);
for( int j = 0; j < n; j++ )
{
int l = j > 0 ? j - 1 : n - 1;
int r2 = j < n-1 ? j + 1 : 0;
if( hist[j] > hist[l] && hist[j] > hist[r2] && hist[j] >= mag_thr ) if( hist[j] > hist[l] && hist[j] > hist[r2] && hist[j] >= mag_thr )
{
float bin = j + 0.5f * (hist[l]-hist[r2]) / (hist[l] - 2*hist[j] + hist[r2]);
bin = bin < 0 ? n + bin : bin >= n ? bin - n : bin;
kpt.angle = 360.f - (float)((360.f/n) * bin);
if(std::abs(kpt.angle - 360.f) < FLT_EPSILON)
kpt.angle = 0.f;
{ {
float bin = j + 0.5f * (hist[l]-hist[r2]) / (hist[l] - 2*hist[j] + hist[r2]); AutoLock autoLock(mutex);
bin = bin < 0 ? n + bin : bin >= n ? bin - n : bin;
kpt.angle = 360.f - (float)((360.f/n) * bin);
if(std::abs(kpt.angle - 360.f) < FLT_EPSILON)
kpt.angle = 0.f;
keypoints.push_back(kpt); keypoints.push_back(kpt);
} }
} }
...@@ -655,6 +679,50 @@ void SIFT_Impl::findScaleSpaceExtrema( const std::vector<Mat>& gauss_pyr, const ...@@ -655,6 +679,50 @@ void SIFT_Impl::findScaleSpaceExtrema( const std::vector<Mat>& gauss_pyr, const
} }
} }
} }
}
private:
int o, i;
int threshold;
int idx, step, cols;
int nOctaveLayers;
double contrastThreshold;
double edgeThreshold;
double sigma;
const std::vector<Mat>& gauss_pyr;
const std::vector<Mat>& dog_pyr;
std::vector<KeyPoint>& keypoints;
Mutex &mutex;
};
//
// Detects features at extrema in DoG scale space. Bad features are discarded
// based on contrast and ratio of principal curvatures.
void SIFT_Impl::findScaleSpaceExtrema( const std::vector<Mat>& gauss_pyr, const std::vector<Mat>& dog_pyr,
std::vector<KeyPoint>& keypoints ) const
{
const int nOctaves = (int)gauss_pyr.size()/(nOctaveLayers + 3);
const int threshold = cvFloor(0.5 * contrastThreshold / nOctaveLayers * 255 * SIFT_FIXPT_SCALE);
keypoints.clear();
Mutex mutex;
for( int o = 0; o < nOctaves; o++ )
for( int i = 1; i <= nOctaveLayers; i++ )
{
const int idx = o*(nOctaveLayers+2)+i;
const Mat& img = dog_pyr[idx];
const int step = (int)img.step1();
const int rows = img.rows, cols = img.cols;
parallel_for_(Range(SIFT_IMG_BORDER, rows-SIFT_IMG_BORDER),
findScaleSpaceExtremaComputer(
o, i, threshold, idx, step, cols,
nOctaveLayers,
contrastThreshold,
edgeThreshold,
sigma,
gauss_pyr, dog_pyr, keypoints, mutex));
}
} }
...@@ -1081,7 +1149,7 @@ void SIFT_Impl::detectAndCompute(InputArray _image, InputArray _mask, ...@@ -1081,7 +1149,7 @@ void SIFT_Impl::detectAndCompute(InputArray _image, InputArray _mask,
{ {
//t = (double)getTickCount(); //t = (double)getTickCount();
findScaleSpaceExtrema(gpyr, dogpyr, keypoints); findScaleSpaceExtrema(gpyr, dogpyr, keypoints);
KeyPointsFilter::removeDuplicated( keypoints ); KeyPointsFilter::removeDuplicatedSorted( keypoints );
if( nfeatures > 0 ) if( nfeatures > 0 )
KeyPointsFilter::retainBest(keypoints, nfeatures); KeyPointsFilter::retainBest(keypoints, nfeatures);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment