基于Pami06论文的阴影去除代码无法生成无阴影图像的排查请求
阴影去除代码错误排查
以下是代码中导致无法生成正确无阴影图像的关键问题及修复方案:
1. 像素循环内重复拷贝导致梯度更新失效
在remove_shadow_channel的嵌套i,j循环中,每次处理单个像素时都重新执行gradx_temp = gradx_free.copy()和grady_temp = grady_free.copy(),这会覆盖之前对gradx_temp/grady_temp的所有修改,最终只有循环最后一个像素的更新生效,其余阴影区域的梯度完全没有被正确迭代更新。
修复方案:将temp数组的拷贝操作移到嵌套循环外面,确保所有像素的修改能累积到temp中:
while t < num_iterations: # 仅在循环开始时拷贝一次 gradx_temp = gradx_free.copy() grady_temp = grady_free.copy() for i in range(1, channel.shape[0] - 1): for j in range(1, channel.shape[1] - 1): if q_s[i, j]: # 直接在已拷贝的temp上修改,不再重复拷贝 gradx_temp[i, j] = (gradx_free[i - 1, j] + gradx_free[i, j - 1] + gradx_free[i + 1, j] + gradx_free[i, j + 1])/4 grady_temp[i, j] = (grady_free[i - 1, j] + grady_free[i, j - 1] + grady_free[i + 1, j] + grady_free[i, j + 1])/4 gradx_free = gradx_temp grady_free = grady_temp # 后续傅里叶变换及停止条件代码...
2. 阴影区域梯度初始化错误
当前将阴影区域的初始梯度直接设为0:
gradx_free = np.where(q_s, 0, gradx) grady_free = np.where(q_s, 0, grady)
这不符合论文中「保留非阴影区域梯度,迭代修正阴影区域梯度」的逻辑,初始0值会导致后续迭代收敛异常,无法还原阴影区域的真实纹理梯度。
修复方案:初始时保留阴影区域的原始梯度,或直接用邻域均值初始化阴影区域梯度,而非设为0:
# 方案1:保留阴影区域原始梯度,后续迭代修正 gradx_free = gradx.copy() grady_free = grady.copy() # 方案2:用邻域均值初始化阴影区域梯度 gradx_free = gradx.copy() grady_free = grady.copy() for i in range(1, channel.shape[0]-1): for j in range(1, channel.shape[1]-1): if q_s[i,j]: gradx_free[i,j] = (gradx[i-1,j]+gradx[i,j-1]+gradx[i+1,j]+gradx[i,j+1])/4 grady_free[i,j] = (grady[i-1,j]+grady[i,j-1]+grady[i+1,j]+grady[i,j+1])/4
3. 傅里叶重建后的图像亮度偏移问题
通过np.fft.ifft2(Z).real得到log域图像后,未调整图像的直流分量(亮度)。由于Z[0,0] = 0,逆傅里叶变换后的图像均值为0,会导致最终输出图像的亮度严重偏离原始非阴影区域。
修复方案:将重建后的log域图像与原始非阴影区域的log域均值对齐:
# 转换回对数域后的处理 shadow_free_channel_log = np.fft.ifft2(Z).real # 对齐非阴影区域的亮度均值 non_shadow_mask = ~q_s if np.any(non_shadow_mask): mean_log = np.mean(channel_log[non_shadow_mask]) shadow_free_channel_log += mean_log - np.mean(shadow_free_channel_log) # 再转换回原始域 shadow_free_channel_exp = np.expm1(shadow_free_channel_log)
4. 输入图像数值范围问题
如果输入的image是0-255的uint8类型,直接对其做log1p会导致数值范围过大(log(256)≈5.54),后续梯度计算和傅里叶变换容易出现数值不稳定。
修复方案:处理前先将图像归一化到0-1的浮点数范围:
def remove_shadow(image, q_s, epsilon, num_iterations): # 归一化到0-1范围 image_norm = image.astype(np.float32) / 255.0 shadow_free_channels = [remove_shadow_channel(image_norm[:, :, i], q_s, epsilon, num_iterations) for i in range(3)] shadow_free_image = np.stack(shadow_free_channels, axis=-1) * 255.0 shadow_free_image = np.clip(shadow_free_image, 0, 255).astype(np.uint8) return shadow_free_image
内容的提问来源于stack exchange,提问作者Triks49
相关产品推荐
相关产品推荐

