图像识别与处理笔记——字符识别、邮政编码识别(10月8日暂存)

今天学习到了邮政编码识别,找到了相关理论与实际的代码,分析了一下,有些地方还不是很懂。
理论是看的杨淑莹的《图像识别与项目实践——VC++、matlab计术实现》 第四章–邮政编码识别。

下面是网上找到的字符识别相关程序

#include <cv.h>
#include <highgui.h>
#include <math.h>
#include <stdio.h>
#include <iostream>
#include <cxcore.h>

using namespace std;

IplImage* rotateImage2(IplImage* img, double angle)    
{    
    //double angle = degree /180*CV_PI; 
    int step;
    int i,j,k;
    uchar*data ;


    cout<<"angle="<<angle<<endl;   // 角度 angle
    double a = sin(angle), b = cos(angle);   
    int width=img->width, height=img->height;  
    //旋转后的新图尺寸  
    int width_rotate= int(height * fabs(a) + width * fabs(b)); //旋转后的宽度,函数:fabs(a):求浮点数a的绝对值 ,强制类型转换
    int height_rotate=int(width * fabs(a) + height * fabs(b));    
    IplImage* img_rotate = cvCreateImage(cvSize(width_rotate, height_rotate), img->depth, img->nChannels); 
    cvZero(img_rotate);    //好像是清除


    step=img->widthStep/sizeof(uchar);
    data   = (uchar*)img->imageData;

    for(i=0;i<img->height;i++)
        for(j=0;j<img->width;j++)
            for(k=0;k<img->nChannels;k++)
                data[i*step+j*img->nChannels+k]=255-data[i*step+j*img->nChannels+k];//反色

    //保证原图可以任意角度旋转的最小尺寸  
    int tempLength = sqrt((double)width * width + (double)height *height) + 10;    
    int tempX = (tempLength + 1) / 2 - width / 2;    
    int tempY = (tempLength + 1) / 2 - height / 2;    
    IplImage* temp = cvCreateImage(cvSize(tempLength, tempLength), img->depth, img->nChannels);    
    cvZero(temp);    
    //将原图复制到临时图像tmp中心  
    cvSetImageROI(temp, cvRect(tempX, tempY, width, height));    
    cvCopy(img, temp, NULL);    
    cvResetImageROI(temp);    
    //旋转数组map  
    // [ m0  m1  m2 ] ===>  [ A11  A12   b1 ]  
    // [ m3  m4  m5 ] ===>  [ A21  A22   b2 ]  
    float m[6];    
    int w = temp->width;    
    int h = temp->height;    
    m[0] = b;    
    m[1] = a;    
    m[3] = -m[1];    
    m[4] = m[0];    
    // 将旋转中心移至图像中间    
    m[2] = w * 0.5f;    
    m[5] = h * 0.5f;    
    CvMat M = cvMat(2, 3, CV_32F, m);    
    cvGetQuadrangleSubPix(temp, img_rotate, &M);  

    step=img_rotate->widthStep/sizeof(uchar);
    data   = (uchar*)img_rotate->imageData;

    for(i=0;i<img_rotate->height;i++)
        for(j=0;j<img_rotate->width;j++)
            for(k=0;k<img_rotate->nChannels;k++)
                data[i*step+j*img_rotate->nChannels+k]=255-data[i*step+j*img_rotate->nChannels+k];//反色

    cvReleaseImage(&temp);    
    return img_rotate;  
} 

int otsu(const IplImage *src)
{
    double sum=0.0;
    double w0=0.0;
    double w1=0.0;
    double u0_temp=0.0;
    double u1_temp=0.0;
    double u0=0.0;
    double u1=0.0;
    double delta_temp=0.0;
    double delta_max=0.0;

    int pixel_count[256]={0};
    float pixel_pro[256]={0};
    int threshold=0;
    uchar *data=(uchar *)src->imageData;

    for(int i=0;i<src->height;i++)
    {
        for(int j=0;j<src->width;j++)
        {
            pixel_count[(int)data[i*src->width+j]]++;
            sum+=(int)data[i*src->width+j];
        }
    }
    cout<<"平均灰度:"<<sum/(src->height*src->width)<<endl;

    for(int i=0;i<256;i++)
    {
        pixel_pro[i]=(float)pixel_count[i]/(src->height*src->width);
    }

    for(int i=0;i<256;i++)
    {
        w0=w1=u0_temp=u1_temp=u0=u1=delta_temp=0;
        for(int j=0;j<256;j++)
        {
            if(j<=i)
            {
                w0+=pixel_pro[j];
                u0_temp+=j*pixel_pro[j];
            }
            else
            {
                w1+=pixel_pro[j];
                u1_temp+=j*pixel_pro[j];
            }
        }
        u0=u0_temp/w0;
        u1=u1_temp/w1;
        delta_temp=(float)(w0*w1*pow((u0-u1),2));
        if(delta_temp>delta_max)
        {
            delta_max=delta_temp;
            threshold=i;
        }
    }
    return threshold;
}


void FillInternalContours(IplImage *pBinary,double dAreaThre)
{
    CvSeq *pContour=NULL;
    int rol_y0=pBinary->height;
    int rol_y1=0;
    int rol_x1=0;
    int rol_x0=pBinary->width;
    CvSeq *pConInner=NULL;
    CvRect rect;
    CvMemStorage *pStorage=NULL;
    if(pBinary)
    {
        pStorage=cvCreateMemStorage(0);
        cvFindContours(pBinary,pStorage,&pContour,sizeof(CvContour),CV_RETR_EXTERNAL,CV_LINK_RUNS);
        cvDrawContours(pBinary,pContour,CV_RGB(255,255,255),CV_RGB(255,255,255),2,CV_FILLED,8,cvPoint(0,0));
        //CvRect rect=cvBoundingRect(pContour,0);
        for(;pContour!=NULL;pContour=pContour->h_next)
        {
            //rect=cvBoundingRect(pContour,0);
            for(int k=0;k<pContour->total;k++)
            {
                CvPoint *pt=(CvPoint *)cvGetSeqElem(pContour,k);
                if(pt->y<rol_y0)
                {
                    rol_y0=pt->y;
                }
                if(pt->x<rol_x0)
                {
                    rol_x0=pt->x;
                }
                if(pt->x>rol_x1)
                {
                    rol_x1=pt->x;
                }
                if(pt->y>rol_y1)
                {
                    rol_y1=pt->y;
                }
            }
            //cvRectangle(pBinary,cvPoint(rect.x,rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height),CV_RGB(255,0,0),1,8,0);
        }
        rect.x=rol_x0;
        rect.y=rol_y0;
        rect.height = (rol_y1 - rol_y0);
        rect.width = (rol_x1 - rol_x0);

        cvRectangle(pBinary,cvPoint(rect.x,rect.y),cvPoint(rect.x+rect.width,rect.y+rect.height),CV_RGB(255,255,255),1,8,0);
        cvReleaseMemStorage(&pStorage);
        pStorage=NULL;
    }
}

IplImage * rotateimage(IplImage *image)
{
    IplImage *img1=cvCreateImage(cvGetSize(image),IPL_DEPTH_8U,1);
    cvSmooth(image,img1,CV_GAUSSIAN,3,0,0,0);

    int threshold=otsu(img1);
    IplImage *img2=cvCreateImage(cvGetSize(img1),IPL_DEPTH_8U,1);
    cvThreshold(img1,img2,threshold,255,CV_THRESH_BINARY);
    FillInternalContours(img2,200);

    return img2;
}

void FillInternalContours1(IplImage *image,double dAreaThre)
{

    //cvCvtColor(image,image,CV_RGB2GRAY);

    IplImage *image_bin=cvCreateImage(cvGetSize(image),8,1);
    int Threshold=otsu(image);
    cvThreshold(image, image_bin, Threshold, 255, CV_THRESH_BINARY);

    double conarea=0.0;
    CvSeq *pContour=NULL;
    CvSeq *pConInner=NULL;
    CvMemStorage *storage0=NULL;
    int id=0;
    char fgname[56]={0};

    if(image)
    {
        storage0=cvCreateMemStorage(0);
        cvFindContours(image_bin, storage0, &pContour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);     
        // 填充所有轮廓      
        cvDrawContours(image_bin, pContour, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 2, CV_FILLED, 8, cvPoint(0, 0));
        for (; pContour != NULL; pContour = pContour->h_next)     
        {         
            // 内轮廓循环      
            for (pConInner = pContour->v_next; pConInner != NULL; pConInner = pConInner->h_next)     
            {    
                 conarea = fabs(cvContourArea(pConInner, CV_WHOLE_SEQ));
                if(conarea<2000)
                {
                    printf("%f\n", conarea);   
                    CvRect rect = cvBoundingRect(pConInner,0);  
                    cvRectangle(image_bin, cvPoint(rect.x, rect.y), cvPoint(rect.x + rect.width, rect.y + rect.height),CV_RGB(255,255, 250), 1, 8, 0); 
                    cout<<"1="<<rect.width<<endl;

                    IplImage *imgfenge=cvCreateImage(cvSize(rect.width,rect.height),8,1);
                    cvSetImageROI(image_bin,rect);
                    cvCopyImage(image_bin,imgfenge);

                    CvSize size_img;
                    size_img.height=60;
                    size_img.width=40;

                    IplImage *imgfg=cvCreateImage(size_img,8,1);
                    cvResize(imgfenge,imgfg);

                    sprintf(fgname, "wnd_%d", id++);
                    cvNamedWindow(fgname);
                    cvShowImage(fgname,imgfg);
                    cvReleaseImage(&imgfg);

                }

            }    

        }     

        cvReleaseMemStorage(&storage0);     
        storage0 = NULL;     
    }     
}

int main()
{
    IplImage* src;
    src=cvLoadImage("F:\\save18.jpg",0);

    IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
    IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* lines = 0;
    int i;
    IplImage* src1=cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);

    //  cvCvtColor(src, src1, CV_BGR2GRAY);  
    cvCopy(src,src1);
    cvCanny( src1, dst, 50, 200, 3 );

    cvCvtColor( dst, color_dst, CV_GRAY2BGR );


    lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 10,30,15);
    int dis=0;
    int max=0;
    int j=0;
    CvPoint *line;
    CvPoint pointOne;
    CvPoint pointTwo;
    int a[1003]={0};
    for(i=0;i<lines->total;i++)
    {
        line = (CvPoint*)cvGetSeqElem(lines,i);
        dis=(line[1].y-line[0].y)*(line[1].y-line[0].y)+(line[1].x-line[0].x)*(line[1].x-line[0].x);
        a[4*i]=line[0].x;
        a[4*i+1]=line[0].y;
        a[4*i+2]=line[1].x;
        a[4*i+3]=line[1].y;
        if(dis>max)
        {
            max=dis;
            j=i;
        }
    }
    pointOne.x=a[4*j];
    //cout<<"pointOne.x="<<pointOne.x<<endl;
    pointOne.y=a[4*j+1];
    //cout<<pointOne.y<<endl;
    pointTwo.x=a[4*j+2];
    //cout<<pointTwo.x<<endl;
    pointTwo.y=a[4*j+3];
    //cout<<pointTwo.y<<endl;
    cvLine( color_dst, pointOne, pointTwo, CV_RGB(255,0,0), 3, 8 );    //画出最长的直线
    double Degree=0.0;
    Degree = atan2(fabs((double)(pointTwo.y-pointOne.y)),fabs((double)(pointTwo.x-pointOne.x)));   //得到最长直线与水平夹角
    cout<<"pointTwo.x="<<pointTwo.x<<";pointOne.x="<<pointOne.x<<";pointTwo.y="<<pointTwo.y<<";pointOne.y="<<pointOne.y<<endl;
    cout<<"Degree="<<Degree<<endl;
    if((pointTwo.x>pointOne.x) &&( pointTwo.y>pointOne.y))
    {
        Degree=-Degree;
    }

    cout<<"弧度= "<<Degree<<endl;
    cvNamedWindow( "Source", 1 );
    cvShowImage( "Source", src );

    cvNamedWindow( "Hough", 1 );
    cvShowImage( "Hough", color_dst );

    IplImage *rotate2=rotateimage(src);
    cvNamedWindow("rotate2",1);
    cvShowImage("rotate2",rotate2);

    IplImage *img_rotate=rotateImage2(rotate2,Degree);
    cvNamedWindow("xzh");
    cvShowImage("xzh",img_rotate);



    /*IplImage *FS=fanse(img_rotate);
    cvNamedWindow("FS");
    cvShowImage("FS",img_rotate);*/
    FillInternalContours1(img_rotate,200);


    cvReleaseMemStorage(&storage);


    cvWaitKey(0);

    cvReleaseImage(&rotate2);
    cvReleaseImage(&src);
    cvReleaseImage(&color_dst);
    cvReleaseImage(&dst);
    cvReleaseImage(&img_rotate);
    cvDestroyAllWindows();

}

下面来一部分一部分的分析

1.

cout<<"angle="<<angle<<endl;   // 角度 angle
    double a = sin(angle), b = cos(angle);   
    int width=img->width, height=img->height;  
    //旋转后的新图尺寸  
    int width_rotate= int(height * fabs(a) + width * fabs(b)); //旋转后的宽度,函数:fabs(a):求浮点数a的绝对值 ,强制类型转换
    int height_rotate=int(width * fabs(a) + height * fabs(b));    
    IplImage* img_rotate = cvCreateImage(cvSize(width_rotate, height_rotate), img->depth, img->nChannels); 
    cvZero(img_rotate);    //好像是清除

这部分程序的作用应该是图像旋转,相关原理可以看下面:
这里写图片描述

上面第二张图片,就是将第一张逆时针旋转了30度,可以看到整体图像尺寸没有改变,所以部分图像看不到了,所以我们应该扩大图像尺寸。

需要计算新图的尺寸,示意图如下:
这里写图片描述

结果
这里写图片描述
今天暂时到这里,对opencv还不是很懂
2.

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翟羽嚄

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值