SIFT算法步骤
1 void extractSiftFeatures(const Mat &img, vector<KeyPoint> &keypoints, Mat &descriptor, int intervals, double sigma, 2 double contrast_thres, int curvature_thres, bool img_dbl, int descr_width, int descr_hist_bins) 3 { 4 Mat init_img = __createInitImg(img, img_dbl, sigma); //根据img_dbl决定是否需要将原来的图片扩大作为第0层 5 6 Size s = init_img.size(); 7 int octaves = log(min(s.width, s.height)) / log(2) - 2; //确定金字塔的组数 8 9 vector<Mat> gaussian_pyramid; 10 __buildGaussPyramid(init_img, gaussian_pyramid, octaves, intervals, sigma); //建立高斯金字塔 11 12 vector<Mat> dog_pyramid; 13 __buildDogPyramid(gaussian_pyramid, dog_pyramid, octaves, intervals); //建立DOG金字塔 14 15 vector<Feature> feats; 16 __scaleSpaceExtrema(dog_pyramid, feats, octaves, intervals, contrast_thres, curvature_thres); //在DOG空间中查找极值,并记录为特征 17 18 __calcFeatureScales(feats, sigma, intervals); //计算特征点的尺度 19 20 if (img_dbl) 21 __adjustForImgDbl(feats); 22 23 __calcFeatureOris(feats, gaussian_pyramid, intervals + 3); //计算特征点的方向 24 25 __computeDescriptors(feats, gaussian_pyramid, intervals + 3, descr_width, descr_hist_bins);//计算描述子 26 27 __feats2KeyPoints(feats, keypoints); 28 29 __featsVec2Mat(feats, descriptor); 30 }
1.根据img_dbl确定是否需要扩大原来的图像
1 Mat __createInitImg(const Mat &img, bool img_dbl, double sigma) { 2 if (img_dbl) { 3 Mat init_img(img.size() * 2, CV_32FC1); 4 resize(img, init_img, init_img.size(), 0, 0, INTER_CUBIC); 5 6 //这一句的理解是,图片初始尺度已经是SIFT_INIT_SIGMA(0.5)了,因为第0层尺度是1.6,所以还需要再把 7 //图片进行一次高斯模糊,使得尺度变成1.6,那么这次高斯模糊所需要的尺度就是sqrt(1.6^2-(0.5*2)^2) 8 //这里0.5*2是因为图片大小扩大了一倍,相当于现在图片的尺度是1.0了 9 double sig_diff = sqrt(sigma * sigma - SIFT_INIT_SIGMA * SIFT_INIT_SIGMA * 4); 10 GaussianBlur(init_img, init_img, Size(), sig_diff, sig_diff); 11 return init_img; 12 } 13 else { 14 Mat init_img = Mat(img.size(), CV_32FC1); 15 16 double sig_diff = sqrt(sigma * sigma - SIFT_INIT_SIGMA * SIFT_INIT_SIGMA); 17 GaussianBlur(img, init_img, Size(), sig_diff, sig_diff); 18 return init_img; 19 } 20 }
2.有了初始图像,就可以建立高斯金字塔了
1 void __buildGaussPyramid(const Mat& base, vector<Mat>& gaussian_pyramid, int octaves, int intervals, double sigma) 2 { 3 //octaves是组数,intervals是组内层数,sigma默认1.6 4 int layer_per_octave = intervals + 3; //每一组中层数加3 5 vector<double> sigmas(layer_per_octave); 6 double k = pow(2.0f, 1.0f / intervals); 7 8 //计算sigma序列,注意因为第0层图片已经经过高斯模糊了,之后的模糊是在第0层的基础上做的 9 //那第1层尺度要变成k*sigma,需要在已经模糊化的第0层的基础上再模糊多少,才能让第1层尺度变成k*sigma呢? 10 //根据高斯模糊性质,sigmas[1]=sqrt((k*sigma)^2-sigma^2),这其实和__createInitImg函数中sig_diff道理是一样的 11 //之后的sigmas[2]=sqrt((k*k*sigma)^2-sigma^2)=k*sigmas[1],依次类推 12 sigmas[0] = sigma; 13 sigmas[1] = sigma*sqrt(k*k - 1); //sigma默认值是1.6,不过这里sigmas[1]的计算方式有点疑问 14 for (int i = 2; i < layer_per_octave; i++) 15 { 16 sigmas[i] = sigmas[i - 1] * k; 17 } 18 int layers = octaves*layer_per_octave; 19 gaussian_pyramid.reserve(layers); 20 21 for (int oct = 0; oct < octaves; oct++) 22 { 23 for (int lay = 0; lay < layer_per_octave; lay++) 24 { 25 if (oct == 0 && lay == 0) 26 { 27 gaussian_pyramid.push_back(base); 28 continue; 29 } 30 31 if (lay == 0) 32 { 33 //因为这一层尺度大小就是2*sigma,所以采样后不需要再高斯模糊。这里也可以看出取倒数第三张可以保证尺度连续 34 const Mat &last = gaussian_pyramid[gaussian_pyramid.size() - 3]; 35 Size s = last.size(); 36 Mat down_img(s.height / 2, s.width / 2, CV_32FC1); 37 resize(last, down_img, down_img.size(), 0, 0, CV_INTER_NN); 38 gaussian_pyramid.push_back(down_img); 39 continue; 40 } 41 42 const Mat &last = gaussian_pyramid.back(); 43 Mat smooth_img(last.size(), CV_32FC1); 44 GaussianBlur(last, smooth_img, Size(), sigmas[lay], sigmas[lay]); 45 gaussian_pyramid.push_back(smooth_img); 46 } 47 } 48 }
3.通过高斯金字塔,计算DOG金字塔,就是同一组中高斯金字塔上一层减去下一层
1 void __buildDogPyramid(const vector<Mat>& gaussian_pyramid, vector<Mat>& dog_pyramid, int octaves, int intervals) 2 { 3 int layer_per_octave_dog = intervals + 2; 4 int layer_per_octave_gaussian = intervals + 3; 5 dog_pyramid.reserve(octaves*layer_per_octave_dog); 6 for (int oct = 0; oct < octaves; oct++) 7 { 8 for (int lay = 0; lay < layer_per_octave_dog; lay++) 9 { 10 int idx = oct*layer_per_octave_gaussian + lay; 11 dog_pyramid.push_back(gaussian_pyramid[idx + 1] - gaussian_pyramid[idx]); 12 } 13 } 14 }
这样,SIFT算法初始化工作算是做好了。
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号