opencv-114-KNN算法介绍

知识点

OpenCV中机器学习模块的最近邻算法KNN, 使用KNN算法实现手写数字识别,OpenCV在sample/data中有一张自带的手写数字数据集图像,0~9 每个有500个样本,总计有5000个数字。图像大小为1000x2000的大小图像,分割为20x20大小的单个数字图像,每个样本400个像素。然后使用KNN相关API实现训练与结果的保存。大致的顺序如下:

  1. 读入测试图像digit.png(可以在我的github下载,不知道地址看置顶帖子)
  2. 构建样本数据与标签
  3. 创建KNN训练并保存训练结果

代码(c++,python)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace cv::ml;
using namespace std;

int main(int argc, char** argv) {
Mat data = imread("D:/projects/opencv_tutorial/data/images/digits.png");
Mat gray;
cvtColor(data, gray, COLOR_BGR2GRAY);

// 分割为5000个cells
Mat images = Mat::zeros(5000, 400, CV_8UC1);
Mat labels = Mat::zeros(5000, 1, CV_8UC1);
Rect rect;
rect.height = 20;
rect.width = 20;
int index = 0;
Rect roi;
roi.x = 0;
roi.height = 1;
roi.width = 400;
for (int row = 0; row < 50; row++) {
int label = row / 5;
for (int col = 0; col < 100; col++) {
Mat digit = Mat::zeros(20, 20, CV_8UC1);
index = row * 100 + col;
rect.x = col * 20;
rect.y = row * 20;
gray(rect).copyTo(digit);
Mat one_row = digit.reshape(1, 1);
roi.y = index;
one_row.copyTo(images(roi));
labels.at<uchar>(index, 0) = label;
}
}
printf("load sample hand-writing data...\n");

// 转换为浮点数
images.convertTo(images, CV_32FC1);
labels.convertTo(labels, CV_32SC1);

// 开始KNN训练
printf("Start to knn train...\n");
Ptr<KNearest> knn = KNearest::create();
knn->setDefaultK(5);
knn->setIsClassifier(true);
Ptr<ml::TrainData> tdata = ml::TrainData::create(images, ml::ROW_SAMPLE, labels);
knn->train(tdata);
knn->save("D:/vcworkspaces/knn_knowledge.yml");
printf("Finished KNN...\n");
return true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
"""
KNN算法介绍
"""

import cv2 as cv
import numpy as np

# 读取数据
img = cv.imread("images/digits.png")
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
cells = [np.hsplit(row, 100) for row in np.vsplit(gray, 50)]
x = np.array(cells)

# 创建训练与测试数据
train = x[:, :50].reshape(-1, 400).astype(np.float32)
test = x[:, 50:100].reshape(-1, 400).astype(np.float32)
k = np.arange(10)
train_labels = np.repeat(k,250)[:, np.newaxis]
test_labels = train_labels.copy()

# 训练KNN
knn = cv.ml.KNearest_create()
knn.train(train, cv.ml.ROW_SAMPLE, train_labels)
ret, result, neighbours, dist = knn.findNearest(test, k=5)

# 计算准确率
matches = result == test_labels
correct = np.count_nonzero(matches)
acc = correct * 100.0 / result.size
print(acc)
# 预测准确率: 91.76

代码地址

github