一、为什么要做"图像预处理"
"小陈,你手机拍的书封面,直接丢给识别程序,八成效果很差。"老周打开一张拍糊的照片,"因为真实世界的照片有各种'脏':"
真实照片的"脏":
① 噪声:传感器/光线带来的颗粒(雪花点)
② 模糊:手抖、对焦不准
③ 光线差:太暗、太亮、有阴影
④ 倾斜/透视:拍照角度歪
⑤ 背景杂乱:书背后有别的书、桌子
图像预处理(Preprocessing)= 在"识别"之前,先"洗图"
目标:突出有用的信息,去掉干扰信息
图像处理在视觉流程中的位置:
原始图像 → 预处理(本章)→ 特征提取/识别(后面)→ 结果
"预处理是视觉流水线的'第一道工序'——图洗得干不干净,直接决定后面识别准不准。老话:'垃圾进,垃圾出'(Garbage in, garbage out)。"
二、灰度化与二值化:从"彩色"到"黑白"
"很多处理不需要颜色,先简化。"老周说:
import cv2
img = cv2.imread("book_cover.jpg")
# 灰度化:彩色 → 灰度(去掉颜色,保留亮度)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化:灰度 → 纯黑/纯白(0 或 255)
# 全局阈值:像素值 > 127 变白,否则变黑
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 自适应阈值:不同区域用不同阈值(应对光照不均,更常用)
adaptive = cv2.adaptiveThreshold(gray, 255,
cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
为什么要灰度/二值化?
① 数据量小:3 通道 → 1 通道(算得快)
② 很多算法只需要亮度信息
③ 二值化让"前景/背景"分明(文字、形状提取)
例子:OCR 之前,通常先灰度+二值化
→ 文字变成白底黑字,识别更准
Otsu 阈值(自动找最佳阈值):
_, binary = cv2.threshold(gray, 0, 255,
cv2.THRESH_BINARY + cv2.THRESH_OTSU)
→ 不用手动设阈值,算法自动找
"灰度化是'减负',二值化是'分家'——把图变成'背景/前景'两家人,后面好处理。OCR、文档扫描都靠它。"
三、滤波:去掉噪声的"磨皮术"
"照片上的颗粒噪声,怎么去掉?用滤波(Filter)。"老周说:
import cv2
# 均值滤波:每个像素 = 周围像素的平均值(简单,但会模糊)
blur = cv2.blur(gray, (5, 5))
# 高斯滤波:加权平均(中间权重高,去噪声更自然,常用)
gauss = cv2.GaussianBlur(gray, (5, 5), 0)
# 中值滤波:取中位数(去椒盐噪声最好,但慢)
median = cv2.medianBlur(gray, 5)
# 双边滤波:去噪声同时保留边缘(磨皮神器,贵)
bilateral = cv2.bilateralFilter(img, 9, 75, 75)
滤波的本质:
用一个"小窗口"(卷积核)滑过图像
每个像素 = 窗口内像素的某种"统计值"
→ 把"异常值"(噪声)抹平
三种滤波对比:
均值/高斯:平滑去噪(会模糊边缘)
中值:去椒盐噪声强(保留边缘较好)
双边:去噪+保边(美颜原理,但慢)
调参:窗口大小(3x3 / 5x5 / 7x7)
越大越模糊,去噪越强
→ 平衡:去噪效果 vs 细节保留
"滤波是'给图像磨皮'——去噪、平滑,但别把细节磨没了。'去噪 vs 保细节'的平衡,是图像处理的永恒主题。"
四、边缘检测:找出物体的"轮廓线"
"识别物体,先找轮廓。边缘检测就是干这个的。"老周说:
import cv2
# Canny 边缘检测(最常用,效果最好)
edges = cv2.Canny(gray, 50, 150)
# 参数:低阈值 50,高阈值 150
# 梯度大于 150 = 确定边缘;小于 50 = 非边缘;中间 = 看连接
# 边缘检测前:先高斯模糊去噪(Canny 对噪声敏感)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
edges = cv2.Canny(blurred, 50, 150)
# 其他边缘算子(了解)
# Sobel:一阶导数算子(水平/垂直边缘)
sobel_x = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
# Laplacian:二阶导数算子(对噪声敏感)
边缘 = 像素亮度"突变"的地方
书和背景交界处:亮度跳变 → 边缘
书脊上的字:也是边缘
Canny 原理(经典五步):
① 高斯滤波去噪
② 计算梯度(方向和强度)
③ 非极大值抑制(边缘变细)
④ 双阈值(确定强/弱边缘)
⑤ 滞后连接(弱边缘跟着强边缘)
用途:
找物体轮廓 → 后续轮廓分析
找书的边界 → 透视矫正(把歪的书扶正)
车道线/文字线检测
"边缘是图像里'信息最密集'的地方——物体边界、文字笔画、纹理转折,全在边缘上。Canny 是边缘检测的'标配',面试常问原理。"
五、形态学操作:给形状"整形"
"二值化后的图形,往往有毛刺、有小洞——用形态学(Morphology)修整。"老周说:
import cv2
import numpy as np
kernel = np.ones((3, 3), np.uint8)
# 腐蚀:白色区域"瘦一圈"(去小毛刺、断开相连)
eroded = cv2.erode(binary, kernel, iterations=1)
# 膨胀:白色区域"胖一圈"(补小洞、连接断裂)
dilated = cv2.dilate(binary, kernel, iterations=1)
# 开运算 = 先腐蚀后膨胀(去小噪点,保留形状)
opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)
# 闭运算 = 先膨胀后腐蚀(补小洞,保留形状)
closing = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
形态学用途:
开运算:去掉孤立小点(文字提取时去噪点)
闭运算:填平小缺口(把断开的文字笔画连起来)
腐蚀/膨胀:控制区域大小
场景:OCR 前
文字二值化后 → 闭运算把"断笔画"连起来 → 识别更准
kernel 大小:窗口大小,影响整形力度
"形态学是二值图的'整形手术'——去掉该去的、补上该补的。OCR、轮廓提取、区域分析都用得上。"
六、直方图与均衡化:拯救过暗/过亮的图
"拍照光线不好,图太暗怎么办?直方图均衡化救场。"老周说:
import cv2
# 直方图:统计每个亮度值有多少像素
# 横轴 0-255 亮度,纵轴 像素数量
hist = cv2.calcHist([gray], [0], None, [256], [0, 256])
# 直方图均衡化:把分布"拉平"(暗的变亮,亮的微调)
# 让对比度更均匀
equalized = cv2.equalizeHist(gray)
# 彩色图均衡(YUV 的 Y 通道做,再转回)
yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
yuv[:, :, 0] = cv2.equalizeHist(yuv[:, :, 0])
img_eq = cv2.cvtColor(yuv, cv2.COLOR_YUV2BGR)
为什么图会"灰蒙蒙"?
像素集中在中间亮度(对比度低)
→ 均衡化把它"拉开"(暗的更暗、亮的更亮)
→ 细节显现
用途:
逆光拍的封面 → 均衡化 → 字和图案清楚
监控视频(夜间)→ 预处理常用
注意:均衡化会改变颜色观感
→ 后续要颜色信息时慎用
"直方图是'图像的体检报告'——一看分布就知道图是过暗、过亮还是对比度低。均衡化是'对比度治疗',拍照搜书、OCR 前的常客。"
七、完整预处理流程:一张"脏图"的逆袭
老周把本章所有技术串成一个完整案例:
import cv2
import numpy as np
def preprocess_for_ocr(image_path):
"""OCR 前的标准预处理流程"""
img = cv2.imread(image_path)
# 1. 灰度化(去掉颜色干扰)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 2. 去噪(高斯滤波,保留边缘)
blur = cv2.GaussianBlur(gray, (3, 3), 0)
# 3. 直方图均衡化(提升对比度,文字更清晰)
eq = cv2.equalizeHist(blur)
# 4. 二值化(自适应阈值,应对光照不均)
binary = cv2.adaptiveThreshold(
eq, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
# 5. 形态学闭运算(连接断笔画)
kernel = np.ones((3, 3), np.uint8)
result = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
return result
# 脏图 → 干净二值图(后面 OCR 直接用)
clean = preprocess_for_ocr("blurry_photo.jpg")
cv2.imwrite("clean_for_ocr.png", clean)
"这套流程是视觉工程的'家常菜'——灰度→去噪→均衡→二值→形态学,五步走。每个视觉项目的第一版,几乎都从这套流程开始。"
八、章末:老周的第三章总结
第二层:图像处理基础
├── 预处理 = 识别前的"洗图"(垃圾进垃圾出)
├── 灰度化/二值化:减负 + 前后景分家(Otsu 自动阈值)
├── 滤波:均值/高斯(去噪)/中值(椒盐)/双边(保边)
├── 边缘检测:Canny(高斯→梯度→双阈值)
├── 形态学:腐蚀/膨胀/开运算/闭运算(整形)
├── 直方图与均衡化:提升对比度(救过暗图)
└── 标准五步:灰度→去噪→均衡→二值→形态学
第四层(预告):特征提取 —— 两张图怎么"找相同"
"小陈,现在你能把'脏图'洗成'干净图'了——这是视觉开发的基本功。"老周说,"但预处理只能'洗图',不能'认图'。怎么判断两张图'是不是同一个东西'?比如拍照搜书,怎么知道你拍的书封和数据库里哪本书最像?下一章:特征提取与匹配——给图像'提取指纹'。"