MATLAB与Python图像显著图差异:暗斑问题的原因及解决方案
图像显著图计算的跨平台差异问题分析
问题背景
针对一张450x620的图像,通过3x3中值滤波与35x35均值滤波结果相减取绝对值的方式计算显著图。MATLAB实现可得到正常输出,但使用PyTorch+OpenCV在Colab中实现时,部分区域的均值滤波与中值滤波像素值完全相同,导致生成图像出现暗斑。
可能原因
- 数据类型与精度差异:MATLAB中
imread读取灰度图后转double是0-255的浮点值,滤波全程基于浮点运算,精度保留完整;而OpenCV的cv.imread默认读取为uint8整数型,后续滤波直接做整数运算,会丢失小数精度,平缓区域的滤波结果易完全重合。 - 边界填充策略不一致:MATLAB的
imfilter使用'replicate'(复制边界像素)填充方式,而OpenCV的cv.blur、cv.medianBlur默认采用零填充。尤其35x35大核均值滤波时,边界区域的均值会被零拉低,与中值滤波结果更易出现完全相等的情况。 - 滤波计算逻辑差异:OpenCV均值滤波直接对整数像素求和取整,中值滤波也仅返回整数结果;MATLAB则全程保持浮点运算,即使是平缓区域,滤波结果也会保留微小的小数差异,不会出现完全相等的情况。
解决方案
- 统一浮点数据类型:读取图像后立即转为浮点型,确保滤波运算在高精度下进行:
import numpy as np import cv2 im1 = cv2.imread('/content/IR12.png', cv2.IMREAD_GRAYSCALE).astype(np.float64) im2 = cv2.imread('/content/VIS12.png', cv2.IMREAD_GRAYSCALE).astype(np.float64) - 对齐边界填充策略:用
cv2.filter2D替代cv2.blur,手动设置borderType=cv2.BORDER_REPLICATE,和MATLAB的边界处理逻辑保持一致;中值滤波可使用scipy.ndimage.median_filter自定义边界填充:from scipy.ndimage import median_filter # 3x3均值滤波(复制边界) kernel_3 = np.ones((3,3), np.float64) / 9 base1 = cv2.filter2D(im1, -1, kernel_3, borderType=cv2.BORDER_REPLICATE) # 35x35均值滤波(复制边界) kernel_35 = np.ones((35,35), np.float64) / (35*35) meanIR = cv2.filter2D(im1, -1, kernel_35, borderType=cv2.BORDER_REPLICATE) # 3x3中值滤波(复制边界) medIR = median_filter(im1, size=3, mode='nearest') - 避免权重计算异常:计算权重时给分母添加极小值
epsilon,防止salIR + salVIS为0导致的暗斑问题:eps = 1e-8 weightIR = salIR / (salIR + salVIS + eps) weightVIS = salVIS / (salIR + salVIS + eps) - 后处理修正:生成融合图像后,将数值钳位到0-255范围并转为
uint8,确保可视化效果正常:fused_np = np.clip(fused.numpy(), 0, 255).astype(np.uint8) cv2_imshow(fused_np)
代码对比与输出
修正前的Google Colab PyTorch代码
# Load the IR and visible images im1 = cv.imread('/content/IR12.png') im1 = cv.cvtColor(im1, cv.COLOR_RGB2GRAY) im2 = cv.imread('/content/VIS12.png') im2 = cv.cvtColor(im2, cv.COLOR_RGB2GRAY) IR = torch.from_numpy(im1).double() VIS = torch.from_numpy(im2).double() # Apply mean filtering base1 = cv.blur(im1,(3,3)) base2 = cv.blur(im2,(3,3)) base1 = torch.from_numpy(base1).double() base2 = torch.from_numpy(base2).double() # Compute detail maps detail1 = IR - base1 detail2 = VIS - base2 #cv2_imshow(detail1) # Apply median filtering medIR = cv.medianBlur(im1, 3) medIR = torch.from_numpy(medIR).double() medVIS = cv.medianBlur(im2, 3) medVIS = torch.from_numpy(medVIS).double() # Apply mean filtering using a larger kernel meanIR = cv.blur(im1,(35,35)) meanIR = torch.from_numpy(meanIR).double() meanVIS = cv.blur(im2,(35,35)) meanVIS = torch.from_numpy(meanVIS).double() # Compute saliency maps salIR = abs(meanIR - medIR) cv2_imshow(salIR.numpy()) salVIS = abs(meanVIS - medVIS) #salIR = torch.from_numpy(salIR).double() #salVIS = torch.from_numpy(salVIS).double() # Compute weight maps weightIR = salIR / (salIR + salVIS) weightVIS = salVIS / (salIR + salVIS) # Fuse the base and detail maps basef = 0.5 * (base1 + base2) detailf = (weightIR * detail1) + (weightVIS * detail2) # Compute the fused image fused = torch.add(basef,detailf) # Convert the fused image to a NumPy array fused_np = fused.numpy() cv2_imshow(fused_np)
修正前Python输出
MATLAB代码
Im2 = imread('D:\ankan\IV_images\IV_images\VIS12.png'); Im1 = imread('D:\ankan\IV_images\IV_images\IR12.png'); IR = double(Im1); VIS = double(Im2); [m,n] = size(Im2); kernel1 = 3; kernel2 = 35; meanFilter1 = ones(kernel1)/(kernel1^2); meanFilter2 = ones(kernel2)/(kernel2^2); base1 = imfilter (IR,meanFilter1,'conv','replicate'); base2 = imfilter (VIS,meanFilter1,'conv','replicate'); detail1 = IR-base1; detail2 = VIS-base2; meanIR = imfilter (IR,meanFilter2,'conv','replicate'); meanVIS = imfilter (VIS,meanFilter2,'conv','replicate'); medIR = medfilt2(IR,[3,3]); medVIS = medfilt2(VIS,[3,3]); salIR = abs(meanIR - medIR); salVIS = abs(meanVIS - medVIS); weightIR = salIR./(salIR+salVIS); weightVIS = salVIS./(salIR+salVIS); basef = 0.5*(base1+base2); detailf = (weightIR.*detail1) + (weightVIS.*detail2); fused = basef+detailf; imshow(uint8(fused))
MATLAB输出
内容的提问来源于stack exchange,提问作者Ankan Banerjee
相关产品推荐
相关产品推荐

