在这个问题中,我询问了如何一步实现一系列模糊。
然后我从维基百科的高斯模糊页面中发现:
对图像应用多个连续的高斯模糊与应用单个更大的高斯模糊具有相同的效果,其半径是实际应用的模糊半径平方和的平方根。例如,应用半径为 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
)。
为什么?
更新:
在要求更多信息的不同评论之后,我会更新答案。
我想要做的是并行化这段代码。特别是,我现在专注于提前计算所有级别的所有模糊。序列号(正常工作)如下:
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 个模糊。
这是“单一模糊”版本,首先我计算每个必须计算的模糊的 sigma(遵循 Wikipedia 的公式),然后应用模糊(请注意,这仍然是串行的且不可并行化):
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 个模糊。
signgleBlurs
然后这是查看每个和之间区别的代码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 来查看真正的区别,但我不明白为什么我正确理解了他。
如果您需要更多详细信息,请告诉我。