摄像头手写数字识别(基于KNN算法)
程序员文章站
2024-03-07 19:09:15
...
文章主要总结一下调试某位大神的程序过程和遇到的问题,代码文章参考来源:摄像头识别手写数字
1、工作环境
Ubuntu16.04,opencv2, IDE : Qt5.9.1Creator, 编译器:cmake
下载了大神的文章程序后发现没有main文件,就是需要打开摄像头的程序,由于对opencv 也是刚入门,走了不少弯路,针对原来的程序主要做了一下更改
2.工作历程
(1)写了主程序main.cpp将打开摄像头并处理训练数据放在主函数里了,读取数据,提取特征还是调用的原程序
原程序为windows下的,读取文件的路径需要更改,原dealData.h中:
//样本数据的保存路径
string dir_path = "E:\\data1\\sample\\";
// 更改为
string dir_path = "/home/sun/catkin_nr/src/nub_r/data1/sample/";
//其中双斜杠都要改为单斜杠
sprintf(path, "%s%d/.", dir_path.c_str(), i);
sprintf(tmp, "%s%d/%s", dir_path.c_str(), i, ptr->d_name);
原
(2)findContours输入为二值数据图,在阈值二值化之前必须先将rgb图灰度化,开始不了解,浪费了好长时间找问题,唉。。。
cvtColor(dstImage, grayImage, COLOR_BGR2GRAY);//extremely important
threshold(grayImage, Image, 120, 255, CV_THRESH_BINARY_INV);
findContours(Image,contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
(3)关于训练图片的尺寸,可以修改,原来博客中为128×128,后来我考虑到数字宽高不是1:1,所以将宽高改为64:96(此处取值也需注意,详见下面的博客),主要是作特征提取用。opencv命令为 HOGDescriptor(),关于此命令相关介绍参考:OpenCV HOGDescriptor 参数图解 讲的很详细。
(4)识别效果图:
门牌识别:
摄像头识别:
3.工作总结
该程序仅能进行 简单的数字识别,且识别距离有限,对图像光照要求比较高,改进空间很大,对于门牌识别还需要对门牌区域进行识别,切割,图像增强处理,畸变处理,路还很长。。。。。。识别算法比KNN好的还有很多,就当是一个开始吧!
4. main.cpp完整代码
(dealdata.h和hogmat.h没多大变化,就改个路径/,参见参考的博客附件)
//created 2018.4.17
#include <ros/ros.h>//用ROS_INFO来输出信息,没有ros环境可以改掉
#include <stdio.h>
#include <iostream>
#include <sstream> // for converting the command line parameter to integer
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/ml/ml.hpp>
#include "dealdata.h"
#include "hogmat.h"
using namespace cv;
using namespace std;
using namespace ml;
Mat trainImage;//用于存放训练图
Mat labelImage;//用于存放标签
int predict(Mat inputImage);
Mat deal_camera(Mat srcImage);
Ptr<KNearest> knn;
int result;
//load picture part added
vector<Mat> ROI;//用于存放图中抠出的数字区域
vector<Rect> ROIposition;//ROI在图像中的位置
vector<vector<Point> > contours;//点容器的容器,用于存放轮廓的点的容器的容器
vector<Vec4i> hierarchy;//点的指针容器
int result_2;//预测的结果
int weigth;//宽度
int height;//高度
Mat _roi;
Rect rect;
Point positiosn;
int brx; //右下角的横坐标
int bry; //右下角的竖坐标
int tlx; //左上角的横坐标
int tly; //左上角的竖坐标
int main(int argc, char** argv)
{ //open the camera
if(argv[1] == NULL)
{
ROS_INFO("argv[1]=NULL\n");
return 1;
}
istringstream video_sourceCmd(argv[1]);//local computer is 0,usb camera is 1!
int video_source;
if(!(video_sourceCmd >> video_source))
{ ROS_INFO("video_sourceCmd is %d\n",video_source);
return 1;
}
VideoCapture cap(video_source);
if (!cap.isOpened())
{ cout << "Failed to open camera." << endl;
return -1;
}
//Train data!
vector<string> samplePath;
vector<int> labels;
dealData::samplePath(samplePath, labels);
//导入样本,并做好标签图
for (int i = 0, _size = (int)samplePath.size(); i < _size; ++i)
{
Mat tmp = hogMat::getHogMat(samplePath[i]);
trainImage.push_back(tmp);
labelImage.push_back(labels[i]);
}
//创建KNN,并且设置N值为5
knn = KNearest::create();
knn->setDefaultK(5);
knn->setIsClassifier(true);
//生成训练数据
Ptr<TrainData> tData = TrainData::create(trainImage, ROW_SAMPLE, labelImage);
cout << "It's training!" << endl;
knn->train(tData);
//send picture
for(;;)
{ Mat frame;
cap >> frame;
frame = deal_camera(frame);
imshow("original", frame);
if(waitKey(30) >= 0)
break;
}
return 0;
}
int predict(Mat inputImage)
{
//预测函数
if (trainImage.size == 0)
{
cout << "请先初始化" << endl;
return -1;
}
Mat input = hogMat::gotHogMat(inputImage);
return (int)knn->predict(input); //返回预测结果
}
Mat deal_camera(Mat srcImage)
{
Mat dstImage, grayImage, Image;
srcImage.copyTo(dstImage);
cvtColor(dstImage, grayImage, COLOR_BGR2GRAY);
threshold(grayImage, Image, 120, 255, CV_THRESH_BINARY_INV);
findContours(Image,contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
//added for picture
vector< vector<Point> >::iterator It;
for (It = contours.begin(); It < contours.end(); It++)
{ //画出可包围数字的最小矩
rect = boundingRect(*It);
weigth = rect.br().x - rect.tl().x;//宽
height = rect.br().y - rect.tl().y;//高
if ((weigth < height && height< 4*weigth) && ((weigth > 10) || (height > 10)))//稍作修改
{ //根据数字的特征排除掉一些可能不是数字的图形,然后进行一下处理
Mat roi = Image(rect);
roi.copyTo(_roi);//深拷贝出来
ROI.push_back(_roi);//保存,方便操作
ROIposition.push_back(rect);
rectangle(srcImage, rect, Scalar(255, 255, 255), 1);
if ((height * 2) < weigth)
result = 1;
else{
Mat pre;
resize(_roi, pre, Size(64,96));
threshold(pre, pre, 120, 255, CV_THRESH_BINARY);
result = predict(pre);
}
char output[10] = { 0 };
sprintf(output, "%d", result);
positiosn = Point(rect.br().x - 7, rect.br().y + 25);
putText(srcImage,output,positiosn,1, 1.0,Scalar(0, 0, 0),1);//在屏幕上打印字
cout<<result<<endl;
}
}
return srcImage ;
}
上一篇: php封装的验证码类分享
下一篇: php生成图片缩略图功能示例