发票、文本等矫正

这里写图片描述

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;

#define ERROR 1234
//度数转换
double DegreeTrans(double theta)
{
    double res = theta / CV_PI * 180;
    return res;
}
//逆时针旋转图像degree角度(原尺寸)    
void rotateImage(Mat src, Mat& img_rotate, double degree)
{
    //旋转中心为图像中心    
    Point2f center;
    center.x = float(src.cols / 2.0);
    center.y = float(src.rows / 2.0);
    int length = 0;
    length = sqrt(src.cols*src.cols + src.rows*src.rows);
    //计算二维旋转的仿射变换矩阵  
    Mat M = getRotationMatrix2D(center, degree, 1);
    warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换,背景色填充为白色  
}
//通过霍夫变换计算角度
double CalcDegree(const Mat &srcImage, Mat &dst)
{
    Mat midImage, dstImage;
    dstImage = srcImage.clone();
    cvtColor(srcImage, midImage, CV_BGR2GRAY);
    Mat bw;
    adaptiveThreshold(~midImage, bw, 255, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
    Mat horizontal = bw.clone();
    int scale = 30; //这个值越大,检测到的直线越多
    int horizontalsize = horizontal.cols / scale;
    Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontalsize, 1));
    erode(horizontal, horizontal, horizontalStructure, Point(-1, -1));
    dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1));
    //Canny(srcImage, midImage, 50, 200, 3);
    //cvtColor(midImage, dstImage, CV_GRAY2BGR);
    //通过霍夫变换检测直线
    vector<Vec2f> lines;
    HoughLines(horizontal, lines, 1, CV_PI / 180, 300, 0, 0);//第5个参数就是阈值,阈值越大,检测精度越高
                                                           //cout << lines.size() << endl;

                                                           //由于图像不同,阈值不好设定,因为阈值设定过高导致无法检测直线,阈值过低直线太多,速度很慢
                                                           //所以根据阈值由大到小设置了三个阈值,如果经过大量试验后,可以固定一个适合的阈值。
    if (!lines.size())
    {
        HoughLines(horizontal, lines, 1, CV_PI / 180, 200, 0, 0);
    }
    //cout << lines.size() << endl;
    if (!lines.size())
    {
        HoughLines(horizontal, lines, 1, CV_PI / 180, 150, 0, 0);
    }
    //cout << lines.size() << endl;
    if (!lines.size())
    {
        cout << "没有检测到直线!" << endl;
        return ERROR;
    }
    float sum = 0;
    //依次画出每条线段
    for (size_t i = 0; i < lines.size(); i++)
    {
        float rho = lines[i][0];
        float theta = lines[i][1];
        Point pt1, pt2;
        //cout << theta << endl;
        double a = cos(theta), b = sin(theta);
        double x0 = a * rho, y0 = b * rho;
        pt1.x = cvRound(x0 + 1000 * (-b));
        pt1.y = cvRound(y0 + 1000 * (a));
        pt2.x = cvRound(x0 - 1000 * (-b));
        pt2.y = cvRound(y0 - 1000 * (a));
        //只选角度最小的作为旋转角度
        sum += theta;
        line(dstImage, pt1, pt2, Scalar(55, 100, 195), 1); //Scalar函数用于调节线段颜色
        imshow("直线探测效果图", dstImage);
    }
    float average = sum / lines.size(); //对所有角度求平均,这样做旋转效果会更好
    cout << "average theta:" << average << endl;
    double angle = DegreeTrans(average) - 90;
    //rotateImage(dstImage, dst, angle);
    //imshow("直线探测效果图2", dstImage);
    return angle;
}
void ImageRecify(const char* pInFileName, const char* pOutFileName)
{
    double degree;
    Mat src = imread(pInFileName);
    imshow("原始图", src);
    Mat dst;
    //倾斜角度矫正
    degree = CalcDegree(src,dst);
    if (degree == ERROR)
    {
        cout << "矫正失败!" << endl;
        return;
    }
    rotateImage(src, dst, degree);
    cout << "angle:" << degree << endl;
    imshow("旋转调整后", dst);
    Mat resulyImage = dst(Rect(0, 0, src.cols, src.rows)); //根据先验知识,估计好文本的长宽,再裁剪下来
    imshow("裁剪之后", resulyImage);
    imwrite(pOutFileName, resulyImage);
}
int main()
{
    ImageRecify("E:\\fengce\\0813\\06R187260B9000.tif", "FinalImage.tif");
    waitKey(0);
    return 0;
}

代码更新 目前采用的方法鲁棒性会比较好一点

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>
#include <io.h>  
using namespace cv;
using namespace std;
#define MAX_PATH 1024  //最长路径长度
#define ERROR 1234

//计算旋转的角度
double  computeIntersect(cv::Vec4i a)
{
    double angle = 0;
    double flage_temp;
    int x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3];
    Point tempPoint;
    double temp;
    tempPoint.x = x2 - x1;
    tempPoint.y = y2 - y1;
    if ((0 == tempPoint.x) && (0 == tempPoint.y))
    {
        return 0;
    }
    if (0 == tempPoint.x)
    {
        angle = 90;
        return angle;
    }
    if (0 == tempPoint.y)
    {
        angle = 0;
        return angle;
    }
    temp = fabsf(float(tempPoint.y) / float(tempPoint.x));
    temp = atan(temp);
    temp = temp * 180 / CV_PI;
    if (tempPoint.y < 0)
    {
        angle = -temp;
        return angle;
    }
    else
    {
        angle =temp;
        return angle;
    }
    return ERROR;
}
//度数转换
double DegreeTrans(double theta)
{
    double res = theta / CV_PI * 180;
    return res;
}
//逆时针旋转图像degree角度(原尺寸)    
void rotateImage(Mat src, Mat& img_rotate, double degree)
{
    //旋转中心为图像中心    
    Point2f center;
    center.x = float(src.cols / 2.0);
    center.y = float(src.rows / 2.0);
    int length = 0;
    length = sqrt(src.cols*src.cols + src.rows*src.rows);
    //计算二维旋转的仿射变换矩阵  
    Mat M = getRotationMatrix2D(center, degree, 1);
    warpAffine(src, img_rotate, M, Size(length, length), 1, 0, Scalar(255, 255, 255));//仿射变换,背景色填充为白色  
}
//通过霍夫变换计算角度
double CalcDegree(const Mat &srcImage, Mat &dst)
{
    Mat midImage, dstImage;
    dstImage = srcImage.clone();
    double threa;
    cvtColor(srcImage, midImage, CV_BGR2GRAY);
    Mat bw;
    adaptiveThreshold(~midImage, bw, 255, CV_ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, 15, -2);
    Mat horizontal = bw.clone();
    int scale = 30; //这个值越大,检测到的直线越多
    int horizontalsize = horizontal.cols / scale;
    Mat horizontalStructure = getStructuringElement(MORPH_RECT, Size(horizontalsize, 1));
    erode(horizontal, horizontal, horizontalStructure, Point(-1, -1));
    dilate(horizontal, horizontal, horizontalStructure, Point(-1, -1));
    vector<Vec4i> lines;
    HoughLinesP(horizontal,lines,1,CV_PI/180,100,200,50);
    if (!lines.size())
    {
        return ERROR;
    }
    float sum = 0;
    //依次画出每条线段
    for (size_t i = 0; i < lines.size(); i++)
    {
        Vec4i l = lines[i];
        threa = computeIntersect(lines[i]);
        sum += threa;
        //cout << threa << endl;
        line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, CV_AA);
    }
    float average = sum / lines.size(); //对所有角度求平均,这样做旋转效果会更好
    return average;
}
void ImageRecify(string pInFileName, string pOutFileName)
{
    double degree;
    Mat src = imread(pInFileName);
    //imshow("原始图", src);
    Mat dst;
    //倾斜角度矫正
    degree = CalcDegree(src,dst);
    if (degree == ERROR)
    {
        cout << "矫正失败!" << endl;
        return;
    }
    rotateImage(src, dst, degree);
    //cout << "angle:" << degree << endl;
    //imshow("旋转调整后", dst);
    Mat resulyImage = dst(Rect(0, 0, src.cols, src.rows)); //根据先验知识,估计好文本的长宽,再裁剪下来
    //imshow("裁剪之后", resulyImage);
    imwrite(pOutFileName, resulyImage);
}
//得到文件名
void getAllFiles(string path, vector<string>& files)
{
    //文件句柄  
    long   hFile = 0;
    //文件信息  
    struct _finddata_t fileinfo;  //很少用的文件信息读取结构
    string p;  //string类很有意思的一个赋值函数:assign(),有很多重载版本
    if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
    {
        do
        {
            if ((fileinfo.attrib &  _A_SUBDIR))  //判断是否为文件夹
            {
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
                {
                    files.push_back(p.assign(path).append("/").append(fileinfo.name));//保存文件夹名字
                    getAllFiles(p.assign(path).append("/").append(fileinfo.name), files);//递归当前文件夹
                }
            }
            else    //文件处理
            {
                files.push_back(p.assign(path).append("/").append(fileinfo.name));//文件名
            }
        } while (_findnext(hFile, &fileinfo) == 0);  //寻找下一个,成功返回0,否则-1
        _findclose(hFile);
    }
}
//读取txt
void readTxt(string file)
{
    ifstream infile;
    infile.open(file.data());   //将文件流对象与文件连接起来 
    assert(infile.is_open());   //若失败,则输出错误消息,并终止程序运行 
    int i = 0;
    string s;
    while (getline(infile, s))
    {
        string path= "E:\\fengce\\0816\\"+static_cast<ostringstream*>(&(ostringstream() <<i))->str()+".tif";
        ImageRecify(s, path);
        cout << s << endl;
        i++;
    }
    infile.close();             //关闭文件输入流 
}
int main()
{
    double timeStart = (double)getTickCount();
    ImageRecify("E:\\fengce\\0815\\08R18726080013.tif","FinalImage.tif");
    double nTime = ((double)getTickCount() - timeStart) / getTickFrequency();
    cout << "运行上面程序共耗时:" << nTime << "秒\n" << endl;
    //waitKey(0);
    //readTxt("AllFiles.txt");
    return 0;
}

效果图
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值