基于OpenCV的未知PSF运动模糊去除技术方案问询
针对横向平移运动模糊的Python去模糊方案(基于OpenCV)
核心思路
由于是横向平移拍摄,运动模糊的PSF(点扩散函数)为水平方向线性核,无需手动定义——可通过图像频域分析或帧间运动估计自动生成,再结合维纳滤波/Lucy-Richardson去卷积算法修复模糊,提升画作提取质量。
实现步骤与代码
1. 从视频帧中定位并提取画作区域
先截取视频帧,通过边缘检测定位画面中的画作(避免背景干扰):
import cv2 import numpy as np # 读取视频指定帧(示例:读取第100帧) cap = cv2.VideoCapture("museum_video.mp4") cap.set(cv2.CAP_PROP_POS_FRAMES, 100) ret, frame = cap.read() cap.release() # 转为灰度图(去模糊对灰度图处理更稳定,后续可转回彩色) gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 边缘检测+轮廓筛选定位画作 edges = cv2.Canny(gray, 50, 150) contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) max_contour = max(contours, key=cv2.contourArea) # 假设画作是最大轮廓 x, y, w, h = cv2.boundingRect(max_contour) painting_gray = gray[y:y+h, x:x+w]
2. 自动生成横向平移PSF
通过频域分析估计模糊长度,再生成对应水平线性核:
def create_horizontal_psf(blur_length, kernel_size=31): # 生成水平方向运动模糊核 psf = np.zeros((kernel_size, kernel_size)) center = kernel_size // 2 psf[center, center - blur_length//2 : center + blur_length//2 + 1] = 1.0 psf /= psf.sum() # 归一化 return psf def estimate_blur_length(gray_img): # 频域分析自动估计模糊长度 fft = np.fft.fft2(gray_img) fft_shift = np.fft.fftshift(fft) magnitude = 20 * np.log(np.abs(fft_shift)) # 提取水平中线频谱,计算峰值间隔推导模糊长度 mid_row = magnitude.shape[0] // 2 horizontal_spectrum = magnitude[mid_row, :] peaks = np.where(np.diff(np.sign(np.diff(horizontal_spectrum))) < 0)[0] + 1 if len(peaks) >= 2: blur_length = int(np.round(gray_img.shape[1] / (peaks[1] - peaks[0]))) return max(5, min(blur_length, 50)) # 限制合理范围 return 15 # 默认值 # 生成适配当前帧的PSF blur_len = estimate_blur_length(painting_gray) psf = create_horizontal_psf(blur_len)
3. 维纳滤波去模糊(OpenCV实现)
利用频域维纳滤波修复模糊,兼顾去模糊与噪声抑制:
def wiener_deblur(img, psf, noise_var=0.001): img_float = img.astype(np.float32) / 255.0 psf_float = psf.astype(np.float32) # 频域转换与滤波计算 img_fft = np.fft.fft2(img_float) psf_fft = np.fft.fft2(psf_float, s=img_float.shape) signal_var = np.var(img_float) wiener_filter = np.conj(psf_fft) / (np.abs(psf_fft)**2 + noise_var / signal_var) deblurred_fft = img_fft * wiener_filter # 逆变换回空域并归一化 deblurred = np.abs(np.fft.ifft2(deblurred_fft)) deblurred = (deblurred * 255).astype(np.uint8) return deblurred # 执行去模糊 deblurred_painting = wiener_deblur(painting_gray, psf) # 对比显示 cv2.imshow("Original", painting_gray) cv2.imshow("Deblurred", deblurred_painting) cv2.waitKey(0) cv2.destroyAllWindows()
4. 可选:Lucy-Richardson迭代去模糊
若维纳滤波效果不足,可使用迭代式Lucy-Richardson算法(需安装opencv-contrib-python):
from cv2.ximgproc import lucyRichardsonDeconvolution img_float = painting_gray.astype(np.float32) / 255.0 psf_float = psf.astype(np.float32) # 迭代10次(次数可根据模糊程度调整) deblurred_lucy = lucyRichardsonDeconvolution(img_float, psf_float, 10) deblurred_lucy = (deblurred_lucy * 255).astype(np.uint8) cv2.imshow("Lucy-Richardson Deblurred", deblurred_lucy) cv2.waitKey(0)
优化建议
- 帧间运动校准:通过
cv2.calcOpticalFlowFarneback计算相邻帧光流,精准获取平移距离,进一步提升PSF准确性。 - 预处理降噪:去模糊前用
cv2.fastNlMeansDenoising抑制噪声,避免去卷积过程放大干扰。 - 彩色图适配:对BGR通道分别执行去模糊,再合并为彩色图像,保留画作色彩信息。
内容的提问来源于stack exchange,提问作者FlorNeufkens
相关产品推荐
相关产品推荐

