Skip to main content

2.1OpenCV预处理

OpenCV预处理

预处理是基本流程,和数据分析前先数据清洗一样。有固定的流程和套路,任何一本Opencv教材都包含这部分内容。

感兴趣区域

好处:

  • 减少无关信息的干扰
  • 加快计算速度

地平线以上的内容其实和我们关系不大,只有检测行人的时候才会有影响。可以在检测到斑马线的时候计算完整图片。

所以我们先设置roi(感兴趣区域)为图像的下面的50%

def extract_roi(image ,roi_start_ratio=0.5):
"""提取感兴趣区域(ROI)

Args:
image: 输入的BGR图像
roi_start_ratio: 感兴趣区域。(0表示整张都感兴趣、0.5表示下半部分感兴趣)

Returns:
roi_image: ROI区域图像
"""
# 获取图像尺寸
height, width = image.shape[:2]

# 计算ROI起始行(从图像中部开始,关注前方地面)
roi_start = int(height * roi_start_ratio)

# 提取ROI区域(图像下半部分)
roi_image = image[roi_start:height, 0:width]

return roi_image

灰度化与二值化

这一步一般是为后面的边缘检测做铺垫,简单的算法也可以直接基于灰度化和二值化的结果做处理。

二值化的算法就很多了,我们的世界是有光源和树木的投影的,另外计算速度要快,所以排除固定阈值法Otsu's 方法自适应高斯法

这里全局平均值法自适应均值法和我们可以都写出来,后面看情况选择。


def preprocess_and_binarize(bgr_image, method='mean', **kwargs):
"""完整的预处理和二值化流程

invert: 是否反向二值化(True=低于阈值变白,False=高于阈值变白)

Args:
bgr_image: 输入的BGR彩色图像
method: 二值化方法,可选 'mean', 'adaptive'
**kwargs: 各方法的额外参数
- invert: 是否反向二值化
- block_size: 自适应方法的邻域大小
- C: 自适应方法的常数偏移

Returns:
binary_image: 二值化结果
"""
# Step 1: 灰度化
gray_image = cv2.cvtColor(bgr_image, cv2.COLOR_BGR2GRAY)

# Step 2: 根据选择的方法进行二值化
invert = kwargs.get('invert', False)

if method == 'adaptive':
# 选择二值化类型
thresh_type = cv2.THRESH_BINARY_INV if invert else cv2.THRESH_BINARY

# 自适应均值法:每个像素的阈值由其邻域的均值决定
binary_image = cv2.adaptiveThreshold(
gray_image,
255, # 最大值
cv2.ADAPTIVE_THRESH_MEAN_C, # 使用邻域均值
thresh_type, # 二值化类型(正向或反向)
11, # 邻域大小(必须是奇数),越大对光照变化越不敏感
2 # 常数偏移从均值中减去的常数,用于微调阈值
)
elif method == 'mean':
thresh_type = cv2.THRESH_BINARY_INV if invert else cv2.THRESH_BINARY
_, binary_image = cv2.threshold(gray_image, gray_image.mean(), 255, thresh_type)
else:
raise ValueError(f"未知的二值化方法: {method}")

return binary_image
去噪

这个项目中都是纯色,只有斑马线附近有异常色块。考虑到实际摄像头会有噪点。做个简单的开运算(先腐蚀后膨胀,用于去除图像中的小噪声)

def denoise_binary_image(binary_image, kernel_size=(5, 5)):
"""使用形态学开运算去除二值图像中的噪声

Args:
binary_image: 输入的二值化图像(0或255)
kernel_size: 结构元素大小,默认为(5, 5)

Returns:
denoised_image: 去噪后的二值图像
"""
# 创建结构元素(矩形核)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, kernel_size)

# 开运算 = 先腐蚀后膨胀
# 作用:去除小的白色噪点(孤立的亮点)
denoised_image = cv2.morphologyEx(binary_image, cv2.MORPH_OPEN, kernel)

return denoised_image

可视化

预处理完成之后就可以可视化展示了,这里我觉得可以展示感兴趣的原图、去噪后的图。

def visualize_preprocessing(roi_image, binary_image):
"""可视化预处理的各个阶段

Args:
roi_image: 感兴趣区域的原图(ROI)
denoised_image: 去噪后的二值化图像
"""
# 显示ROI区域原图
cv2.imshow('ROI', roi_image)

# 显示去噪后的结果
cv2.imshow('ROI-II', binary_image)

cv2.waitKey(1)