应用多个连续的高斯模糊到图像上,其效果与应用单个更大半径的高斯模糊相同,其半径为实际应用的模糊半径平方和的平方根。例如,连续应用半径为6和8的高斯模糊产生的结果与应用半径为10的单个高斯模糊相同,因为sqrt {6^{2}+8^{2}}=10。
所以我认为以下代码中的“blur”和“singleBlur”是相同的:
cv::Mat firstLevel;
float sigma1, sigma2;
//intialize firstLevel, sigma1 and sigma2
cv::Mat blur = gaussianBlur(firstLevel, sigma1);
blur = gaussianBlur(blur, sigma2);
float singleSigma = std::sqrt(std::pow(sigma1,2)+std::pow(sigma2,2));
cv::Mat singleBlur = gaussianBlur(firstLevel, singleSigma);
cv::Mat diff = blur != singleBLur;
// Equal if no elements disagree
assert( cv::countNonZero(diff) == 0);
但是这个
assert
失败了(例如,blur
的第一行与singleBlur
的第一行不同)。为什么?
更新:
在不同的评论要求更多信息后,我将更新答案。
我正在尝试并行化this代码。特别是,我现在专注于预先计算所有级别的所有模糊。串行代码(正确工作)如下:
vector<Mat> blurs ((par.numberOfScales+3)*levels, Mat());
cv::Mat octaveLayer = firstLevel;
int scaleCycles = par.numberOfScales+2;
//compute blurs at all layers (not parallelizable)
for(int i=0; i<levels; i++){
blurs[i*scaleCycles+1] = octaveLayer.clone();
for (int j = 1; j < scaleCycles; j++){
float sigma = par.sigmas[j]* sqrt(sigmaStep * sigmaStep - 1.0f);
blurs[j+1+i*scaleCycles] = gaussianBlur(blurs[j+i*scaleCycles], sigma);
if(j == par.numberOfScales)
octaveLayer = halfImage(blurs[j+1+i*scaleCycles]);
}
}
在哪里:
Mat halfImage(const Mat &input)
{
Mat n(input.rows/2, input.cols/2, input.type());
float *out = n.ptr<float>(0);
for (int r = 0, ri = 0; r < n.rows; r++, ri += 2)
for (int c = 0, ci = 0; c < n.cols; c++, ci += 2)
*out++ = input.at<float>(ri,ci);
return n;
}
Mat gaussianBlur(const Mat input, const float sigma)
{
Mat ret(input.rows, input.cols, input.type());
int size = (int)(2.0 * 3.0 * sigma + 1.0); if (size % 2 == 0) size++;
GaussianBlur(input, ret, Size(size, size), sigma, sigma, BORDER_REPLICATE);
return ret;
}
抱歉以上的索引很糟糕,但我尽力尊重原始代码系统(它很糟糕,比如从
1
而不是0
开始计数)。上面的代码具有scaleCycles=5
和levels=6
,因此总共生成30个模糊度。这是“单次模糊”版本,首先我计算每个需要计算的模糊度的西格玛值(按照维基百科的公式),然后应用模糊度(请注意,这仍然是串行的,不能并行化)。
vector<Mat> singleBlurs ((par.numberOfScales+3)*levels, Mat());
vector<float> singleSigmas(scaleCycles);
float acc = 0;
for (int j = 1; j < scaleCycles; j++){
float sigma = par.sigmas[j]* sqrt(sigmaStep * sigmaStep - 1.0f);
acc += pow(sigma, 2);
singleSigmas[j] = sqrt(acc);
}
octaveLayer = firstLevel;
for(int i=0; i<levels; i++){
singleBlurs[i*scaleCycles+1] = octaveLayer.clone();
for (int j = 1; j < scaleCycles; j++){
float sigma = singleSigmas[j];
std::cout<<"j="<<j<<" sigma="<<sigma<<std::endl;
singleBlurs[j+1+i*scaleCycles] = gaussianBlur(singleBlurs[j+i*scaleCycles], sigma);
if(j == par.numberOfScales)
octaveLayer = halfImage(singleBlurs[j+1+i*scaleCycles]);
}
}
当然,上面的代码还是使用相同的参数生成了30个模糊效果。
以下是用于查看每个
singleBlurs
和blurs
之间差异的代码: assert(blurs.size() == singleBlurs.size());
vector<Mat> blurDiffs(blurs.size());
for(int i=1; i<levels*scaleCycles; i++){
cv::Mat diff;
absdiff(blurs[i], singleBlurs[i], diff);
std::cout<<"i="<<i<<"diff rows="<<diff.rows<<" cols="<<diff.cols<<std::endl;
blurDiffs[i] = diff;
std::cout<<"blurs rows="<<blurs[i].rows<<" cols="<<blurs[i].cols<<std::endl;
std::cout<<"singleBlurs rows="<<singleBlurs[i].rows<<" cols="<<singleBlurs[i].cols<<std::endl;
std::cout<<"blurDiffs rows="<<blurDiffs[i].rows<<" cols="<<blurDiffs[i].cols<<std::endl;
namedWindow( "blueDiffs["+std::to_string(i)+"]", WINDOW_AUTOSIZE );// Create a window for display.
//imshow( "blueDiffs["+std::to_string(i)+"]", blurDiffs[i] ); // Show our image inside it.
//waitKey(0); // Wait for a keystroke in the window
Mat imageF_8UC3;
std::cout<<"converting..."<<std::endl;
blurDiffs[i].convertTo(imageF_8UC3, CV_8U, 255);
std::cout<<"converted"<<std::endl;
imwrite( "blurDiffs_"+std::to_string(i)+".jpg", imageF_8UC3);
}
现在,我看到的是
blurDiffs_1.jpg
和blurDiffs_2.jpg
是黑色的,但突然从blurDiffs_3.jpg
到blurDiffs_29.jpg
越来越白。由于某种原因,blurDiffs_30.jpg
几乎完全是黑色的。第一个(正确的)版本生成1761个描述符。第二个(不正确的)版本生成超过2.3k个描述符。
我无法发布
blurDiffs
矩阵,因为(特别是前面的几个)非常大,而帖子空间有限。我会发布一些样本。我不会发布blurDiffs_1.jpg
和blurDiffs_2.jpg
,因为它们完全是黑色的。请注意,由于halfImage
,图像变得越来越小(如预期)。
blurDiffs_3.jpg:
blurDiffs_6.jpg:
blurDiffs_15.jpg:
blurDiffs_29.jpg:
图片的读取方式:
Mat tmp = imread(argv[1]);
Mat image(tmp.rows, tmp.cols, CV_32FC1, Scalar(0));
float *out = image.ptr<float>(0);
unsigned char *in = tmp.ptr<unsigned char>(0);
for (size_t i=tmp.rows*tmp.cols; i > 0; i--)
{
*out = (float(in[0]) + in[1] + in[2])/3.0f;
out++;
in+=3;
}
有人在这里建议将diff
除以255以查看真正的差异,但如果我理解正确的话,我不明白为什么。
如果您需要更多细节,请告诉我。
cv::Mat
中,每个元素的类型是什么?如果它是浮点类型,那么由于浮点值在c ++
中的表示方式,差异恰好为零的概率非常小。 - G.M.