图像卷积与高斯模糊,加速可能吗?

Image convolution with a Gaussian Blur, speedups possible?

如前所述,这是一道作业题,不过我已经做完了,就是慢了点。这与报告无关。但无论如何我都在努力加快速度。

所以我正在尝试对图像应用高斯模糊

const unsigned char KERNAL_SIZE = 5;
const unsigned char KERNAL_MEAN = KERNAL_SIZE / 2;
const unsigned char GaussianBlurKernal[KERNAL_SIZE][KERNAL_SIZE] =
{ { 1, 4, 7, 4, 1 },
{ 4, 16, 26, 16, 4 },
{ 7, 26, 41, 26, 7 },
{ 4, 16, 26, 16, 4 },
{ 1, 4, 7, 4, 1 }
};
const int GAUSSIAN_KERNAL_SIZE = 273;

并执行以下代码:

Mat CustomGuassianBlur(const Mat & inputImage)
{
    Size maxSize = inputImage.size();
    Mat outputImage(maxSize, CV_8UC1, Scalar(0, 0, 0));
    for (int i = 0; i < maxSize.width; i++)
    {
        for (int j = 0; j < maxSize.height; j++)
        {
            unsigned int sum = 0;
            for (int k = -KERNAL_MEAN; k <= KERNAL_MEAN; k++)
            {
                for (int l = -KERNAL_MEAN; l <= KERNAL_MEAN; l++)
                {
                    Point imagePoint = { (i + l + maxSize.width) % maxSize.width, (j + k + maxSize.height) % maxSize.height };
                    sum = sum + inputImage.at<uchar>(imagePoint) * GaussianBlurKernal[k + KERNAL_MEAN][l + KERNAL_MEAN];
                }
            }
            sum = sum / GAUSSIAN_KERNAL_SIZE;
            outputImage.at<uchar>(j, i) = uchar(sum);
        }
    }
return outputImage;
}

过滤器大约需要 8 秒。我试图近似的 OpenCV 代码:

GaussianBlur(src_gray, detected_edges, Size(5, 5), 0, 0);

在同一张图片上用时不到四分之一秒。

我可以做些什么来加快这个过程?我读过一些关于应用两个一维滤波器的内容,但老实说我不太理解。我也读过一些关于对图像和滤波器进行 FFT、将它们相乘、然后进行 IFFT 的内容,但我认为这不是我想在这里做的事情:我发现的资源只是提到了当涉及到更大的过滤器时效率更高。

我的几毛钱:

  1. 请将您的索引变量命名为rc,以便您知道什么是行什么是列。它将帮助你在漫长的运行.
  2. 内核?这不应该是KERNEL吗?或者这是另一种语言?
  3. 记住您的缓存:您的矩阵以行优先顺序存储,因此每一行都要经过每一列。
  4. 如果您的内核大小是固定的,请展开内部双循环。
  5. 如果您的内核大小必须更改,请在一个内部循环中使用 cv::Mat::ptr() 获取当前行的地址,以至少在列索引中节省一些计算。
  6. 模数宽度和高度听起来不对。您正在使用环形图像表示。不寻常。

除了@CostantinoGrana 的回答之外,我还想指出 2D 高斯平滑是线性可分的。您可以使用 2 个 1D 内核,而不是使用 2D 内核——第一次遍历行,第二次遍历列。

此外,如果您可以访问多个内核,则可以并行地对行/列进行一维过滤。请参阅 cv::parallel_for_ 构造。