#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <algorithm>
#include <iterator>
#include <vector>
#include <math.h>
#include <vector>
#include <assert.h>
#include <string.h>
#include <dirent.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include "classification.cpp"
using namespace std;
using namespace cv;
//hanshu shengming
class Cuter
{
public:
Cuter();
Mat newThreshold(Mat img);
vector<RotatedRect> findTextRegion(Mat img);
int detect(Mat tmp,int type,int &title_right);
//将部分图片切成行
bool vcut(Mat srcImage,char *name);
Mat append(Mat src);
Mat hcut_spare(Mat srcImage);
bool hcut_big(Mat srcImage,char *name);
bool hcut_small();
bool hcut_title();
Mat preprocess(Mat gray,int type);
bool findtitle_cut(Mat src,char *name);
//void linecut(Mat img,char *name,int lineRank,int ranks);
bool hcut_search(Mat srcImage,char *name,int lineRank);
bool hcut_digit_single(Mat roiImg);
Mat merge(Mat leftImg,Mat rightImg);
void digit_classify();
void word_classify(int avg_width);
void linecut(int avg_width);
bool isDigit(string result)
{
if(result=="1"||result=="2"||result=="3"||result=="0"||result=="4"||result=="5"||result=="6"||result=="7"||result=="8"||result=="9"||result=="0")
return true;
else return false;
}
void show()
{
cout<<"数字的行数 "<<digit_line<<endl;
for(int i=0;i<singleList.size();i++)
{
char savePath[64];
sprintf(savePath,"singleList/%d.png",tmpRank++);
imwrite(savePath,singleList[i]);
}
}
void writeClassifyList()
{
for(int i=0;i<classifyList.size();i++)
{
char savePath[64];
sprintf(savePath,"classifyList/%d.png",tmpRank2++);
imwrite(savePath,classifyList[i]);
}
}
bool printResult(char *picName,bool isSuccess)
{
int cutPos=0;
for(int i=strlen(picName);i>=0;i--)
{
if(picName[i]=='/')
{
cutPos=i;
break;
}
}
string name;
for(int i=cutPos+1;i<strlen(picName);i++)
{
name+=picName[i];
}
FILE *fpRead=fopen("result_two","a");
if(digitResult.size()<=12||wordResult.size()<=0||!isSuccess)
{
string tmpResult;
tmpResult=tmpResult+name+" 识别错误 识别错误";
//out<<name<<" 识别错误 "<<"识别错误"<<endl;
char saveResult[256];
strcpy(saveResult,tmpResult.c_str());
fprintf(fpRead,"%s\n",saveResult);
fclose(fpRead);
return false;
}
string tmpResult;
char saveResult[256];
string digitAll;
for(int i=0;i<digitResult.size();i++)
{
string result=digitResult[i];
digitAll+=result;
/*
if(result=="A"||result=="B"||result=="C"||result=="D"||result=="E"||result=="F"||result=="G"||result=="H"||result=="I"||result=="J"||result=="K"||result=="L"||result=="M"||result=="N"||result=="O"||result=="P"||result=="Q"||result=="R"||result=="S"||result=="T"||result=="V"||result=="U"||result=="W"||result=="X"||result=="Y"||result=="Z")break;
*/
}
cout<<digitAll<<endl;
string wordAll;
int endPos=0;
string add;
for(int i=0;i<wordResult.size();i++)
{
string result=wordResult[i];
if(result=="有")
{
add="有限公司";
endPos=i-1;
break;
}
if(result=="限")
{
add="限公司";
endPos=i-2;
break;
}
if(result=="公")
{
add="公司";
endPos=i-3;
break;
}
if(result=="司")
{
add="司";
endPos=i-4;
break;
}
if(result=="厂")
{
add="厂";
endPos=i-1;
break;
}
}
if(endPos<0)
{
//cout<<"识别矫正错误"<<endl;
return false;
}
for(int i=0;i<=endPos;i++)
{
string result=wordResult[i];
wordAll+=result;
}
wordAll+=add;
cout<<wordAll<<endl;
tmpResult=tmpResult+name+" "+digitAll+" "+wordAll;
strcpy(saveResult,tmpResult.c_str());
fprintf(fpRead,"%s\n",saveResult);
fclose(fpRead);
return true;
}
Mat myRotate(Mat src,int rotateType)
{
if(rotateType==1)
{
// 矩阵转置
transpose(src, src);
//0: 沿X轴翻转; >0: 沿Y轴翻转; <0: 沿X轴和Y轴翻转
flip(src, src, 1);// 翻转模式,flipCode == 0垂直翻转(沿X轴翻转),flipCode>0水平翻转(沿Y轴翻转),flipCode<0水平垂直翻转(先沿X轴翻转,再沿Y轴翻转,等价于旋转180°)
return src;
}
else if(rotateType==2)
{
//0: 沿X轴翻转; >0: 沿Y轴翻转; <0: 沿X轴和Y轴翻转
flip(src, src, 0);// 翻转模式,flipCode == 0垂直翻转(沿X轴翻转),flipCode>0水平翻转(沿Y轴翻转),flipCode<0水平垂直翻转(先沿X轴翻转,再沿Y轴翻转,等价于旋转180°)
flip(src, src, 1);
return src;
}
else if(rotateType==3)
{
transpose(src, src);// 翻转模式,flipCode == 0垂直翻转(沿X轴翻转),flipCode>0水平翻转(沿Y轴翻转),flipCode<0水平垂直翻转(先沿X轴翻转,再沿Y轴翻转,等价于旋转180°)
flip(src, src, 0);
return src;
}
return src;
}
Mat quzao(Mat src);
void tmplinecut(int avg_width);
Mat getVcutImg()
{
return vcutImg;
}
private:
vector<double> rateList;
Mat vcutImg;
int classifyRank;
int imageType; //图片类型
int digit_line;
bool isFirstDigitLine;
bool isFirstWordLine;
bool hasFindWordLine;
int word_line;
int currentLine;
int currentSingle;
int lineDigitNum;
int maxLineDigitNum;
vector<Mat> lineList;
vector<Mat> preLineList;
vector<Mat> singleList;
vector<Mat> classifyList;
vector<string> digitResult;
vector<string> wordResult;
Classifier *allClassifier;
Classifier *digitClassifier;
int tmpRank;
int tmpRank2;
int avg_word_width;
/*
type 0 height>width
1 width>height && title on the left
2 width>height && title on the center
*/
};
Cuter::Cuter()
{
hasFindWordLine=false;
tmpRank=0;
tmpRank2=0;
isFirstDigitLine=true;
isFirstWordLine=true;
maxLineDigitNum=0;
classifyRank=0;
imageType=-1;
digit_line=-1;
word_line=-1;
currentLine=0;
currentSingle=0;
string model_file="45-word-new/lenet.prototxt";
string trained_file="45-word-new/lenet_solver_iter_405000.caffemodel";
string label_file="45-word-new/label";
//初始化分类器
allClassifier=new Classifier(model_file, trained_file, label_file);
model_file="45-digit-model/lenet.prototxt";
trained_file="45-digit-model/lenet_solver_iter_45000.caffemodel";
label_file="45-digit-model/label";
digitClassifier=new Classifier(model_file,trained_file,label_file);
}
Mat Cuter::newThreshold(Mat img)
{
int pixcount=0;
int height=img.rows;
int width=img.cols;
for(int i=0;i<height;i++)
{
for(int j=0;j<width;j++)
{
pixcount+=img.at<uchar>(i,j);
}
}
int avg_pix=(pixcount)/(height*width);
//cout<<avg_pix<<endl;
threshold(img,img,avg_pix-10,255,CV_THRESH_BINARY);
return img;
}
Mat Cuter::preprocess(Mat gray,int type)
{
//1.Sobel算子,x方向求梯度
Mat sobel;
Sobel(gray, sobel, CV_8U, 2, 1, 5);
//2.二值化
Mat binary;
// threshold(sobel, binary, 0, 255, THRESH_OTSU + THRESH_BINARY);
//imwrite("binary.png",sobel);
//3.膨胀和腐蚀操作核设定
Mat element1,element2;
if(type==0)
{
element1 = getStructuringElement(MORPH_RECT, Size(40, 5));
//控制高度设置可以控制上下行的膨胀程度,例如3比4的区分能力更强,但也会造成漏检
element2 = getStructuringElement(MORPH_RECT, Size(45,3));
}
else
{
element1 = getStructuringElement(MORPH_RECT, Size(65, 10));
//控制高度设置可以控制上下行的膨胀程度,例如3比4的区分能力更强,但也会造成漏检
element2 = getStructuringElement(MORPH_RECT, Size(40,4));
}
//4.膨胀一次,让轮廓突出
Mat dilate1;
dilate(sobel, dilate1, element2);
//5.腐蚀一次,去掉细节,表格线等。这里去掉的是竖直的线
Mat erode1;
erode(dilate1, erode1, element1);
//6.再次膨胀,让轮廓明显一些
Mat dilate2;
dilate(erode1, dilate2, element2);
//7.存储中间图片
return dilate2;
}
vector<RotatedRect> Cuter::findTextRegion(Mat img)
{
vector<RotatedRect> rects;
//1.查找轮廓
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(img, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE, Point(0, 0));
//2.筛选那些面积小的
for (int i = 0; i < contours.size(); i++)
{
//cout<<"contours.size "<<contours.size()<<endl;
//计算当前轮廓的面积
double area = contourArea(contours[i]);
//面积小于1000的全部筛选掉
if (area < 2000)
continue;
//轮廓近似,作用较小,approxPolyDP函数有待研究
double epsilon = 0.001*arcLength(contours[i], true);
Mat approx;
approxPolyDP(contours[i], approx, epsilon, true);
//找到最小矩形,该矩形可能有方向
RotatedRect rect = minAreaRect(contours[i]);
//计算高和宽
软件杯赛题——工商营业执照的切割和识别
最新推荐文章于 2023-07-04 09:24:17 发布