这个是树莓派上运行的, opencv3
opencv提供了一张手写数字图片给我们,如下图所示,可以作为识别手写数字的样本库。
0到9共十个数字,每个数字有五行,一行100个数字。首先要把这5000个数字截取出来。
图片大小为1000*2000,则每个数字块大小为20*20。
1.截取样本并存储
以下代码为截取以上数字并将其存储在矩阵中的过程
训练的数据,一般都会是两个矩阵,一个矩阵存放着数据图像,另一个矩阵存放数据图像对应的数字
Mat src = imread("sample.png");
Mat grayImage;
cvtColor(src, grayImage, CV_BGR2GRAY);
threshold(grayImage, grayImage, , , CV_THRESH_BINARY);
int p = ; //一个数字大小为20*20
int m = grayImage.rows / p; //横行的数字个数m
int n = grayImage.cols / p; //纵列的数字个数n
Mat data, labels; //data存放样本数据,label为data样本所对应的数字 for( int i = ; i < n; i++){
int y = i * p; //纵列第i个数字开始的位置
for(int j = ; j < m; j++){
int x = j * p; //横行第i个数字开始的位置
Mat dst;
grayImage(Range(x,x + p), Range(y, y + p)).copyTo(dst); data.push_back(dst.reshape(,)); //将20*20大小矩阵变为1*400 向量
labels.push_back( j / ); //对应数据向量存储的数字
}
} data.convertTo(data, CV_32F); //改变像素的数据类型为浮点型
Mat trainData, trainLabels;
trainData = data(Range(, ), Range::all());
trainLabels = labels(Range(, ), Range::all());
2.处理待识别数字的图像
//处理代检测图像
Mat Image, dst;
Image = imread("6.png");
cvtColor(Image, Image, COLOR_BGR2GRAY);
threshold(Image, Image, , , CV_THRESH_BINARY_INV);
imshow("Image", Image);
Image.copyTo(dst);
vector< vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(Image,contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
vector<Point> point = contours[];
Rect rect = boundingRect(point);
int x = rect.x, y = rect.y;
int h=rect.height, w = rect.width;
Mat now = dst(Range(x, x+h-), Range(y, y+w-));
//dst(rect).copyTo(now);
resize(now,now,Size(,));
3.使用knn算法进行识别,要将识别的图像也进行像训练样本一样的处理
我在运行程序时,一直有如下的错误,换了好几种处理图片的方式,仍然没有用
Mat_<float> nums;
nums = now.reshape(,);
nums.convertTo(nums, CV_32F);
imshow("待测图像", now);
/* Mat mm;
mm.push_back(now.reshape(0,1));
mm.convertTo(mm,CV_32F);
Mat nums = mm(Range(0,1),Range::all());
/*float imagedata[20*20];
for(int i =0; i < 20; i++){
for(int j=0;j<20;j++){
imagedata[ i *20 +j] = now.data[i *20+j];
}
}
Mat nums(1,20*20, CV_32F, imagedata);*/
最后查看源代码才发现不是其他参数的问题:
/// 错误 knn->findNearest(nums, 1, Mat()); Mat temp;
knn->findNearest(nums, 1, temp);
//要传入一个具体的Mat类型
最后的识别代码为
//创建knn分类器
Ptr<ml::KNearest> knn = (ml::KNearest::create());
knn->setIsClassifier(true);
Ptr<ml::TrainData> tData = ml::TrainData::create(trainData,ml::ROW_SAMPLE, trainLabels);
knn->train(tData);
Mat temp;
float result = knn->findNearest(nums, , temp); cout << result<<endl;
检查了好多遍,也只是不能识别出所有
程序缺陷:待检测的图像处理问题。不能截取出合适的roi区域
再改进吧。