一种自动搜索图像矫正参考点的算法
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
= 0; //初始化数组
}
/// 统计图像中的灰度值
for ( i = 0; i < m_InfoHeader.biHeight; i++ ) //逐行扫描
{
for ( j = 0; j < lineBytes; j++ ) //逐列扫描
{
Hist[dataNoRealColor[j]]++; //累加图像中不同的灰度的总值
}
}
uT = 0.0;
area = m_InfoHeader.biHeight * lineBytes; //图像的总像素
for ( i = 0; i < 256; i++ )
{
p = Hist / ( float ) area; //计算相应灰度值占总像素的比例
uT = uT + i * p; //?
}
//??? 最大类间方差求得二值化是的灰度阀值
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;
w0[j] = w0[j] + p;
}
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;
///找出ob2[]中最大值所在的位置,并赋值给bwth
for ( i = 0; i < 256; i++ )
{
if ( ob2 > maxob2 )
{
maxob2 = ob2;
bwth = i;
}
}
////对图像进行二值化? (类似二值化,算法相同,阀值不同)
for(i = 0; i < m_InfoHeader.biHeight; i++) //逐行扫描
for(j = 0; j < m_InfoHeader.biWidth; j++) //逐列扫描
{
if( dataNoRealColor[j] < bwth + 15 ) //这里是要检验出参考点,因而适当放大域值,以增强抗干扰能力
binaryImageData[j] = 0;
else
binaryImageData[j] = 255;
}
//构造一个检测参考点的模板图像数组
// 构造一个 ________ 模版(3行3列为黑色,其余为白色的30*30的图像)
// |
// |
// |
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[j] = 0;
else
modelImage[j] = 255;
}
//////// 在搜索范围内进行折形结构图像搜索
/////// 搜索左上角参考点(i,j)
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;
//// 从位置(i,j)处开始搜索一个长度为15,宽度为3的矩形区域,统计这个区域的黑点数
for( m = 0; m <= 2; m++ )
for( n = 5; n < 20; n++ )
{
if( binaryImageData[i + m][j + n] == 0 )
rcountPixel++;
}
//// 从位置(i,j)处开始搜索一个长度为3,宽度为15的矩形区域,统计这个区域的黑点数
for( m = 5; m < 20; m++ )
for( n = 0; n <= 2; n++ )
{
if( binaryImageData[i + m][j + n] == 0 )
dcountPixel++;
}
////如果两个矩形的黑点都数>=15,则要找的折形结构出现,搜索成功,进入模版匹配程序,否则继续搜索。
if( rcountPixel < 15 || dcountPixel < 15 ) //保证出现所要求的折形结构,否则不予判断
matchValue = 1000000000;
else
{////进行模版匹配,查找参考点的位置(i,j)
for( m = 0; m <= 5; m++ )//扫描模版上边的6行,统计模版与图像的匹配度(即像素值相同即同为黑点的像素总数)
for( n = 0; n < 30; n++ )
{//算法的关键,累加图像像素(0,255)和模版像素(0,255)(其实只有0)的“与”运算结果,结果越小说明匹配度越好
matchValue = matchValue + (int)fabs( binaryImageData[i + m][j + n] - modelImage[m][n] );
}
for( m = 6; m < 30; m++ )//扫描模版左边的6列,统计模版与图像的匹配度(即像素值相同即同为黑点的像素总数)
for( n = 0; n <= 5; n++ )
{//算法的关键,累加图像像素(0,255)和模版像素(0,255)(其实只有0)的“与”运算结果,结果越小说明匹配度越好
matchValue = matchValue + (int)fabs( binaryImageData[i + m][j + n] - modelImage[m][n] );
}
if( matchValue < minMatchValue )//minMatchValue 精度因子,当匹配度小于指定的精度因子时,匹配成功,也即找到参考点
//的位置(i,j)
{
minMatchValue = matchValue;
LT_REF_X = j;
LT_REF_Y = i;
}
}
}
/////// 搜索右上角的参考点(i,j)
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;
}
}
}
///////搜索左下角的参考点(i,j)
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[j] = dataNoRealColor[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[j] = tempImageData[sourceY][sourceX];
else //其他部分用白色填充
dataNoRealColor[j] = 255;
}
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
////
//// 此算法的缺陷:1、参考点搜索范围与搜索精度与成功有很大的关系,如果参考点范围内有多个模版(折形结构),
//// 则搜索出来的是最后一个折形结构的位置,达不到预期目的。
//// 2、匹配精度因子直接递归搜索,增加运算量与搜索时间,降低效率。
//// 对此算法的改进设想:1、把图像分割为四块,分别对其进行镜像与旋转,转换成与左上角部分一致的临时图像。
//// 2、 把参考点搜索范围设为图像大小的1/4小10-20个像素,采用上面算法左上角搜索步骤
//// 对四个临时图像分别进行搜索参考点,在进行(折形结构)搜索和模版匹配时,搜索并匹配成功第一个即停止搜索
//// (找到参考点),匹配精度因子由外部参数指定。
//// 3、把另三块临时图像的参考点还原成相应的原参考点。
////
//// 找出其参考点之后,即可对图像进行线性或非线性纠正。
原文:http://playsea45.popo.blog.163.c ... 632320073290337192/