如何检测图像中的模糊区域?重点识别运动模糊
图像运动模糊区域检测方案优化
需求说明
需要实现图像中模糊区域的检测与选中,重点针对运动模糊场景:比如移动硬币照片的左右模糊区域、移动车辆照片的模糊区域。此前采用梯度搜索方法效果最优,但该方法在非均匀背景下失效,无法检测车辆照片中的模糊区域,原实现代码如下:
import cv2 import numpy as np import blure as bl def put_mask(image, mask): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) return cv2.filter2D(src=gray, ddepth=-1, kernel=mask) width, height, x, y = 550, 400, 50, 100 img = cv2.imread("car.jpg") image = img[y:y+height, x:x+width] gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) mask_1 = np.array([ [1, 0, -1], [2, 0, -2], [1, 0, -1]]) mask_2 = np.array([ [1, 2, 1], [0, 0, 0], [-1, -2, -1]]) masked_1 = cv2.filter2D(gray, ddepth=-1, kernel=mask_1) masked_2 = cv2.filter2D(gray, ddepth=-1, kernel=mask_2) masked = cv2.bitwise_or(masked_1, masked_2) cv2.imshow("edges", image) cv2.imshow("grad", masked) cv2.waitKey(0) cv2.destroyAllWindows()
原方法核心问题:所用的Sobel梯度算子仅对边缘强度敏感,非均匀背景的高反差会掩盖模糊区域的低梯度特征,导致检测失效。以下是三种针对性优化方案:
方案1:局部拉普拉斯方差检测
利用拉普拉斯算子的方差反映局部清晰度——模糊区域的拉普拉斯方差远小于清晰区域。通过分块计算方差并阈值化,可得到模糊区域掩码。
实现代码
import cv2 import numpy as np def detect_blur_laplacian(image, block_size=25, threshold=30): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) laplacian = cv2.Laplacian(gray, cv2.CV_64F) h, w = gray.shape blur_mask = np.zeros_like(gray, dtype=np.uint8) # 分块遍历计算方差 for y in range(0, h, block_size): for x in range(0, w, block_size): block = laplacian[y:y+block_size, x:x+block_size] var = np.var(block) if var < threshold: blur_mask[y:y+block_size, x:x+block_size] = 255 # 形态学操作优化掩码,消除噪声 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5)) blur_mask = cv2.morphologyEx(blur_mask, cv2.MORPH_CLOSE, kernel) return blur_mask # 测试逻辑 img = cv2.imread("car.jpg") width, height, x, y = 550, 400, 50, 100 image = img[y:y+height, x:x+width] blur_mask = detect_blur_laplacian(image) # 叠加掩码显示检测结果 result = cv2.bitwise_and(image, image, mask=blur_mask) cv2.imshow("Original", image) cv2.imshow("Blur Mask", blur_mask) cv2.imshow("Detected Blur Areas", result) cv2.waitKey(0) cv2.destroyAllWindows()
适用场景
通用模糊检测,支持运动模糊、失焦模糊等多种类型,对非均匀背景有较好适应性。
方案2:运动模糊定向梯度分析
运动模糊具有方向性(如水平运动模糊会导致垂直方向梯度幅度显著降低),通过分析不同方向梯度的均值差异,可精准定位运动模糊区域。
实现代码
import cv2 import numpy as np def detect_motion_blur(image, threshold=15): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 计算x、y方向Sobel梯度幅度 sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3) sobel_y = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3) mag_x = np.abs(sobel_x) mag_y = np.abs(sobel_y) # 局部平滑梯度幅度,减少噪声干扰 mean_x = cv2.blur(mag_x, (15,15)) mean_y = cv2.blur(mag_y, (15,15)) # 判定运动模糊:某一方向梯度均值远低于另一方向,且整体均值低于阈值 blur_mask = np.zeros_like(gray, dtype=np.uint8) mask_horizontal = (mean_y < threshold) & (mean_x > mean_y * 1.5) mask_vertical = (mean_x < threshold) & (mean_y > mean_x * 1.5) blur_mask[mask_horizontal | mask_vertical] = 255 # 形态学操作优化掩码 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7)) blur_mask = cv2.morphologyEx(blur_mask, cv2.MORPH_OPEN, kernel) return blur_mask # 测试逻辑 img = cv2.imread("car.jpg") width, height, x, y = 550, 400, 50, 100 image = img[y:y+height, x:x+width] motion_blur_mask = detect_motion_blur(image) result = cv2.bitwise_and(image, image, mask=motion_blur_mask) cv2.imshow("Original", image) cv2.imshow("Motion Blur Mask", motion_blur_mask) cv2.imshow("Detected Motion Blur", result) cv2.waitKey(0) cv2.destroyAllWindows()
适用场景
专门针对运动模糊检测,可区分水平/垂直等运动方向,适合车辆、移动物体的运动模糊检测。
方案3:归一化梯度改进(解决非均匀背景问题)
通过CLAHE局部对比度增强对图像做归一化处理,消除非均匀背景的干扰,再计算梯度幅度,筛选低梯度的模糊区域。
实现代码
import cv2 import numpy as np def detect_blur_normalized_gradient(image, threshold=20): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # CLAHE增强局部对比度,弱化背景不均影响 clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) gray_clahe = clahe.apply(gray) # 计算梯度幅度 sobel_x = cv2.Sobel(gray_clahe, cv2.CV_64F, 1, 0, ksize=3) sobel_y = cv2.Sobel(gray_clahe, cv2.CV_64F, 0, 1, ksize=3) mag = np.sqrt(sobel_x**2 + sobel_y**2) # 局部平滑梯度幅度 mag_blur = cv2.blur(mag, (10,10)) # 阈值化得到模糊区域掩码 blur_mask = np.where(mag_blur < threshold, 255, 0).astype(np.uint8) # 形态学操作优化掩码 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5)) blur_mask = cv2.morphologyEx(blur_mask, cv2.MORPH_CLOSE, kernel) return blur_mask # 测试逻辑 img = cv2.imread("car.jpg") width, height, x, y = 550, 400, 50, 100 image = img[y:y+height, x:x+width] blur_mask = detect_blur_normalized_gradient(image) result = cv2.bitwise_and(image, image, mask=blur_mask) cv2.imshow("Original", image) cv2.imshow("Normalized Gradient Blur Mask", blur_mask) cv2.imshow("Detected Blur", result) cv2.waitKey(0) cv2.destroyAllWindows()
适用场景
针对非均匀背景下的模糊检测,是原梯度方法的直接优化,兼容性强。
内容的提问来源于stack exchange,提问作者Лев Изъюров
相关产品推荐
相关产品推荐

