OpenCV 阈值与模糊:全局/自适应阈值、Canny 边缘检测与三种模糊

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_BINARYTHRESH_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 四步
输入图像
灰度图

  1. 高斯降噪
  2. 计算梯度
  3. 非极大值抑制
  4. 滞后阈值

(下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 单数

核心易错点

  1. 阈值/边缘检测在灰度图上做 (BGR 先 cvtColor 转灰度)
  2. threshold 返回两个值(阈值, 二值图像)
  3. 自适应阈值的 blockSize 必须为奇数(如 21)
  4. Canny 上下阈值:高于上阈值是边缘,低于下阈值被拒,中间看连接
  5. 中值模糊的 ksize 也要单数
相关推荐
GIR72042 分钟前
重构全球关节腔内注射物行业竞争格局:市场占有率、销量排名及主要竞争对手分析
大数据·人工智能
宋哥转AI42 分钟前
深入理解 AI Agent · 多 Agent 编排 #01:多 Agent 编排的四种核心模式
人工智能·agent·ai编程
故七月1 小时前
让AI“看见”好服务——生成式引擎优化(GEO)的底层逻辑与产业实践
大数据·人工智能·机器学习
用户5274675614211 小时前
Agent 之间别互抄聊天记录:把交接做成可验证的 Artifact Envelope
人工智能
刘立军1 小时前
插件化与扩展点:引导 AI 模块化插拔开发,功能解耦便于迭代
人工智能·后端·架构
腾视科技-AIoT1 小时前
让安全驾驶有“AI”相伴|腾视科技DMS视频监控一体机,守护每一次出行
大数据·人工智能·科技·安全·行车记录仪·ainas·腾视科技
欧特克_Glodon1 小时前
OpenCV计算机视觉开发入门与实践<二十一>:灰度直方图清晰化图像
c++·人工智能·opencv·计算机视觉
码视野1 小时前
基于 Vue3 + Element Plus 的【青少年心理健康智能测评与 AI 情绪树洞陪护干预系统】设计与实现(含PRD/三端源码/大屏)
前端·vue.js·人工智能·vue3