一种自动搜索图像矫正参考点的算法

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/