如题,如图

上图为识别有误样张,下图为识别正常样张。

现在是简单的贴票识别没问题,但是较复杂的贴票就会识别有误,识别不全,请教大家谁能帮我看下原因?

代码段:
void do_bill_image(const char* pTifFile)
{
    if (NULL == pTifFile)
        return;

int p[3];
    p[0] = CV_IMWRITE_JPEG_QUALITY;
    p[1] = 85;
    p[2] = 0;

IplImage* lpImgSrc = cvLoadImage(pTifFile, CV_LOAD_IMAGE_COLOR);*/
    if (lpImgSrc)
    {
        std::map<int, RECT> mapRC;
        mapRC.clear();

IplImage* lpImgBinary = get_image_binary(lpImgSrc, 0);
        if (lpImgBinary)
        {
            removice_noise_image(lpImgBinary, 3);//降噪

cvErode(lpImgBinary, lpImgBinary, NULL, 3);//腐蚀
            //cvDilate(lpImgBinary, lpImgBinary, NULL, 3);//膨胀
            
            removeblack(lpImgBinary);//漫水填充

int iSpace = lpImgBinary->width/2;
            std::vector<UINT> vecHistogramSum;
            vecHistogramSum.clear();

{    // 图片像素统计(垂直投影)
                IplImage* lpImageOut = cvCreateImage(cvGetSize(lpImgBinary), lpImgBinary->depth, lpImgBinary->nChannels);
                if (lpImageOut)
                {
                    SumImageHistogram(lpImgBinary, lpImageOut, vecHistogramSum, 8, 0);

int iCount = 0;
                    unsigned long ulSum = 0;
                    std::vector<UINT>::iterator it = vecHistogramSum.begin();
                    while (it != vecHistogramSum.end())
                    {
                        if (*it)
                        {
                            ulSum += *it;
                            iCount++;
                        }

it++;
                    }

int iAvg = ulSum / iCount;
                    int ithreshold = iAvg / 5;

//如果获取的高度小于50个像素,认为是空白
                    if (8 > ithreshold)
                        return;

RECT rc;
                    ZeroMemory(&rc, sizeof(RECT));
                    rc.right  = lpImageOut->width-1;
                    rc.bottom = lpImageOut->height/2;

std::vector<RECT> vecRegionalism;
                    vecRegionalism.clear();

statistical_image_chang_count_pos(lpImageOut, rc, vecRegionalism, ithreshold/2, ithreshold/2, false);

if (!vecRegionalism.empty())
                    {
                        //if (1 == vecRegionalism.size())
                        //{
                        //    
                        //}
                        //else
                        {
                            std::vector<RECT>::iterator it = vecRegionalism.begin();
                            while (it != vecRegionalism.end())
                            {
                                if (100 > (it->right - it->left))
                                {
                                    it++;

continue;
                                }

IplImage* lpImgTemp = Copy_Image_roi_data(lpImgBinary, it->left, 0, it->right, lpImgBinary->height);
                                if (lpImgTemp)
                                {
                                    // 记录图片的水平投影
                                    std::vector<RECT> vecRegsm;
                                    vecRegsm.clear();

{    // 图片像素统计(水平投影)
                                        IplImage* lpImgOut = cvCreateImage(cvGetSize(lpImgTemp), lpImgTemp->depth, lpImgTemp->nChannels);
                                        if (lpImgOut)
                                        {
                                            vecHistogramSum.clear();

SumImageHistogram(lpImgTemp, lpImgOut, vecHistogramSum, 8, 1);

rc.left = 0;
                                            rc.top  = 0;
                                            rc.right  = lpImgOut->width  - 1;
                                            rc.bottom = lpImgOut->height - 1;
                                            statistical_image_chang_count_pos(lpImgOut, rc, vecRegsm, 8, 8, true);

cvReleaseImage(&lpImgOut);
                                        }
                                    }

std::map<int, RECT> mapRcs;    // 记录符合条件的椭圆数量
                                    mapRcs.clear();

{    // 图片轮廓跟踪
                                        //contour = cvApproxPoly(contour, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 3, 1);

IplImage* pContourImg = cvCreateImage(cvGetSize(lpImgTemp), lpImgTemp->depth, 3);
                                        IplImage* pImgeare = cvCreateImage(cvGetSize(lpImgTemp), lpImgTemp->depth, 3);
                                        //cvZero(pContourImg);
                                        //cvZero(pImgeare);

RECT rcClear;
                                        memset(&rcClear, 0, sizeof(RECT));
                                        rcClear.right  = pContourImg->width  - 1;
                                        rcClear.bottom = pContourImg->height - 1;

clear_Image_rect(pContourImg, rcClear);
                                        clear_Image_rect(pImgeare, rcClear);

CvBox2D32f *box;
                                        CvPoint *PointArray;
                                        CvPoint2D32f *PointArray2D32f;

CvScalar external_color;
                                        CvScalar hole_color;
                                        int color;
                                        CvMemStorage* storage = cvCreateMemStorage(0);
                                        CvSeq* contour = 0;

int contours_num = cvFindContours(lpImgTemp, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cvPoint(0, 0)); // 轮廓跟踪

int iIndex = 0;
                                        //绘制所有轮廓并用椭圆拟合    
                                        while (contour)
                                        {
                                            int i;
                                            int count = contour->total;//轮廓个数    
                                            CvPoint center;
                                            CvSize size;

/*个数必须大于6,这是cvFitEllipse_32f的要求*/
                                            if (count < 6)
                                            {
                                                contour = contour->h_next;
                                                continue;
                                            }

cout << "count: " << count << ", Index: " << iIndex++ << endl;

//分配内存给点集    
                                            PointArray = (CvPoint *)malloc(count * sizeof(CvPoint));
                                            PointArray2D32f = (CvPoint2D32f*)malloc(count * sizeof(CvPoint2D32f));

//分配内存给椭圆数据    
                                            box = (CvBox2D32f *)malloc(sizeof(CvBox2D32f));

//得到点集(这个方法值得借鉴)    
                                            cvCvtSeqToArray(contour, PointArray, CV_WHOLE_SEQ);

//将CvPoint点集转化为CvBox2D32f集合    
                                            for (i = 0; i < count; i++)
                                            {
                                                PointArray2D32f[i].x = (float)PointArray[i].x;
                                                PointArray2D32f[i].y = (float)PointArray[i].y;
                                            }

//拟合当前轮廓    
                                            cvFitEllipse(PointArray2D32f, count, box);
                                            double c = sqrt((box->size.height)*(box->size.height) / 4 - (box->size.width)*(box->size.width) / 4);
                                            double lxl = 2 * c / box->size.height;
                                            if ((48.00 < box->size.height && 100.00 < box->size.width) &&
                                                (lpImgBinary->height/3 > box->size.height && lpImgBinary->width/2 > box->size.width))
                                            {
                                                cout << "离心率: " << lxl << ", Height: " << box->size.height << ", Width: " << box->size.width << ", Height/Width: " << (box->size.height/box->size.width) << endl;

//绘制当前轮廓    
                                                cvDrawContours(pImgeare, contour, CV_RGB(0, 0, 0), CV_RGB(0, 0, 0), 0, 3, CV_AA, cvPoint(0, 0));

//将椭圆数据从浮点转化为整数表示    
                                                center.x = cvRound(box->center.x);
                                                center.y = cvRound(box->center.y);
                                                size.width  = cvRound(box->size.width*0.5);
                                                size.height = cvRound(box->size.height*0.5);
                                                box->angle  = -box->angle;

RECT rc;
                                                rc.left = box->center.x - box->size.height*0.5;
                                                rc.top  = box->center.y - box->size.width *0.5;
                                                rc.right  = rc.left + box->size.height;
                                                rc.bottom = rc.top  + box->size.width;
                                                //mapRcs.insert(std::map<int, RECT>::value_type(rc.top, rc));
                                                //画椭圆  
                                                if (TRUE == InsertRcMap(mapRcs, rc))  
                                                    cvEllipse(pContourImg, center, size, box->angle, 0, 360, CV_RGB(0, 0, 0), 3, CV_AA, 0);
                                            }

free(PointArray);
                                            free(PointArray2D32f);
                                            free(box);

contour = contour->h_next;
                                        }

cvReleaseMemStorage(&storage);

IplImage* pImgEareBin = get_image_binary(pImgeare, 0);

cvReleaseImage(&pContourImg);
                                        cvReleaseImage(&pImgeare);

if (pImgEareBin)
                                        {
                                            std::vector<RECT> vecRegiona;
                                            vecRegiona.clear();

RECT rcTmp;
                                            memset(&rcTmp, 0, sizeof(RECT));
                                            rcTmp.right  = pImgEareBin->width  - 1;
                                            rcTmp.bottom = pImgEareBin->height - 1;

statistical_image_chang_count_pos(pImgEareBin, rcTmp, vecRegiona, 2, 2, true);

cvReleaseImage(&pImgEareBin);

if (!vecRegiona.empty())
                                            {
                                                int iSize = vecRegiona.size();
                                                int iCount = iSize%2;
                                                if (iCount)
                                                {    // 奇数各

}
                                                else
                                                {    // 偶数个
                                                    std::vector<RECT>::iterator it1, it2;
                                                    it1 = vecRegiona.begin();
                                                    it2 = vecRegiona.begin();
                                                    it2++;

while (it1 != vecRegiona.end() && it2 != vecRegiona.end())
                                                    {
                                                        RECT rect;
                                                        memset(&rect, 0, sizeof(RECT));
                                                        rect.top    = it1->top;
                                                        rect.bottom = it2->bottom;
                                                        rect.left   = it->left;
                                                        rect.right  = it->right;

{
                                                            std::vector<RECT>::iterator ittemp1;
                                                            ittemp1 = vecRegsm.begin();

while (ittemp1 != vecRegsm.end())
                                                            {
                                                                if (64 > abs(rect.top - ittemp1->top))
                                                                {
                                                                    rect.top = __min(rect.top, ittemp1->top);
                                                                }

if (100 > abs(rect.bottom - ittemp1->bottom))
                                                                {
                                                                    rect.bottom = __max(rect.bottom, ittemp1->bottom);
                                                                }

ittemp1++;
                                                            }

}

mapRC[rect.top] = rect;

it1++;
                                                        it2++;

if (it1 != vecRegiona.end() && it2 != vecRegiona.end())
                                                        {
                                                            it1++;
                                                            it2++;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }

cvReleaseImage(&lpImgTemp);
                                }

it++;
                            }
                        }
                    }
                    else
                    {
                        // 空的白纸
                        return ;
                    }
                    
                    cvReleaseImage(&lpImageOut);
                }
            }

cvReleaseImage(&lpImgBinary);
        }

{
            std::map<int, RECT>::iterator it;
            it = mapRC.begin();

while (it != mapRC.end())
            {
                // 判断加载图片的长宽比是否满足VAT发票的要求
                int itemp = (int)(((double)(it->second.right-it->second.left)/(double)(it->second.bottom-it->second.top))*10.00);    // 一般发票长宽比例为1.5% ~ 1.8%左右
                if (itemp > 20)    
                {    // 清单
                    mapRC.erase(it);

if (!mapRC.empty())
                    {
                        it = mapRC.begin();
                        continue;
                    }
                    else
                    {
                        break;
                    }
                }

it++;
            }
        }

if (mapRC.empty())
        {
            IplImage* lpImgBinary = get_image_binary(lpImgSrc, 0);
            if (lpImgBinary)
            {
                std::vector<UINT> vecHistogramSum;
                vecHistogramSum.clear();

removice_noise_image(lpImgBinary, 3);

cvErode(lpImgBinary, lpImgBinary, NULL, 3);

// 记录图片的水平投影
                std::vector<RECT> vecRegsm;
                vecRegsm.clear();

{    // 图片像素统计(水平投影)
                    IplImage* lpImgOut = cvCreateImage(cvGetSize(lpImgBinary), lpImgBinary->depth, lpImgBinary->nChannels);
                    if (lpImgOut)
                    {
                        vecHistogramSum.clear();

SumImageHistogram(lpImgBinary, lpImgOut, vecHistogramSum, 8, 1);

RECT rc;
                        rc.left = 0;
                        rc.top  = 0;
                        rc.right  = lpImgOut->width  - 1;
                        rc.bottom = lpImgOut->height - 1;
                        statistical_image_chang_count_pos(lpImgOut, rc, vecRegsm, 8, 8, true);

cvReleaseImage(&lpImgOut);
                    }
                }

if (!vecRegsm.empty())
                {
                    std::vector<RECT>::iterator it;
                    it = vecRegsm.begin();
                    while (it != vecRegsm.end())
                    {
                        if (it->bottom - it->top > 100)
                        {
                            IplImage* lpImgTemp = Copy_Image_roi_data(lpImgBinary, it->left, it->top, it->right, it->bottom);
                            if (lpImgTemp)
                            {
                                IplImage* lpImgOut = cvCreateImage(cvGetSize(lpImgTemp), lpImgTemp->depth, lpImgTemp->nChannels);
                                if (lpImgOut)
                                {
                                    vecHistogramSum.clear();

SumImageHistogram(lpImgTemp, lpImgOut, vecHistogramSum, 8, 0);

RECT rc;
                                    rc.left = 0;
                                    rc.top  = 0;
                                    rc.right  = lpImgOut->width  - 1;
                                    rc.bottom = lpImgOut->height - 1;

std::vector<RECT> vecRegsmons;
                                    vecRegsmons.clear();

statistical_image_chang_count_pos(lpImgOut, rc, vecRegsmons, 3, 3, false);

if (!vecRegsmons.empty())
                                    {
                                        int iCount = 0;
                                        std::vector<RECT>::iterator itor;
                                        itor = vecRegsmons.begin();
                                        while (itor != vecRegsmons.end())
                                        {
                                            if (itor->right - itor->left > 100)
                                            {
                                                RECT rt;
                                                rt.left   = itor->left;
                                                rt.top    = it->top;
                                                rt.right  = itor->right;
                                                rt.bottom = it->bottom;

mapRC[rt.top+iCount] = rt;
                                            }

iCount++;

itor++;
                                        }
                                    }

cvReleaseImage(&lpImgOut);
                                }

cvReleaseImage(&lpImgTemp);
                            }
                        }

it++;
                    }
                }

cvReleaseImage(&lpImgBinary);
            }
        }

if (!mapRC.empty())
        {
            std::map<int, RECT>::iterator it;
            it = mapRC.begin();

while (it != mapRC.end())
            {
                cv::Point pt1, pt2;
                pt1.x = it->second.left;
                pt1.y = it->second.top;

pt2.x = it->second.right;
                pt2.y = it->second.bottom;

//cv::rectangle(cv::cvarrToMat(&lpImgSrc), pt1, pt2, CV_RGB(0, 255, 0), 4, 8, 0);

CvPoint pt[4];
                pt[0].x = it->second.left;
                pt[0].y = it->second.top;

pt[1].x = it->second.right;
                pt[1].y = it->second.top;

pt[2].x = it->second.right;
                pt[2].y = it->second.bottom;

pt[3].x = it->second.left;
                pt[3].y = it->second.bottom;

cvLine( lpImgSrc, pt[0], pt[1], CV_RGB(0, 255, 0), 8, 8, 0);
                cvLine( lpImgSrc, pt[1], pt[2], CV_RGB(0, 255, 0), 8, 8, 0);
                cvLine( lpImgSrc, pt[2], pt[3], CV_RGB(0, 255, 0), 8, 8, 0);
                cvLine( lpImgSrc, pt[3], pt[0], CV_RGB(0, 255, 0), 8, 8, 0);

it++;
            }

char szFile[MAX_PATH];
            memset(szFile, 0, sizeof(char)*MAX_PATH);
            strcpy(szFile, pTifFile);

char* pPos = strrchr(szFile, '.');
            if (pPos)
            {
                strcpy(pPos, "_result");

const char * pP = strrchr(pTifFile, '.');
                if (pP)
                {
                    strcat(szFile, pP);
                }
            }
            
            pPos = strrchr(szFile, '.');
            if (pPos && 0 == stricmp(pPos, ".jpg"))
            {
                cvSaveImage(szFile, lpImgSrc, p);
            }
            else
            {
                cvSaveImage(szFile, lpImgSrc);
            }
        }
        
        cvReleaseImage(&lpImgSrc);
    }
}

VC++ 利用Opencv 做的一个发票识别程序,识别有误相关推荐

  1. VC利用WORD替换功能打印发票

    VC利用WORD替换功能打印发票 摘自网络 在用VC开发一项目时,需要打印发票.由于发票的种类比较多,而且有的是已经有文字,有的空白的,还有一部分文字是可变的,动态改变.如果用VC直接控制它的输出,是 ...

  2. nodejs android 推送,利用Nodejs怎么实现一个微信小程序消息推送功能

    利用Nodejs怎么实现一个微信小程序消息推送功能 发布时间:2021-01-20 13:55:29 来源:亿速云 阅读:92 作者:Leah 今天就跟大家聊聊有关利用Nodejs怎么实现一个微信小程 ...

  3. 用php实现随机点名,使用javascript做的一个随机点名程序

    这篇文章主要介绍了使用javascript做的一个随机点名程序,经测试,效果相当不错,需要的朋友可以参考下 /p> "http://www.w3.org/TR/html4/loose. ...

  4. opencv做的美女找茬程序~

    // CMP.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h" #include <cv.h> #include <highg ...

  5. 利用OpenCV做个熊猫表情包吧

    有的时候很想把一些有意思的图中的人脸做成熊猫表情,但是由于不太会ps,只能无奈放弃,so sad... 正好最近想了解下opencv的使用,那就先试试做个简单的熊猫表情生成器把~~ 思路就是,工具给两 ...

  6. 如何利用论坛做推广 | 一个每天可以吸引50粉丝的推广思路

    转载自:http://ido258.com/article/184.html 论坛推广很多人都在做,我想大部分人在电脑上做推广,都是从免费的论坛开始的. 那么,到底该怎么进行论坛推广呢,有哪些技巧和方 ...

  7. 大学生利用Python做了一个答题助手!别人自己搜,他的全自动!

    自从同学用Python开发出了自动搜索答案后,每次网课(选修)他都在玩游戏,而我们作死的在百度搜答案! 使用平台 windows7 python3.6 MIX2手机 1.使用Airdroid 将手机屏 ...

  8. 【学习笔记】大三集中实训做的一个微信小程序之点餐系统(静态页面不包含java后台逻辑)

    点餐系统 注:大三集中实训的时候由于没有什么经验,只实现了静态页面,但微信小程序开发文档里面所有的功能差不多都实现(视频的上传与下载以及登录等等)所以在这里记录自己的学习笔记 目录 **点餐系统** ...

  9. opencv快速入门人脸检测与人脸识别

    让"它"认得你 --利用opencv快速入门人脸检测与人脸识别 opencv,顾名思义"开源,计算机视觉".OpenCV就是这样的一个特殊的框架,一群大牛然绕自 ...

最新文章

  1. winscp是什么软件_winscp ftp,winscp ftp是什么软件?软件介绍
  2. MySQL 复制滞后怎么办?其实方法很简单
  3. python界面开发pyqt_Python2.7+PyQt4进行界面开发
  4. python聚类的结果显示_使用Python进行聚类
  5. 轻松解决linux磁盘分配不均问题
  6. java设计模式--基础思想总结--抽象类与架构设计思想
  7. [ASM] 基础概念
  8. Unity 2D 打地鼠游戏制作过程总结
  9. python练习-prat1
  10. 带你去旅游 伴我游世界
  11. 作业5 - 团队展示
  12. Bhuman应用篇——带球及踢球
  13. 鸿蒙系统升级到第几批了,鸿蒙系统第四批升级名单有哪些 鸿蒙系统第四批升级机型介绍...
  14. 怎么把ppt转化成图片
  15. 光辉国际宣布陈兆丰先生为新任中国区总裁
  16. IBM ThinkPad 机子无法开机的解决办法 - 按开机键没有反应 - E49
  17. 用 CSS3 做一个流星雨动画
  18. 〔转载〕从蓝色巨人到四海一家 IBM品牌塑造及转型
  19. V2X、OBU、RSU、V2V之间的协作关系
  20. matlab simulink Buck三电平dcdc变换器

热门文章

  1. 双非菜鸡3个月收割头条大数据offer,方向真的比努力更重要!
  2. python的基本使用
  3. 【FFMPEG】视频压制效果对比
  4. 黑莓手机高级使用技巧
  5. 微信公众平台开发:接入JS-SDK和实现分享功能
  6. 全网最细海龟 (turtle) 画图讲解 (四):绘制图形
  7. 美创科技再次入选《2023杭州独角兽准独角兽企业榜单》
  8. 最短路径——迪杰斯坷垃算法(有向图、单源最短路径)
  9. 下个路口的转变—黑马
  10. 个人上传文件进服务器,个人上传文件进服务器