You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

卷积后星系表面亮度图出现黑边,求保尺寸的解决方法及成因

卷积星系表面亮度图像的黑边问题与解决方法

问题描述

我正在对未剪切和已剪切星系的表面亮度执行高斯核卷积,以模拟大气与仪器像差的影响。但卷积后结果图的外缘出现黑条,属于异常现象。

原始数组尺寸为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)

黑边成因分析

  1. 零填充引入边缘伪影:代码中使用np.zeros创建填充区域,这些零值与原始图像边缘像素卷积时,会拉低边缘区域的亮度值,形成黑边。
  2. 循环遍历范围错误:卷积循环基于原始图像的尺寸(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 15:00:00