具有可分离内核的 2D 模糊卷积

2D Blur convolution with separable kernel

本文关键字:2D 模糊 卷积 内核 可分离      更新时间:2023-10-16

我正在尝试使用自定义float数组进行模糊卷积。

我的数组定义为float array[width*height]。我编辑了这些函数,因此它可以与自定义数组一起使用,而不仅仅是 OpenCVcv::Mat

我的代码如下所示:

int reflect(int M, int x)
{
if(x < 0)
{
return -x - 1;
}
if(x >= M)
{
return 2*M - x - 1;
}
return x;
}
void separable2DConvolution(float * data, Size dataSize, float *kernel, int kernelSize)
{
// make copy of original image
float * dataCopy = new float[dataSize.width()*dataSize.height()];
memcpy(dataCopy, data, dataSize.width()*dataSize.height());
float * temp = new float[dataSize.width()*dataSize.height()];
memcpy(temp, data, dataSize.width()*dataSize.height());
float sum;
int x1, y1;
int kernelRadius = floor(kernelSize/2);
// along y - direction
for(int y = 0; y < dataSize.height(); y++){
for(int x = 0; x < dataSize.width(); x++){
sum = 0.0;
for(int i = -kernelRadius; i <= kernelRadius; i++){
y1 = reflect(dataSize.height(), y - i);
sum = sum + kernel[i + kernelRadius]*dataCopy[y1*x+y1];
}
temp[y*x+y] = sum;
}
}
// along x - direction
for(int y = 0; y < dataSize.height(); y++){
for(int x = 0; x < dataSize.width(); x++){
sum = 0.0;
for(int i = -kernelRadius; i <= kernelRadius; i++){
x1 = reflect(dataSize.width(), x - i);
sum = sum + kernel[i + kernelRadius]*temp[x1*y+x1];
}
data[x*y+y] = sum;
}
}
delete [] temp;
delete [] dataCopy;
}

数组作为data传递给separable2DConvolutionSize是具有定义宽度和高度的自定义类(两者都有效且大于 0(,kernel规范化的高斯数组(几乎与cv::getGaussianKernel中的数组相同(,kernelSize是高斯数组的大小(我使用大小 11(。

我使用此函数替换OpenCV中的cv::sepFilter2D,但不知何故,输出是不同的。 使用我的函数后,我正在转换图像以查看差异。

OpenCV 输出具有(如预期的那样("模糊"值,但将相同的输入传递给我的函数时,前三分之一是噪声的(根本没有模糊(,图像的另一部分完好无损。

我的代码有什么问题?

感谢您的帮助!

您保存像素和的下标是错误的。temp[y*x+y]会将第一列的所有结果写入第一个像素(temp[0](。 许多其他像素将保持不变。 您可能想要temp[y * dataSize.width() + x],在下一个循环中和计算下标以读取像素值时对data[x*y+y]进行类似的更改。

不相关,您无需memcpy位图即可制作副本,因为您应该写入图像中的每个像素。 您根本不需要dataCopy,因为原始data数组尚未更改。

对于整数,使用floor是矫枉过正的。 由于kernelSize是积极的,你可以说int kernelRadius = kernelSize / 2;因为这会四舍五入。