卷积后星系表面亮度图出现黑边,求保尺寸的解决方法及成因
卷积星系表面亮度图像的黑边问题与解决方法
问题描述
我正在对未剪切和已剪切星系的表面亮度执行高斯核卷积,以模拟大气与仪器像差的影响。但卷积后结果图的外缘出现黑条,属于异常现象。
原始数组尺寸为64×64,核尺寸为5×5,padding设为2,stride为1。根据卷积尺寸公式 [(W−K+2P)/S]+1,输出数组应与原图尺寸一致,padding设置逻辑无误,但无法定位黑边成因。
将padding改为0时黑边消失,但输出尺寸会缩小。需要在保持输出尺寸与输入一致的前提下消除黑边,同时明确黑边出现的原因。
相关代码
生成星系图像的函数
import numpy as np def generateGalaxy(size, r_disk, f_brightness_ratio, r_bulge): x = np.arange(-size/2, size/2) y = np.arange(-size/2, size/2) X, Y = np.meshgrid(x, y) r = (X**2 + Y**2)**0.5 values = np.exp(-r/r_disk) + f_brightness_ratio*np.exp(-(r/r_bulge)**0.25) return values, X, Y
自定义2D卷积函数
def convolve2D(image, kernel, padding = 2, strides =1): kernel = np.flipud (np.fliplr(kernel)) xKernShape = kernel.shape[0] yKernShape = kernel.shape[1] xImgShape = image.shape[0] yImgShape = image.shape[1] xOutput = int(((xImgShape-xKernShape + 2* padding)/strides)+1) yOutput = int(((yImgShape-yKernShape + 2* padding)/strides)+1) output = np.zeros((xOutput, yOutput)) if padding != 0: imagePadded = np.zeros((image.shape[0] + padding *2, image.shape[1]+padding*2)) imagePadded[int(padding):int(-1*padding), int(padding):int(-1*padding)] = image else: imagePadded = image for y in range(image.shape[1]): # y value goes from 0 to image.shape[1] from top to down if y > image.shape[1] - yKernShape: break if y % strides == 0: for x in range(image.shape[0]): if x > image.shape[0] - xKernShape: break try: if x % strides == 0: output [x,y] = (kernel * imagePadded [x:x+xKernShape, y:y+yKernShape]).sum() except: break return output
生成高斯核的函数
def gkern(sidelength, sigma): """ creates gaussian kernel with side length `l` and a sigma of `sig` """ ax = np.linspace(-(sidelength - 1) / 2., (sidelength - 1) / 2., sidelength) gauss = np.exp(-0.5 * np.square(ax) / np.square(sigma)) kernel = np.outer(gauss, gauss) return kernel / np.sum (kernel)
黑边成因分析
- 零填充引入边缘伪影:代码中使用
np.zeros创建填充区域,这些零值与原始图像边缘像素卷积时,会拉低边缘区域的亮度值,形成黑边。 - 循环遍历范围错误:卷积循环基于原始图像的尺寸(64×64)进行遍历,而非填充后的图像尺寸(68×68)。这导致输出数组的边缘位置未被正确计算,保留了初始化的零值,表现为黑条。
解决方案
1. 替换零填充为合理的填充方式
对于星系图像这类连续分布的数据,使用镜像填充或边缘延伸填充可以保持边缘像素的连续性,避免零值带来的伪影。修改convolve2D中的填充逻辑:
if padding != 0: # 镜像填充,也可选择'mode=edge'进行边缘延伸 imagePadded = np.pad(image, pad_width=padding, mode='reflect') else: imagePadded = image
2. 修正卷积循环的遍历范围
循环应基于填充后图像的尺寸和步长来计算索引,确保所有输出位置都被正确赋值。替换原循环代码:
# 遍历填充后图像的有效卷积区域,步长为strides for y in range(0, imagePadded.shape[1] - yKernShape + 1, strides): for x in range(0, imagePadded.shape[0] - xKernShape + 1, strides): # 计算输出数组的对应索引 out_x = x // strides out_y = y // strides output[out_x, out_y] = (kernel * imagePadded[x:x+xKernShape, y:y+yKernShape]).sum()
3. 验证效果
修改后,输出尺寸会保持与输入一致(64×64),同时边缘区域的卷积计算使用了连续的填充值,不会出现黑边。
内容的提问来源于stack exchange,提问作者Gene
相关产品推荐
相关产品推荐

