【OpenCV 入门到精通 11】机器学习应用:KNN、SVM 与 K-Means 实战

【OpenCV 入门到精通 11】机器学习应用:KNN、SVM 与 K-Means 实战

标签OpenCV KNN SVM K-Means 机器学习 OCR

难度 :⭐⭐⭐⭐ | 阅读时长 :约 60 分钟 | 系列 :第 11/12 集

前置10 视频分析 | 下一集12 综合实战


写在前面

深度学习之前,传统机器学习 是 CV 的主流方案。OpenCV 内置了 KNN、SVM、K-Means 等经典算法,至今仍在 OCR、简单分类等场景有用。本集对应官方 第8章 机器学习


本集学习目标

  • 使用 KNN 进行手写数字识别
  • 使用 SVM 进行分类
  • 使用 K-Means 进行图像分割
  • 理解传统 ML 与深度学习的适用边界

文章目录

  • [【OpenCV 入门到精通 11】机器学习应用:KNN、SVM 与 K-Means 实战](#【OpenCV 入门到精通 11】机器学习应用:KNN、SVM 与 K-Means 实战)
    • 写在前面
    • 本集学习目标
    • [11.1 OpenCV ML 模块](#11.1 OpenCV ML 模块)
    • [11.2 KNN 手写数字识别](#11.2 KNN 手写数字识别)
      • [简化版:用 sklearn 数据](#简化版:用 sklearn 数据)
    • [11.3 SVM 分类](#11.3 SVM 分类)
      • [SVM 核函数](#SVM 核函数)
    • [11.4 K-Means 聚类](#11.4 K-Means 聚类)
    • [11.5 传统 ML vs 深度学习](#11.5 传统 ML vs 深度学习)
    • [11.6 踩坑指南](#11.6 踩坑指南)
    • [11.7 本集小结](#11.7 本集小结)

11.1 OpenCV ML 模块

算法 用途
KNN cv2.ml.KNearest_create() 最近邻分类
SVM cv2.ml.SVM_create() 支持向量机
决策树 cv2.ml.DTrees_create() 决策树
随机森林 cv2.ml.RTrees_create() 集成学习
贝叶斯 cv2.ml.NormalBayesClassifier_create() 朴素贝叶斯
K-Means cv2.kmeans() 聚类

通用流程

#mermaid-svg-Ks1HSrQfksnZtHak{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-Ks1HSrQfksnZtHak .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Ks1HSrQfksnZtHak .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Ks1HSrQfksnZtHak .error-icon{fill:#552222;}#mermaid-svg-Ks1HSrQfksnZtHak .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Ks1HSrQfksnZtHak .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Ks1HSrQfksnZtHak .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Ks1HSrQfksnZtHak .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Ks1HSrQfksnZtHak .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Ks1HSrQfksnZtHak .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Ks1HSrQfksnZtHak .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Ks1HSrQfksnZtHak .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Ks1HSrQfksnZtHak .marker.cross{stroke:#333333;}#mermaid-svg-Ks1HSrQfksnZtHak svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Ks1HSrQfksnZtHak p{margin:0;}#mermaid-svg-Ks1HSrQfksnZtHak .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Ks1HSrQfksnZtHak .cluster-label text{fill:#333;}#mermaid-svg-Ks1HSrQfksnZtHak .cluster-label span{color:#333;}#mermaid-svg-Ks1HSrQfksnZtHak .cluster-label span p{background-color:transparent;}#mermaid-svg-Ks1HSrQfksnZtHak .label text,#mermaid-svg-Ks1HSrQfksnZtHak span{fill:#333;color:#333;}#mermaid-svg-Ks1HSrQfksnZtHak .node rect,#mermaid-svg-Ks1HSrQfksnZtHak .node circle,#mermaid-svg-Ks1HSrQfksnZtHak .node ellipse,#mermaid-svg-Ks1HSrQfksnZtHak .node polygon,#mermaid-svg-Ks1HSrQfksnZtHak .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Ks1HSrQfksnZtHak .rough-node .label text,#mermaid-svg-Ks1HSrQfksnZtHak .node .label text,#mermaid-svg-Ks1HSrQfksnZtHak .image-shape .label,#mermaid-svg-Ks1HSrQfksnZtHak .icon-shape .label{text-anchor:middle;}#mermaid-svg-Ks1HSrQfksnZtHak .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Ks1HSrQfksnZtHak .rough-node .label,#mermaid-svg-Ks1HSrQfksnZtHak .node .label,#mermaid-svg-Ks1HSrQfksnZtHak .image-shape .label,#mermaid-svg-Ks1HSrQfksnZtHak .icon-shape .label{text-align:center;}#mermaid-svg-Ks1HSrQfksnZtHak .node.clickable{cursor:pointer;}#mermaid-svg-Ks1HSrQfksnZtHak .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Ks1HSrQfksnZtHak .arrowheadPath{fill:#333333;}#mermaid-svg-Ks1HSrQfksnZtHak .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Ks1HSrQfksnZtHak .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Ks1HSrQfksnZtHak .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ks1HSrQfksnZtHak .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Ks1HSrQfksnZtHak .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ks1HSrQfksnZtHak .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Ks1HSrQfksnZtHak .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Ks1HSrQfksnZtHak .cluster text{fill:#333;}#mermaid-svg-Ks1HSrQfksnZtHak .cluster span{color:#333;}#mermaid-svg-Ks1HSrQfksnZtHak 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-Ks1HSrQfksnZtHak .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Ks1HSrQfksnZtHak rect.text{fill:none;stroke-width:0;}#mermaid-svg-Ks1HSrQfksnZtHak .icon-shape,#mermaid-svg-Ks1HSrQfksnZtHak .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Ks1HSrQfksnZtHak .icon-shape p,#mermaid-svg-Ks1HSrQfksnZtHak .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Ks1HSrQfksnZtHak .icon-shape .label rect,#mermaid-svg-Ks1HSrQfksnZtHak .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Ks1HSrQfksnZtHak .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Ks1HSrQfksnZtHak .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Ks1HSrQfksnZtHak :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 准备数据
特征提取
训练模型
预测
评估


11.2 KNN 手写数字识别

python 复制代码
import cv2
import numpy as np

# 加载 OpenCV 自带的手写数字样本
samples = np.loadtxt("digits.png", np.float32)
samples = samples.reshape(-1, 20, 20)  # 5000 个 20x20 图像

# 准备训练数据
train_data = samples.reshape(-1, 400).astype(np.float32)
labels = np.repeat(np.arange(10), 250)[:, np.newaxis].astype(np.float32)

knn = cv2.ml.KNearest_create()
knn.train(train_data, cv2.ml.ROW_SAMPLE, labels)

# 预测
test_sample = samples[1023].reshape(1, 400).astype(np.float32)
ret, result, neighbours, dist = knn.findNearest(test_sample, k=5)
print(f"预测: {int(result[0][0])}")

简化版:用 sklearn 数据

python 复制代码
from sklearn.datasets import load_digits
import cv2
import numpy as np

digits = load_digits()
X = digits.data.astype(np.float32)
y = digits.target.astype(np.float32)

# 划分训练/测试
split = int(0.8 * len(X))
knn = cv2.ml.KNearest_create()
knn.train(X[:split], cv2.ml.ROW_SAMPLE, y[:split])

correct = 0
for i in range(split, len(X)):
    _, result, _, _ = knn.findNearest(X[i:i+1], k=5)
    if int(result[0][0]) == int(y[i]):
        correct += 1
print(f"准确率: {correct/(len(X)-split)*100:.1f}%")

11.3 SVM 分类

python 复制代码
import cv2
import numpy as np

# 生成简单二分类数据
np.random.seed(42)
data1 = np.random.randn(50, 2).astype(np.float32) + np.array([2, 2])
data2 = np.random.randn(50, 2).astype(np.float32) + np.array([-2, -2])
train_data = np.vstack([data1, data2])
labels = np.array([1]*50 + [-1]*50, dtype=np.float32)

svm = cv2.ml.SVM_create()
svm.setType(cv2.ml.SVM_C_SVC)
svm.setKernel(cv2.ml.SVM_LINEAR)
svm.train(train_data, cv2.ml.ROW_SAMPLE, labels)

# 预测
test = np.array([[0, 0]], dtype=np.float32)
_, result = svm.predict(test)
print(f"预测类别: {int(result[0][0])}")

SVM 核函数

适用
SVM_LINEAR 线性可分
SVM_RBF 非线性(最常用)
SVM_POLY 多项式
SVM_SIGMOID S 形

11.4 K-Means 聚类

将图像像素按颜色聚类,实现简单分割:

python 复制代码
import cv2
import numpy as np

img = cv2.imread("photo.jpg")
data = img.reshape((-1, 3)).astype(np.float32)

K = 3  # 聚类数
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 1.0)
_, labels, centers = cv2.kmeans(data, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)

centers = np.uint8(centers)
segmented = centers[labels.flatten()].reshape(img.shape)

cv2.imshow("K-Means", segmented)
cv2.waitKey(0)
参数 说明
K 聚类数量
criteria 终止条件
attempts 不同初始化的尝试次数

11.5 传统 ML vs 深度学习

维度 传统 ML (KNN/SVM) 深度学习 (YOLO/CNN)
特征 需手工设计 自动学习
数据量 小数据可用 需要大量数据
速度 较慢(GPU 加速)
精度 简单任务够用 复杂任务更强
可解释性 较好 较差

💡 选择建议:OCR 简单场景、颜色聚类 → 传统 ML;目标检测、复杂分类 → 深度学习。


11.6 踩坑指南

解决
数据类型错误 训练数据用 float32
KNN k 值不当 通常 k=3~7,奇数
SVM 训练慢 减少数据量或换 LINEAR 核
K-Means 结果随机 增加 attempts

11.7 本集小结

算法 场景 核心 API
KNN 简单分类、OCR KNearest_create().train()
SVM 二/多分类 SVM_create().train()
K-Means 颜色聚类/分割 cv2.kmeans()

← 第10集 第12集:综合实战 →

参考:8_1 KNN | 8_3 SVM | 8_5 K-Means

相关推荐
liferecords1 小时前
第 12 讲 · Python 侧接入:火焰图定位热点与间接使用硬件加速
python·性能分析·鲲鹏·火焰图·ctypes
YOLO数据集集合1 小时前
全球无人机航拍树冠覆盖数据集 | 树冠分割 语义分割 无人机航拍 全球森林监测 GeoTIFF 生态恢复9083期
深度学习·yolo·目标检测·无人机·无人机视角·全球森林
小巫山云子1 小时前
相机到主机接口简介
人工智能·计算机视觉·视觉检测·相机
Bode_20021 小时前
人机环交互的具身智能系统
人工智能·智能制造·具身智能
LDR0061 小时前
Type-C 供电入口重构延长器设计:LDR6100 解决 USB 远距离延长量产供电难题
人工智能
K 旺仔小馒头1 小时前
【项目】商城系统用户端测试报告
自动化测试·python·功能测试
residual_fan1 小时前
航空发动机故障诊断专用智能体(三):基于对比学习的时序特征区分方法
人工智能·算法·数据挖掘·数据分析
揽秀亭长1 小时前
音轨分离处理方案及效果测试分析
人工智能·音视频
东莞市云毅网络有限公司1 小时前
用 SQLite FTS5 给企业文档建本地全文索引:中文分词与权重调优
python·数据清洗·rag·企业知识库·文档解析