mydiblib.h
上传用户:kennygump
上传日期:2022-07-22
资源大小:347k
文件大小:49k
源码类别:

图形/文字识别

开发平台:

Visual C++

  1. #include "dibapi.h"
  2. #include <iostream>
  3. #include <deque>
  4. #include <math.h>
  5. using namespace std;
  6. typedef deque<CRect> CRectLink;
  7. typedef deque<HDIB>  HDIBLink;
  8. //声明一些必要的全局变量
  9. int w_sample=8;
  10. int h_sample=16;
  11. bool fileloaded;
  12. bool gyhinfoinput;
  13. bool gyhfinished;
  14. int digicount;
  15. int m_lianXuShu;
  16. CRectLink m_charRectCopy;
  17. CRectLink m_charRect;
  18. HDIBLink  m_dibRect;
  19. HDIBLink  m_dibRectCopy;
  20. HDIB m_hDIB;
  21. CString strPathName;
  22. CString strPathNameSave;
  23. /********************************function declaration*************************************/
  24. //清楚屏幕
  25. void ClearAll(CDC* pDC);
  26. //在屏幕上显示位图
  27. void DisplayDIB(CDC* pDC,HDIB hDIB);
  28. //对分割后的位图进行尺寸标准归一化
  29. void StdDIBbyRect(HDIB hDIB, int tarWidth, int tarHeight);
  30. //整体斜率调整
  31. void SlopeAdjust(HDIB hDIB);
  32. //去除离散噪声点
  33. void RemoveScatterNoise(HDIB hDIB);
  34. //梯度锐化
  35. void GradientSharp(HDIB hDIB);
  36. //画框
  37. void DrawFrame(CDC* pDC,HDIB hDIB, CRectLink charRect,unsigned int linewidth,COLORREF color);
  38. //将灰度图二值化
  39. void ConvertGrayToWhiteBlack(HDIB hDIB);
  40. //将256色位图转为灰度图
  41. void Convert256toGray(HDIB hDIB);
  42. //细化
  43. void Thinning(HDIB hDIB);
  44. //对位图进行分割.返回一个存储着每块分割区域的链表
  45. CRectLink CharSegment(HANDLE hDIB);
  46. //紧缩、重排调整
  47. HDIB AutoAlign(HDIB hDIB);
  48. //判断是否是离散噪声点
  49. bool DeleteScaterJudge(LPSTR lpDIBBits,WORD lLineBytes, LPBYTE lplab, int lWidth, int lHeight, int x, int y, CPoint lab[], int lianXuShu);
  50. //对图像进行模板操作
  51. HDIB Template(HDIB hDIB,double * tem ,int tem_w,int tem_h,double xishu);
  52. //对图像进行中值滤波
  53. HDIB MidFilter(HDIB hDIB,int tem_w,int tem_h);
  54. //对图像进行直方图均衡
  55. void Equalize(HDIB hDIB);
  56. /***********************************implementation*************************************/
  57. /*********************************** ************************************
  58. 函数名称:DisplayDIB
  59. 参数:
  60. CDC* pDC -指向当前设备上下文(Divice Context)的指针
  61. HDIB hDIB -要显示的位图的句柄
  62. **********************************************************************/
  63. void DisplayDIB(CDC* pDC,HDIB hDIB)
  64. {
  65. BYTE* lpDIB=(BYTE*)::GlobalLock((HGLOBAL)hDIB);
  66. // 获取DIB宽度和高度
  67. int cxDIB =  ::DIBWidth((char*) lpDIB);
  68. int cyDIB =  ::DIBHeight((char*)lpDIB);
  69. CRect rcDIB,rcDest;
  70. rcDIB.top = rcDIB.left = 0;
  71. rcDIB.right = cxDIB;
  72. rcDIB.bottom = cyDIB;
  73. //设置目标客户区输出大小尺寸
  74. rcDest = rcDIB;
  75. //CDC* pDC=GetDC();
  76. ClearAll(pDC);
  77. //在客户区显示图像
  78. //for(int ii=0;ii<10;ii++)
  79. ::PaintDIB(pDC->m_hDC,rcDest,hDIB,rcDIB,NULL);
  80. ::GlobalUnlock((HGLOBAL)hDIB);
  81. }
  82. void ClearAll(CDC *pDC)
  83. {
  84. CRect rect;
  85. //GetClientRect(&rect);
  86. rect.left =0;rect.top =0;rect.right =2000;rect.bottom =330;
  87. CPen pen;
  88. pen.CreatePen (PS_SOLID,1,RGB(255,255,255));
  89. pDC->SelectObject (&pen);
  90. pDC->Rectangle (&rect);
  91. ::DeleteObject (pen);
  92. }
  93. /*******************************************
  94. *
  95. *  函数名称:
  96. *  AutoAlign()
  97. *
  98. *  参数:
  99. *    HDIB   hDIB        -原图像的句柄
  100. *
  101. *  返回值   
  102. *    HDIB               -紧缩排列后的新图像的句柄
  103. *
  104. *  功能:
  105. *     将经过了标准化处理的字符进行规整的排列,以方便下一步的处理
  106. *
  107. *  说明:
  108. *     紧缩排列的操作必须在标准化操作之后进行
  109. *
  110. ********************************************************/
  111. HDIB AutoAlign(HDIB hDIB)
  112. {   
  113. //指向图像的指针
  114.   BYTE* lpDIB=(BYTE*)::GlobalLock ((HGLOBAL)hDIB);
  115. //指向象素起始位置的指针
  116. BYTE* lpDIBBits=(BYTE*)::FindDIBBits ((char*)lpDIB);
  117. //指向象素的指针
  118. BYTE* lpSrc;
  119. //获取图像的宽度
  120. LONG lWidth=::DIBWidth ((char*)lpDIB);
  121. //获取图像的高度
  122. LONG lHeight=::DIBHeight ((char*)lpDIB);
  123. //获取标准化的宽度
  124. int w=m_charRect.front ().Width() ;
  125. //获取标准化的高度
  126. int h=m_charRect.front ().Height() ;
  127. //建立一个新的图像正好能够将标准化的字符并排放置
  128. HDIB hNewDIB=::NewDIB (digicount*w,h,8);
  129. //指向新的图像的指针
  130. BYTE* lpNewDIB=(BYTE*) ::GlobalLock((HGLOBAL)hNewDIB);
  131. //指向象素起始位置的指针
  132. BYTE* lpNewDIBBits=(BYTE*)::FindDIBBits((char*)lpNewDIB);
  133. //指向象素的指针
  134. BYTE* lpDst=lpNewDIBBits;
  135. //计算原图像每行的字节数
  136. LONG lLineBytes=(lWidth+3)/4*4;
  137. //计算新图像每行的字节数
  138. LONG lLineBytesnew =(digicount*w+3)/4*4;
  139. //将新的图像初始化为白色
  140. memset(lpDst,(BYTE)255,lLineBytesnew * h);
  141. //映射操作的坐标变量
  142. int i_src,j_src;
  143. //循环变量
  144. int i,j;
  145. //统计字符个数的变量
  146. int counts=0;
  147. //存放位置信息的结构体
  148. CRect rect,rectnew;
  149. //清空一个新的链表来存放新的字符位置信息
  150. m_charRectCopy.clear ();
  151. //从头至尾逐个扫描原链表的各个结点
  152. while(!m_charRect.empty() )
  153. {   
  154. //从表头上得到一个矩形框
  155. rect=m_charRect.front ();
  156. //将这个矩形框从链表上删除
  157. m_charRect.pop_front ();
  158. //计算新的矩形框的位置信息
  159. //左边界
  160. rectnew.left =counts*w;
  161. //右边界
  162. rectnew.right =(counts+1)*w;
  163. //上边界
  164. rectnew.top =0;
  165. //下边界
  166. rectnew.bottom =h;
  167. //将获得的新的矩形框插入到新的链表中
  168. m_charRectCopy.push_back (rectnew);
  169. //将原矩形框内的象素映射到新的矩形框中
  170. for(i=0;i<h;i++)
  171. {  
  172. for(j=counts*w;j<(counts+1)*w;j++)
  173. {   
  174. //计算映射坐标
  175.            i_src=rect.top +i;
  176. j_src=rect.left +j-counts*w;
  177. //进行象素的映射
  178. lpSrc=(BYTE *)lpDIBBits + lLineBytes *  i_src + j_src;
  179. lpDst=(BYTE *)lpNewDIBBits + lLineBytesnew * i + j;
  180. *lpDst=*lpSrc;
  181. }
  182. }
  183. //字符个数加1
  184. counts++;
  185. }
  186. //将获得的新的链表复制到原链表中,以方便下一次的调用
  187. m_charRect=m_charRectCopy;
  188. //解除锁定
  189. ::GlobalUnlock (hDIB);
  190. ::GlobalUnlock (hNewDIB);
  191. return hNewDIB;
  192. }
  193. /**************************************************
  194. * 函数名称:
  195. *     ThinnerHilditch
  196. *
  197. * 参数:
  198. *   void*     image             -二值化图像矩阵前景色为1背景色为0
  199. *   unsigned  longlx             -图像的宽度
  200. *   unsigned  longly             -图像的高度
  201. *
  202. * 返回值
  203. *       无
  204. *
  205. *函数功能:
  206. *       对输入的图像进行细化,输出细化后的图像
  207. ***********************************************************/
  208. void ThinnerHilditch(void *image, unsigned long lx, unsigned long ly)
  209. {
  210.     char *f, *g;
  211.     char n[10];
  212.     unsigned int counter;
  213.     short k, shori, xx, nrn;
  214.     unsigned long i, j;
  215.     long kk, kk11, kk12, kk13, kk21, kk22, kk23, kk31, kk32, kk33, size;
  216.     size = (long)lx * (long)ly;
  217.     g = (char *)malloc(size);
  218.     if(g == NULL)
  219.     {
  220.        // printf("error in allocating memory!n");
  221.         return;
  222.     }
  223.     f = (char *)image;
  224.     for(i=0; i<lx; i++)
  225.     {
  226.         for(j=0; j<ly; j++)
  227.         {
  228.             kk=i*ly+j;
  229.             if(f[kk]!=0)
  230.             {
  231.                 f[kk]=1;
  232.                 g[kk]=f[kk];
  233.             }
  234.         }
  235.     }
  236.     counter = 1;
  237.     do
  238.     {
  239.         
  240.         counter++;
  241.         shori = 0;
  242.         for(i=0; i<lx; i++)
  243.         {
  244.             for(j=0; j<ly; j++)
  245.             {
  246.                 kk = i*ly+j;
  247.                 if(f[kk]<0)
  248.                     f[kk] = 0;
  249.                 g[kk]= f[kk];
  250.             }
  251.         }
  252.         for(i=1; i<lx-1; i++)
  253.         {
  254.             for(j=1; j<ly-1; j++)
  255.             {
  256.                 kk=i*ly+j;
  257.                 if(f[kk]!=1)
  258.                     continue;
  259.                 kk11 = (i-1)*ly+j-1;
  260.                 kk12 = kk11 + 1;
  261.                 kk13 = kk12 + 1;
  262.                 kk21 = i*ly+j-1;
  263.                 kk22 = kk21 + 1;
  264.                 kk23 = kk22 + 1;
  265.                 kk31 = (i+1)*ly+j-1;
  266.                 kk32 = kk31 + 1;
  267.                 kk33 = kk32 + 1;
  268.                 if((g[kk12]&&g[kk21]&&g[kk23]&&g[kk32])!=0)
  269.                     continue;
  270.                 nrn = g[kk11] + g[kk12] + g[kk13] + g[kk21] + g[kk23] + 
  271.                     g[kk31] + g[kk32] + g[kk33];
  272.                 if(nrn <= 1)
  273.                 {
  274.                     f[kk22] = 2;
  275.                     continue;
  276.                 }
  277.                 n[4] = f[kk11];
  278.                 n[3] = f[kk12];
  279.                 n[2] = f[kk13];
  280.                 n[5] = f[kk21];
  281.                 n[1] = f[kk23];
  282.                 n[6] = f[kk31];
  283.                 n[7] = f[kk32];
  284.                 n[8] = f[kk33];
  285.                 n[9] = n[1];
  286.                 xx = 0;
  287.                 for(k=1; k<8; k=k+2)
  288.                 {
  289.                     if((!n[k])&&(n[k+1]||n[k+2]))
  290.                         xx++;
  291.                 }
  292.                 if(xx!=1)
  293.                 {
  294.                     f[kk22] = 2;
  295.                     continue;
  296.                 }
  297.                 if(f[kk12] == -1)
  298.                 {
  299.                     f[kk12] = 0;
  300.                     n[3] = 0;
  301.                     xx = 0;
  302.                     for(k=1; k<8; k=k+2)
  303.                     {
  304.                         if((!n[k])&&(n[k+1]||n[k+2]))
  305.                             xx++;
  306.                     }
  307.                     if(xx != 1)
  308.                     {
  309.                         f[kk12] = -1;
  310.                         continue;
  311.                     }
  312.                     f[kk12] = -1;
  313.                     n[3] = -1;
  314.                 }
  315.                 if(f[kk21]!=-1)
  316.                 {
  317.                     f[kk22] = -1;
  318.                     shori = 1;
  319.                     continue;
  320.                 }
  321.                 f[kk21] = 0;
  322.                 n[5] = 0;
  323.                 xx = 0;
  324.                 for(k=1; k<8; k=k+2)
  325.                 {
  326.                     if((!n[k])&&(n[k+1]||n[k+2]))
  327.                     {
  328.                         xx++;
  329.                     }
  330.                 }
  331.                 if(xx == 1)
  332.                 {
  333.                     f[kk21] = -1;
  334.                     f[kk22] = -1;
  335.                     shori =1;
  336.                 }
  337.                 else
  338.                     f[kk21] = -1;
  339.             }
  340.         }
  341.     }while(shori);
  342.     free(g);
  343. }
  344. /**************************************************
  345. * 函数名称:
  346. *     ThinnerRosenfeld
  347. *
  348. * 参数:
  349. *   void*     image             -二值化图像矩阵前景色为1背景色为0
  350. *   unsigned  longlx             -图像的宽度
  351. *   unsigned  longly             -图像的高度
  352. *
  353. * 返回值
  354. *       无
  355. *
  356. *函数功能:
  357. *       对输入的图像进行细化,输出细化后的图像
  358. ***********************************************************/
  359. void ThinnerRosenfeld(void *image, unsigned long lx, unsigned long ly)
  360. {
  361.     char *f, *g;
  362.     char n[10];
  363.     char a[5] = {0, -1, 1, 0, 0};
  364.     char b[5] = {0, 0, 0, 1, -1};
  365.     char nrnd, cond, n48, n26, n24, n46, n68, n82, n123, n345, n567, n781;
  366.     short k, shori;
  367.     unsigned long i, j;
  368.     long ii, jj, kk, kk1, kk2, kk3, size;
  369.     size = (long)lx * (long)ly;
  370.     g = (char *)malloc(size);
  371.     if(g==NULL)
  372.     {
  373.         printf("error in alocating mmeory!n");
  374.         return;
  375.     }
  376.     f = (char *)image;
  377.     for(kk=0l; kk<size; kk++)
  378.     {
  379.         g[kk] = f[kk];
  380.     }
  381.     do
  382.     {
  383.         shori = 0;
  384.         for(k=1; k<=4; k++)
  385.         {
  386.             for(i=1; i<lx-1; i++)
  387.             {
  388.                 ii = i + a[k];
  389.                 for(j=1; j<ly-1; j++)
  390.                 {
  391.                     kk = i*ly + j;
  392.                     if(!f[kk])
  393.                         continue;
  394.                     jj = j + b[k];
  395.                     kk1 = ii*ly + jj;
  396.                     if(f[kk1])
  397.                         continue;
  398.                     kk1 = kk - ly -1;
  399.                     kk2 = kk1 + 1;
  400.                     kk3 = kk2 + 1;
  401.                     n[3] = f[kk1];
  402.                     n[2] = f[kk2];
  403.                     n[1] = f[kk3];
  404.                     kk1 = kk - 1;
  405.                     kk3 = kk + 1;
  406.                     n[4] = f[kk1];
  407.                     n[8] = f[kk3];
  408.                     kk1 = kk + ly - 1;
  409.                     kk2 = kk1 + 1;
  410.                     kk3 = kk2 + 1;
  411.                     n[5] = f[kk1];
  412.                     n[6] = f[kk2];
  413.                     n[7] = f[kk3];
  414.                     nrnd = n[1] + n[2] + n[3] + n[4]
  415.                         +n[5] + n[6] + n[7] + n[8];
  416.                     if(nrnd<=1)
  417.                         continue;
  418.                     cond = 0;
  419.                     n48 = n[4] + n[8];
  420.                     n26 = n[2] + n[6];
  421.                     n24 = n[2] + n[4];
  422.                     n46 = n[4] + n[6];
  423.                     n68 = n[6] + n[8];
  424.                     n82 = n[8] + n[2];
  425.                     n123 = n[1] + n[2] + n[3];
  426.                     n345 = n[3] + n[4] + n[5];
  427.                     n567 = n[5] + n[6] + n[7];
  428.                     n781 = n[7] + n[8] + n[1];
  429.                     if(n[2]==1 && n48==0 && n567>0)
  430.                     {
  431.                         if(!cond)
  432.                             continue;
  433.                         g[kk] = 0;
  434.                         shori = 1;
  435.                         continue;
  436.                     }
  437.                     if(n[6]==1 && n48==0 && n123>0)
  438.                     {
  439.                         if(!cond)
  440.                             continue;
  441.                         g[kk] = 0;
  442.                         shori = 1;
  443.                         continue;
  444.                     }
  445.                     if(n[8]==1 && n26==0 && n345>0)
  446.                     {
  447.                         if(!cond)
  448.                             continue;
  449.                         g[kk] = 0;
  450.                         shori = 1;
  451.                         continue;
  452.                     }
  453.                     if(n[4]==1 && n26==0 && n781>0)
  454.                     {
  455.                         if(!cond)
  456.                             continue;
  457.                         g[kk] = 0;
  458.                         shori = 1;
  459.                         continue;
  460.                     }
  461.                     if(n[5]==1 && n46==0)
  462.                     {
  463.                         if(!cond)
  464.                             continue;
  465.                         g[kk] = 0;
  466.                         shori = 1;
  467.                         continue;
  468.                     }
  469.                     if(n[7]==1 && n68==0)
  470.                     {
  471.                         if(!cond)
  472.                             continue;
  473.                         g[kk] = 0;
  474.                         shori = 1;
  475.                         continue;
  476.                     }
  477.                     if(n[1]==1 && n82==0)
  478.                     {
  479.                         if(!cond)
  480.                             continue;
  481.                         g[kk] = 0;
  482.                         shori = 1;
  483.                         continue;
  484.                     }
  485.                     if(n[3]==1 && n24==0)
  486.                     {
  487.                         if(!cond)
  488.                             continue;
  489.                         g[kk] = 0;
  490.                         shori = 1;
  491.                         continue;
  492.                     }
  493.                     cond = 1;
  494.                     if(!cond)
  495.                         continue;
  496.                     g[kk] = 0;
  497.                     shori = 1;
  498.                 }
  499.             }
  500.             for(i=0; i<lx; i++)
  501.             {
  502.                 for(j=0; j<ly; j++)
  503.                 {
  504.                     kk = i*ly + j;
  505.                     f[kk] = g[kk];
  506.                 }
  507.             }
  508.         }
  509.     }while(shori);
  510.     free(g);
  511. }              
  512. /*************************************************
  513. *
  514. * 函数名称:
  515. *       CharSegment()
  516. *
  517. *  参数:
  518. *      HDIB  hDIB      -原图像的句柄
  519. *
  520. *  返回值:
  521. *     CRectLink        -存放被分割的各个字符位置信息的链表
  522. *
  523. * 功能:
  524. *    将图像中待识别的字符逐个分离出来并返回存放各个字符的位置信息的链表
  525. *
  526. *  说明:
  527. *    此函数只能对2值化后的图像进行处理
  528. *
  529. *********************************************************/
  530. CRectLink CharSegment(HANDLE hDIB)
  531. {
  532. //清空用来保存每个字符区域的链表
  533. CRectLink charRect1,charRect2;
  534. charRect1.clear();
  535. charRect2.clear();
  536. // 指向DIB的指针
  537. LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL)hDIB);
  538. // 指向DIB象素指针
  539. LPSTR    lpDIBBits;
  540. // 找到DIB图像象素起始位置
  541. lpDIBBits = ::FindDIBBits(lpDIB);
  542. //指向象素的的指针
  543. BYTE* lpSrc;
  544. //图像的长度和宽度
  545. int height,width;
  546. //获取图像的宽度
  547. width=(int)::DIBWidth(lpDIB);
  548. //获取图像的长度
  549. height=(int)::DIBHeight(lpDIB);
  550. //计算图像每行的字节数
  551. LONG lLineBytes = WIDTHBYTES(width * 8);
  552. //定义上下边界两个变量
  553. int top,bottom;
  554.     //象素的灰度值
  555.     int gray; 
  556. //设置循环变量
  557. int i,j;
  558. //用来统计图像中字符个数的计数器
  559. digicount=0;
  560. //从上往下扫描,找到上边界
  561. //行
  562. for (i=0;i<height;i++)
  563. {
  564.          //列
  565.    for (j=0;j<width;j++)
  566. {
  567.             // 指向图像第i行,第j个象素的指针
  568. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * i + j;
  569. //获得该点的灰度值
  570. gray = *(lpSrc);
  571. //看是否为黑点
  572. if (gray == 0)
  573. {   
  574.                //若为黑点,把此点作为字符大致的最高点
  575. top = i;
  576. //对i强行赋值以中断循环
  577. i=height;
  578. //跳出循环
  579. break;
  580. }
  581.         //如果该点不是黑点,继续循环
  582. }
  583. }
  584.     //从下往上扫描,找下边界
  585. //行
  586. for (i = height-1;i>=0;i--)
  587.     {
  588. //列
  589. for (j=0;j<width;j++)
  590. {
  591. // 指向图像第i行,第j个象素的指针
  592. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * i + j;
  593. //获取该点的灰度值
  594. gray = *(lpSrc);
  595. //判断是否为黑点
  596. if (gray == 0)
  597. {
  598. //若为黑点,把此点作为字符大致的最低点
  599. bottom = i;
  600. //对i强行赋值以中断循环
  601. i=-1;
  602. //跳出循环
  603. break;
  604. }
  605.           //如果该点不是黑点,继续循环
  606. }
  607. }
  608. //lab 用作是否进入一个字符分割的标志
  609. bool lab = false;
  610. //表明扫描一列中是否发现黑色点
  611. bool black = false;
  612.     //存放位置信息的结构体
  613. CRect rect;
  614. //计数器置零
  615. digicount=0;
  616.    
  617. //行
  618. for (i=0;i<width;i++)
  619. {
  620. //开始扫描一列
  621. black=false;
  622. for (j=0;j<height;j++)
  623. {
  624. // 指向图像第i行,第j个象素的指针
  625. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i;
  626. //获取该点的灰度值
  627. gray = *(lpSrc);
  628.                 //判断是否为黑点
  629. if (gray == 0)
  630. {
  631. //如果发现黑点,设置标志位
  632. black=true;
  633. //如果还没有进入一个字符的分割
  634. if(lab==false)
  635. {
  636. //设置左侧边界
  637. rect.left = i;
  638. //字符分割开始
  639. lab = true;
  640. }
  641. //如果字符分割已经开始了
  642. else
  643.                       //跳出循环
  644. break;
  645. }
  646. }
  647. //如果已经扫到了最右边那列,说明整副图像扫描完毕。退出
  648.            if(i==(width-1))
  649.    
  650.  //退出整个循环    
  651.    break;
  652. //如果到此black仍为false,说明扫描了一列,都没有发现黑点。表明当前字符分割结束
  653. if(lab==true&&black==false)
  654. {   
  655.            //将位置信息存入结构体中
  656.            //设置右边界
  657. rect.right =i;
  658. //设置上边界
  659. rect.top =top;
  660. //设置下边界
  661. rect.bottom =bottom;
  662. //将框外括一个象素,以免压到字符
  663. rect.InflateRect (1,1);
  664.             //将这个结构体插入存放位置信息的链表1的后面
  665. charRect1.push_back (rect);
  666. //设置标志位,开始下一次的字符分割
  667. lab=false;
  668. //字符个数统计计数器加1
  669. digicount++;
  670. }
  671. //进入下一列的扫描
  672. }
  673.    //再将矩形轮廓矩形的top和bottom精确化
  674. //将链表1赋值给链表2
  675. charRect2=charRect1;
  676.     //将链表2的内容清空
  677.     charRect2.clear ();
  678. //建立一个新的存放位置信息的结构体
  679. CRect rectnew;
  680. //对于链表1从头至尾逐个进行扫描
  681. while(!charRect1.empty())
  682. {    
  683. //从链表1头上得到一个矩形
  684. rect= charRect1.front();
  685. //从链表1头上面删掉一个
  686. charRect1.pop_front();
  687. //计算更加精确的矩形区域
  688. //获得精确的左边界
  689. rectnew.left =rect.left-1 ;
  690. //获得精确的右边界
  691. rectnew.right =rect.right+1 ;
  692. //通过获得的精确左右边界对上下边境重新进行精确定位
  693. // 由下而上扫描计算上边界
  694. //行
  695. for(i=rect.top ;i<rect.bottom ;i++)
  696. {   
  697.           //列
  698. for(j=rect.left ;j<rect.right ;j++)
  699. {   
  700.                  // 指向图像第i行,第j个象素的指针
  701. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * i + j;
  702. //如果这个象素是黑点
  703. if (*lpSrc == 0)
  704. {
  705. //设置上边界
  706. rectnew.top = i-1;
  707. //对i进行强制定义以跳出循环
  708. i=rect.bottom  ;
  709. //跳出循环
  710. break;
  711. }
  712. }
  713. }
  714. //由下而上扫描计算下边界
  715.    
  716.         //行
  717. for(i=rect.bottom-1 ;i>=rect.top  ;i--)
  718. {
  719. //列
  720. for(j=rect.left ;j<rect.right ;j++)
  721. {
  722. // 指向图像第i行,第j个象素的指针
  723. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * i + j;
  724. //该点如果为黑点
  725. if (*lpSrc == 0)
  726. {
  727. //设置下边界
  728. rectnew.bottom = i+1;
  729.                     //对i进行强制定义以跳出循环
  730. i=-1;
  731.                     //跳出循环
  732. break;
  733. }
  734. }
  735. }
  736. //将得到的新的准确的位置信息从后面插到链表2的尾上
  737. charRect2.push_back (rectnew);
  738. }
  739. //将链表2 传递给链表1
  740. charRect1=charRect2;
  741. //解除锁定
  742. ::GlobalUnlock(hDIB);
  743. //将链表1返回
  744. return charRect1;
  745. }
  746. /****************************************************************
  747. * 函数名称:
  748. *      Convert256toGray()
  749. *
  750. * 参数:
  751. *     HDIB hDIB     -图像的句柄
  752. *
  753. *  返回值:
  754. *        无
  755. *
  756. *  功能:
  757. *     将256色位图转化为灰度图
  758. *
  759. ***************************************************************/
  760. void Convert256toGray(HDIB hDIB)
  761. {
  762. LPSTR lpDIB;
  763. // 由DIB句柄得到DIB指针并锁定DIB
  764. lpDIB = (LPSTR) ::GlobalLock((HGLOBAL)hDIB);
  765. // 指向DIB象素数据区的指针
  766. LPSTR   lpDIBBits;
  767. // 指向DIB象素的指针
  768. BYTE * lpSrc;
  769. // 图像宽度
  770. LONG lWidth;
  771. // 图像高度
  772. LONG   lHeight;
  773. // 图像每行的字节数
  774. LONG lLineBytes;
  775. // 指向BITMAPINFO结构的指针(Win3.0)
  776. LPBITMAPINFO lpbmi;
  777. // 指向BITMAPCOREINFO结构的指针
  778. LPBITMAPCOREINFO lpbmc;
  779. // 获取指向BITMAPINFO结构的指针(Win3.0)
  780. lpbmi = (LPBITMAPINFO)lpDIB;
  781. // 获取指向BITMAPCOREINFO结构的指针
  782. lpbmc = (LPBITMAPCOREINFO)lpDIB;
  783. // 灰度映射表
  784. BYTE bMap[256];
  785. // 计算灰度映射表(保存各个颜色的灰度值),并更新DIB调色板
  786. int i,j;
  787. for (i = 0; i < 256; i ++)
  788. {
  789. // 计算该颜色对应的灰度值
  790. bMap[i] = (BYTE)(0.299 * lpbmi->bmiColors[i].rgbRed +
  791.      0.587 * lpbmi->bmiColors[i].rgbGreen +
  792.          0.114 * lpbmi->bmiColors[i].rgbBlue + 0.5);
  793. // 更新DIB调色板红色分量
  794. lpbmi->bmiColors[i].rgbRed = i;
  795. // 更新DIB调色板绿色分量
  796. lpbmi->bmiColors[i].rgbGreen = i;
  797. // 更新DIB调色板蓝色分量
  798. lpbmi->bmiColors[i].rgbBlue = i;
  799. // 更新DIB调色板保留位
  800. lpbmi->bmiColors[i].rgbReserved = 0;
  801. }
  802. // 找到DIB图像象素起始位置
  803. lpDIBBits = ::FindDIBBits(lpDIB);
  804. // 获取图像宽度
  805. lWidth = ::DIBWidth(lpDIB);
  806. // 获取图像高度
  807. lHeight = ::DIBHeight(lpDIB);
  808. // 计算图像每行的字节数
  809. lLineBytes = WIDTHBYTES(lWidth * 8);
  810. // 更换每个象素的颜色索引(即按照灰度映射表换成灰度值)
  811. //逐行扫描
  812. for(i = 0; i < lHeight; i++)
  813. {
  814.   //逐列扫描
  815. for(j = 0; j < lWidth; j++)
  816. {
  817. // 指向DIB第i行,第j个象素的指针
  818. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  819. // 变换
  820. *lpSrc = bMap[*lpSrc];
  821. }
  822. }
  823. //解除锁定
  824. ::GlobalUnlock ((HGLOBAL)hDIB);
  825. }
  826. /******************************************************************
  827. *
  828. * 函数名称ConvertGrayToWhiteBlack()
  829. *
  830. * 参数 :HDIB hDIB     -原图的句柄
  831. *
  832. * 返回值:无
  833. *
  834. * 功能: ConvertGrayToWhiteBlack函数采用硬阈值的方法,实现将图像二值化的功能。
  835. * 说明:
  836. 要求待处理的图片为256色
  837. ************************************************************************/
  838. void ConvertGrayToWhiteBlack(HDIB hDIB)
  839. {
  840. // 指向DIB的指针
  841. LPSTR lpDIB;
  842. // 由DIB句柄得到DIB指针并锁定DIB
  843. lpDIB = (LPSTR) ::GlobalLock((HGLOBAL)hDIB);
  844. // 指向DIB象素数据区的指针
  845. LPSTR   lpDIBBits;
  846. // 指向DIB象素的指针
  847. BYTE * lpSrc;
  848. // 图像宽度
  849. LONG lWidth;
  850. // 图像高度
  851. LONG lHeight;
  852. // 图像每行的字节数
  853. LONG lLineBytes;
  854. // 找到DIB图像象素起始位置
  855. lpDIBBits = ::FindDIBBits(lpDIB);
  856. // 获取图像宽度
  857. lWidth = ::DIBWidth(lpDIB);
  858. // 获取图像高度
  859. lHeight = ::DIBHeight(lpDIB);
  860. // 计算图像每行的字节数
  861. lLineBytes = WIDTHBYTES(lWidth * 8);
  862. // 更换每个象素的颜色索引(即按照灰度映射表换成灰度值)
  863. int i,j;
  864.     //逐行扫描
  865. for(i = 0; i < lHeight; i++)
  866.  {
  867.    //逐列扫描
  868. for(j = 0; j < lWidth; j++)
  869. {
  870. // 指向DIB第i行,第j个象素的指针
  871. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * i + j;
  872. // 二值化处理
  873.    //大于220,设置为255,即白点
  874. if(*lpSrc>220) *lpSrc=255;
  875.   //否则设置为0,即黑点
  876. else *lpSrc=0;
  877. }
  878. }
  879.  //解除锁定
  880. ::GlobalUnlock((HGLOBAL)hDIB);
  881. }
  882. /*****************************************************************
  883. *
  884. *  函数名称 
  885. *       DeleteScaterJudge()
  886. *
  887. *  参数:
  888. *     LPSTR   lpDIBBits      -指向象素起始位置的指针
  889. *   WORD    lLineBytes     -图像每行的字节数
  890. *     LPBYTE  lplab          -标志位数组
  891. *     int     lWidth         -图像的宽度
  892. *   int     lHeight        -图像的高度
  893. *     int     x              -当前点的横坐标
  894. *   int     y              -当前点的纵坐标 
  895. *     CPoint  lab[]          -存放议考察过的连续点坐标
  896. *     int     lianXuShu      -离散点的判定长度
  897. *
  898. *  返回值:
  899. *     Bool                   -是离散点返回false 不是离散点返回true
  900. *  
  901. *  功能:
  902. *     利用递归算法统计连续点的个数,通过阈值来判定是否为离散点
  903. *
  904. *  说明:
  905. *     只能对2值图像进行处理
  906. ******************************************************************/     
  907. bool DeleteScaterJudge(LPSTR lpDIBBits, WORD lLineBytes, LPBYTE lplab, int lWidth, int lHeight, int x, int y, CPoint lab[], int lianXuShu)
  908. {
  909. //如果连续长度满足要求,说明不是离散点,返回
  910. if(m_lianXuShu>=lianXuShu)
  911. return TRUE;
  912. //长度加一
  913. m_lianXuShu++;
  914. //设定访问标志
  915. lplab[lWidth * y +x] = true;
  916. //保存访问点坐标
  917. lab[m_lianXuShu-1].x = x;
  918. lab[m_lianXuShu-1].y = y;
  919. //象素的灰度值
  920. int gray;
  921.   
  922. //指向象素的指针
  923. LPSTR lpSrc;
  924. //长度判定
  925.     //如果连续长度满足要求,说明不是离散点,返回
  926. if(m_lianXuShu>=lianXuShu)
  927. return TRUE;
  928. //下面进入递归
  929. else
  930. {
  931. //考察上下左右以及左上、右上、左下、右下八个方向
  932. //如果是黑色点,则调用函数自身进行递归
  933. //考察下面点
  934. lpSrc=(char*)lpDIBBits + lLineBytes * (y-1) + x;
  935. //传递灰度值
  936. gray=*lpSrc;
  937. //如果点在图像内、颜色为黑色并且没有被访问过
  938. if(y-1 >=0 && gray == 0 && lplab[(y-1)*lWidth+x] == false)
  939. //进行递归处理
  940. DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x,y-1,lab,lianXuShu);
  941. //判断长度
  942. //如果连续长度满足要求,说明不是离散点,返回
  943. if(m_lianXuShu>=lianXuShu)
  944. return TRUE;
  945. //左下点
  946. lpSrc=(char*)lpDIBBits + lLineBytes * (y-1) + x-1;
  947.         //传递灰度值
  948. gray=*lpSrc;
  949.         //如果点在图像内、颜色为黑色并且没有被访问过
  950. if(y-1 >=0 &&  x-1 >=0 && gray== 0 && lplab[(y-1)*lWidth+x-1] == false)
  951.        //进行递归处理
  952. DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x-1,y-1,lab,lianXuShu);
  953.         //判断长度
  954. //如果连续长度满足要求,说明不是离散点,返回
  955. if(m_lianXuShu>=lianXuShu)
  956. return TRUE;
  957. //左边
  958. lpSrc=(char*)lpDIBBits + lLineBytes * y + x-1;
  959. //传递灰度值
  960. gray=*lpSrc;
  961.         //如果点在图像内、颜色为黑色并且没有被访问过
  962. if(x-1 >=0 &&  gray== 0 && lplab[y*lWidth+x-1] == false)
  963.         //进行递归处理
  964. DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x-1,y,lab,lianXuShu);
  965.         //判断长度
  966. //如果连续长度满足要求,说明不是离散点,返回
  967. if(m_lianXuShu>=lianXuShu)
  968. return TRUE;
  969. //左上
  970. lpSrc=(char*)lpDIBBits + lLineBytes * (y+1) + x-1;
  971. //传递灰度值
  972. gray=*lpSrc;
  973.         //如果点在图像内、颜色为黑色并且没有被访问过
  974. if(y+1 <lHeight && x-1 >= 0 && gray == 0 && lplab[(y+1)*lWidth+x-1] == false)
  975. //进行递归处理
  976. DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x-1,y+1,lab,lianXuShu);
  977.         //判断长度
  978. //如果连续长度满足要求,说明不是离散点,返回
  979. if(m_lianXuShu>=lianXuShu)
  980. return TRUE;
  981. //上面
  982. lpSrc=(char*)lpDIBBits + lLineBytes * (y+1) + x;
  983.         //传递灰度值
  984. gray=*lpSrc;
  985.         //如果点在图像内、颜色为黑色并且没有被访问过
  986. if(y+1 < lHeight && gray == 0 && lplab[(y+1)*lWidth+x] == false)
  987.         //进行递归处理
  988. DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x,y+1,lab,lianXuShu);
  989.         //判断长度
  990. //如果连续长度满足要求,说明不是离散点,返回
  991. if(m_lianXuShu>=lianXuShu)
  992. return TRUE;
  993. //右上
  994. lpSrc=(char*)lpDIBBits + lLineBytes * (y+1) + x+1;
  995.         
  996. //传递灰度值
  997. gray=*lpSrc;
  998.         //如果点在图像内、颜色为黑色并且没有被访问过
  999. if(y+1 <lHeight && x+1 <lWidth &&  gray == 0 && lplab[(y+1)*lWidth+x+1] == false)
  1000.         //进行递归处理
  1001. DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x+1,y+1,lab,lianXuShu);
  1002.         //判断长度
  1003. //如果连续长度满足要求,说明不是离散点,返回
  1004. if(m_lianXuShu>=lianXuShu)
  1005. return TRUE;
  1006. //右边
  1007. lpSrc=(char*)lpDIBBits + lLineBytes * y + x+1;
  1008.         //传递灰度值
  1009. gray=*lpSrc;
  1010. //如果点在图像内、颜色为黑色并且没有被访问过
  1011. if(x+1 <lWidth && gray==0 && lplab[y*lWidth+x+1] == false)
  1012.         //进行递归处理
  1013. DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x+1,y,lab,lianXuShu);
  1014.         //判断长度
  1015. //如果连续长度满足要求,说明不是离散点,返回
  1016. if(m_lianXuShu>=lianXuShu)
  1017. return TRUE;
  1018. //右下
  1019. lpSrc=(char*)lpDIBBits + lLineBytes * (y-1) + x+1;
  1020.         //传递灰度值
  1021. gray=*lpSrc;
  1022.         //如果点在图像内、颜色为黑色并且没有被访问过
  1023. if(y-1 >=0 && x+1 <lWidth && gray == 0 && lplab[(y-1)*lWidth+x+1] == false)
  1024.        //进行递归处理
  1025.    DeleteScaterJudge(lpDIBBits,lLineBytes,lplab,lWidth,lHeight,x+1,y-1,lab,lianXuShu);
  1026.         //判断长度
  1027. //如果连续长度满足要求,说明不是离散点,返回
  1028. if(m_lianXuShu>=lianXuShu)
  1029. return TRUE;
  1030. }
  1031. //如果递归结束,返回false,说明是离散点
  1032. return FALSE;
  1033. }
  1034. /*****************绘制数字字符外面的矩形框*******************/
  1035. void DrawFrame(CDC* pDC,HDIB hDIB, CRectLink charRect,unsigned int linewidth,COLORREF color)
  1036. {
  1037. CPen pen;
  1038. pen.CreatePen (PS_SOLID,linewidth,color);
  1039. pDC->SelectObject (&pen);
  1040. ::SelectObject (*pDC,GetStockObject(NULL_BRUSH));
  1041. CRect rect,rect2;
  1042. BYTE* lpDIB=(BYTE*)::GlobalLock ((HGLOBAL)hDIB);
  1043. while(!charRect.empty())
  1044. {
  1045. //从表头上得到一个矩形
  1046. rect2=rect= charRect.front();
  1047. //从链表头上面删掉一个
  1048. charRect.pop_front();
  1049. //注意,这里原先的rect是相对于图像原点(左下角)的,
  1050. //而在屏幕上绘图时,要转换以客户区为原点的坐标
  1051. rect.top =::DIBHeight ((char*)lpDIB)-rect2.bottom;
  1052. rect.bottom =::DIBHeight ((char*)lpDIB)-rect2.top ;
  1053. pDC->Rectangle (&rect);
  1054. }
  1055. ::GlobalUnlock ((HGLOBAL)hDIB);
  1056. }
  1057. /***********************************************
  1058. *
  1059. * 函数名称:
  1060. *   GradientSharp() 
  1061. *
  1062. *参数 :
  1063. *  HDIB hDIB    -待处理图像的句柄
  1064. *
  1065. * 返回值:
  1066. *       无
  1067. *功能:
  1068. *    现图像的梯度锐化
  1069. *说明:
  1070. *    只能对2值图像进行处理,如果图像本身边缘较细,可能造成信息的损失
  1071. **********************************************************************/
  1072. void GradientSharp(HDIB hDIB)
  1073. {
  1074. // 指向DIB的指针
  1075. LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL)hDIB);
  1076. // 指向DIB象素指针
  1077. LPSTR    lpDIBBits;
  1078. // 找到DIB图像象素起始位置
  1079. lpDIBBits = ::FindDIBBits(lpDIB);
  1080.     //获取图像的宽度
  1081. LONG lWidth=::DIBWidth ((char*)lpDIB);
  1082.     //获取图像的长度
  1083. LONG lHeight=::DIBHeight ((char*)lpDIB);
  1084.     // 阈值
  1085. BYTE bThre = 2;
  1086. // 调用GradSharp()函数进行梯度板锐化
  1087. // 指向源图像的指针
  1088. unsigned char* lpSrc;
  1089. unsigned char* lpSrc1;
  1090. unsigned char* lpSrc2;
  1091. // 循环变量
  1092. LONG i;
  1093. LONG j;
  1094. // 图像每行的字节数
  1095. LONG lLineBytes;
  1096. // 中间变量
  1097. BYTE bTemp;
  1098. // 计算图像每行的字节数
  1099. lLineBytes = WIDTHBYTES(lWidth * 8);
  1100. // 每行
  1101.    for(i = 0; i < lHeight; i++)
  1102. {
  1103.      // 每列
  1104.  for(j = 0; j < lWidth; j++)
  1105. {
  1106.              // 指向DIB第i行,第j个象素的指针
  1107. lpSrc  = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  1108. // 指向DIB第i+1行,第j个象素的指针
  1109. lpSrc1 = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 2 - i) + j;
  1110.      // 指向DIB第i行,第j+1个象素的指针
  1111.      lpSrc2 = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j + 1;
  1112.               //计算梯度值
  1113.      bTemp = abs((*lpSrc)-(*lpSrc1)) + abs((*lpSrc)-(*lpSrc2));
  1114.     // 判断是否小于阈值
  1115.     if (bTemp < 255)
  1116. {  
  1117.      // 判断是否大于阈值,对于小于情况,灰度值不变。
  1118.    if (bTemp >= bThre)
  1119.    {
  1120. // 直接赋值为bTemp
  1121.  *lpSrc = bTemp;
  1122.    }
  1123. }
  1124.            else
  1125. {
  1126. // 直接赋值为255
  1127. *lpSrc = 255;
  1128. }
  1129.  }
  1130.    }
  1131. //最后还要处理一下图像中最下面那行
  1132. for(j = 0; j < lWidth; j++)
  1133. {   
  1134.  //指向最下边一行,第j个象素的指针
  1135.   lpSrc  = (unsigned char*)lpDIBBits + lLineBytes * 0 + j;
  1136.    //将此位置的象素设置为255,即白点
  1137. *lpSrc=255;
  1138. }
  1139.    //解除锁定
  1140. ::GlobalUnlock ((HGLOBAL)hDIB);
  1141. }
  1142. /************************************************************
  1143. *
  1144. *  函数名称:
  1145. *       RemoveScatterNoise()
  1146. *
  1147. *  参数:
  1148. *     HDIB    hDIB     -原图像的句柄
  1149. *
  1150. *  返回值:
  1151. *       无
  1152. *
  1153. *  功能:
  1154. *     通过对连续点长度的统计来去除离散杂点
  1155. *
  1156. *  说明:
  1157. *      只能对2值图像进行处理
  1158. ****************************************************************/
  1159. void RemoveScatterNoise(HDIB hDIB)
  1160. {
  1161. // 指向DIB的指针
  1162. LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL)hDIB);
  1163. // 指向DIB象素指针
  1164. LPSTR    lpDIBBits;
  1165. // 找到DIB图像象素数据区的起始位置
  1166. lpDIBBits = ::FindDIBBits(lpDIB);
  1167. //获得图像的长度
  1168. LONG lWidth=::DIBWidth ((char*)lpDIB);
  1169. //获得图像的高度
  1170. LONG lHeight=::DIBHeight ((char*)lpDIB);
  1171. //设置判定噪声的长度阈值为15
  1172. //即如果与考察点相连接的黑点的数目小于15则认为考察点是噪声点
  1173. int length=15;
  1174. // 循环变量
  1175. m_lianXuShu=0;
  1176. LONG i;
  1177. LONG j;
  1178. LONG    k;
  1179. // 图像每行的字节数
  1180. LONG lLineBytes;
  1181. // 计算图像每行的字节数
  1182. lLineBytes = WIDTHBYTES(lWidth * 8);
  1183.     
  1184. LPSTR lpSrc;
  1185. //开辟一块用来存放标志的内存数组
  1186. LPBYTE lplab = new BYTE[lHeight * lWidth];
  1187. //开辟一块用来保存离散判定结果的内存数组
  1188. bool *lpTemp = new bool[lHeight * lWidth];
  1189.     //初始化标志数组
  1190. for (i=0;i<lHeight*lWidth;i++)
  1191.     {
  1192.     //将所有的标志位设置为非
  1193. lplab[i] = false;
  1194. }
  1195. //用来存放离散点的坐标的数组
  1196. CPoint lab[21];
  1197.    
  1198. //为循环变量赋初始值
  1199. k=0;
  1200. //扫描整个图像
  1201. //逐行扫描
  1202. for(i =0;i<lHeight;i++)
  1203. {  
  1204.        
  1205.    //逐行扫描
  1206. for(j=0;j<lWidth;j++)
  1207. {
  1208. //先把标志位置false
  1209. for(k=0;k<m_lianXuShu;k++)
  1210. lplab[lab[k].y * lWidth + lab[k].x] = false;
  1211. //连续数置0
  1212. m_lianXuShu =0;
  1213.     //进行离散性判断
  1214.     lpTemp[i*lWidth+j] = DeleteScaterJudge(lpDIBBits,(WORD)lLineBytes,lplab,lWidth,lHeight,j,i,lab,length);
  1215. }
  1216. }
  1217. //扫描整个图像,把离散点填充成白色
  1218. //逐行扫描
  1219. for(i = 0;i<lHeight;i++)
  1220. {
  1221.       //逐列扫描
  1222. for(j=0;j<lWidth;j++)
  1223. {       
  1224.     //查看标志位,如果为非则将此点设为白点
  1225. if(lpTemp[i*lWidth+j] == false)
  1226. {
  1227.                    //指向第i行第j个象素的指针
  1228. lpSrc=(char*)lpDIBBits + lLineBytes * i + j;
  1229. //将此象素设为白点
  1230. *lpSrc=BYTE(255);
  1231. }
  1232. }
  1233. }
  1234. //解除锁定
  1235. ::GlobalUnlock ((HGLOBAL)hDIB);
  1236. }
  1237. /*********************************************************
  1238. * 函数名称:
  1239. *         SlopeAdjust()
  1240. *
  1241. * 参数:
  1242. *     HDIB   hDIB       -原图像的句柄
  1243. *
  1244. * 返回值:
  1245. *         无
  1246. *
  1247. * 功能:
  1248. *     通过对图像左右半边平均高度的统计来进行倾斜的调整
  1249. *
  1250. * 说明:
  1251. *      只能对2值图像进行处理
  1252. *
  1253. ****************************************************************/
  1254. void SlopeAdjust(HDIB hDIB)
  1255. {
  1256. // 指向DIB的指针
  1257. LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL)hDIB);
  1258. // 指向DIB象素指针
  1259. LPSTR    lpDIBBits;
  1260. // 找到DIB图像象素起始位置
  1261. lpDIBBits = ::FindDIBBits(lpDIB);
  1262. // 指向源图像的指针
  1263. unsigned char* lpSrc;
  1264. // 循环变量
  1265. LONG i;
  1266. LONG j;
  1267. // 图像每行的字节数
  1268. LONG lLineBytes;
  1269. //图像的长度
  1270. LONG    lWidth;
  1271. //图像的宽度
  1272. LONG lHeight;
  1273. //获取图像的长度
  1274. lWidth=::DIBWidth ((char*)lpDIB);
  1275. //获取图像的宽度
  1276. lHeight=::DIBHeight ((char*)lpDIB);
  1277. // 计算图像每行的字节数
  1278. lLineBytes = WIDTHBYTES(lWidth * 8);
  1279.     
  1280. //图像左半边的平均高度
  1281. double leftaver=0.0;
  1282.    //图像右半边的平均高度
  1283. double rightaver=0.0;
  1284. //图像的倾斜度
  1285. double slope;
  1286. //统计循环变量
  1287. LONG counts=0;
  1288. //扫描左半边的图像,求黑色象素的平均高度
  1289. //行
  1290. for (i=0;i<lHeight;i++)
  1291. {   
  1292.       //列
  1293. for (j=0;j<lWidth/2;j++)
  1294. {
  1295.  
  1296.  //指向第i行第j个象素的指针
  1297.  lpSrc=(unsigned char*)lpDIBBits + lLineBytes *  i + j;
  1298.       
  1299.  //如果为黑点
  1300.  if (*lpSrc == 0)
  1301.  {
  1302.           
  1303.           //对其高度进行统计叠加
  1304.   counts +=lWidth/2 -j;
  1305.   leftaver += i*(lWidth/2 -j);
  1306.  }
  1307. }
  1308. }
  1309.     //计算平均高度
  1310. leftaver /= counts;
  1311. //将统计循环变量重新赋值
  1312. counts =0;
  1313. //扫描右半边的图像,求黑色象素的平均高度
  1314. //行
  1315. for (i =0;i<lHeight;i++)
  1316. {
  1317.        //列
  1318. for (j=lWidth/2;j<lWidth;j++)
  1319. {
  1320. //指向第i行第j个象素的指针
  1321. lpSrc=(unsigned char*)lpDIBBits + lLineBytes *  i + j;
  1322.             //如果为黑点
  1323. if (*lpSrc == 0)
  1324. {
  1325.   //进行统计叠加
  1326. counts +=lWidth -j;
  1327. rightaver += i*(lWidth -j);
  1328. }
  1329. }
  1330. }
  1331. //计算右半边的平均高度
  1332. rightaver /= counts;
  1333. //计算斜率
  1334. slope = (leftaver - rightaver) / (lWidth/2);
  1335. //指向新的图像象素起始位置的指针
  1336. LPSTR lpNewDIBBits;
  1337.    
  1338. //指向新图像的指针
  1339. LPSTR lpDst;
  1340.     
  1341. //新图像的句柄
  1342. HLOCAL nNewDIBBits=LocalAlloc(LHND,lLineBytes*lHeight);
  1343.     
  1344. //锁定内存
  1345. lpNewDIBBits=(char*)LocalLock(nNewDIBBits);
  1346.     
  1347. //指向新图像象素的指针
  1348. lpDst=(char*)lpNewDIBBits;
  1349.     
  1350. //为新图像赋初始值
  1351. memset(lpDst,(BYTE)255,lLineBytes*lHeight);
  1352.     
  1353. //象素点的灰度值
  1354. int gray;
  1355.     
  1356. //位置映射值
  1357. int i_src;
  1358. //根据斜率,把当前新图像的点映射到源图像的点
  1359. //行
  1360. for (i=0;i<lHeight;i++)
  1361. {
  1362. //列
  1363.     for (j=0;j<lWidth;j++)
  1364. {
  1365.    //计算映射位置
  1366. i_src=int(i - (j-lWidth/2)*slope);
  1367. //如果点在图像外,象素置白色
  1368. if (i_src <0 || i_src >=lHeight )
  1369. gray = 255;
  1370. else
  1371. {
  1372. //否则到源图像中找点,取得象素值
  1373. //指向第i_src行第j个象素的指针
  1374. lpSrc=(unsigned char *)lpDIBBits + lLineBytes *  i_src + j;
  1375. gray = *lpSrc;
  1376. }
  1377. //把新图像的点用得到的象素值填充
  1378.             //指向第i行第j个象素的指针
  1379. lpDst = (char *)lpNewDIBBits + lLineBytes * i + j;
  1380. *lpDst=gray;
  1381. }
  1382. }
  1383. // 将新的图像的内容拷贝到旧的图像中
  1384. memcpy(lpDIBBits,lpNewDIBBits,lLineBytes*lHeight);
  1385.    // 解除锁定
  1386. ::GlobalUnlock ((HGLOBAL)hDIB);
  1387. }
  1388. /******************************************************************
  1389. *
  1390. *  函数名称:
  1391. *      StdDIBbyRect()
  1392. *
  1393. *  参数:
  1394. *     HDIB  hDIB          -图像的句柄
  1395. *     int   tarWidth      -标准化的宽度
  1396. *     int   tarHeight     -标准化的高度
  1397. *
  1398. *  返回值:
  1399. *         无
  1400. *
  1401. *  功能:
  1402. *     将经过分割的字符,进行缩放处理使他们的宽和高一直,以方便特征的提取
  1403. *
  1404. *  说明:
  1405. *     函数中用到了,每个字符的位置信息,所以必须在执行完分割操作之后才能执行标准化操作
  1406. *
  1407. ******************************************************************/
  1408. void StdDIBbyRect(HDIB hDIB, int tarWidth, int tarHeight)
  1409. {
  1410. //指向图像的指针
  1411. BYTE* lpDIB=(BYTE*)::GlobalLock ((HGLOBAL)hDIB);
  1412. //指向象素起始位置的指针
  1413. BYTE* lpDIBBits=(BYTE*)::FindDIBBits ((char*)lpDIB);
  1414. //指向象素的指针
  1415. BYTE* lpSrc;
  1416. //获取图像的的宽度
  1417. LONG lWidth=::DIBWidth ((char*)lpDIB);
  1418. //获取图像的高度
  1419. LONG lHeight=::DIBHeight ((char*)lpDIB);
  1420. // 循环变量
  1421. int i;
  1422. int j;
  1423. // 图像每行的字节数
  1424. LONG lLineBytes = WIDTHBYTES(lWidth * 8);
  1425. //宽度、高度方向上的缩放因子
  1426. double wscale,hscale;
  1427. //开辟一块临时缓存区,来存放变化后的图像信息
  1428. LPSTR lpNewDIBBits;
  1429. LPSTR lpDst;
  1430.  
  1431.     //缓存区的大小和原图像的数据区大小一样
  1432. HLOCAL nNewDIBBits=LocalAlloc(LHND,lLineBytes*lHeight);
  1433. //指向缓存区开始位置的指针
  1434. lpNewDIBBits=(char*)LocalLock(nNewDIBBits);
  1435. //指向缓存内信息的指针
  1436. lpDst=(char*)lpNewDIBBits;
  1437. //将缓存区的内容赋初始值
  1438. memset(lpDst,(BYTE)255,lLineBytes*lHeight);
  1439. //进行映射操作的坐标变量
  1440. int i_src,j_src;
  1441. //存放字符位置信息的结构体
  1442. CRect rect;
  1443. CRect rectnew;
  1444. //先清空一个新的矩形区域链表以便存储标准化后的矩形区域链表
  1445. m_charRectCopy.clear ();
  1446. //从头到尾逐个扫描各个结点
  1447. while(!m_charRect.empty())
  1448. {
  1449. //从表头上得到一个矩形
  1450. rect= m_charRect.front();
  1451. //从链表头上面删掉一个
  1452. m_charRect.pop_front();
  1453. //计算缩放因子
  1454. //横坐标方向的缩放因子
  1455. wscale=(double)tarWidth/rect.Width ();
  1456. //纵坐标方向的缩放因子
  1457. hscale=(double)tarHeight/rect.Height ();
  1458. //计算标准化矩形
  1459. //上边界
  1460. rectnew.top =rect.top ;
  1461. //下边界
  1462. rectnew.bottom =rect.top +tarHeight;
  1463. //左边界
  1464. rectnew.left =rect.left ;
  1465. //右边界
  1466. rectnew.right =rectnew.left +tarWidth;
  1467. //将原矩形框内的象素映射到新的矩形框内
  1468. for(i=rectnew.top ;i<rectnew.bottom ;i++)
  1469. {
  1470. for(j=rectnew.left ;j<rectnew.right ;j++)
  1471. {   
  1472. //计算映射坐标
  1473. i_src=rectnew.top +int((i-rectnew.top )/hscale);
  1474. j_src=rectnew.left +int((j-rectnew.left )/wscale);
  1475. //将相对应的象素点进行映射操作
  1476. lpSrc=(unsigned char *)lpDIBBits + lLineBytes *  i_src + j_src;
  1477. lpDst = (char *)lpNewDIBBits + lLineBytes * i + j;
  1478. *lpDst=*lpSrc;
  1479. }
  1480. }
  1481. //将标准化后的矩形区域插入新的链表
  1482. m_charRectCopy.push_back (rectnew);
  1483. }
  1484. //存储标准化后新的rect区域
  1485.     m_charRect=m_charRectCopy;
  1486. //将缓存区的内容拷贝到图像的数据区内
  1487. memcpy(lpDIBBits,lpNewDIBBits,lLineBytes*lHeight);
  1488. //解除锁定
  1489. ::GlobalUnlock ((HGLOBAL)hDIB);
  1490. }
  1491. void Thinning(HDIB hDIB)
  1492. {
  1493. // 指向DIB的指针
  1494. LPSTR lpDIB=(LPSTR) ::GlobalLock((HGLOBAL)hDIB);
  1495. // 指向DIB象素指针
  1496. LPSTR    lpDIBBits;
  1497. // 找到DIB图像象素起始位置
  1498. lpDIBBits = ::FindDIBBits(lpDIB);
  1499. // 指向源图像的指针
  1500. LPSTR lpSrc;
  1501. //图像的高度和宽度
  1502. LONG lWidth;
  1503. LONG lHeight;
  1504. //获取图像的宽度
  1505. lWidth=::DIBWidth ((char*)lpDIB);
  1506. //获取图像的高度
  1507. lHeight=::DIBHeight ((char*)lpDIB);
  1508.     //计算每行的字节数
  1509.     LONG  lLineBytes = (lWidth+3)*4/4;
  1510. //循环变量
  1511.     int i,j;
  1512.     //建立存储区存放2值矩阵
  1513. BYTE *image = (BYTE*)malloc(lWidth*lHeight*sizeof(BYTE));
  1514. //给2值矩阵赋值
  1515. for(i=0;i<lHeight;i++)
  1516. {
  1517.     for(j=0;j<lWidth;j++)
  1518. {
  1519.       lpSrc=lpDIBBits+i*lLineBytes+j;
  1520.     
  1521.       if(*lpSrc==0)
  1522.       image[i*lWidth+j]=1;
  1523.   else
  1524.          image[i*lWidth+j]=0;
  1525. }
  1526. }
  1527.    //调用函数进行细化,两种函数可以选择
  1528.    ThinnerRosenfeld(image,lHeight,lWidth);
  1529.    //ThinnerHilditch(image,lHeight,lWidth);
  1530.    //将结果赋值到原图像中
  1531.    for(i=0;i<lHeight;i++)
  1532.    {
  1533.      for(j=0;j<lWidth;j++)
  1534.  {
  1535.    lpSrc=lpDIBBits+i*lLineBytes+j;
  1536.        if(image[i*lWidth+j]==1)
  1537.    *lpSrc=(BYTE)0;
  1538.    else
  1539.        *lpSrc=(BYTE)255;
  1540.  }
  1541.    
  1542.    }
  1543.  //清空内存
  1544.    free(image);
  1545.    ::GlobalUnlock ((HGLOBAL)hDIB);
  1546. return;
  1547. }
  1548. /*****************************************************
  1549. *   函数名称:
  1550. *      Template:
  1551. *
  1552. *    参数:
  1553. *    HDIB    hDIB         -图像的句柄
  1554. *      double  *tem         -指向模板的指针
  1555. *      int  tem_w           -模板的宽度
  1556. *      int  tem_h           -模板的高度
  1557. *      double xishu         -模板的系数
  1558. *         
  1559. *    功能:
  1560. *    对图像进行模板操作
  1561. *
  1562. *    说明:
  1563. *    为处理方便起见,模板的宽度和高度都应为奇数
  1564. *******************************************************/
  1565.  HDIB Template(HDIB hDIB,double * tem ,int tem_w,int tem_h,double xishu)
  1566. {
  1567.     //统计中间值
  1568.     double sum;
  1569.     //指向图像起始位置的指针
  1570.     BYTE *lpDIB=(BYTE*)::GlobalLock((HGLOBAL) hDIB);
  1571. //指向象素起始位置的指针
  1572. BYTE *pScrBuff =(BYTE*)::FindDIBBits((char*)lpDIB);
  1573.    
  1574. //获取图像的颜色信息
  1575.     int numColors=(int) ::DIBNumColors((char *)lpDIB);
  1576.     //如果图像不是256色返回
  1577.      if (numColors!=256) 
  1578.  {   
  1579.         //解除锁定
  1580.    ::GlobalUnlock((HGLOBAL) hDIB);
  1581. //返回
  1582. return(hDIB);
  1583.  }
  1584.     
  1585.     //将指向图像象素起始位置的指针,赋值给指针变量
  1586.     BYTE* oldbuf = pScrBuff;
  1587.     //循环变量
  1588.     int i,j,m,n;
  1589. int w, h, dw;
  1590. //获取图像的宽度
  1591. w = (int) ::DIBWidth((char *)lpDIB);
  1592. //获取图像的高度
  1593. h = (int) ::DIBHeight((char *)lpDIB);
  1594. //计算图像每行的字节数
  1595. dw = (w+3)/4*4;      
  1596. //建立一个和原图像大小相同的25色灰度位图
  1597.     HDIB newhDIB=NewDIB(w,h,8);  
  1598.     
  1599. //指向新的位图的指针
  1600. BYTE *newlpDIB=(BYTE*)::GlobalLock((HGLOBAL) newhDIB);
  1601. //指向新的位图的象素起始位置的指针 
  1602.     BYTE *destBuf = (BYTE*)FindDIBBits((char *)newlpDIB);
  1603.     
  1604.    //将指向新图像象素起始位置的指针,赋值给指针变量
  1605.     BYTE *newbuf=destBuf; 
  1606. //对图像进行扫描
  1607.    
  1608. //行 
  1609.     for(i=0;i<h;i++)
  1610.     {  
  1611. //列
  1612.    for(j=0;j<w;j++)
  1613.    {   
  1614.    //为统计变量赋初始值
  1615.        sum=0;
  1616.          //对于图像的4个边框的象素保持原灰度不变
  1617.      if( j<((tem_w-1)/2) || j>(w-(tem_w+1)/2) || i<((tem_h-1)/2) || i>(h-(tem_h+1)/2) )
  1618.       *(newbuf+i*dw+j)=*(oldbuf+i*dw+j);
  1619.  
  1620.          //对于其他的象素进行模板操作
  1621.  else 
  1622.          { 
  1623.           //将点(i,j)点作为模板的中心
  1624.           for(m=i-((tem_h-1)/2);m<=i+((tem_h-1)/2);m++)
  1625.           {
  1626.      for(n=j-((tem_w-1)/2);n<=j+((tem_w-1)/2);n++)
  1627.     
  1628.              //将以点(i,j)为中心,与模板大小相同的范围内的象素与模板对用位置的系数
  1629.  //进行相乘并线形叠加
  1630.      sum+=*(oldbuf+m*dw+n)* tem[(m-i+((tem_h-1)/2))*tem_w+n-j+((tem_w-1)/2)];
  1631.   
  1632.   }
  1633.           
  1634.   //将结果乘上总的模板系数
  1635.           sum=(int)sum*xishu;
  1636.   //计算绝对值
  1637.   sum = fabs(sum);
  1638.   //如果小于0,强制赋值为0
  1639.           if(sum<0)     
  1640.           sum=0;
  1641.   //如果大于255,强制赋值为255
  1642.           if(sum>255)
  1643.   sum=255;
  1644.   //将计算的结果放到新的位图的相应位置
  1645.       *(newbuf+i*dw+j)=sum;
  1646.  }
  1647.    }
  1648.    
  1649. //解除锁定
  1650. ::GlobalUnlock((HGLOBAL)hDIB);
  1651.     
  1652. //返回新的位图的句柄
  1653.     return(newhDIB);
  1654. }
  1655. /*****************************************************
  1656. *   函数名称:
  1657. *      Template:
  1658. *
  1659. *    参数:
  1660. *    HDIB    hDIB         -图像的句柄
  1661. *      int  tem_w           -模板的宽度
  1662. *      int  tem_h           -模板的高度
  1663. *      
  1664. *    功能:
  1665. *    对图像进行中值
  1666. *
  1667. *    说明:
  1668. *    为处理方便起见,模板的宽度和高度都应为奇数
  1669. *******************************************************/
  1670. HDIB MidFilter(HDIB hDIB,int tem_w,int tem_h)
  1671. {
  1672.     //统计中间值
  1673.     double mid;
  1674. BYTE *temp=(BYTE*)malloc(tem_w*tem_h*sizeof(BYTE));
  1675.     //指向图像起始位置的指针
  1676.     BYTE *lpDIB=(BYTE*)::GlobalLock((HGLOBAL) hDIB);
  1677. //指向象素起始位置的指针
  1678. BYTE *pScrBuff =(BYTE*)::FindDIBBits((char*)lpDIB);
  1679.    
  1680. //获取图像的颜色信息
  1681.     int numColors=(int) ::DIBNumColors((char *)lpDIB);
  1682.     //如果图像不是256色返回
  1683.      if (numColors!=256) 
  1684.  {   
  1685.         //解除锁定
  1686.    ::GlobalUnlock((HGLOBAL) hDIB);
  1687. //返回
  1688. return(hDIB);
  1689.  }
  1690.     
  1691.     //将指向图像象素起始位置的指针,赋值给指针变量
  1692.     BYTE* oldbuf = pScrBuff;
  1693.     //循环变量
  1694.     int i,j,m,n;
  1695. int w, h, dw;
  1696. //获取图像的宽度
  1697. w = (int) ::DIBWidth((char *)lpDIB);
  1698. //获取图像的高度
  1699. h = (int) ::DIBHeight((char *)lpDIB);
  1700. //计算图像每行的字节数
  1701. dw = (w+3)/4*4;      
  1702. //建立一个和原图像大小相同的25色灰度位图
  1703.     HDIB newhDIB=NewDIB(w,h,8);  
  1704.     
  1705. //指向新的位图的指针
  1706. BYTE *newlpDIB=(BYTE*)::GlobalLock((HGLOBAL) newhDIB);
  1707. //指向新的位图的象素起始位置的指针 
  1708.     BYTE *destBuf = (BYTE*)FindDIBBits((char *)newlpDIB);
  1709.     
  1710.    //将指向新图像象素起始位置的指针,赋值给指针变量
  1711.     BYTE *newbuf=destBuf; 
  1712. //对图像进行扫描
  1713.    
  1714. //行 
  1715.     for(i=0;i<h;i++)
  1716.     {  
  1717. //列
  1718.    for(j=0;j<w;j++)
  1719.    {   
  1720.    //为统计变量赋初始值
  1721.        
  1722.          //对于图像的4个边框的象素保持原灰度不变
  1723.      if( j<((tem_w-1)/2) || j>(w-(tem_w+1)/2) || i<((tem_h-1)/2) || i>(h-(tem_h+1)/2) )
  1724.       *(newbuf+i*dw+j)=*(oldbuf+i*dw+j);
  1725.  
  1726.          //对于其他的象素进行模板操作
  1727.  else 
  1728.          { 
  1729.           //将点(i,j)点作为模板的中心
  1730.           for(m=i-((tem_h-1)/2);m<=i+((tem_h-1)/2);m++)
  1731.           {
  1732.      for(n=j-((tem_w-1)/2);n<=j+((tem_w-1)/2);n++)
  1733.     
  1734.              //将以点(i,j)为中心,与模板大小相同的范围内的象素传递到模板矩阵中
  1735.      temp[(m-i+((tem_h-1)/2))*tem_w+n-j+((tem_w-1)/2)]=*(oldbuf+m*dw+n);
  1736.   
  1737.   }
  1738.           
  1739.  //利用气泡法计算中值
  1740.            for(m=0;m<tem_w*tem_h-1;m++)
  1741.            {
  1742.    
  1743.       for(n=0;n<tem_w*tem_h-m-1;n++)
  1744.   {
  1745.     if(temp[n]>temp[n+1]) 
  1746.     mid=temp[n];
  1747.                 temp[n]=temp[n+1];
  1748.     temp[n+1]=mid;
  1749.   }
  1750.    
  1751.    } 
  1752.            //将计算的结果放到新的位图的相应位置
  1753.       *(newbuf+i*dw+j)=temp[(tem_w*tem_h-1)/2];
  1754.  }
  1755.    }
  1756.    
  1757. //解除锁定
  1758. ::GlobalUnlock((HGLOBAL)hDIB);
  1759.     
  1760. //返回新的位图的句柄
  1761.     return(newhDIB);
  1762. }
  1763. /*************************************************************************
  1764.  *
  1765.  * 函数名称:
  1766.  *   Equalize()
  1767.  *
  1768.  * 参数:
  1769.  *   HDIB hDIB
  1770.  *
  1771.  *
  1772.  * 说明:
  1773.  *   该函数用来对图像进行直方图均衡。
  1774.  *
  1775.  ************************************************************************/
  1776. void Equalize(HDIB hDIB)
  1777. {
  1778. BYTE* lpDIB=(BYTE*)::GlobalLock ((HGLOBAL)hDIB);
  1779. BYTE* lpDIBBits=(BYTE*)::FindDIBBits((char*)lpDIB);
  1780. LONG lHeight=::DIBHeight ((char*)lpDIB);
  1781. LONG lWidth=::DIBWidth ((char*)lpDIB);
  1782. // 指向源图像的指针
  1783. unsigned char* lpSrc;
  1784. // 临时变量
  1785. LONG lTemp;
  1786. // 循环变量
  1787. LONG i;
  1788. LONG j;
  1789. // 灰度映射表
  1790. BYTE bMap[256];
  1791. // 灰度映射表
  1792. LONG lCount[256];
  1793. // 图像每行的字节数
  1794. LONG lLineBytes;
  1795. // 计算图像每行的字节数
  1796. lLineBytes = WIDTHBYTES(lWidth * 8);
  1797. // 重置计数为0
  1798. for (i = 0; i < 256; i ++)
  1799. {
  1800. // 清零
  1801. lCount[i] = 0;
  1802. }
  1803. // 计算各个灰度值的计数
  1804. for (i = 0; i < lHeight; i ++)
  1805. {
  1806. for (j = 0; j < lWidth; j ++)
  1807. {
  1808. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
  1809. // 计数加1
  1810. lCount[*(lpSrc)]++;
  1811. }
  1812. }
  1813. // 计算灰度映射表
  1814. for (i = 0; i < 256; i++)
  1815. {
  1816. // 初始为0
  1817. lTemp = 0;
  1818. for (j = 0; j <= i ; j++)
  1819. {
  1820. lTemp += lCount[j];
  1821. }
  1822. // 计算对应的新灰度值
  1823. bMap[i] = (BYTE) (lTemp * 255 / lHeight / lWidth);
  1824. }
  1825. // 每行
  1826. for(i = 0; i < lHeight; i++)
  1827. {
  1828. // 每列
  1829. for(j = 0; j < lWidth; j++)
  1830. {
  1831. // 指向DIB第i行,第j个象素的指针
  1832. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  1833. // 计算新的灰度值
  1834. *lpSrc = bMap[*lpSrc];
  1835. }
  1836. }
  1837. ::GlobalUnlock ((HGLOBAL)hDIB);
  1838. }