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

学习笔记   2007-04-29 12:03   阅读67   评论0  
字号:    

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;
 ///找出ob2[]中最大值所在的位置,并赋值给bwth
 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;
  }

 //构造一个检测参考点的模板图像数组
 // 构造一个 ________  模版(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[i][j] = 0;
   else
    modelImage[i][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[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;
}

//////////////////////////////////////////////////////////////////////////////
////
////   此算法的缺陷:1、参考点搜索范围与搜索精度与成功有很大的关系,如果参考点范围内有多个模版(折形结构),
////   则搜索出来的是最后一个折形结构的位置,达不到预期目的。
////                 2、匹配精度因子直接递归搜索,增加运算量与搜索时间,降低效率。
////   对此算法的改进设想:1、把图像分割为四块,分别对其进行镜像与旋转,转换成与左上角部分一致的临时图像。
////                       2、 把参考点搜索范围设为图像大小的1/4小10-20个像素,采用上面算法左上角搜索步骤
////   对四个临时图像分别进行搜索参考点,在进行(折形结构)搜索和模版匹配时,搜索并匹配成功第一个即停止搜索              
////   (找到参考点),匹配精度因子由外部参数指定。
////                       3、把另三块临时图像的参考点还原成相应的原参考点。
////
////  找出其参考点之后,即可对图像进行线性或非线性纠正。

评论(?)
阅读(?)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
网易公司版权所有 ©1997-2009