如何仅对图像的非零区域应用同态滤波(频域高通)
图像同态滤波的局部应用问题
我有一个用于图像同态滤波的Python函数,处理光照不均的图像时效果良好:

但处理带有黑色背景的图像时,会出现异常效果:

请问如何仅对这类图像的非零区域应用该滤波?
原始代码
import cv2 import matplotlib.pyplot as plt from scipy import fftpack as fft import numpy as np def homomorphic_filter(img, low_cutoff=0.05, high_cutoff=0.5, order=2, boost=25): rows, cols = img.shape rh, rl, c = high_cutoff, low_cutoff, boost # 创建高斯滤波器 x = np.linspace(-1, 1, cols) y = np.linspace(-1, 1, rows) X, Y = np.meshgrid(x, y) d = np.sqrt(X**2 + Y**2) mask = (rh - rl) * (1 - np.exp(-c * d**order)) + rl # 应用同态滤波 img_log = np.log1p(img) img_fft = fft.fft2(img_log) img_fft_shift = fft.fftshift(img_fft) img_fft_filt = img_fft_shift * mask img_filt = np.real(fft.ifft2(fft.ifftshift(img_fft_filt))) img_exp = np.expm1(img_filt) img_norm = cv2.normalize(img_exp, None, 0, 255, cv2.NORM_MINMAX) return img_norm # 读取图像 image = cv2.imread('/image_1.jpeg') # 转换到HSV色彩空间 hsv_image = cv2.cvtColor(image, cv2.COLOR_RGB2HSV) h, s, v = cv2.split(hsv_image) # 对整个亮度通道应用同态滤波 v_filtered = homomorphic_filter(v) v_filtered = v_filtered.astype(np.uint8) # 转换为与色调、饱和度通道一致的类型 hsv_filtered = cv2.merge((h, s, v_filtered)) image_out = cv2.cvtColor(hsv_filtered, cv2.COLOR_HSV2RGB) # 显示图像 plt.subplot(121), plt.imshow(image) plt.title('Original Image'), plt.xticks([]), plt.yticks([]) plt.subplot(122), plt.imshow(image_out) plt.title('Homomorphic Filtered Image'), plt.xticks([]), plt.yticks([]) plt.show()
解决方案
要实现仅对非零区域应用滤波,核心是提取非零区域掩码,对掩码内的区域单独做滤波,再将结果与原背景合并。修改后的代码如下:
import cv2 import matplotlib.pyplot as plt from scipy import fftpack as fft import numpy as np def homomorphic_filter(img, low_cutoff=0.05, high_cutoff=0.5, order=2, boost=25): rows, cols = img.shape rh, rl, c = high_cutoff, low_cutoff, boost # 创建高斯滤波器 x = np.linspace(-1, 1, cols) y = np.linspace(-1, 1, rows) X, Y = np.meshgrid(x, y) d = np.sqrt(X**2 + Y**2) mask = (rh - rl) * (1 - np.exp(-c * d**order)) + rl # 应用同态滤波 img_log = np.log1p(img) img_fft = fft.fft2(img_log) img_fft_shift = fft.fftshift(img_fft) img_fft_filt = img_fft_shift * mask img_filt = np.real(fft.ifft2(fft.ifftshift(img_fft_filt))) img_exp = np.expm1(img_filt) img_norm = cv2.normalize(img_exp, None, 0, 255, cv2.NORM_MINMAX) return img_norm # 读取黑背景图像 image = cv2.imread('/image_2.jpeg') # 转换到HSV色彩空间(修正:cv2.imread默认读BGR,对应COLOR_BGR2HSV) hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) h, s, v = cv2.split(hsv_image) # 生成非零区域掩码(针对亮度通道v) mask = (v > 0).astype(np.uint8) * 255 # 可选:膨胀掩码优化边缘过渡,避免断层 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) mask = cv2.dilate(mask, kernel, iterations=1) # 提取非零区域的ROI non_zero_coords = np.where(mask > 0) min_y, max_y = np.min(non_zero_coords[0]), np.max(non_zero_coords[0]) min_x, max_x = np.min(non_zero_coords[1]), np.max(non_zero_coords[1]) v_roi = v[min_y:max_y+1, min_x:max_x+1] # 对ROI应用同态滤波 v_roi_filtered = homomorphic_filter(v_roi) v_roi_filtered = v_roi_filtered.astype(np.uint8) # 合并滤波结果与原背景 v_filtered = v.copy() v_filtered[min_y:max_y+1, min_x:max_x+1] = v_roi_filtered # 转换回RGB并显示 hsv_filtered = cv2.merge((h, s, v_filtered)) image_out = cv2.cvtColor(hsv_filtered, cv2.COLOR_HSV2RGB) plt.subplot(121), plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) plt.title('Original Image'), plt.xticks([]), plt.yticks([]) plt.subplot(122), plt.imshow(image_out) plt.title('Homomorphic Filtered Image'), plt.xticks([]), plt.yticks([]) plt.show()
关键修改说明
- 生成掩码:通过
v > 0提取亮度通道的非零区域,生成二值掩码,可选膨胀操作优化边缘过渡。 - 提取ROI:根据掩码定位非零区域的边界,截取对应的亮度通道子区域。
- 局部滤波合并:仅对ROI应用同态滤波,再将结果放回原亮度通道的对应位置,保留背景区域不变。
内容的提问来源于stack exchange,提问作者qwerty123
相关产品推荐
相关产品推荐

