c - 图像边缘周围的高斯模糊 "Discontinuity"

标签 c

我一直在尝试使用特定半径 rs=((int)2.75*sigma+0.5) 的高斯核实现 nxn 图像的高斯模糊函数。

for (x=0;x<n;x++){
    for (y=0;y<n;y++){

        sum=0.0,wsum=0.0;

        //Position correction at the edges

        if(x-rs<0){
            ix=0;
        }
        else ix=rs;

        if(y-rs<0){
            iy=0;
        }
        else iy=rs;

        if (x+rs>n-1){
            jx=n-1-x;
        }
        else jx=rs;

        if (y+rs>n-1){
            jy=n-1-y;
        }
        else jy=rs;
        //Kernel mean value correction at the edges

        if ( x-rs < 0 ){
            meanx=x+((int)rs/2);
        }
        else meanx=x;

        if(y-rs<0){
            meany=y+((int)rs/2);
        }
        else meany=y;

        if (x+rs>n-1){
            meanx=x-((int)rs/2);
        }
        else meanx=x;

        if (y+rs>n-1){
            meany=y-((int)rs/2);
        }
        else meany=y;   


        for (i=x-ix;i<=x+jx;i++){
            for (j=y-iy;j<=y+jy;j++){

                weight=1/(2*M_PI*sigma*sigma)*exp(-((meanx-i)*(meanx-i)+(meany-j)*(meany-j))/(2*sigma*sigma));
                sum+=pic1.intenzity[i][j]*weight;
                wsum+=weight;
            }
        }

        pic2->intenzity[x][y]=((int)sum/wsum+0.5);

        fprintf(fw,"%d\n",pic2->intenzity[x][y]);   
    }

当我不在边缘使用均值校正时,结果如下所示:

without mean value correction

当我尝试移动内核的平均值时,它也在图像的右下边缘创建了一个不连续点:

with shifting the mean value to rs/2

我不得不进行边缘位置修正,因为总和会溢出。现在看来,当高斯卷积位于距离 x 和 y 的上边缘和左边缘的位置 rs 时,由于某种原因突然跳跃。我想让它的行为方式与它在图像“内部”中的行为方式相同,或者可能使强度随着位置接近边缘而逐渐变为 0。

我可能会将图像放大 rs,但这会导致边缘位置出现问题。

感谢您提供的任何有见地的帮助:)

最佳答案

让我们以伪代码的形式看一下应用于图像的典型滤波器内核。让我们使用变量

# source[y][x]    Old image (read-only)
# target[y][x]    New image (write-only)
# image_height    Image height (y = 0 .. image_height-1)
# image_width     Image width (x = 0 .. image_width-1)
# filter[y][x]    Filter (weights) to be applied
# filter_height   Filter height (y = 0 .. filter_height-1)
# filter_width    Filter width (x = 0 .. filter_width-1)
# filter_y        Target pixel y coordinate in filter (filter_height/2)
# filter_x        Target pixel x coordinate in filter (filter_width/2)

如果过滤器以目标像素为中心(即对称),则 filter_y = floor(filter_width/2)filter_x = floor(filter_height/2)。那么伪代码大概就是

For base_y = 0 to image_height - 1:

   # y range relative to base_y ...
   min_y = -filter_y
   max_y = filter_height - 1 - filter_y

   # ... must not exceed the image boundaries.
   If min_y + base_y < 0:
       min_y = -base_y
   End If

   If max_y + base_y < 0:
       max_y = -base_y
   End If

   If min_y + base_y >= image_height:
       min_y = image_height - 1 - base_y
   End If

   If max_y + base_y >= image_height:
       max_y = image_height - 1 - base_y
   End If

   For base_x = 0 to image_width - 1:

       # x range relative to base_x ...
       min_x = -filter_x
       max_x = filter_width - 1 - filter_x

       # ... must not exceed the image boundaries.
       If min_x + base_x < 0:
           min_x = -base_x
       End If

       If max_x + base_x < 0:
           max_x = -base_x
       End If

       If min_x + base_x >= image_width:
           min_x = image_width - 1 - base_x
       End If

       If max_x + base_x >= image_height:
           max_x = image_width - 1 - base_x
       End If

       ValueSum = 0
       WeightSum = 0

       For y = min_y to max_y:
           For x = min_x to max_x:
               Value = source[y + base_y][x + base_x]
               Weight = filter[y + filter_y][x + filter_x]
               ValueSum = ValueSum + Value * Weight
               WeightSum = WeightSum + Weight
           End For
        End For

        If WeightSum != 0:
            target[base_y][base_x] = ValueSum / WeightSum
        End If

    End For
End For

在最内层的循环中,[base_y][base_x] 指的是目标像素,即我们正在计算的像素; [y+base_y][x+base_x] 是指由[y+filter_y][x+filter_x] 加权的源像素。 xy是相对值,范围从-filter_x-filter_yfilter_width-1-分别为 filter_xfilter_height-1-filter_y

只要 ValueSumWeightSum 具有足够的范围,无论图像和过滤器数据是整数还是 float ,相同的代码都有效。

棘手的部分,以及导致 OP 看到的伪像的部分,是如何计算 min_ymax_ymin_xmax_x 正确。

要调试,删除最里面的两个循环,而是打印类似的内容

printf("y = %d, ymin = %d (%d), ymax = %d (%d)\n",
       base_y, min_y, min_y + base_y, max_y, max_y + base_y);

在外层循环中(不需要为每个 base_x 打印它!),以及

printf("x = %d, xmin = %d (%d), xmax = %d (%d)\n",
       base_x, min_x, min_x + base_x, max_x, max_x + base_x);

在最内层循环中一次(无需为每个 base_y 再次打印),例如if (y == 0) printf("...");。这将输出 image_width + image_height 行,并让您验证您定义的范围是否正确。

在 OP 的情况下,图像边缘附近的范围不正确;即,它们的某些 if 子句对应于上述伪代码计算/分配不正确的 min_xmax_xmin_ymax_y 值。

关于c - 图像边缘周围的高斯模糊 "Discontinuity",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40423128/

相关文章:

c - C 中的哈希表 init_hash

c - GNU 读取线 : avoid prompt string in output if input is not interactive

C - malloc 和结构、段错误

c++ - %*c 是什么意思?

判断闰年的C程序

c - 嵌入式 C 中的信号量和可能的不可重入函数

c - 基于 2 个输入的伪随机数生成器

在c中编译ImageMagick核心

c - 未初始化(排队)就使用的变量

c++ - CreateFile vs fopen vs ofsteam 优势和劣势?