版权声明:本文为博主原创文章,转载注明出处。 https://blog.csdn.net/pengjc2001/article/details/62036476
前面有过用halcon识别字符,现在用opencv折腾下。比较一下
排除svm算法的问题,对我们来说就是构建合适的分类数据, 在这还是采用《Mastering OpenCV with Practical Computer Vision》中说的 水平方向字符投影 + 竖直方向字符投影 + 缩小后的字符像素信息矩阵(把它平铺)
将所有16个字符的信息 放在 一个 2维矩阵中 16X (characterOriginalWidth + characterOriginalHeight + characterWidth*characterHeight) 大小
还有需要注意的是 顺序, 找到的轮廓顺序不一定是你相应的分类顺序
#include "stdafx.h"
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
#include <vector>
#include <string>
#include <sstream>
#define HORIZONTAL 1
#define VERTICAL 0
#define characterOriginalWidth 58
#define characterOriginalHeight 120
#define characterWidth 5
#define characterHeight 10
#define testCount 16
using namespace cv;
using namespace cv::ml;
using std::vector;
using std::string;
Mat ProjectedHistogram(Mat img, int t)
{
int sz = (t) ? img.rows : img.cols;
Mat mhist = Mat::zeros(1, sz, CV_32F);
for (int j = 0; j < sz; j++)
{
Mat data = (t) ? img.row(j) : img.col(j);
mhist.at<float>(j) = countNonZero(data);
}
//Normalize histogram
double min, max;
minMaxLoc(mhist, &min, &max);
if (max > 0)
mhist.convertTo(mhist, -1, 1.0f / max, 0);
return mhist;
}
Mat features(Mat in, int sizeData_X, int sizeData_Y)
{
Mat vhist = ProjectedHistogram(in, VERTICAL);
Mat hhist = ProjectedHistogram(in, HORIZONTAL);
Mat lowData;
resize(in, lowData, Size(sizeData_X, sizeData_Y));
int numCols = vhist.cols + hhist.cols + lowData.rows*lowData.cols;
Mat out = Mat::zeros(1, numCols, CV_32F);
int j = 0;
for (int i = 0; i < vhist.cols; i++)
{
out.at<float>(j) = vhist.at<float>(i);
j++;
}
for (int i = 0; i < hhist.cols; i++)
{
out.at<float>(j) = hhist.at<float>(i);
j++;
}
for (int y = 0; y<lowData.rows; y++)
{
for (int x = 0; x<lowData.cols; x++)
{
out.at<float>(j) = (float)lowData.at<unsigned char>(y, x);
j++;
}
}
return out;
}
bool SortByIndex(Rect i, Rect j)
{
return (i.x<j.x);
}
int main()
{
char res[20];
vector<string> letters{"0","1","2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" };
Mat img = imread("D:\\Visual Studio 2015\\Projects\\numbers\\Debug\\1.bmp", CV_LOAD_IMAGE_GRAYSCALE);
imshow("输入原图像", img);
Mat binaryImg, meanImg, contoursImg(img.size(), CV_8U, Scalar(255));
GaussianBlur(img, meanImg, Size(5, 19), 0, 0);
threshold(meanImg,binaryImg,200,255,CV_THRESH_BINARY_INV);
vector<vector<Point>> contours;
findContours(binaryImg,contours,CV_RETR_EXTERNAL,CHAIN_APPROX_NONE);
drawContours(contoursImg, contours, -1, Scalar(0), 3);
int numCols = characterOriginalWidth + characterOriginalHeight + characterWidth*characterHeight;
Mat data = Mat::zeros(testCount, numCols, CV_32FC1); //预先产生一个 testCount X 2 的矩阵
Mat labels = Mat::zeros(testCount, 1, CV_32SC1);
// Draw blue contours on a white image
cv::Mat result;
img.copyTo(result);
cvtColor(result, result, CV_GRAY2RGB);
vector<vector<Point> >::iterator itc = contours.begin();
vector<cv::Rect> contoursRect;
//构建轮廓的最小矩形
while (itc != contours.end())
{
Rect mr = boundingRect(Mat(*itc));
contoursRect.push_back(mr);
++itc;
}
//最小矩形轮廓按左上角的x值由小到达排序为了和分类顺序对应
sort(contoursRect.begin(),contoursRect.end(), SortByIndex);
vector<Rect> ::iterator itcontoursRect = contoursRect.begin();
int i = 0;
while (itcontoursRect != contoursRect.end())
{
//用矩形切割图像
Mat auxRoi(img, *itcontoursRect);
sprintf_s(res, "train_data_%d.jpg", i);
//把分割好的图像统一大小(characterOriginalWidth * characterOriginalHeight)
resize(auxRoi, auxRoi, Size(characterOriginalWidth, characterOriginalHeight));
imwrite(res, auxRoi);
rectangle(result, *itcontoursRect, Scalar(0, 0, 255), 2);
Mat f = features(auxRoi, characterWidth, characterHeight);
f.row(0).copyTo(data.row(i));
labels.at<int>(i, 0) = i;
++itcontoursRect;
i++;
}
imshow("矩形分割后的输入原图像", result);
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
svm->train(data, ROW_SAMPLE, labels);
Mat imgPredict = imread("D:\\Visual Studio 2015\\Projects\\numbers\\Debug\\2.bmp", CV_LOAD_IMAGE_GRAYSCALE);
Mat binaryImgPredict, meanImgPredict, contoursImgPredict(img.size(), CV_8U, Scalar(255));
imshow("需要预测的图像", imgPredict);
GaussianBlur(imgPredict, meanImgPredict, Size(5, 19), 0, 0);
threshold(meanImgPredict, binaryImgPredict, 200, 255, CV_THRESH_BINARY_INV);
vector<vector<Point>> contoursPredict;
findContours(binaryImgPredict, contoursPredict, CV_RETR_EXTERNAL, CHAIN_APPROX_NONE);
drawContours(contoursImgPredict, contoursPredict, -1, Scalar(0), 3);
vector<vector<Point> >::iterator itcPredict = contoursPredict.begin();
Mat imgPredicted(imgPredict.size().height, imgPredict.size().width,CV_8UC3,Scalar(255,255,255));
while (itcPredict != contoursPredict.end())
{
Rect mr = boundingRect(Mat(*itcPredict));
Point point(mr.x, 80);
Mat auxRoi(imgPredict, mr);
resize(auxRoi, auxRoi, Size(characterOriginalWidth, characterOriginalHeight));
Mat f = features(auxRoi, characterWidth, characterHeight);
float response = svm->predict(f);
++itcPredict;
int index = response;
putText(imgPredicted, letters[index], point, CV_FONT_HERSHEY_SIMPLEX, 1, Scalar(255,0,0));
}
imshow("预测结果", imgPredicted);
waitKey(0);
return 0;
}