为什么SIFT花费更多的时间和更少的倍频程层



我在OpenCV 4.5.2中使用SIFT特征检测器。通过调整cv::SIFT::create()中的nOctaveLayers参数,我从detectAndCompute():中得到了这些结果

时间成本(ms(//tr>
nActionLayers 关键点
1 1026 63.41
2 1795 45.07
3 2043 45.74
4 2173 47.83
5 2224 51.86

经过数小时的分析,我终于找到了原因:GaussianBlur

SIFT算法的流水线是:

  1. 创建初始图像:将源图像的数据类型转换为float,将分辨率提高一倍,并执行GaussianBlur(西格玛=1.56(
  2. 构建高斯金字塔
  3. 寻找关键点:建立DoG金字塔并找到尺度空间极值
  4. 计算描述符

八度音阶的数量是根据图像分辨率计算的(请参见此处(。nOctaveLayers控制每个八度音阶的层数(高斯金字塔为nOctaveLayers + 3(。

事实上,当nOctaveLayers增加时,层的数目和关键点的数目都增加。结果,步骤3&4增加。然而,在并行计算中,这种时间增量并不是很显著(几毫秒(。

相反,步骤2花费的时间超过总时间的一半。当nOctaveLayers为3时花费25.27ms(43.49ms(,当nOctaveLayers为1时花费51.16ms(63.10ms(。那么,为什么会发生这种情况呢?

因为层数越少,GaussianBlur()的西格玛增加得越快,这对GaussianBlur()消耗的时间至关重要。参见下面的测试:

vector<double> sig1 = { 1.6, 2.77128, 5.54256, 11.0851 };
vector<double> sig3 = { 1.6, 1.22627, 1.54501, 1.94659, 2.45255, 3.09002 };
vector<double> sig5 = { 1.6, 0.9044, 1.03888, 1.19336, 1.37081, 1.57465, 1.8088, 2.07777 };
auto blurTest = [](const vector<double>& sigs, const string& label) {
const int test_num = 100;
auto t1 = chrono::high_resolution_clock::now();
for (int i = 0; i < test_num; ++i) {
vector<Mat> pyr;
pyr.resize(sigs.size());
pyr[0] = Mat::zeros(960, 1280, CV_32FC1);
for (size_t i = 1; i < sigs.size(); ++i)
GaussianBlur(pyr[i - 1], pyr[i], Size(), sigs[i], sigs[i]);
}
auto t2 = chrono::high_resolution_clock::now();
auto time = chrono::duration<double>(t2 - t1).count() * 1e3 / test_num;
cout << label << ": " << time << " msn";
};
blurTest(sig1, "1");
blurTest(sig3, "3");
blurTest(sig5, "5");
/* output:
1: 45.3958 ms
3: 28.5943 ms
5: 31.4827 ms
*/

nOctaveLayers为1、3和5时,上面的代码模拟buildGaussianPyramid()。西格玛值来自cv::SIFT计算。这就解释了为什么当CCD_ 17为1时,SIFT花费更多的时间。

最新更新