我一直在尝试实现具有特定半径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,"%dn",pic2->intenzity[x][y]);
}
当我在边缘不使用平均值校正时,结果看起来像这样:
没有平均值校正
,当我尝试移动内核的平均值时,它也在图像的下部和右侧边缘产生不连续:
的平均值移动到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]
加权后的源像素。x
、y
为相对值,取值范围为-filter_x
、-filter_y
~ filter_width-1-filter_x
、filter_height-1-filter_y
。
只要ValueSum
和WeightSum
有足够的取值范围,无论图像和过滤器数据是整数还是浮点,相同的代码都可以工作。
棘手的部分,以及引起OP看到的伪像的部分,是如何正确计算min_y
, max_y
, min_x
和max_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_x
、max_x
、min_y
和max_y
的值。