车牌图像倾斜校正

车牌图片有一拍摄的角度不同,图像会存在或多或少的倾斜,如不对图像进行校正,将会影响到后来的字符分割。图像倾斜校正首先要获得图像的倾斜角度,我们采用Hough变换求得图像的倾斜角度。

//Hough变换求图像倾斜角度
     /*************************************************************************
 *
 * 函数名称:
 *   HoughDIB()
 *
 * 参数:
 *   LPSTR lpDIBBits    - 指向源DIB图像指针
 *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
 *   LONG  lHeight      - 源图像高度(象素数)
 * 返回值:
 *   BOOL               - 运算成功返回TRUE,否则返回FALSE。
 *
 * 说明:
 * 该函数用于对检测图像中的直线
 * 要求目标图像为只有0和255两个灰度值的灰度图像。
 ************************************************************************/


float HoughDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
{
        int Anglenumber;
        #define pi 3.1415926
        // 指向源图像的指针
        LPSTR        lpSrc;
        
        // 指向缓存图像的指针
        LPSTR        lpDst;
        
        // 指向变换域的指针
        LPSTR   lpTrans;


        // 图像每行的字节数
        LONG lLineBytes;
        
        // 指向缓存DIB图像的指针
        LPSTR        lpNewDIBBits;
        HLOCAL        hNewDIBBits;


        //指向变换域的指针
        LPSTR        lpTransArea;
        HLOCAL        hTransArea;


        //变换域的尺寸
        int iMaxDist;


int iMaxAngleNumber;


        //变换域的坐标
        int iDist;
        int iAngleNumber;


        //循环变量
        long i;
        long j;


        //像素值
        unsigned char pixel;


        //存储变换域中的两个最大值
        MaxValue MaxValue1;
        MaxValue MaxValue2;


        // 暂时分配内存,以保存新图像
        hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);


        if (hNewDIBBits == NULL)
        {
                // 分配内存失败
                return FALSE;
        }
        
        // 锁定内存
        lpNewDIBBits = (char * )LocalLock(hNewDIBBits);


        // 初始化新分配的内存,设定初始值为255
        lpDst = (char *)lpNewDIBBits;
        memset(lpDst, (BYTE)255, lWidth * lHeight);


        //计算变换域的尺寸
        //最大距离
        iMaxDist = (int) sqrt(lWidth*lWidth + lHeight*lHeight);


        //角度从0-180,每格2度
        iMaxAngleNumber = 180;


        //为变换域分配内存
        hTransArea = LocalAlloc(LHND, lWidth * lHeight * sizeof(int));


        if (hNewDIBBits == NULL)


{
                // 分配内存失败
                return FALSE;
        }
        
        // 锁定内存
        lpTransArea = (char * )LocalLock(hTransArea);
                
        // 初始化新分配的内存,设定初始值为0
        lpTrans = (char *)lpTransArea;
        memset(lpTrans, 0, lWidth * lHeight * sizeof(int));


        // 计算图像每行的字节数
        lLineBytes = WIDTHBYTES(lWidth * 8);


        for(j = 0; j <lHeight; j++)
        {
                for(i = 0;i <lWidth; i++)
                {


                        // 指向源图像倒数第j行,第i个象素的指针                        
                        lpSrc = (char *)lpDIBBits + lLineBytes * j + i;


                        //取得当前指针处的像素值,注意要转换为unsigned char型
                        pixel = (unsigned char)*lpSrc;


                        //目标图像中含有0和255外的其它灰度值
                        if(pixel != 255 && *lpSrc != 0)
                                return FALSE;


                        //如果是黑点,则在变换域的对应各点上加1
                        if(pixel == 0)
                        {
                                //注意步长是2度
                                for(iAngleNumber=0; iAngleNumber<iMaxAngleNumber; iAngleNumber++)
                                {
                                        iDist = (int) fabs(i*cos(iAngleNumber*pi/180.0) + \
                                                j*sin(iAngleNumber*pi/180.0));
                                
                                        //变换域的对应点上加1
                                        *(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber) = \
                                                *(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber) +1;
                                }
                        }


}
        }
                                
        //找到变换域中的两个最大值点
        MaxValue1.Value=0;
        MaxValue2.Value=0;
        
        //找到第一个最大值点
        for (iDist=0; iDist<iMaxDist;iDist++)
        {
                for(iAngleNumber=0; iAngleNumber<iMaxAngleNumber; iAngleNumber++)
                {
                        if((int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber)>MaxValue1.Value)
                        {
                                MaxValue1.Value = (int)*(lpTransArea+iDist*iMaxAngleNumber+iAngleNumber);
                                MaxValue1.Dist = iDist;
                                MaxValue1.AngleNumber = iAngleNumber;
                        }


                }
        }


        //将第一个最大值点附近清零
        for (iDist = -9;iDist < 10;iDist++)
        {
                for(iAngleNumber=-1; iAngleNumber<2; iAngleNumber++)
                {
                        if(iDist+MaxValue1.Dist>=0 && iDist+MaxValue1.Dist<iMaxDist \
                                && iAngleNumber+MaxValue1.AngleNumber>=0 && iAngleNumber+MaxValue1.AngleNumber<=iMaxAngleNumber)
                        {
                                *(lpTransArea+(iDist+MaxValue1.Dist)*iMaxAngleNumber+\
                                        (iAngleNumber+MaxValue1.AngleNumber))=0;
                        }
                }
        }


        Anglenumber=MaxValue1.AngleNumber;
                
//        }


        // 释放内存
        LocalUnlock(hNewDIBBits);


LocalFree(hNewDIBBits);


        // 释放内存
        LocalUnlock(hTransArea);
        LocalFree(hTransArea);
   if(Anglenumber>0)
   {
        // 返回
           //MessageBox("ok",0,0);
           return Anglenumber+90;
   }
   else
   {
              return 90-abs(Anglenumber);
   }
}


//图像倾斜校正


void CPhotodealView::Rectinication(HDIB hDIB,float fAngel)
{
   #define PI 3.1415926
        //循环变量
   long i0;
   long j0;
   long i1;
   long j1;
   float ffAngle;


   LONG lWidth;
   LONG lHeight;
   LONG lLineBytes;
   
   
   CPhotodealDoc* pDoc = GetDocument();
   // 指向DIB的指针
        LPSTR lpDIB;
        
        // 指向DIB象素指针
        LPSTR    lpDIBBits;
   //锁定DIB
           lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());
   //找到DIB图像象素起始位置
   lpDIBBits = ::FindDIBBits(lpDIB);


// 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图,其它的可以类推)
        if (::DIBNumColors(lpDIB) != 256)
        {
                // 提示用户
                MessageBox("目前只支持查看256色位图灰度直方图!", "系统提示" , MB_ICONINFORMATION | MB_OK);
                
                // 解除锁定
                ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
                
                // 返回
                return;
        }
   // 更改光标形状
        BeginWaitCursor();
    //DIB的宽度
        lWidth =::DIBWidth(lpDIB);
    //DIB的高度
    lHeight =::DIBHeight(lpDIB);
    //计算图像每行的字节数
        lLineBytes =WIDTHBYTES(lWidth * 8);


        if(fAngel>90)
        {
                fAngel=180-fAngel;
        }
    //旋转角度的弧度
        ffAngle=(fAngel*PI/180);
    //角的正余旋
        float fSinAngle=(float)sin(ffAngle);
    float fCosAngle=(float)cos(ffAngle);
        float fTgAngle=fSinAngle/fCosAngle;
        unsigned char* m_temp;
        m_temp=new unsigned char[lLineBytes*lHeight];


    //复制空白数据到中间缓存
        for (i0=0;i0<lLineBytes*lHeight;i0++)
                 m_temp[i0]=255;
    //先对X方向进行校正处理
    for (i0=0;i0<lHeight;i0++)
        {
                for(j0=0;j0<lWidth;j0++)
                {


//计算校正后的坐标位置
                           //MessageBox("ok");
                                j1=(LONG)((j0-lWidth/2)*fCosAngle+(lHeight/2-i0)*fSinAngle+lWidth/2+0.5f);
                            i1=(LONG)(-(j0-lWidth/2)*fSinAngle-(lHeight/2-i0)*fCosAngle+lHeight/2+0.5f);
                        


            //将原始象素复制到目标位置000
                        if(i1>=0&&i1<lHeight&&j1>=0&&j1<lWidth)
                        {
                                m_temp[lLineBytes*(lHeight-i1-1)+j1]=*(lpDIBBits+lLineBytes*(lHeight-i0-1)+j0);
            }
                }
        }
    //回存处理结果到DIB
        for(i0=0;i0<lLineBytes*lHeight;i0++)
                *(lpDIBBits+i0)=m_temp[i0];


        /
    //调用中值滤波进行平滑处理
    // 锁定DIB
/*        lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->GetHDIB());
        // 找到DIB图像象素起始位置
        lpDIBBits = ::FindDIBBits(lpDIB);
                // 判断是否是8-bpp位图(这里为了方便,只处理8-bpp位图的中值滤波,其它的可以类推)
        if (::DIBNumColors(lpDIB) != 256)
        {
                // 提示用户
                MessageBox("目前只支持256色位图的中值滤波!", "系统提示" ,
                        MB_ICONINFORMATION | MB_OK);
                // 解除锁定
                ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());
                // 返回
                return;
        }
                // 更改光标形状
        BeginWaitCursor();
        // 调用MedianFilter()函数中值滤波
        if (::MedianFilter(lpDIBBits, ::DIBWidth(lpDIB), ::DIBHeight(lpDIB), 
                  3, 1, 0, 1))
        {
                
                // 设置脏标记
                pDoc->SetModifiedFlag(TRUE);


// 更新视图
                pDoc->UpdateAllViews(NULL);
        }
        else
        {
                // 提示用户
                MessageBox("分配内存失败!", "系统提示" , MB_ICONINFORMATION | MB_OK);
        }*/
        
        // 解除锁定
        ::GlobalUnlock((HGLOBAL) pDoc->GetHDIB());


        // 恢复光标
        //EndWaitCursor();
        delete[]m_temp;
    //恢复光标
        EndWaitCursor();
}


说明上面只提供了功能模块的主要函数。




转自:http://www.opencvchina.com/thread-812-1-1.html

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值