📄 dib.cpp
字号:
// Dib.cpp: implementation of the CDib class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "INVCR.h"
#include "Dib.h"
#include <math.h>
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CDib::CDib()
{
int i,j;
LineBytes = 0;
for( i = 0; i < IMAGE_HEIGHT; i++ )
{
dataRealColor[i] = new RGBData[IMAGE_WIDTH];
dataNoRealColor[i] = new BYTE[IMAGE_WIDTH];
binaryImageData[i] = new BYTE[IMAGE_WIDTH];
for( j = 0; j < IMAGE_WIDTH; j++ )
{
dataRealColor[i][j].Blue = 255;
dataRealColor[i][j].Green = 255;
dataRealColor[i][j].Red = 255;
dataNoRealColor[i][j] = 255;
binaryImageData[i][j] = 255;
}
}
}
CDib::~CDib()
{
int i;
//释放图像数组空间
for( i = 0; i < IMAGE_HEIGHT; i++ )
{
if( dataRealColor[i] != NULL )
{
delete dataRealColor[i];
dataRealColor[i] = NULL;
}
if( dataNoRealColor[i] != NULL )
{
delete dataNoRealColor[i];
dataNoRealColor[i] = NULL;
}
if( binaryImageData[i] != NULL )
{
delete binaryImageData[i];
binaryImageData[i] = NULL;
}
}
}
BOOL CDib::Load(const char* pszFilename)
{
int i,j;
int offset;
int m_bit24;
CFile cf;
if(!cf.Open(pszFilename,CFile::modeRead))
return FALSE;
BITMAPFILEHEADER BFH;
BITMAPINFOHEADER BIH;
if(cf.Read(&BFH,sizeof(BITMAPFILEHEADER))!=sizeof(BITMAPFILEHEADER))
return FALSE;
if(cf.Read(&BIH,sizeof(BITMAPINFOHEADER))!=sizeof(BITMAPINFOHEADER))
return FALSE;
if( BFH.bfType!='MB' )
{
AfxMessageBox( " 输入图像格式不对,请将扫描图像格式转化为bmp格式,再重试! " );
return FALSE;
}
m_FileHeader.bfSize = BFH.bfSize;
m_InfoHeader.biWidth = BIH.biWidth;
m_InfoHeader.biHeight = BIH.biHeight;
m_InfoHeader.biBitCount = BIH.biBitCount;
LineBytes=WIDTHBYTES( BIH.biWidth*BIH.biBitCount );
if( BIH.biBitCount != 24 )
{
m_bit24 = 1;
}
else
m_bit24 = 2;
offset=BFH.bfOffBits;
if(m_bit24 == 2)
{
cf.Seek(offset,CFile::begin);
DWORD atemp = WIDTHBYTES( BIH.biWidth * 24 );
for( j = BIH.biHeight - 1; j >= 0; j-- )
cf.Read( dataRealColor[j], atemp );
cf.Close();
//将彩色图变换成灰度图
for( i = 0; i < BIH.biHeight; i++ )
for( j = 0; j< BIH.biWidth; j++ )
dataNoRealColor[i][j]=(int)(dataRealColor[i][j].Blue*0.114+dataRealColor[i][j].Green*0.587+dataRealColor[i][j].Red*0.299); //将24bit位图变为8bit位图的处理,RGB转化为亮度
}
else if(m_bit24 == 1)
{
cf.Seek( offset, CFile::begin );
for( j = BIH.biHeight - 1; j >= 0; j-- )
cf.Read( dataNoRealColor[j], LineBytes );
cf.Close();
}
else
{
AfxMessageBox("输入图像格式错误!");
return FALSE;
}
return TRUE;
}
BOOL CDib::inclineEmendation() //发票倾斜校正处理
{
//左上角点参考点搜索的范围
int LT_REF_TOP = 300;
int LT_REF_BOTTOM = 400;
int LT_REF_LEFT = 60;
int LT_REF_RIGHT = 150;
//右上角点参考点搜索的范围
int RT_REF_TOP = 280;
int RT_REF_BOTTOM = 450;
int RT_REF_LEFT = 2450;
int RT_REF_RIGHT = 2580;
//左下角点参考点搜索的范围
int LB_REF_TOP = 1400;
int LB_REF_BOTTOM = 1550;
int LB_REF_LEFT = 30;
int LB_REF_RIGHT = 140;
int LT_REF_X,LT_REF_Y; //左上角点参考点的坐标
int RT_REF_X,RT_REF_Y; //右上角点参考点的坐标
int LB_REF_X,LB_REF_Y; //右上角点参考点的坐标
int i,j,m,n;
int matchValue; //匹配变量
long int minMatchValue = 100000000;
int rcountPixel,dcountPixel;
//最大类间方差二值化全局图像,找出定位参考点
int Hist[256], area;
int bwth;
int lineBytes = WIDTHBYTES( m_InfoHeader.biWidth * 8 ); //这里处理的都是256级灰度图象,所以biBitCount都取8
float uT, maxob2, p[256], u[256], u0[256], u1[256], w0[256], w1[256], ob2[256];
for ( i = 0; i < 256; i++ )
{
Hist[i] = 0;
}
for ( i = 0; i < m_InfoHeader.biHeight; i++ )
{
for ( j = 0; j < lineBytes; j++ )
{
Hist[dataNoRealColor[i][j]]++;
}
}
uT = 0.0;
area = m_InfoHeader.biHeight * lineBytes;
for ( i = 0; i < 256; i++ )
{
p[i] = Hist[i] / ( float ) area;
uT = uT + i * p[i];
}
for ( j = 0; j < 256; j++ )
{
u[j] = 0.0;
w0[j] = 0.0;
for ( i = 0; i < j; i++ )
{
u[j] = u[j] + i * p[i];
w0[j] = w0[j] + p[i];
}
w1[j] = 1 - w0[j];
if ( ( w0[j] > 0 ) && ( w1[j] > 0 ) )
{
u0[j] = u[j] / w0[j];
u1[j] = ( uT - u[j] ) / w1[j];
ob2[j] = w0[j] * ( u0[j] - uT ) * ( u0[j] - uT ) + w1[j] * ( u1[j] - uT ) * ( u1[j] - uT );
}
else
{
ob2[j] = 0;
}
}
maxob2 = 0;
for ( i = 0; i < 256; i++ )
{
if ( ob2[i] > maxob2 )
{
maxob2 = ob2[i];
bwth = i;
}
}
for(i = 0; i < m_InfoHeader.biHeight; i++)
for(j = 0; j < m_InfoHeader.biWidth; j++)
{
if( dataNoRealColor[i][j] < bwth + 15 ) //这里是要检验出参考点,因而适当放大域值,以增强抗干扰能力
binaryImageData[i][j] = 0;
else
binaryImageData[i][j] = 255;
}
//构造一个检测参考点的模板图像数组
BYTE modelImage[30][30];
for( i = 0; i < 30; i++ )
for( j = 0; j < 30; j++ )
{
if( i == 0 || i == 1 || i == 2 || j == 0 || j == 1 || j == 2 )
modelImage[i][j] = 0;
else
modelImage[i][j] = 255;
}
for( i = LT_REF_TOP; i <= LT_REF_BOTTOM; i++ )
for( j = LT_REF_LEFT; j <= LT_REF_RIGHT; j++ )
{
matchValue = 0;
//为了减少运算量,只在上面六行和右边六行进行模板匹配,并且为了增强抗干扰性,先判断是否进行模板匹配的计算
rcountPixel = 0;
dcountPixel = 0;
for( m = 0; m <= 2; m++ )
for( n = 5; n < 20; n++ )
{
if( binaryImageData[i + m][j + n] == 0 )
rcountPixel++;
}
for( m = 5; m < 20; m++ )
for( n = 0; n <= 2; n++ )
{
if( binaryImageData[i + m][j + n] == 0 )
dcountPixel++;
}
if( rcountPixel < 15 || dcountPixel < 15 ) //保证出现所要求的折形结构,否则不予判断
matchValue = 1000000000;
else
{
for( m = 0; m <= 5; m++ )
for( n = 0; n < 30; n++ )
{
matchValue = matchValue + (int)fabs( binaryImageData[i + m][j + n] - modelImage[m][n] );
}
for( m = 6; m < 30; m++ )
for( n = 0; n <= 5; n++ )
{
matchValue = matchValue + (int)fabs( binaryImageData[i + m][j + n] - modelImage[m][n] );
}
if( matchValue < minMatchValue )
{
minMatchValue = matchValue;
LT_REF_X = j;
LT_REF_Y = i;
}
}
}
minMatchValue = 1000000000;
for( i = RT_REF_TOP; i <= RT_REF_BOTTOM; i++ )
for( j = RT_REF_LEFT; j <= RT_REF_RIGHT; j++ )
{
matchValue = 0;
//为了减少运算量,只在上面六行和右边六行进行模板匹配,并且为了增强抗干扰性,先判断是否进行模板匹配的计算
rcountPixel = 0;
dcountPixel = 0;
for( m = 0; m <= 2; m++ )
for( n = 5; n < 20; n++ )
{
if( binaryImageData[i + m][j - n] == 0 )
rcountPixel++;
}
for( m = 5; m < 20; m++ )
for( n = 0; n <= 2; n++ )
{
if( binaryImageData[i + m][j - n] == 0 )
dcountPixel++;
}
if( rcountPixel < 15 || dcountPixel < 15 ) //保证出现所要求的折形结构,否则不予判断
matchValue = 1000000000;
else
{
for( m = 0; m <= 5; m++ )
for( n = 0; n < 30; n++ )
{
matchValue = matchValue + (int)fabs( binaryImageData[i + m][j - n] - modelImage[m][n] ); //理解算法的精妙
}
for( m = 6; m < 30; m++ )
for( n = 0; n <= 5; n++ )
{
matchValue = matchValue + (int)fabs( binaryImageData[i + m][j - n] - modelImage[m][n] );
}
if( matchValue < minMatchValue )
{
minMatchValue = matchValue;
RT_REF_X = j;
RT_REF_Y = i;
}
}
}
minMatchValue = 1000000000;
for( i = LB_REF_TOP; i <= LB_REF_BOTTOM; i++ )
for( j = LB_REF_LEFT; j <= LB_REF_RIGHT; j++ )
{
matchValue = 0;
//为了减少运算量,只在上面六行和右边六行进行模板匹配,并且为了增强抗干扰性,先判断是否进行模板匹配的计算
rcountPixel = 0;
dcountPixel = 0;
for( m = 0; m <= 2; m++ )
for( n = 5; n < 20; n++ )
{
if( binaryImageData[i - m][j + n] == 0 )
rcountPixel++;
}
for( m = 5; m < 20; m++ )
for( n = 0; n <= 2; n++ )
{
if( binaryImageData[i - m][j + n] == 0 )
dcountPixel++;
}
if( rcountPixel < 15 || dcountPixel < 15 ) //保证出现所要求的折形结构,否则不予判断
matchValue = 1000000000;
else
{
for( m = 0; m <= 5; m++ )
for( n = 0; n < 30; n++ )
{
matchValue = matchValue + (int)fabs( binaryImageData[i - m][j + n] - modelImage[m][n] ); //理解算法的精妙
}
for( m = 6; m < 30; m++ )
for( n = 0; n <= 5; n++ )
{
matchValue = matchValue + (int)fabs( binaryImageData[i - m][j + n] - modelImage[m][n] );
}
}
if( matchValue < minMatchValue )
{
minMatchValue = matchValue;
LB_REF_X = j;
LB_REF_Y = i;
}
}
//旋转校正
if( abs( RT_REF_Y - LT_REF_Y ) > 4 )
{
double rotateAngle;
double param1,param2;
int sourceX,sourceY;
BYTE tempImageData[IMAGE_HEIGHT][IMAGE_WIDTH];
//先备份图像数据
for( i = 0; i < m_InfoHeader.biHeight; i++ )
for( j = 0; j < m_InfoHeader.biWidth; j++ )
tempImageData[i][j] = dataNoRealColor[i][j];
rotateAngle = atan( (double)( RT_REF_Y - LT_REF_Y )/( RT_REF_X - LT_REF_X ) );
param1 = LT_REF_X - LT_REF_X * cos( rotateAngle ) + LT_REF_Y * sin( rotateAngle );
param2 = LT_REF_Y - LT_REF_X * sin( rotateAngle ) - LT_REF_Y * cos( rotateAngle );
for( i = 0; i < m_InfoHeader.biHeight; i++ )
for( j = 0; j < m_InfoHeader.biWidth; j++ )
{
sourceX = (int)( j * cos( rotateAngle ) - i * sin( rotateAngle ) + param1 + 0.5 );
sourceY = (int)( i * cos( rotateAngle ) + j * sin( rotateAngle ) + param2 + 0.5 );
//判断是否位于图像范围内
if( sourceX >= 0 && sourceX < m_InfoHeader.biWidth && sourceY >= 0 && sourceY < m_InfoHeader.biHeight )
dataNoRealColor[i][j] = tempImageData[sourceY][sourceX];
else //其他部分用白色填充
dataNoRealColor[i][j] = 255;
}
}
return TRUE;
}
BOOL CDib::mergeImageFile() //批处理最大类间方差全局二值化发票图像
{
CFile cf;
int lineBytes;
if(!cf.Open("D:\\test.bmp",CFile::modeRead))
{
AfxMessageBox("打开图像文件失败!");
return FALSE;
}
if(cf.Read(&m_FileHeader,sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER))
{
AfxMessageBox("读位图文件头失败!");
return FALSE;
}
if(cf.Read(&m_InfoHeader,sizeof(BITMAPINFOHEADER)) != sizeof(BITMAPINFOHEADER))
{
AfxMessageBox("读位图信息头失败!");
return FALSE;
}
if(cf.Read(m_grayPalette,1024) != 1024)
{
AfxMessageBox("读位图调色板失败!");
return FALSE;
}
lineBytes = WIDTHBYTES( m_InfoHeader.biWidth * 8 ); //这里处理的都是256级灰度图象,所以biBitCount都取8
if(!cf.Open("D:\\emendationImage.bmp",CFile::modeCreate|CFile::modeWrite))
{
AfxMessageBox("创建图像文件失败!");
return FALSE;
}
cf.Write(&m_FileHeader,sizeof(BITMAPFILEHEADER));
cf.Write(&m_InfoHeader,sizeof(BITMAPINFOHEADER));
cf.Write(m_grayPalette,1024);
for( int i = m_InfoHeader.biHeight - 1; i >= 0 ; i-- )
cf.Write(dataNoRealColor[i],lineBytes);
cf.Close();
AfxMessageBox("finished!");
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -