优化的浮动模糊变化

时间:2011-10-22 15:28:28

标签: c++ optimization image-processing blur

我正在寻找c ++中的优化函数来计算浮点数的面积平均值。该函数传递一个源浮点数组,一个目标浮点数组(与源数组大小相同),数组宽度和高度,“模糊”区域宽度和高度。

该函数应该“环绕”边缘以进行模糊/平均值计算。

以下是使用矩形模糊的示例代码:

/*****************************************
*   Find averages extended variations
*****************************************/

void findaverages_ext(float *floatdata, float *dest_data, int fwidth, int fheight, int scale, int aw, int ah, int weight, int xoff, int yoff)
{
printf("findaverages_ext scale: %d, width: %d, height: %d, weight: %d \n", scale, aw, ah, weight);

float total = 0.0;
int spos = scale * fwidth * fheight;
int apos;

int w = aw;
int h = ah;

float* f_temp       = new float[fwidth * fheight];

// Horizontal
for(int y=0;y<fheight   ;y++)
{
    Sleep(10);      // Do not burn your processor 

    total = 0.0;

    // Process entire window for first pixel (including wrap-around edge)
    for (int kx = 0; kx <= w; ++kx)
        if (kx >= 0 && kx < fwidth)
            total += floatdata[y*fwidth + kx];
    // Wrap
    for (int kx = (fwidth-w); kx < fwidth; ++kx)
        if (kx >= 0 && kx < fwidth)
            total += floatdata[y*fwidth + kx];

    // Store first window
    f_temp[y*fwidth] = (total / (w*2+1));

    for(int x=1;x<fwidth    ;x++)           // x width changes with y
    {
        // Substract pixel leaving window
        if (x-w-1 >= 0)
            total -= floatdata[y*fwidth + x-w-1];

        // Add pixel entering window
        if (x+w < fwidth)
            total += floatdata[y*fwidth + x+w];
        else
            total += floatdata[y*fwidth + x+w-fwidth];

        // Store average
        apos = y * fwidth + x;
        f_temp[apos] = (total / (w*2+1));
    }
}


// Vertical
for(int x=0;x<fwidth    ;x++)
{
    Sleep(10);      // Do not burn your processor 

    total = 0.0;

    // Process entire window for first pixel
    for (int ky = 0; ky <= h; ++ky)             
        if (ky >= 0 && ky < fheight)
            total += f_temp[ky*fwidth + x];
    // Wrap
    for (int ky = fheight-h; ky < fheight; ++ky)                
        if (ky >= 0 && ky < fheight)
            total += f_temp[ky*fwidth + x];

    // Store first if not out of bounds
    dest_data[spos + x] = (total / (h*2+1));

    for(int y=1;y< fheight  ;y++)           // y width changes with x
    {
        // Substract pixel leaving window
        if (y-h-1 >= 0)
            total -= f_temp[(y-h-1)*fwidth + x];

        // Add pixel entering window
        if (y+h < fheight)
            total += f_temp[(y+h)*fwidth + x];
        else
            total += f_temp[(y+h-fheight)*fwidth + x];

        // Store average
        apos = y * fwidth + x;
        dest_data[spos+apos] = (total / (h*2+1));
    }
}

delete f_temp;
}

我需要的是类似的功能,每个像素找到不同于矩形的像素的平均(模糊)像素。

具体形状为:“S”(锐边),“O”(矩形但空心),“+”和“X”,其中平均浮点数存储在目标数据阵列的中心像素上。模糊形状的大小应该是可变的,宽度和高度。

这些功能不需要像素完美,只针对性能进行了优化。每种形状都可以有单独的功能。

如果有人能告诉我如何针对矩形模糊优化上面的示例函数,我也很高兴。

2 个答案:

答案 0 :(得分:4)

您尝试实施的是各种用于图像处理的数字滤镜。这相当于卷积两个信号,其中第二个信号是滤波器的脉冲响应。到目前为止,您已经认识到“矩形平均值”是可分离的。通过可分离我的意思是,你可以将过滤器分成两部分。一个沿X轴操作,一个沿Y轴操作 - 在每种情况下都是一维滤波器。这很好,可以节省很多周期。但并非每个过滤器都是可分离的。沿其他shapres(S,O,+,X)求平均值是不可分的。您需要为这些实际计算2D卷积。

至于性能,您可以通过正确实施“移动平均线”来加快1D平均值。无论平均“窗口”如何,适当的“移动平均”实现仅需要每像素固定的少量工作。这可以通过识别目标图像的相邻像素由几乎相同像素的平均值来计算来完成。您可以通过添加一个新的像素强度并减去较旧的像素强度(对于1D情况),将这些总和重用于相邻目标像素。

在任意不可分离滤波器的情况下,性能最佳的选择是“快速卷积”,这是基于FFT的。结帐www.dspguide.com。如果我没记错的话,甚至还有一章讨论如何使用FFT算法正确地进行“快速卷积”。虽然,他们解释了它对于一维信号,但它也适用于二维信号。对于图像,您必须执行2D-FFT / iFFT变换。

答案 1 :(得分:4)

要添加到sellibitze的答案,您可以使用summed area table作为O,S和+内核(但不是X的内核)。这样你就可以在一个恒定的时间内对像素进行卷积,对于允许它的内核形状来说,它可能是最快的方法。

基本上,SAT是一种数据结构,可用于计算任何轴对齐矩形的总和。对于O内核,在构建SAT之后,您将获取外部矩形像素的总和并减去内部矩形像素的总和。 S和+内核可以类似地实现。

对于X内核,您可以使用不同的方法。倾斜的盒式过滤器是可分离的:

Skewed box filter

您可以使用两个细长的倾斜盒式滤镜进行卷积,然后将两个生成的图像一起添加。 X的中心将被计数两次,因此您需要与另一个偏斜的盒式过滤器进行卷积,然后减去它。

除此之外,您还可以通过多种方式优化盒子模糊。

  • 通过将该循环分成三个循环 - 两个用于检查的短循环和一个不循环的长循环,从内循环中删除两个ifs。或者您可以使用来自所有方向的额外元素填充阵列 - 这样您就可以简化代码。
  • 在循环外计算h * 2 + 1之类的值。
  • f_temp[ky*fwidth + x]这样的表达式会进行两次加法和一次乘法运算。您可以在循环外初始化指向&f_temp[ky*fwidth]的指针,只需在循环中递增该指针。
  • 请勿在水平步骤中按h * 2 + 1进行除法。相反,除以垂直步骤中的平方。