opencv实现KNN手写数字的识别
人工智能是当下很热门的话题,手写识别是一个典型的应用。为了进一步了解这个领域,我阅读了大量的论文,并借助opencv完成了对28x28的数字图片(预处理后的二值图像)的识别任务。
预处理一张图片:
首先采用opencv读取图片的构造函数读取灰度的图片,再采用大津法求出图片的二值化的阈值,并且将图片二值化。
int otsu(const IplImage* src_image) {
double sum = 0.0;
double w0 = 0.0;
double w1 = 0.0;
double u0_temp = 0.0;
double u1_temp = 0.0;
double u0 = 0.0;
double u1 = 0.0;
double delta_temp = 0.0;
double delta_max = 0.0; int pixel_count[] = { };
float pixel_pro[] = { };
int threshold = ;
uchar* data = (uchar*)src_image->imageData;
for (int i = ; i < src_image->height; i++) {
for (int j = ; j < src_image->width; j++) {
pixel_count[(int)data[i * src_image->width + j]]++;
sum += (int)data[i * src_image->width + j];
}
}
for (int i = ; i < ; i++) {
pixel_pro[i] = (float)pixel_count[i] / (src_image->height * src_image->width);
}
for (int i = ; i < ; i++) {
w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = ;
for (int j = ; j < ; j++) {
if (j <= i) {
w0 += pixel_pro[j];
u0_temp += j * pixel_pro[j];
}
else {
w1 += pixel_pro[j];
u1_temp += j * pixel_pro[j];
}
}
u0 = u0_temp / w0;
u1 = u1_temp / w1;
delta_temp = (float)(w0 *w1* pow((u0 - u1), ));
if (delta_temp > delta_max) {
delta_max = delta_temp;
threshold = i;
}
}
return threshold;
}
大津法
void imageBinarization(IplImage* src_image) {
IplImage* binImg = cvCreateImage(cvGetSize(src_image), src_image->depth, src_image->nChannels);
CvScalar s;
int ave = ;
int binThreshold = otsu(src_image); for (int i = ; i < src_image->height; i++) {
for (int j = ; j < src_image->width; j++) {
s = cvGet2D(src_image, i, j);
ave = (s.val[] + s.val[] + s.val[]) / ;
if (ave < binThreshold) {
s.val[] = s.val[] = s.val[] = 0xff;
cvSet2D(src_image, i, j, s);
}
else {
s.val[] = s.val[] = s.val[] = 0x00;
cvSet2D(src_image, i, j, s);
}
}
}
cvCopy(src_image, binImg);
cvSaveImage(bined, binImg);
//cvShowImage("binarization", binImg);
//waitKey(0);
}
二值化
由于是只进行简单的识别模拟,因此没有做像素断点的处理。获取minst提供的数据集,提取每个图片的hog特征,参数如下:
HOGDescriptor *hog = new HOGDescriptor(
cvSize(ImgWidht, ImgHeight), cvSize(, ), cvSize(, ), cvSize(, ), );
(9个方向换成18个可能会取得更准确的结果,这取决于对图片本身的复杂程度的分析
之后即可训练knn分类器,进行分类了。
void knnTrain() {
#ifdef SAVETRAINED
//knn training;
samples.clear();
dat_mat = Mat::zeros( * nImgNum, , CV_32FC1);
res_mat = Mat::zeros( * nImgNum, , CV_32FC1);
for (int i = ; i != ; i++) {
getFile(dirNames[i], i);
}
preTrain();
cout << "------ Training finished. -----" << endl << endl;
knn.train(dat_mat, res_mat, Mat(), false, ); #ifdef SAVEASXML
knn.save("./trained/knnTrained.xml");
#endif #else
knn.load("./trained/knnTrained.xml");
#endif //knn test
cout << endl << "--- KNN test mode : ---" << endl;
int tCnt = ;
int tAc = ;
selfknnTest(tCnt, tAc); cout << endl << endl << "Total number of test samples : " << tCnt << endl; cout << "Accuracy : " << float(float(tAc) / float(tCnt)) * << "%" << endl;
}
train
训练结果如下,准确率还是很令人满意的。
opencv实现KNN手写数字的识别的更多相关文章
- OpenCV+TensorFlow图片手写数字识别(附源码)
初次接触TensorFlow,而手写数字训练识别是其最基本的入门教程,网上关于训练的教程很多,但是模型的测试大多都是官方提供的一些素材,能不能自己随便写一串数字让机器识别出来呢?纸上得来终觉浅,带着这 ...
- 手把手教你使用LabVIEW OpenCV DNN实现手写数字识别(含源码)
@ 目录 前言 一.OpenCV DNN模块 1.OpenCV DNN简介 2.LabVIEW中DNN模块函数 二.TensorFlow pb文件的生成和调用 1.TensorFlow2 Keras模 ...
- 机器学习(二)-kNN手写数字识别
一.kNN算法是机器学习的入门算法,其中不涉及训练,主要思想是计算待测点和参照点的距离,选取距离较近的参照点的类别作为待测点的的类别. 1,距离可以是欧式距离,夹角余弦距离等等. 2,k值不能选择太大 ...
- kaggle 实战 (1): PCA + KNN 手写数字识别
文章目录 加载package read data PCA 降维探索 选择50维度, 拆分数据为训练集,测试机 KNN PCA降维和K值筛选 分析k & 维度 vs 精度 预测 生成提交文件 本 ...
- 用Keras搭建神经网络 简单模版(三)—— CNN 卷积神经网络(手写数字图片识别)
# -*- coding: utf-8 -*- import numpy as np np.random.seed(1337) #for reproducibility再现性 from keras.d ...
- 10,knn手写数字识别
# 导包 import numpy as np import matplotlib.pyplot as plt from sklearn.neighbors import KNeighborsClas ...
- KNN手写数字识别
import numpy as np import matplotlib .pyplot as plt from sklearn.neighbors import KNeighborsClassifi ...
- caffe+opencv3.3dnn模块 完成手写数字图片识别
最近由于项目需要用到caffe,学习了下caffe的用法,在使用过程中也是遇到了些问题,通过上网搜索和问老师的方法解决了,在此记录下过程,方便以后查看,也希望能为和我一样的新手们提供帮助. 顺带附上老 ...
- 用tensorflow求手写数字的识别准确率 (简单版)
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data #载入数据集 mnist = in ...
随机推荐
- 【BZOJ】【1269】【AHOI2006】文本编辑器editor
Splay Splay序列维护的模板题了……为了便于处理边界情况,我们可以先插入两个空格当作最左端和最右端,然后……其实本题主要考察的就是Build.splay和Findkth这三个操作,我们可以实现 ...
- [COCI]coci2015/2016 nekameleoni
题意: 初始数列,每个数都在1~k以内 支持两种操作:1.修改一个数,修改后的数在1~k内 2.查询一个最短包含1~k的序列的长度 查询100000 ...
- noi2006day2_最大获利 网络流
这道题是上一题的数据加强版,dinic表示毫无压力: #include<iostream> #include<cstdio> #include<cstring> # ...
- Git 局域网简单配置
Git核心:http://code.google.com/p/msysgit/downloads/list?q=full+installer+official+gitTortoiseGit :http ...
- Nodejs Express 4.X 中文API 1--- Application篇
相关阅读: Express 4.X API 翻译[一] -- Application篇 Express4.XApi 翻译[二] -- Request篇 Express4.XApi 翻译[三] -- ...
- LUCAS 定理
原来一张图就就能证明:C(N,M)%P,p是素数. 简直太炫酷 先膜拜会 #include<iostream>#include<cstdio>#include<ctime ...
- android SDK更新
在proxy.ini里的[profile]下加上如下配置即可更新android SDK了 dl-ssl.google.com = nofakehttps Oct 26, 2014 #2 2828qw. ...
- Rust: move和borrow
感觉Rust官方的学习文档里关于ownship,borrow和lifetime介绍的太简略了,无法真正理解这些语法设计的原因以及如何使用(特别是lifetime).所以找了一些相关的blog来看,总结 ...
- Linux关于watch的用法
Linux关于watch的用法 2011-07-20 0个评论 收藏 我要投稿 watch 是一个非常实用的命令,基本所有的 Linux 发行版都带有这个小工具,如同名字一 ...
- JAVA 异常对于性能的影响
陶炳哲 - MAY 12, 2015 在对OneAPM的客户做技术支持时,我们常常会看到很多客户根本没意识到的异常.在消除了这些异常之后,代码运行速度与以前相比大幅提升.这让我们产生一种猜测,就是在代 ...