#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <string>
#include <io.h>
#include <vector>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;
//author dedong
//机器学习实战 矩阵运算问题
/************************************************************************/
/* 获取文件夹下所有文件名
输入:
path : 文件夹路径
exd : 所要获取的文件名后缀,如jpg、png等;如果希望获取所有
文件名, exd = ""
输出:
files : 获取的文件名列表
*/
/************************************************************************/
void getFiles(string path, string exd, vector<string>& files)
{
//文件句柄
long hFile = 0;
//文件信息
struct _finddata_t fileinfo;
string pathName, exdName;
if (0 != strcmp(exd.c_str(), ""))
{
exdName = "\\*." + exd;
}
else
{
exdName = "\\*";
}
if ((hFile = _findfirst(pathName.assign(path).append(exdName).c_str(), &fileinfo)) != -1)
{
do
{
//如果是文件夹中仍有文件夹,迭代之
//如果不是,加入列表
if ((fileinfo.attrib & _A_SUBDIR))
{
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
getFiles(pathName.assign(path).append("\\").append(fileinfo.name), exd, files);
}
else
{
if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
files.push_back(pathName.assign(path).append("\\").append(fileinfo.name));
}
} while (_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
//字符串分割
void SplitString(const string& s, vector<string>& v, const string& c)
{
string::size_type pos1, pos2;
pos2 = s.find(c);
pos1 = 0;
while (string::npos != pos2)
{
v.push_back(s.substr(pos1, pos2 - pos1));
pos1 = pos2 + c.size();
pos2 = s.find(c, pos1);
}
if (pos1 != s.length())
v.push_back(s.substr(pos1));
}
vector<string> split(const string &s, const string &seperator){
vector<string> result;
typedef string::size_type string_size;
string_size i = 0;
while (i != s.size()){
//找到字符串中首个不等于分隔符的字母;
int flag = 0;
while (i != s.size() && flag == 0){
flag = 1;
for (string_size x = 0; x < seperator.size(); ++x)
if (s[i] == seperator[x]){
++i;
flag = 0;
break;
}
}
//找到又一个分隔符,将两个分隔符之间的字符串取出;
flag = 0;
string_size j = i;
while (j != s.size() && flag == 0){
for (string_size x = 0; x < seperator.size(); ++x)
if (s[j] == seperator[x]){
flag = 1;
break;
}
if (flag == 0)
++j;
}
if (i != j){
result.push_back(s.substr(i, j - i));
i = j;
}
}
return result;
}
//读取txt数据
void getFromText(String pathStr, Mat &myMat, uchar *pCurrentFace)
{
ifstream myFaceFile;
myFaceFile.open(pathStr, ios::in);
int temp;
for (int r = 0; r < 1024; r++)
{
myFaceFile >> temp;
pCurrentFace[r] = (uchar)temp;
}
for (int i = 0; i < 32; i++)
{
uchar *pixelPtr = myMat.ptr<uchar>(i);
for (int j = 0; j < 32; j++)
{
pixelPtr[j] = pCurrentFace[i*j + j];
}
}
myFaceFile.close();
}
/*----------------------------
* 功能 : 从 .txt 文件中读入数据,保存到 cv::Mat 矩阵
* - 默认按 float 格式读入数据,
* - 如果没有指定矩阵的行、列和通道数,则输出的矩阵是单通道、N 行 1 列的
*----------------------------
* 函数 : LoadData
* 访问 : public
* 返回 : -1:打开文件失败;0:按设定的矩阵参数读取数据成功;1:按默认的矩阵参数读取数据
*
* 参数 : fileName [in] 文件名
* 参数 : matData [out] 矩阵数据
* 参数 : matRows [in] 矩阵行数,默认为 0
* 参数 : matCols [in] 矩阵列数,默认为 0
* 参数 : matChns [in] 矩阵通道数,默认为 0
*/
int LoadData(string fileName, cv::Mat& matData, int matRows = 0, int matCols = 0, int matChns = 0)
{
int retVal = 0;
//ifstream myFaceFile;
//myFaceFile.open(pathStr, ios::in);
// 打开文件
ifstream inFile(fileName.c_str(), ios_base::in);
//ifstream inFile;
//inFile.open(fileName.c_str(), ios::in);
if (!inFile.is_open())
{
cout << "读取文件失败" << endl;
retVal = -1;
return (retVal);
}
// 载入数据
istream_iterator<float> begin(inFile); //按 float 格式取文件数据流的起始指针
istream_iterator<float> end; //取文件流的终止位置
vector<float> inData(begin, end); //将文件数据保存至 std::vector 中
cv::Mat tmpMat = cv::Mat(inData); //将数据由 std::vector 转换为 cv::Mat
cout << inData.at(0) << endl;
// 输出到命令行窗口
//copy(vec.begin(),vec.end(),ostream_iterator<double>(cout,"\t"));
// 检查设定的矩阵尺寸和通道数
size_t dataLength = inData.size(); //32
//1.通道数
if (matChns == 0)
{
matChns = 1;
}
//2.行列数
if (matRows != 0 && matCols == 0)
{
matCols = dataLength / matChns / matRows;
}
else if (matCols != 0 && matRows == 0)
{
matRows = dataLength / matChns / matCols;
}
else if (matCols == 0 && matRows == 0)
{
matRows = dataLength / matChns;
matCols = 1;
}
//3.数据总长度
//cout << dataLength << endl;
//cout << matRows * matCols * matChns << endl;
if (dataLength != (matRows * matCols * matChns))
{
cout << "读入的数据长度 不满足 设定的矩阵尺寸与通道数要求,将按默认方式输出矩阵!" << endl;
retVal = 1;
matChns = 1;
matRows = dataLength;
}
// 将文件数据保存至输出矩阵
matData = tmpMat.reshape(matChns, matRows).clone();
return (retVal);
}
//图片转矩阵
Mat img2Vec(const string &fileName){
Mat returnVec = Mat::zeros(1, 1024, CV_8UC1);
//cout << "returnVec=" << endl << " " << returnVec << endl << endl;
//uchar *pCurrentFace = (uchar*)malloc(1024 * sizeof(uchar));
//getFromText(fileName, returnVec, pCurrentFace);
LoadData(fileName, returnVec, 1, 1024, 1);
//imshow("读取txt", returnVec);
return returnVec;
//ifstream infile;
//int data;
//cout << "存入矩阵" << endl;
//int a[3][4];
//int*p = &returnVec[0][0];
//while (infile >> data) //遇到空白符结束
//{
// *p = data;
// p++;
//}
//infile.close();
//for (int i = 0; i<3; i++)
//{
// for (int j = 0; j<4; j++)
// cout << a[i][j] << "\t";
// cout << endl;
//}
}
//获取字符串最后的数字D:\\workspace\\Spyder\\MLinAct\\Ch02\\trainingDigits\\0
int getnum(string s)
{
//return s[s.length() - 1];
int num = 0;
int n = s.length();
int wei = 1;
for (int i = n - 1; i >= 0; i--){
if (s[i] == '\\'){ return num; }
else {
num += (s[i] - '0')*wei;
wei *= 10;
}
}
return wei;
}
//txt数据文件转矩阵
Mat txt2Vec(const string &fileName)
{
Mat returnVec = Mat::zeros(1, 1024, CV_8UC1);
fstream testByCharFile;
char c;
//testByCharFile.open("D:\\workspace\\Spyder\\MLinAct\\Ch02\\trainingDigits\\0_0.txt", ios::in);
testByCharFile.open(fileName, ios::in);
while (!testByCharFile.eof())
{
testByCharFile >> c;
//cout << c;
for (int i = 0; i < 1024; i++)
{
returnVec.at<char>(0, i) = c;
}
}
testByCharFile.close();
return returnVec;
}
//快排
void quick_sort(int *arr, int low, int high) {
if (low < high) {
int i = low, j = high, pivot = arr[low];
while (i < j) {
while (i < j&&arr[j] >= pivot) //从右开始遍历,直到找到小于pivot的值为止
--j;
if (i < j)
arr[i++] = arr[j];
while (i < j&&arr[i] <= pivot) //从左开始遍历直到找到大于pivot的值为止
++i;
if (i < j)
arr[j--] = arr[i];
}
arr[i] = pivot;
quick_sort(arr, low, i - 1);
quick_sort(arr, i + 1, high);
}
}
//排序,然后返回前K位在原数组中的下标
void argsort(int K, float *arr, int *label, int Size_trainData){
int *tmp = (int *)malloc(sizeof(int)*Size_trainData);
int *cmp = (int *)malloc(sizeof(int)*Size_trainData);
int i;
for (i = 0; i < Size_trainData; cmp[i] = (int)
(arr[i++] * 1000));
for (i = 0; i < Size_trainData; tmp[i] = (int)
(arr[i++] * 1000));
quick_sort(tmp, 0, Size_trainData - 1);
for (i = 0; i < K; ++i) {
for (int j = 0; j < Size_trainData; ++j) {
if (abs(tmp[i] == cmp[j]))
label[i] = j;
}
}
}
typedef pair<string, int> PAIR;
bool cmp_by_value(const PAIR& lhs, const PAIR& rhs) {
return lhs.second < rhs.second;
}
struct CmpByValue {
bool operator()(const PAIR& lhs, const PAIR& rhs) {
return lhs.second > rhs.second;
}
};
//kNN算法 根据机器学习实战python代码改编
string kNNClassifier(Mat inX, Mat dataSet, vector<string> labels, int k){
int dataSetSize = dataSet.size().height;
Mat inMat = Mat::zeros(dataSetSize, 1024, CV_8UC1);
Mat diffMat = Mat::zeros(dataSetSize, 1024, CV_8UC1);
Mat rowMat(dataSetSize, 1, CV_8UC1, Scalar(0));
Mat resultMat = Mat::zeros(dataSetSize, dataSetSize, CV_8UC1);
float *dist = (float *)malloc(sizeof(float)*dataSetSize);
int distance = 0; //平方差距离
//for (int i = 0; i < dataSetSize; i++)
//{
// for (int j = 0; j < 1024; j++)
// {
// diffMat.at<int>(i, j) = pow(inX.at<int>(j) -dataSet.at<int>(i, j), 2);
// distance += diffMat.at<int>(i, j);
// }
// dist[i] = pow(distance, 0.5);
//}
//cout << endl << inX.reshape(0, 1).clone() << endl;
for (int i = 0; i < dataSetSize; i++)
{
inX.reshape(0, 1).clone().row(0).copyTo(inMat.row(i)); //inX矩阵转换成一行再复制给inMat
}
diffMat = inMat - dataSet; //矩阵差值
//cout << endl << diffMat << endl << endl;
resultMat = diffMat.mul(diffMat); //矩阵对应项相乘 1934*1024
//cout << endl << resultMat << endl << endl;
for (int i = 0; i < dataSetSize; i++) //对矩阵行求和 距离平方和
{
distance = 0;
uchar* data = resultMat.ptr<uchar>(i);
for (int j = 0; j < 1024; j++)
{
distance = data[j] + distance;
}
dist[i] = distance;
}
int *label = (int *)malloc(sizeof(int)*k); //
argsort(k, dist, label, dataSetSize); //对kNN计算结果排序 返回K个 label
map<string, int> class_count_map;
int newValue;
std::map<string, int>::iterator it;
for (int i = 0; i < k; i++)
{
string vote = labels[label[i]]; //计算结果,辨别出0-9,投票
//if (class_count_map.count(vote)>0){
// class_count_map[vote] ++;
//}
//else{
// class_count_map[vote] = 1;
//}
it = class_count_map.find(vote);
if (it == class_count_map.end()) //如果没出现过,就赋值1
class_count_map.insert(std::make_pair(vote, 1));
else
{
newValue = ++class_count_map[vote]; //出现过就++
it->second = newValue; //对键值的修改
}
}
//cout << endl << class_count_map << endl << endl;
vector<PAIR> class_count_vec(class_count_map.begin(), class_count_map.end());
sort(class_count_vec.begin(), class_count_vec.end(), CmpByValue()); //排序从大到小
return class_count_vec[0].first;
}
int main()
{
Mat srcImage = imread("F:\\Projects\\Elevator\\EleDigit\\digits-crop\\test-images\\2_6.bmp");
Mat dstImage, grayImage, Image, normalImage, inverseImage, invNorImage, trainMat, diffImg;
string fileNameStr, fileName, classNumStr;
vector<string> v1, v2, labelVec, vRe;
string realClass;
srcImage.copyTo(dstImage);
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
threshold(grayImage, Image, 48, 1, CV_THRESH_BINARY);
threshold(grayImage, inverseImage, 48, 1, CV_THRESH_BINARY_INV);
resize(Image, normalImage, Size(32, 32), 0, 0, CV_INTER_LINEAR);
resize(inverseImage, invNorImage, Size(32, 32), 0, 0, CV_INTER_LINEAR);
cout << "normalImage=" << endl << " " << normalImage << endl << endl;
//normalImage = ~normalImage;
cout << "invNorImage=" << endl << " " << invNorImage << endl << endl;
diffImg = normalImage.mul(normalImage);
cout << "diffImg=" << endl << " " << diffImg << endl << endl;
//waitKey(2000);
//trainFileList
string filePath = "F:\\Projects\\Elevator\\EleDigit\\trainingDigits";
vector<string> fileVec;
getFiles(filePath, "txt", fileVec);
int fileVecSize = fileVec.size();
//for (int i = 0; i < fileVecSize; i++)
//{
// cout << fileVec[i].c_str() << endl;
//}
trainMat = Mat::zeros(fileVecSize, 1024, CV_8UC1); // 全零矩阵
//cout << "trainMat=" << endl << " " << trainMat << endl << endl;
for (int i = 0; i < fileVecSize; i++)
{
fileNameStr = fileVec[i].c_str();
v1 = split(fileNameStr, ".");
fileName = v1[0];
v2 = split(fileName, "_");
classNumStr = v2[0];
realClass = classNumStr[classNumStr.length() - 1];
labelVec.push_back(realClass); //数字标签 存入labelVec
Mat returnVec = txt2Vec(fileNameStr);
//cout << endl << i << endl;
//cout << fileNameStr << endl;
//cout << "returnVec=" << endl << " " << returnVec << endl << endl;
returnVec.row(0).copyTo(trainMat.row(0));
//for (int j = 0; j < 1024; j++)
//{
// trainMat.at<int>(i, j) = returnVec.at<int>(j);
//}
}
string classResult = kNNClassifier(normalImage, trainMat, labelVec, 3); //kNN
cout << endl << "识别结果:" << " " << classResult << endl << endl;
//char result = classResult[classResult.length() - 1];
//cout << endl << "识别结果:" << " " << result << endl << endl;
//testFileList
//string testFilePath = "D:\\workspace\\Spyder\\MLinAct\\Ch02\\testDigits\\";
//vector<string> testFileVec;
//getFiles(testFilePath, "txt", testFileVec);
//int testFileVecSize = testFileVec.size();
//for (int i = 0; i < testFileVecSize; i++){
// testFileNameStr = testFileVec[i].c_str();
// SplitString(testFileNameStr, v3, ".");
// testFileName = v3[0];
// SplitString(testFileName, v4, "_");
// classNumStr = v4[0];
//}
system("pause");
//定义轮廓和层次结构
//vector<vector<Point>> contours;
//vector<Vec4i> hierarchy;
//findContours(Image, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
//int i = 0;
//Point2f pp[5][4];
//vector<vector<Point>>::iterator It;
//Rect rect[10];
return 0;
}
数字识别
最新推荐文章于 2024-05-25 20:18:05 发布