OpenCV 阈值与模糊:全局/自适应阈值、Canny 边缘检测与三种模糊
OpenCV 图像处理课程 · 第 6 章「Threshold and Blurring」学习笔记
环境:Python 3.10 + opencv-python 4.5.5.64 + PyCharm(
chapter6目录)包含 4 课:全局阈值 / 自适应阈值 / Canny 边缘检测 / 图像模糊
章节总览
| 课 | 主题 | 核心函数 | 文件 |
|---|---|---|---|
| 01 | 全局阈值 | cv2.threshold() |
global_threshold.py |
| 02 | 自适应阈值 | cv2.adaptiveThreshold() |
adaptive_threshold.py |
| 03 | Canny 边缘检测 | cv2.Canny() |
canny_image.py |
| 04 | 图像模糊 | cv2.blur() / GaussianBlur() / medianBlur() |
image_blur.py |
本章说明 :阈值用于创建二值图像 (0~255 黑白);模糊(平滑)用于去噪。两者都是图像预处理的核心步骤。
第 1 课 · 全局阈值(cv2.threshold)
概念
- 每个像素与一个固定阈值比较:小于阈值 → 0,大于 → 255
- 用于把物体从背景中分离(前景/背景)
- 必须在灰度图像上做(若为 BGR 要先转灰度)
函数签名
python
cv2.threshold(src, thresh, maxval, type)
| 参数 | 含义 |
|---|---|
src |
输入灰度图像 |
thresh |
阈值(0~255) |
maxval |
像素大于阈值时设置的最大值(如 255) |
type |
阈值类型(cv2.THRESH_BINARY 等) |
完整代码(global_threshold.py)
python
import cv2
image_path = "../data/balloon.jpg"
image = cv2.imread(image_path)
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 转灰度
thresh, image_bin = cv2.threshold(image_gray, 127, 255,
cv2.THRESH_BINARY)
cv2.imshow("image", image_gray)
cv2.imshow("image binary", image_bin)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.threshold返回 两个值 :(阈值, 二值图像)。
常见阈值类型
| 类型 | 效果 |
|---|---|
THRESH_BINARY |
像素>阈值设为 maxval,否则 0 |
THRESH_BINARY_INV |
反相:像素>阈值设为 0,否则 maxval |
THRESH_TRUNC |
超过阈值截断为 maxval |
THRESH_TOZERO |
低于阈值置 0,否则不变 |
阈值曲线示意
#mermaid-svg-68nLfIRcuJUp2miG{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-68nLfIRcuJUp2miG .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-68nLfIRcuJUp2miG .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-68nLfIRcuJUp2miG .error-icon{fill:#552222;}#mermaid-svg-68nLfIRcuJUp2miG .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-68nLfIRcuJUp2miG .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-68nLfIRcuJUp2miG .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-68nLfIRcuJUp2miG .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-68nLfIRcuJUp2miG .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-68nLfIRcuJUp2miG .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-68nLfIRcuJUp2miG .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-68nLfIRcuJUp2miG .marker{fill:#333333;stroke:#333333;}#mermaid-svg-68nLfIRcuJUp2miG .marker.cross{stroke:#333333;}#mermaid-svg-68nLfIRcuJUp2miG svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-68nLfIRcuJUp2miG p{margin:0;}#mermaid-svg-68nLfIRcuJUp2miG .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-68nLfIRcuJUp2miG .cluster-label text{fill:#333;}#mermaid-svg-68nLfIRcuJUp2miG .cluster-label span{color:#333;}#mermaid-svg-68nLfIRcuJUp2miG .cluster-label span p{background-color:transparent;}#mermaid-svg-68nLfIRcuJUp2miG .label text,#mermaid-svg-68nLfIRcuJUp2miG span{fill:#333;color:#333;}#mermaid-svg-68nLfIRcuJUp2miG .node rect,#mermaid-svg-68nLfIRcuJUp2miG .node circle,#mermaid-svg-68nLfIRcuJUp2miG .node ellipse,#mermaid-svg-68nLfIRcuJUp2miG .node polygon,#mermaid-svg-68nLfIRcuJUp2miG .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-68nLfIRcuJUp2miG .rough-node .label text,#mermaid-svg-68nLfIRcuJUp2miG .node .label text,#mermaid-svg-68nLfIRcuJUp2miG .image-shape .label,#mermaid-svg-68nLfIRcuJUp2miG .icon-shape .label{text-anchor:middle;}#mermaid-svg-68nLfIRcuJUp2miG .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-68nLfIRcuJUp2miG .rough-node .label,#mermaid-svg-68nLfIRcuJUp2miG .node .label,#mermaid-svg-68nLfIRcuJUp2miG .image-shape .label,#mermaid-svg-68nLfIRcuJUp2miG .icon-shape .label{text-align:center;}#mermaid-svg-68nLfIRcuJUp2miG .node.clickable{cursor:pointer;}#mermaid-svg-68nLfIRcuJUp2miG .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-68nLfIRcuJUp2miG .arrowheadPath{fill:#333333;}#mermaid-svg-68nLfIRcuJUp2miG .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-68nLfIRcuJUp2miG .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-68nLfIRcuJUp2miG .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-68nLfIRcuJUp2miG .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-68nLfIRcuJUp2miG .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-68nLfIRcuJUp2miG .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-68nLfIRcuJUp2miG .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-68nLfIRcuJUp2miG .cluster text{fill:#333;}#mermaid-svg-68nLfIRcuJUp2miG .cluster span{color:#333;}#mermaid-svg-68nLfIRcuJUp2miG div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-68nLfIRcuJUp2miG .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-68nLfIRcuJUp2miG rect.text{fill:none;stroke-width:0;}#mermaid-svg-68nLfIRcuJUp2miG .icon-shape,#mermaid-svg-68nLfIRcuJUp2miG .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-68nLfIRcuJUp2miG .icon-shape p,#mermaid-svg-68nLfIRcuJUp2miG .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-68nLfIRcuJUp2miG .icon-shape .label rect,#mermaid-svg-68nLfIRcuJUp2miG .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-68nLfIRcuJUp2miG .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-68nLfIRcuJUp2miG .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-68nLfIRcuJUp2miG :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 二值图像
cv2.threshold(thresh, maxval)
输入灰度图 (0~255)
pixel < thresh
pixel ≥ thresh
比较每个像素
置 0(黑)
置 maxval(白)
真实演示图:
| 灰度输入 | 二值输出(THRESH_BINARY) | 反相(INV) |
|---|---|---|
![]() |
![]() |
![]() |
阈值 127:亮圆和渐变亮部变白,暗部变黑;反相则黑白互换。
第 2 课 · 自适应阈值(cv2.adaptiveThreshold)
概念
- 全局阈值对有阴影/多物体的场景效果差(整个图像只有一个阈值)
- 自适应阈值把图像分成小的邻域区域,每个区域单独计算阈值 → 更精准
函数签名
python
cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType,
blockSize, C)
| 参数 | 含义 |
|---|---|
src |
输入灰度图像 |
maxValue |
像素最大值(255) |
adaptiveMethod |
cv2.ADAPTIVE_THRESH_MEAN_C(邻域均值)或 ADAPTIVE_THRESH_GAUSSIAN_C(加权和) |
thresholdType |
THRESH_BINARY 或 THRESH_BINARY_INV |
blockSize |
邻域大小(必须是奇数,如 21) |
C |
从阈值减去的常数(微调) |
完整代码(adaptive_threshold.py)
python
import cv2
image_path = "../data/doc.png"
image = cv2.imread(image_path)
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(image_gray, 255,
cv2.ADAPTIVE_THRESH_MEAN_C,
cv2.THRESH_BINARY, 21, 10)
cv2.imshow("image", image_gray)
cv2.imshow("adaptive threshold", thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
自适应算法
#mermaid-svg-0YPHV2CNEokOtqnT{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0YPHV2CNEokOtqnT .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0YPHV2CNEokOtqnT .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0YPHV2CNEokOtqnT .error-icon{fill:#552222;}#mermaid-svg-0YPHV2CNEokOtqnT .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0YPHV2CNEokOtqnT .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0YPHV2CNEokOtqnT .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0YPHV2CNEokOtqnT .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0YPHV2CNEokOtqnT .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0YPHV2CNEokOtqnT .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0YPHV2CNEokOtqnT .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0YPHV2CNEokOtqnT .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0YPHV2CNEokOtqnT .marker.cross{stroke:#333333;}#mermaid-svg-0YPHV2CNEokOtqnT svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0YPHV2CNEokOtqnT p{margin:0;}#mermaid-svg-0YPHV2CNEokOtqnT .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-0YPHV2CNEokOtqnT .cluster-label text{fill:#333;}#mermaid-svg-0YPHV2CNEokOtqnT .cluster-label span{color:#333;}#mermaid-svg-0YPHV2CNEokOtqnT .cluster-label span p{background-color:transparent;}#mermaid-svg-0YPHV2CNEokOtqnT .label text,#mermaid-svg-0YPHV2CNEokOtqnT span{fill:#333;color:#333;}#mermaid-svg-0YPHV2CNEokOtqnT .node rect,#mermaid-svg-0YPHV2CNEokOtqnT .node circle,#mermaid-svg-0YPHV2CNEokOtqnT .node ellipse,#mermaid-svg-0YPHV2CNEokOtqnT .node polygon,#mermaid-svg-0YPHV2CNEokOtqnT .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0YPHV2CNEokOtqnT .rough-node .label text,#mermaid-svg-0YPHV2CNEokOtqnT .node .label text,#mermaid-svg-0YPHV2CNEokOtqnT .image-shape .label,#mermaid-svg-0YPHV2CNEokOtqnT .icon-shape .label{text-anchor:middle;}#mermaid-svg-0YPHV2CNEokOtqnT .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-0YPHV2CNEokOtqnT .rough-node .label,#mermaid-svg-0YPHV2CNEokOtqnT .node .label,#mermaid-svg-0YPHV2CNEokOtqnT .image-shape .label,#mermaid-svg-0YPHV2CNEokOtqnT .icon-shape .label{text-align:center;}#mermaid-svg-0YPHV2CNEokOtqnT .node.clickable{cursor:pointer;}#mermaid-svg-0YPHV2CNEokOtqnT .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-0YPHV2CNEokOtqnT .arrowheadPath{fill:#333333;}#mermaid-svg-0YPHV2CNEokOtqnT .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-0YPHV2CNEokOtqnT .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-0YPHV2CNEokOtqnT .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0YPHV2CNEokOtqnT .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-0YPHV2CNEokOtqnT .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0YPHV2CNEokOtqnT .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-0YPHV2CNEokOtqnT .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0YPHV2CNEokOtqnT .cluster text{fill:#333;}#mermaid-svg-0YPHV2CNEokOtqnT .cluster span{color:#333;}#mermaid-svg-0YPHV2CNEokOtqnT div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-0YPHV2CNEokOtqnT .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0YPHV2CNEokOtqnT rect.text{fill:none;stroke-width:0;}#mermaid-svg-0YPHV2CNEokOtqnT .icon-shape,#mermaid-svg-0YPHV2CNEokOtqnT .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-0YPHV2CNEokOtqnT .icon-shape p,#mermaid-svg-0YPHV2CNEokOtqnT .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-0YPHV2CNEokOtqnT .icon-shape .label rect,#mermaid-svg-0YPHV2CNEokOtqnT .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-0YPHV2CNEokOtqnT .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0YPHV2CNEokOtqnT .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0YPHV2CNEokOtqnT :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 每个区域各自二值化
adaptiveThreshold(blockSize, C)
输入灰度图(含阴影/多物体)
区域1
区域2
区域N
分块=按邻域算阈值
MEAN_C: 邻域均值
GAUSSIAN_C: 加权和
不同区域不同阈值
结果更精准
真实演示图(带噪声的渐变图,全局 vs 自适应):
| 带噪声灰度图 | 自适应二值化 |
|---|---|
![]() |
![]() |
自适应阈值能更好处理光照不均/阴影场景(比全局阈值更稳健)。
第 3 课 · Canny 边缘检测(cv2.Canny)
概念
Canny 算法包含四步 :降噪 → 计算图像梯度 → 非极大值抑制 → 滞后阈值(用上下两个阈值)。
| 判定 | 结果 |
|---|---|
| 梯度 > 上阈值 | 接受为边缘 |
| 梯度 < 下阈值 | 拒绝 |
| 处于两阈值之间 | 仅当连接到高于上阈值的像素时接受 |
函数签名
python
cv2.Canny(image, threshold1, threshold2, apertureSize=3, L2gradient=False)
| 参数 | 含义 |
|---|---|
image |
输入灰度图像 |
threshold1 |
下阈值 |
threshold2 |
上阈值 |
apertureSize |
Sobel 孔径(默认 3,范围 3~7,越大越细) |
L2gradient |
bool;True 用 L2 梯度(更精细),False 用 L1 |
完整代码(canny_image.py)
python
import cv2
image_path = "../data/balloon.jpg"
image = cv2.imread(image_path)
image_edges = cv2.Canny(image, 100, 200) # 下100, 上200
cv2.imshow("image", image)
cv2.imshow("image edges", image_edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
边缘检测流程
#mermaid-svg-TxXF2uSLTtzz4Nq8{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .error-icon{fill:#552222;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .marker.cross{stroke:#333333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TxXF2uSLTtzz4Nq8 p{margin:0;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .cluster-label text{fill:#333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .cluster-label span{color:#333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .cluster-label span p{background-color:transparent;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .label text,#mermaid-svg-TxXF2uSLTtzz4Nq8 span{fill:#333;color:#333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .node rect,#mermaid-svg-TxXF2uSLTtzz4Nq8 .node circle,#mermaid-svg-TxXF2uSLTtzz4Nq8 .node ellipse,#mermaid-svg-TxXF2uSLTtzz4Nq8 .node polygon,#mermaid-svg-TxXF2uSLTtzz4Nq8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .rough-node .label text,#mermaid-svg-TxXF2uSLTtzz4Nq8 .node .label text,#mermaid-svg-TxXF2uSLTtzz4Nq8 .image-shape .label,#mermaid-svg-TxXF2uSLTtzz4Nq8 .icon-shape .label{text-anchor:middle;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .rough-node .label,#mermaid-svg-TxXF2uSLTtzz4Nq8 .node .label,#mermaid-svg-TxXF2uSLTtzz4Nq8 .image-shape .label,#mermaid-svg-TxXF2uSLTtzz4Nq8 .icon-shape .label{text-align:center;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .node.clickable{cursor:pointer;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .arrowheadPath{fill:#333333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TxXF2uSLTtzz4Nq8 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TxXF2uSLTtzz4Nq8 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-TxXF2uSLTtzz4Nq8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .cluster text{fill:#333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .cluster span{color:#333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TxXF2uSLTtzz4Nq8 rect.text{fill:none;stroke-width:0;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .icon-shape,#mermaid-svg-TxXF2uSLTtzz4Nq8 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .icon-shape p,#mermaid-svg-TxXF2uSLTtzz4Nq8 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .icon-shape .label rect,#mermaid-svg-TxXF2uSLTtzz4Nq8 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TxXF2uSLTtzz4Nq8 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-TxXF2uSLTtzz4Nq8 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-TxXF2uSLTtzz4Nq8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 边缘图像
Canny 四步
输入图像
灰度图
- 高斯降噪
- 计算梯度
- 非极大值抑制
- 滞后阈值
(下100/上200)
物体边界轮廓
真实演示图:
| 输入图像 | Canny 边缘输出 |
|---|---|
![]() |
![]() |
Canny 清晰勾勒出亮圆的轮廓和暗矩形的边界线------这就是自动驾驶中检测车道标记的基础。
第 4 课 · 图像模糊(Image Blurring)
概念
- 图像模糊也叫图像平滑 ,用低通滤波器处理图像
- 目的:去除噪声(使像素亮度/发生变化的异常点)
- 模糊通过降低像素差异减少清晰度,让图像更平滑
三种模糊函数
| 函数 | 原理 | 参数 | 示例 |
|---|---|---|---|
cv2.blur() |
平均模糊:邻域像素平均值 | (src, ksize) |
(img, (5,5)) |
cv2.GaussianBlur() |
高斯模糊:加权(中心权重高) | (src, ksize, sigmaX) |
(img, (7,7), 0) |
cv2.medianBlur() |
中值模糊:邻域像素中值 | (src, ksize)(单数) |
(img, 5) |
完整代码(image_blur.py)
python
import cv2
image_path = "../data/balloon.jpg"
image = cv2.imread(image_path)
# 平均模糊
image_blur = cv2.blur(image, (5, 5))
# 高斯模糊(注释平均模糊后放开)
image_blur = cv2.GaussianBlur(image, (7, 7), 0)
# 中值模糊(注释后放开)
image_blur = cv2.medianBlur(image, 5)
cv2.imshow("image", image)
cv2.imshow("image blur", image_blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
模糊原理示意
#mermaid-svg-m8XQPeCzn0eGTnkt{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-m8XQPeCzn0eGTnkt .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-m8XQPeCzn0eGTnkt .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-m8XQPeCzn0eGTnkt .error-icon{fill:#552222;}#mermaid-svg-m8XQPeCzn0eGTnkt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-m8XQPeCzn0eGTnkt .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-m8XQPeCzn0eGTnkt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-m8XQPeCzn0eGTnkt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-m8XQPeCzn0eGTnkt .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-m8XQPeCzn0eGTnkt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-m8XQPeCzn0eGTnkt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-m8XQPeCzn0eGTnkt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-m8XQPeCzn0eGTnkt .marker.cross{stroke:#333333;}#mermaid-svg-m8XQPeCzn0eGTnkt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-m8XQPeCzn0eGTnkt p{margin:0;}#mermaid-svg-m8XQPeCzn0eGTnkt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-m8XQPeCzn0eGTnkt .cluster-label text{fill:#333;}#mermaid-svg-m8XQPeCzn0eGTnkt .cluster-label span{color:#333;}#mermaid-svg-m8XQPeCzn0eGTnkt .cluster-label span p{background-color:transparent;}#mermaid-svg-m8XQPeCzn0eGTnkt .label text,#mermaid-svg-m8XQPeCzn0eGTnkt span{fill:#333;color:#333;}#mermaid-svg-m8XQPeCzn0eGTnkt .node rect,#mermaid-svg-m8XQPeCzn0eGTnkt .node circle,#mermaid-svg-m8XQPeCzn0eGTnkt .node ellipse,#mermaid-svg-m8XQPeCzn0eGTnkt .node polygon,#mermaid-svg-m8XQPeCzn0eGTnkt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-m8XQPeCzn0eGTnkt .rough-node .label text,#mermaid-svg-m8XQPeCzn0eGTnkt .node .label text,#mermaid-svg-m8XQPeCzn0eGTnkt .image-shape .label,#mermaid-svg-m8XQPeCzn0eGTnkt .icon-shape .label{text-anchor:middle;}#mermaid-svg-m8XQPeCzn0eGTnkt .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-m8XQPeCzn0eGTnkt .rough-node .label,#mermaid-svg-m8XQPeCzn0eGTnkt .node .label,#mermaid-svg-m8XQPeCzn0eGTnkt .image-shape .label,#mermaid-svg-m8XQPeCzn0eGTnkt .icon-shape .label{text-align:center;}#mermaid-svg-m8XQPeCzn0eGTnkt .node.clickable{cursor:pointer;}#mermaid-svg-m8XQPeCzn0eGTnkt .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-m8XQPeCzn0eGTnkt .arrowheadPath{fill:#333333;}#mermaid-svg-m8XQPeCzn0eGTnkt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-m8XQPeCzn0eGTnkt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-m8XQPeCzn0eGTnkt .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m8XQPeCzn0eGTnkt .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-m8XQPeCzn0eGTnkt .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m8XQPeCzn0eGTnkt .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-m8XQPeCzn0eGTnkt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-m8XQPeCzn0eGTnkt .cluster text{fill:#333;}#mermaid-svg-m8XQPeCzn0eGTnkt .cluster span{color:#333;}#mermaid-svg-m8XQPeCzn0eGTnkt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-m8XQPeCzn0eGTnkt .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-m8XQPeCzn0eGTnkt rect.text{fill:none;stroke-width:0;}#mermaid-svg-m8XQPeCzn0eGTnkt .icon-shape,#mermaid-svg-m8XQPeCzn0eGTnkt .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-m8XQPeCzn0eGTnkt .icon-shape p,#mermaid-svg-m8XQPeCzn0eGTnkt .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-m8XQPeCzn0eGTnkt .icon-shape .label rect,#mermaid-svg-m8XQPeCzn0eGTnkt .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-m8XQPeCzn0eGTnkt .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-m8XQPeCzn0eGTnkt .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-m8XQPeCzn0eGTnkt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 平滑图像
低通滤波
图像(含噪声)
噪点像素
blur: 邻域平均
Gaussian: 加权平均
median: 邻域中值
噪点被清除/中和
真实演示图(带噪声输入 vs 三种模糊):
| 带噪声原图 | 平均模糊 (5×5) | 高斯模糊 (7×7) | 中值模糊 (5) |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
三种模糊都能减小噪点、让图像更平滑;测试图中椒盐噪声被中和。
本章小结(速查表)
| 操作 | 函数 | 关键点 |
|---|---|---|
| 全局阈值 | cv2.threshold(src, thresh, maxval, type) |
固定阈值,需灰度图,返回(thresh, bin) |
| 自适应阈值 | cv2.adaptiveThreshold(src, maxval, method, type, block, C) |
blockSize 必须奇数 |
| 边缘检测 | cv2.Canny(img, t1, t2, ksize, L2) |
上下两阈值,滞后阈值 |
| 平均模糊 | cv2.blur(img, ksize) |
邻域均值 |
| 高斯模糊 | cv2.GaussianBlur(img, ksize, sigmaX) |
加权均值,中心权重大 |
| 中值模糊 | cv2.medianBlur(img, ksize) |
邻域中值,ksize 单数 |
核心易错点
- 阈值/边缘检测在灰度图上做 (BGR 先
cvtColor转灰度) threshold返回两个值 :(阈值, 二值图像)- 自适应阈值的 blockSize 必须为奇数(如 21)
- Canny 上下阈值:高于上阈值是边缘,低于下阈值被拒,中间看连接
- 中值模糊的 ksize 也要单数







