仅对图像中抛射体添加运动模糊而非整图的高效实现问询
问题:仅对抛射体区域添加水平运动模糊,保留背景清晰
我是图像分析新手,现有一张含静止抛射体的图像,已获取其轮廓数组,格式如下:
contour = [[x1 x2 x3,..., xn] [y1 y2 y3,..., yn]]
其中(x1,y1),(x2,y2),...,(xn,yn)是抛射体轮廓的像素坐标。
我想给抛射体添加水平运动模糊,模拟它相对背景运动的效果。最初直接对整图应用水平模糊核:
# 创建水平模糊核 kernel_h = np.zeros((kernel_size, kernel_size)) # 填充中间行为1 kernel_h[int((kernel_size - 1)/2), :] = np.ones(kernel_size) # 归一化 kernel_h /= kernel_size
然后用卷积实现:
horizonal_blurred_image = cv2.filter2D(src=img, ddepth=-1, kernel=kernel_h)
结果虽然有运动模糊,但背景也被模糊了——这是因为整图都做了水平均值计算,相当于模拟相机运动,而非抛射体相对背景运动。
之后我尝试用cv2.pointPolygonTest判断像素是否在轮廓内或边缘,想给轮廓外像素用单位核(不模糊),轮廓内/边缘用水平核,写了个函数:
def Motion_Blur_Kernel(img, kernel_size,x,y, contour): # img:原始未模糊图像 # kernel_size:核大小,越大模糊效果越强 # contour:轮廓点数组,格式[[x1...xn],[y1...yn]] # 判断像素位置 result = cv2.pointPolygonTest(np.column_stack(contour_x_values, contour_y_values), (x,y), False) if result == 1 or result == 0: # 创建水平核 kernel_h = np.zeros((kernel_size, kernel_size)) kernel_h[int((kernel_size - 1)/2), :] = np.ones(kernel_size) kernel_h /= kernel_size else: # 单位核,不改变像素 kernel_h = [[0, 0, 0], [0, 1, 0], [0, 0, 0]] return kernel_h
但不知道怎么高效把这个核和原图卷积,因为要处理100张图,效率很重要。
高效实现方案
核心思路
不用逐像素判断并应用不同核,而是先分别生成模糊后的抛射体区域和原始背景区域,再通过掩码合并两者,所有操作基于OpenCV/numpy的底层优化实现,速度远快于Python循环。
步骤代码
生成抛射体掩码
用cv2.drawContours快速生成二值掩码,轮廓内/边缘为白色(255),背景为黑色(0):import cv2 import numpy as np # 转换轮廓为OpenCV要求的格式:(N,1,2)的int32数组 contour_opencv = np.column_stack((contour[0], contour[1])).reshape(-1, 1, 2).astype(np.int32) # 创建与原图尺寸一致的单通道掩码 mask = np.zeros_like(img[:, :, 0]) # 填充轮廓内部 cv2.drawContours(mask, [contour_opencv], 0, 255, thickness=cv2.FILLED)对整图应用水平模糊
生成水平核并模糊整张图:kernel_size = 15 # 可根据需求调整,建议用奇数 kernel_h = np.zeros((kernel_size, kernel_size)) kernel_h[int((kernel_size - 1)/2), :] = np.ones(kernel_size) kernel_h /= kernel_size blurred_img = cv2.filter2D(img, ddepth=-1, kernel=kernel_h)合并模糊目标与原始背景
通过掩码拼接两个区域,两种方法任选:# 方法1:numpy索引(简洁高效) result_img = img.copy() result_img[mask == 255] = blurred_img[mask == 255] # 方法2:位运算(适合复杂掩码场景) blurred_object = cv2.bitwise_and(blurred_img, blurred_img, mask=mask) original_background = cv2.bitwise_and(img, img, mask=cv2.bitwise_not(mask)) result_img = cv2.add(blurred_object, original_background)
效率说明
- 所有操作都是OpenCV/numpy的C++底层实现,避免了Python级别的逐像素循环,单张图处理时间与整图卷积相当。
- 处理100张图的总耗时仅为逐像素方法的几十分之一,完全满足效率需求。
注意事项
- 确保轮廓格式转换正确,OpenCV的
drawContours要求输入轮廓为(N,1,2)的int32类型数组。 - 彩色图像无需生成多通道掩码,单通道掩码即可作用于所有颜色通道。
- kernel_size选奇数时,中间行的索引计算更直观(如size=15时,中间行索引为7)。
内容的提问来源于stack exchange,提问作者MOOSE
相关产品推荐
相关产品推荐

