图像处理:去除背景光照梯度【优先使用Python实现】
我太懂你这个踩坑点了——直接灰度相减效果拉胯,十有八九是因为光照梯度不是简单的叠加关系,而是乘法性的(光照是给每个像素乘上一个渐变的系数),再加上两张图可能存在细微的光照波动或者拍摄时的小偏移,直接相减自然没用。下面给你几个亲测有效的改进方案:
方案1:背景归一化(除法校正)
这是处理光照渐变最经典的方法,核心思路是:既然光照是乘法影响,那把目标图和背景图做除法,就能按比例消除背景的光照梯度,让锥体的亮度更均匀。
代码示例(用PIL+Numpy实现):
from PIL import Image import numpy as np # 读取图像并转为灰度浮点型(避免整数除法丢失精度) target_img = np.array(Image.open('../Pics/image.png').convert('L')).astype(np.float32) background_img = np.array(Image.open('../Pics/background.png').convert('L')).astype(np.float32) # 加个小epsilon防止除以0的情况 epsilon = 1e-5 # 归一化后把亮度拉回0-255范围 normalized_img = (target_img / (background_img + epsilon)) * 255 # 裁剪超出范围的像素值,转回uint8格式 normalized_img = np.clip(normalized_img, 0, 255).astype(np.uint8) # 保存结果 Image.fromarray(normalized_img).save('../Pics/corrected_cone.png')
这个方法出来的结果,锥体的亮度会明显更均匀,背景的渐变也会被大幅削弱。
方案2:自适应阈值+背景差分
如果除法后还是残留一些噪点或者模糊的边缘,可以结合自适应阈值来精准提取锥体:
代码示例(用OpenCV实现):
import cv2 import numpy as np # 读取灰度图 target = cv2.imread('../Pics/image.png', cv2.IMREAD_GRAYSCALE) background = cv2.imread('../Pics/background.png', cv2.IMREAD_GRAYSCALE) # 先计算两张图的差分 diff = cv2.absdiff(target, background) # 用自适应阈值处理——局部区域自动调整阈值,完美适配光照不均 adaptive_thresh = cv2.adaptiveThreshold( diff, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2 ) # 可选:用形态学操作去掉小噪点 kernel = np.ones((3,3), np.uint8) cleaned_result = cv2.morphologyEx(adaptive_thresh, cv2.MORPH_OPEN, kernel) cv2.imwrite('../Pics/segmented_cone.png', cleaned_result)
这个方法能直接把锥体从背景里抠出来,适合你只关心锥体对象的需求。
方案3:先对齐图像(如果有偏移)
如果拍摄时相机动了哪怕一点点,两张图的像素不对齐,前面的方法都会有重影或模糊。这时候先做图像对齐:
代码示例(用Scikit-Image实现):
from skimage.feature import match_template from skimage.transform import warp_affine from PIL import Image import numpy as np target = np.array(Image.open('../Pics/image.png').convert('L')) background = np.array(Image.open('../Pics/background.png').convert('L')) # 用模板匹配找两张图的偏移量 match_result = match_template(target, background) y_shift, x_shift = np.unravel_index(np.argmax(match_result), match_result.shape) # 生成变换矩阵,把目标图对齐到背景图的位置 transform_matrix = np.array([[1, 0, -x_shift], [0, 1, -y_shift]]) aligned_target = warp_affine(target, transform_matrix, background.shape) # 对齐后再用方案1或方案2处理就行 aligned_target = (aligned_target / (background + 1e-5)) * 255 aligned_target = np.clip(aligned_target, 0, 255).astype(np.uint8) Image.fromarray(aligned_target).save('../Pics/aligned_corrected.png')
总结
优先试方案1的除法归一化,这是解决光照梯度最直接的方法;如果结果有模糊或重影,就先做方案3的对齐;最后用方案2的自适应阈值来精准提取锥体。
内容的提问来源于stack exchange,提问作者Liris
相关产品推荐
相关产品推荐

