代码拉取完成,页面将自动刷新
#include<iostream>
#include<omp.h>
#include<time.h>
#include<fstream>
#include<string>
#include<vector>
#include<queue>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
#define wenJianLuJing "C:\\OpenCV\\rec5\\" //要识别的图片
#define simplepath "C:\\OpenCV\\simple3\\" //模板存储路径
#define logShuChuLuJing "C:\\OpenCV\\out.txt" //调试日志输出路径
#define yongDuoXianCheng//是否开启多线程优化 如果没有环境,请关闭
//#define debug1 //一级debug 用于测试,输出图片
//#define debug2 //二级debug 用于演示,输出debug信息
ofstream fout;
vector<string> filenames;//正确结果
//用于debug的一些函数
void showImg(Mat m, string lable = "debug") {
#ifdef debug1
imshow(lable, m);
waitKey();
#endif // debug1
}
int i = 0;
void writeImg(Mat m, string name = "") {
#ifdef debug1
if (name == "")
{
name = to_string(i);
i++;
}
writeImg(m, name + ".jpg");
//waitKey();
#endif // debug1
}
///////////////////////////////////开始///////////////////////////////////////////////
/*
文件名预处理
获取文件名,转化为可以对比的字符串
输入为文件路径,输出完整文件名。
完成人:
*/
string ChuLiWenJianMing(string s) {
string r;
string base = wenJianLuJing;
int j = s.find(wenJianLuJing);
s = s.substr(s.find(wenJianLuJing) + base.size());
for (size_t i = 0; i < s.size(); i++)
{
if (s[i] == 'x' || s[i] == 'X' || (s[i] >= '0' && s[i] <= '9'))
{
r.push_back(s[i]);
}
}
#ifdef debug1
cout << "处理的文件名:" << r << endl;
#endif // debug1
return r;
}
//////////////////////////////////////////////////////////////////////////////////////
/*
图片读取加载
从文件夹中读取文件
完成人:
*/
vector<Mat> ShuRuTuPian() {//暂定 内存不足再改
vector<string> tuPianMen;//存储路径
glob(wenJianLuJing, tuPianMen, 0);
vector < Mat> tuPian;
for (int i = 0; i < tuPianMen.size(); i++)
{
Mat img = imread(tuPianMen[i]);
tuPian.push_back(img);
#ifdef debug2
cout << "读取 " << i << " 成功:" + tuPianMen[i] << endl;
#endif // debug2
filenames.push_back(ChuLiWenJianMing(tuPianMen[i]));
}
return tuPian;
}
//////////////////////////////////////////////////////////////////////////////////////
/*
图片降噪
降噪
输入为一个图像的数组 代表需要处理的所有图片 输出为处理好的图像的数组
完成人:
*/
//排序求中值
int reorder(vector<int>& shuzu)
{
int zhongzhi;
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9 - i - 1; j++)
{
if (shuzu[j] > shuzu[j + 1])
{
int temp;
temp = shuzu[j + 1];
shuzu[j + 1] = shuzu[j];
shuzu[j] = temp;
}
}
}
zhongzhi = shuzu[4];
return zhongzhi;
}
//单个图片降噪
void denoising(Mat grayImg, Mat& grayImg2)
{
grayImg2 = Mat(grayImg.rows, grayImg.cols, CV_8UC1);
vector<int>temp(9); //定义九个方向
int xx[9] = { 1,-1,1,-1,-1,0,1,0,0 };
int yy[9] = { 1,-1,-1,1,0,1,0,-1,0 };
for (int i = 0; i < grayImg.rows; i++)
{
for (int j = 0; j < grayImg.cols; j++)
{
//边缘部分不做处理
if (i == 0 || i == grayImg.rows - 1 || j == 0 || j == grayImg.cols - 1)
{
grayImg2.at<uchar>(i, j) = grayImg.at<uchar>(i, j);
}
else
{
for (int k = 0; k < 9; k++)
{
temp[k] = grayImg.at<uchar>(i + xx[k], j + yy[k]);
}
grayImg2.at<uchar>(i, j) = reorder(temp);
}
}
}
}
//降噪
Mat jiangZaoTuPian(Mat m) {
//GaussianBlur(m, m, Size(9, 9), 0); //高斯滤波
medianBlur(m, m, 9); //中值滤波
//denoising(m, m); //自己的中值滤波
return m;
}
//////////////////////////////////////////////////////////////////////////////////////
/*
图像转正
图像转正
完成人:
*/
Mat zhuanZhengTuPian(Mat vm)
{
Mat temp;
Sobel(vm, temp, -1, 0, 1, 5);
//霍夫直线检测(第5个参数是阈值,阈值越大,检测精度越高)
vector<Vec2f> Line;
HoughLines(temp, Line, 1, CV_PI / 180, 180, 0, 0);
// 画出直线
//计算偏转角度
double jiao = 0;
int zhiXianShu = 0;
for (int i = 0; i < Line.size(); i++)
{
if (Line[i][1] < 1.2 || Line[i][1]>1.8) continue;
jiao += Line[i][1];
zhiXianShu++;
}
if (zhiXianShu == 0)
jiao = CV_PI / 2;
else
jiao /= zhiXianShu;
jiao = 180 * jiao / CV_PI - 90;
Mat tempEr = getRotationMatrix2D(Point(vm.cols / 2, vm.rows / 2), jiao, 1);
warpAffine(vm, vm, tempEr, Size(vm.cols * 1.42, vm.rows));
return vm;
}
//////////////////////////////////////////////////////////////////////////////////////
/*
*
水漫处理
对图片进行水漫处理
输入为一个图像的数组 代表需要处理的所有图片 输出为处理好的图像的数组
完成人:
*/
struct position
{
position(int x, int y) :x(x), y(y) {
}
int x;
int y;
};
Mat shuiMan(Mat r) {
Mat m;
r.copyTo(m);
uchar* s = m.ptr<uchar>(0);
queue<position> qp;
for (size_t i = 0; i < m.rows; i++)
{
if (s[i] != 0)
{
position p(0, i);
qp.push(p);
//s[i] = 0;
}
}
while (!qp.empty())
{
position p = qp.front(); qp.pop();
if (p.x >= m.rows || p.x < 0 || p.y < 0 || p.y >= m.cols)
{
continue;//超出的p直接丢弃
}
uchar* u = m.ptr<uchar>(p.x);
if (m.at<uchar>(p.x, p.y) != 0)
{
m.at<uchar>(p.x, p.y) = 0;
qp.push(position(p.x + 1, p.y));
qp.push(position(p.x, p.y + 1));
qp.push(position(p.x - 1, p.y));
qp.push(position(p.x, p.y - 1));
}
}
return m;
}
//////////////////////////////////////////////////////////////////////////////////////
/*
*
二值化处理
对图片进行二值化处理
输入为一个图像的数组 代表需要处理的所有图片 输出为处理好的图像的数组
完成人:
*/
bool heiBaiSHu(Mat m) {//检查是否为黑白颠倒图片
Mat mat;
m.copyTo(mat);
threshold(mat, mat, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
int baishu = 0, heishu = 0;
for (int i = 0; i < mat.rows; i++)
{
for (int j = 0; j < mat.cols; j++)
{
/*image.at<Vec3b>(i, j)[0] = image.at<Vec3b>(i, j)[0] / div * div + div / 2;
image.at<Vec3b>(i, j)[1] = image.at<Vec3b>(i, j)[1] / div * div + div / 2;
image.at<Vec3b>(i, j)[2] = image.at<Vec3b>(i, j)[2] / div * div + div / 2;*/
if (mat.at<uchar>(i, j) == 0)
{
heishu++;
}
else
{
baishu++;
}
}
}
return heishu < baishu;
}
Mat ErZhiHuaTuPian(Mat mat, int moShi) {
Mat m;
mat.copyTo(m);
if (moShi == 0)
{
threshold(m, m, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
}
else if (moShi == 3)
{
adaptiveThreshold(m, m, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY_INV, 159, 18);
}
else if (moShi == 1)
{
adaptiveThreshold(m, m, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 11, 6);
}
else if (moShi == 2)
{
adaptiveThreshold(m, m, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 159, 18);
}
else if (moShi == 4)
{
adaptiveThreshold(m, m, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 99, 30);
}
else if (moShi == 5)
{
adaptiveThreshold(m, m, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 33, 11);
}
else if (4)
{
if (heiBaiSHu(m))
{
threshold(m, m, 0, 255, THRESH_BINARY | THRESH_OTSU);
}
else
{
threshold(m, m, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
}
}
return m;
}
//////////////////////////////////////////////////////////////////////////////////////
/*
预处理核心
调整合适大小 灰度化 二值化
输入为一个图像的数组 代表需要处理的所有图片 输出为处理好的图像的数组
完成人:
*/
Mat yuChuLiTuPian(Mat vm, int moShi = 0) {
#ifdef debug2
//cout << "YuChuLiShu: " << k << endl;
#endif // debug2
//调整图像大小呢
double kuan = 1200;
double gao = (double(vm.rows) / vm.cols) * kuan;
Size s(kuan, gao);
resize(vm, vm, s);
//灰度化
cvtColor(vm, vm, COLOR_BGR2GRAY);
vm = jiangZaoTuPian(vm);
//denoising(vmEr[k],vmEr[k]);
//二值化
//adaptiveThreshold(vmEr[k], vmEr[k], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 11, 6);
//adaptiveThreshold(vmEr[k], vmEr[k], 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY_INV, 159, 18);
//threshold(vmEr[k], vmEr[k], 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
if (moShi == 7)//针对可能出现的无法水漫的情况
{
vm = ErZhiHuaTuPian(vm, 0);
vm = zhuanZhengTuPian(vm);
return vm;
}
vm = ErZhiHuaTuPian(vm, moShi);
vm = zhuanZhengTuPian(vm);
vm = shuiMan(vm);
return vm;
}
//////////////////////////////////////////////////////////////////////////////////////
/*
图片分割
输入一个图片将图片分割为数字
输入为一个带有条码数字的图片 输出为数字图片的数组
完成人:
*/
vector<Mat> fenGeTuPian(Mat vm) {
vector<Mat> tupian;
//----这些声明可能需要在前面进行,因为我需要用就擅自声明了,可以调整位置
typedef pair<int, pair<int, int>> OPPP;
typedef pair<int, int> OPP;
vector<Point> pointsnumber; // 用于表示:每一行的像素值大于100像素点的数量
vector<int> rows_element; // 行ROI感兴趣区域
vector<OPPP> answervector; // 存储答案的容器
Mat res_image; // 处理完成的图像,提取兴趣框时用 *重要
Mat src_copy_image; // 拷贝输入图片
Range ROI_range; // y字符兴趣框位置
Mat ROI_image; // 提取兴趣框
vector<int> num_area; // 数字的ROI感兴趣区域,即字符分割
vector<OPP> num_position; // 数字的位置信息,用于字符分割
res_image = vm;
res_image.copyTo(src_copy_image);
Range ROI_range_x; // x字符兴趣框位置
//清除上一次的输入数据
answervector.clear();
pointsnumber.clear();
rows_element.clear();
for (int i = 0; i < res_image.rows; i++) {
int sum = 0;
uchar* ff = res_image.ptr(i);// 获取当前行的指针
// 遍历当前行的每个像素
for (int j = 0; j < res_image.cols; j++) {
if (*(ff + j) >= 100) { sum++; }
}// 统计亮度大于等于100的像素数量
rows_element.push_back(sum);// 将统计结果存储
// 存储点,横坐标为行内亮度大于等于100的像素数量的一半,纵坐标为行号
// 如果不是第一行,则在原图上画线连接当前点和前一个点
pointsnumber.push_back(Point(sum / 2, i));
if (i) line(src_copy_image, pointsnumber[max(0, i - 1)], pointsnumber[i], Scalar(255, 0, 0), 2);
}
int idx = -1;
// 索引初始化为-1
// 对行元素数组的前半部分进行遍历
for (int i = 0; i < rows_element.size() / 2; i++) {
if (rows_element[i] >= 35) // 如果当前行的亮度统计值大于等于35
{
OPPP item = { ++idx, {i, 0} }; // 创建一个新项,索引加1,起始行为i
answervector.push_back(item); // 将该项添加到结果中
int idx = i;// 更新idx为当前行号
// 循环直到找到一个行的亮度统计值小于35
while (idx < rows_element.size() && rows_element[idx] >= 35) {
idx++;
}
answervector[item.first].second.second = idx;// 更新当前项的结束行为idx
i = ++idx;// 更新遍历的行号
}
}
// 获取倒数第二个结果的起始和结束行号
int _begin = answervector[max(0, (int)answervector.size() - 2)].second.first, _end = answervector[max(0, (int)answervector.size() - 2)].second.second;
priority_queue<double> heap; // 定义一个最大堆
// 检查提取的区域是否过大或过小
if (_end - _begin >= 400 || _end - _begin <= 40) {
answervector.clear(); // 清空结果
idx = -1; // 索引重置为-1
// 重新遍历行元素数组的前半部分
for (int i = 0; i < rows_element.size() / 2; i++) {
// 如果当前行亮度统计值大于等于35,并且堆为空或当前行与堆顶元素差值不超过300
if (rows_element[i] >= 35 && (!heap.size() || heap.top() - rows_element[i] <= 300)) {
heap.push(rows_element[i]); // 将当前行亮度统计值推入堆
OPPP item = { ++idx, {i, 0} }; // 创建新项
answervector.push_back(item); // 添加到结果中
int idx = i; // 更新idx为当前行号
// 循环直到找到一个行的亮度统计值小于35或与堆顶元素差值超过300
while (idx < rows_element.size() && rows_element[idx] >= 35 && heap.top() - rows_element[idx] <= 300) {
//cout << "非法输入测试: idx " << idx <<" "<<rows_element.size()<< endl;
heap.push(rows_element[idx++]); // 将当前行亮度统计值推入堆
}
answervector[item.first].second.second = idx; // 更新当前项的结束行为idx
i = ++idx; // 更新遍历的行号
}
else {
// 如果不满足条件,则清空堆
while (heap.size()) heap.pop();
}
}
_begin = answervector[max(0, (int)answervector.size() - 2)].second.first, _end = answervector[max(0, (int)answervector.size() - 2)].second.second;
}
if (_begin >= _end || _begin > 114514)
return vector<Mat>();
// 保存兴趣框位置
ROI_range = Range(_begin, _end);
// 提取兴趣框
ROI_image = res_image(Range(_begin, _end), Range::all());
// 清空之前存储的区域数和位置信息
num_area.clear();
num_position.clear();
// 遍历ROI图像的每一列
for (int i = 0; i < ROI_image.cols; i++) {
int num = 0; // 用于统计当前列中亮度大于等于103的像素数量
// 遍历当前列的每一行
for (int j = 0; j < ROI_image.rows; j++) {
uchar* ch = ROI_image.ptr(j); // 获取当前行的指针
if (*(ch + i) >= 103) num++; // 如果当前像素的亮度大于等于103,则计数加1
}
num_area.push_back(num); // 将当前列的计数结果存储起来
}
// 遍历每一列的统计结果
for (int i = 0; i < num_area.size(); i++) {
// 如果当前列的亮度大于等于103的像素数量大于等于2
if (num_area[i] >= 2) {
OPP item = { max(i - 1, 0), 0 }; // 创建一个新的位置项,起始位置为当前位置减1(但不小于0),结束位置暂时设置为0
int idx = i; // 保存当前索引
// 继续向后遍历,直到找到一个列的亮度大于等于103的像素数量为0
while (num_area[idx]) idx++;
item.second = idx; // 更新位置项的结束位置为idx
i = idx; // 更新外层循环的索引,跳过已经检测过的区域
num_position.push_back(item); // 将位置项添加到结果列表中
}
}
// 保存x方向的边界
// 设置感兴趣区域的起始x坐标为第一个位置项的起始位置
if (num_position.empty())
{//数字为空 说明剪切失败一个字也没切出来
#ifdef debug2
cout << "E:图像分割失败,一个字也没分割" << endl;
fout << "E:图像分割失败,一个字也没分割" << endl;
#endif // debug2
return vector<Mat>();
}
ROI_range_x.start = num_position[0].first;
// 设置感兴趣区域的结束x坐标为最后一个位置项的结束位置
ROI_range_x.end = num_position[num_position.size() - 1].second;
for (int i = 0; i < num_position.size(); i++)
{
// 根据位置信息提取字符图像
Mat item_image = ROI_image(Range::all(), Range(num_position[i].first, num_position[i].second));
int head = 0;
// 查找字符图像的顶部位置
for (int j = 0; j < item_image.rows; j++) {
auto ff = item_image.ptr(j);
int num = 0;
for (int k = 0; k < item_image.cols; k++) {
num += ff[k]; // 计算当前行像素值之和
}
if (num) {
head = j; // 找到第一个非空行,记录位置为顶部位置
break;
}
}
int end = 0;
// 查找字符图像的底部位置
for (int j = item_image.rows - 1; j >= 0; j--)
{
auto ff = item_image.ptr(j);
int num = 0;
for (int k = 0; k < item_image.cols; k++) {
num += ff[k]; // 计算当前行像素值之和
}
if (num) {
end = j; // 找到最后一个非空行,记录位置为底部位置
break;
}
}
// 根据顶部位置和底部位置裁剪字符图像
item_image = item_image(Range(head, end), Range::all());
tupian.push_back(item_image);
}
return tupian;
}
//////////////////////////////////////////////////////////////////////////////////
/*
图片识别
输入一个图片确定是什么
输入为一个数字图片 图片内容是什么输出什么数字,输出-1为非数字(待定)
完成人:
*/
double jisuan(Mat inputImg)
{
double nums = 0;
int temp = 0;
for (int i = 0; i < inputImg.rows; i++)
{
for (int j = 0; j < inputImg.cols; j++)
{
if (inputImg.ptr(i)[j] != 0)
{
nums += inputImg.ptr(i)[j];
temp++;
}
}
}
return nums / (temp);
}
//字符识别
char shiBieTuPian(Mat inputImg)
{
if (double(inputImg.rows) / inputImg.cols < 0.5) {
///imshow("图片", inputImg);
waitKey(); return'-';
}
if (double(inputImg.rows) / inputImg.cols > 5) {
//imshow("图片", inputImg);
waitKey(); return'?';
}
if (double(inputImg.rows) * inputImg.cols < 400) {
//imshow("图片", inputImg);
waitKey(); return'=';
}
if (double(inputImg.rows) * inputImg.cols > 5500) {
//imshow("图片", inputImg);
waitKey(); return'`';
}
string sampleImgPath = simplepath;
vector<String> sampleImgFN;
glob(sampleImgPath, sampleImgFN, false);
int sampleImgNums = sampleImgFN.size();
vector<pair< double, int> >nums(sampleImgNums + 1);
for (int i = 0; i < sampleImgNums; i++) {
nums[i].second = i;
Mat numImg = imread(sampleImgFN[i], 0);
Mat delImg, demo_del_image;
resize(numImg, numImg, Size(inputImg.cols, inputImg.rows));
absdiff(numImg, inputImg, delImg);
//matchTemplate(inputImg, numImg, demo_del_image, TM_SQDIFF_NORMED);
nums[i].first = jisuan(delImg);
}
#ifdef debug1
//imshow("图片", inputImg);
#endif // debug1
waitKey();
//排序 越小说明匹配度越高
sort(&nums[0], &nums[sampleImgNums]);
int index = nums[0].second;
//index = index / 3;
return sampleImgFN[index][sampleImgPath.size()];
/*if (index >= 0 && index <= 9)
return index + '0';
else if (index == 10) return 'B';
else if (index == 11) return 'I';
else if (index == 12) return 'N';
else if (index == 13) return 'S';
else if (index == 14) return 'X';
else return ' ';*/
}
/////////////////////////////////////////////////////////////////////////////
/*
isbn码合法性检查
*/
bool isbnhefa13(string s) {
int sum = 0;
for (int i = 0; i < 12; i++) {
sum += (i % 2 == 0) ? s[i] - '0' : (s[i] - '0') * 3;
}
int check_digit = 10 - (sum % 10);
if (check_digit == 10) {
check_digit = 0;
}
return (check_digit == s[12] - '0');
}
bool isbnhefa10(const string s) {
int len = s.length();
int sum = 0;
for (int i = 0; i < len - 1; i++) {
sum += (i + 1) * (s[i] - '0');
}
if (s[len - 1] == 'X') {
sum += 10;
}
else {
sum += 10 * (s[len - 1] - '0');
}
return sum % 11 == 0;
}
bool isbnhefa(string s) {
if (s.size() == 10)
{
return isbnhefa10(s);
}
if (s.size() == 13)
{
return isbnhefa13(s);
}
return false;
}
//////////////////////////////////////////////////////////////////////////////////////
/*
计算字符正确率
*/
void zifuzql(string s1, string s2, int& zhengQueShuZi, int& shuZiShu)
{
shuZiShu = shuZiShu + s2.size();
if (s1 == s2)
{
zhengQueShuZi = zhengQueShuZi + s1.size();
}
else
{
int ks = 0;
for (int i = 0; i < s2.size(); i++)
{
int j = ks;
for (j; j < s1.size(); j++)
{
if (s2[i] == s1[j])
{
ks++;
#ifdef yongDuoXianCheng
#pragma omp atomic
#endif
zhengQueShuZi++;
}
}
}
}
}
//////////////////////////////////////////////////////////////////////////////////////
/*
计算结果并输出
计算结果 输出结果 注意输出美观
完成人:
*/
void jiSuanJieGuo(int tuPianShu = 0, int zhengQueTuPianShu = 0, int shuZiShu = 0, int zhengQueShuZi = 0) {
double tuPianShu2 = static_cast<double>(tuPianShu);
double zhengQueTuPianShu2 = static_cast<double>(zhengQueTuPianShu);
double shuZiShu2 = static_cast<double>(shuZiShu);
double zhengQueShuZi2 = static_cast<double>(zhengQueShuZi);
double zhengQueLv = zhengQueTuPianShu2 / tuPianShu2;
double zhunQueLv = zhengQueShuZi2 / shuZiShu2;
cout << endl;
cout << "图片总数:" << tuPianShu << " 正确识别数:" << zhengQueTuPianShu;
cout << fixed << setprecision(5) << "正确率:" << zhengQueLv << endl;
cout << "字符总数:" << shuZiShu << " 正确识别数:" << zhengQueShuZi << fixed << setprecision(5) << "准确率:" << zhunQueLv << endl;
fout << "正确率:" << zhengQueLv << endl << "准确率:" << zhunQueLv << endl;
}
////////////////////////////////////识别字符串处理////////////////////////////////////
/*
结果处理
计算正确率并输出
完成人:
*/
string JIeGuoChuLi(string s) {
string r;
bool zhanDaoN = false;
for (size_t i = 0; i < s.size(); i++)
{
char c = s[i];
if (c == 'N')
{
zhanDaoN = 1;
}
if (!zhanDaoN)
{
continue;
}
if (c == 'x' || c == 'X' || (c >= '0' && c <= '9'))
{
r.push_back(c);
}
if (c == 'B')
{
r.push_back('8');
}
//if (c=='S')
//{
//r.push_back('5');
//}
//if (c == 'I')
//{
//r.push_back('1');
//}
}
return r;
}
/////////////////////////////////////非核心部分结束/////////////////////////////////////////////
#define MODENUM 7 //用于预处理的模式数
//用于识别单张图片的函数
string chuLiDanZhuangTuPian(Mat mat, int i) {
string s1;//第一次识别的结果
string s;//最终识别结果呢
string s2;//中间变量
//尝试使用多种预处理模式,当某个模式得到合法结果时退出循环,反之继续尝试下一个算法
int k = 0;
for (; k <= MODENUM; k++)
{
s = s2 = "";
Mat m;
mat.copyTo(m);//opencv中mat应当用copyto函数生成副本,因为使用=只是传递指针
m = yuChuLiTuPian(m, k);//!!!重点 调用预处理模块预处理图片,m为图片,k为预处理的模式(截止目前有七种)
showImg(m);//debug的 显示一下图片
vector<Mat>vm = fenGeTuPian(m);//将图片按照字符分割
int j = 0;
for (size_t j = 0; j < vm.size(); j++)
{
//cout <<"识别测试:"<< shiBieTuPian(vm[j])<<endl;
char c = shiBieTuPian(vm[j]);
s2.push_back(c);
//showImg(vm[j]);
}
s = JIeGuoChuLi(s2);//处理结果,去掉明显不对的字符
//showImg(yiChuLiTuPianMen[i]);
if (k == 0)
{
s1 = s;
}
//通过isbn合法性验证函数验证isbn码是否合法
if (isbnhefa(s))
{
break;
}
}
#ifdef debug2
cout << s2 << ": 识别结果处理过:" << s << " 正确结果" << filenames[i];
fout << i << ": 识别结果:" << s2 << ": 识别结果处理过:" << s << " 正确结果" << filenames[i];
if (s == filenames[i])
{
cout << " √";
fout << " √";
}
fout << endl;
cout << endl;
#endif // debug2
if (k > MODENUM)
{
return s1;//如果所有模式都无法得出正确结果,则使用第一种模式的识别结果
}
return s;
}
int main() {
int tuPianShu = 0;
int hengQueTuPianShu = 0;
int shuZiShu = 0;
int zhengQueShuZi = 0;
vector<string> ShibieDe;
fout.open(logShuChuLuJing);//用于输出测试的文件
vector<Mat> yuanShiTuPianMen = ShuRuTuPian();//读入图片
tuPianShu = yuanShiTuPianMen.size();
clock_t start, end;
start = clock();//打点 用于记录程序运行时间
#ifndef debug2
int k = 0;
#endif // !debug2
#ifdef yongDuoXianCheng
#pragma omp parallel for //开启多线程优化
#endif // yongDuoXianCheng
for (int i = 0; i < tuPianShu; i++)
{
Mat m = yuanShiTuPianMen[i];
string s = chuLiDanZhuangTuPian(m, i);
if (s == filenames[i])
{
#ifdef yongDuoXianCheng
#pragma omp atomic //多线程线相关
#endif
hengQueTuPianShu++;
}
zifuzql(s, filenames[i], zhengQueShuZi, shuZiShu);
#ifndef debug2
#ifdef yongDuoXianCheng
#pragma omp atomic //多线程相关
#endif
k++;
cout << "\r当前进度:" << double(k) / tuPianShu * 100 << "%";
#endif // !debug2
}
end = clock();//打点 记录运行时间
fout << "\r" << endl;
fout << "正确识别:" << hengQueTuPianShu;
jiSuanJieGuo(tuPianShu, hengQueTuPianShu, shuZiShu, zhengQueShuZi);
cout << "运行时间 " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。