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 也要单数
相关推荐
清水白石0083 小时前
Python 异步编程深度解析:Cancellation 到底是异常还是控制信号?从 asyncio 取消机制到企业级事务设计最佳实践
开发语言·python
sarasuki3 小时前
MCP 客户端接入:一行注册一个 GitHub 工具
人工智能·agent·mcp
kolyle3 小时前
万级 QPS 下的 Token 分发系统架构:从 0 到 1 跑通 AI 时代的“水电煤“
开发语言·人工智能·系统架构·token·qps·极智词元·大模型私有化部署
Patrick在香港3 小时前
Python 审计香港开放数据目录:两个端点差 10 倍,只有 9.3% 的资源标了「最后修改时间」
开发语言·数据库·python·数据分析·api·数据治理·开放数据
IT毕设梦工厂3 小时前
计算机毕业设计选题推荐:基于大数据的草鱼价格分析与可视化|毕业设计选题|计算机毕设|选题推荐|毕设指导|项目定制|源码|高质量项目
大数据·hadoop·python·数据挖掘·数据分析·课程设计·大数据毕设项目
GISHUB3 小时前
基于QGIS 3.44开发Python插件完整教程
python·qgis
古少侠4 小时前
deepseek转word工具怎么选?DS随心转与4种方案对比实测
人工智能·word·powerpoint
大数据魔法师4 小时前
curl_cffi从入门到实战
爬虫·python
Code_Artist4 小时前
☢︎自然语言 → 机器码:这到底是 AI 编程的终极形态,还是一个伪命题?
人工智能·llm·ai编程
Sylvia33.4 小时前
火星数据体育API|一站式接入足球篮球电竞等18+项目实时数据
java·开发语言·python·websocket·游戏