ImageAnalysis.cpp
上传用户:xjt2008yy
上传日期:2010-01-18
资源大小:272k
文件大小:24k
源码类别:

生物技术

开发平台:

Visual C++

  1. #include "stdafx.h"
  2. #include "GlobalApi.h"
  3. #include "Cdib.h"
  4. #include <io.h>
  5. #include <errno.h>
  6. #include <math.h>
  7. #include <direct.h>
  8. /*************************************************************************
  9.  *
  10.  * 函数名称:
  11.  *   DIBHOLENUMBER()
  12.  *
  13.  * 参数:
  14.  *   CDib * pDib        - 指向CDib类的指针
  15.  *
  16.  * 返回值:
  17.  *   BOOL               - 成功返回True,否则返回False。
  18.  *
  19.  * 说明:
  20.  *   该函数将消去图象中面积小于阈值的小区域
  21.  *
  22.  *************************************************************************/
  23. BOOL DIBHOLENUMBER(CDib *pDib)
  24. {
  25. // 指向源图像的指针
  26. BYTE * lpSrc;
  27. //图象的宽度和高度
  28. LONG    lWidth;
  29. LONG    lHeight;
  30. // 图像每行的字节数
  31. LONG lLineBytes;
  32. //得到图象的宽度和高度
  33. CSize   SizeDim;
  34. SizeDim = pDib->GetDimensions();
  35. lWidth  = SizeDim.cx;
  36. lHeight = SizeDim.cy;
  37. //得到实际的Dib图象存储大小
  38. CSize   SizeRealDim;
  39. SizeRealDim = pDib->GetDibSaveDim();
  40. // 计算图像每行的字节数
  41. lLineBytes = SizeRealDim.cx;
  42. //图像数据的指针
  43. LPBYTE  lpDIBBits = pDib->m_lpImage;
  44. // 循环变量
  45. int i, j, s, n;
  46. // 空穴的数目以及面积阈值
  47. int nHoleNum, nMinArea;
  48. int nBlackPix, temp;
  49. // 正向和反响传播标志
  50. int nDir1,nDir2;
  51. // 用来存储的一位数组
  52. int *pnBinary;
  53. pnBinary =new int[lHeight*lLineBytes];
  54. // 小区域的阈值面积为20个象素点
  55. nMinArea = 50;
  56. // 将图象二值化
  57. for (j = 0; j < lHeight; j++)
  58. {
  59. for(i = 0; i < lWidth; i++)
  60. {
  61. // 指向源图像倒数第j行,第i个象素的指针
  62. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  63. // 白色象素为背景,存成0
  64. if(*lpSrc > 200)
  65. {
  66. pnBinary[lLineBytes * j + i] = 0;
  67. }
  68. // 黑象素存成-1
  69. else
  70. {
  71. pnBinary[lLineBytes * j + i] = -1;
  72. }
  73. }
  74. }
  75. // 空穴数赋初值
  76. nHoleNum = 1;
  77. do
  78. {
  79. s=0;
  80. // 寻找每个空穴的初始象素值 
  81. for (j = 1; j < lHeight - 1; j++)
  82. {
  83. for(i = 1; i < lWidth - 1; i++)
  84. {
  85. // 找到初始象素
  86. if(pnBinary[lLineBytes * j + i] == -1)
  87. {
  88. s = 1;
  89. // 将象素值改成当前的空穴数值
  90. pnBinary[lLineBytes * j + i] = nHoleNum;
  91. // 跳出循环
  92. j = lHeight;
  93. i = lLineBytes;
  94. }
  95. }
  96. }
  97. //没有初始象素,跳出循环
  98. if(s == 0)
  99. break;
  100. else
  101. {
  102. do
  103. {
  104. // 正向和反响传播系数赋初值0
  105. nDir1 = 0;
  106. nDir2 = 0;
  107. // 正向扫描
  108. for (j = 1; j < lHeight-1; j++)
  109. {
  110. for(i = 1; i < lWidth-1; i++)
  111. {
  112. nBlackPix = pnBinary[lLineBytes * j + i];
  113. // 如果象素已经被扫描,或者是背景色,进行下一个循环
  114. if(nBlackPix != -1)
  115. continue;
  116. // 如果上侧或者左侧的象素值已经被扫描,且属于当前的空穴,当前的象素值
  117. // 改成空穴的数值
  118. nBlackPix=pnBinary[lLineBytes * (j-1) + i];
  119. if(nBlackPix == nHoleNum)
  120. {
  121. pnBinary[lLineBytes * j + i] = nHoleNum;
  122. nDir1 = 1;
  123. continue;
  124. }
  125. nBlackPix =pnBinary[lLineBytes * j + i - 1];
  126. if(nBlackPix == nHoleNum)
  127. {
  128. pnBinary[lLineBytes * j + i] = nHoleNum;
  129. nDir1 = 1;
  130. }
  131. }
  132. }
  133. // 正向象素全部被扫描,跳出循环
  134. if(nDir1 == 0)
  135. break;
  136. // 反向扫描
  137. for (j = lHeight-2; j >= 1 ; j--)
  138. {
  139. for(i = lWidth-2; i >= 1 ; i--)
  140. {
  141. nBlackPix = pnBinary[lLineBytes * j + i];
  142. // 如果象素已经被扫描,或者是背景色,进行下一个循环
  143. if(nBlackPix != -1)
  144. continue;
  145. // 如果下侧或者右侧的象素值已经被扫描,且属于当前的空穴,当前的象素值
  146. // 改成空穴的数值
  147. nBlackPix=pnBinary[lLineBytes * (j+1) + i];
  148. if(nBlackPix == nHoleNum)
  149. {
  150. pnBinary[lLineBytes * j + i] = nHoleNum;
  151. nDir2 = 1;
  152. continue;
  153. }
  154. nBlackPix =pnBinary[lLineBytes * j + i + 1];
  155. if(nBlackPix == nHoleNum)
  156. {
  157. pnBinary[lLineBytes * j + i] = nHoleNum;
  158. nDir2 = 1;
  159. }
  160. }
  161. }
  162. if(nDir2 == 0)
  163. break;
  164. }
  165. while(1);
  166. }
  167. // 空穴数增加
  168. nHoleNum++;
  169. }
  170. while(1);
  171. nHoleNum -- ;
  172. // 寻找面积小于阈值的空穴区域
  173. for(n = 1; n <= nHoleNum; n++)
  174. {
  175. s = 0;
  176. for (j = 0; j < lHeight - 1; j++)
  177. {
  178. for(i = 0; i < lWidth - 1; i++)
  179. {
  180. nBlackPix =pnBinary[lLineBytes * j + i];
  181. if(nBlackPix == n)
  182. s++;
  183. // 如果区域面积已经大于阈值,跳出循环
  184. if(s > nMinArea)
  185. break;
  186. }
  187. if(s > nMinArea)
  188. break;
  189. }
  190. // 小于阈值的区域,赋以与背景一样的颜色,进行消去
  191. if(s <= nMinArea)
  192. {
  193. for (j = 0; j < lHeight - 1; j++)
  194. {
  195. for(i = 0; i < lWidth - 1; i++)
  196. {
  197. nBlackPix =pnBinary[lLineBytes * j + i + 1];
  198. if(nBlackPix == n)
  199. {
  200. pnBinary[lLineBytes * j + i + 1] = 0;
  201. }
  202. }
  203. }
  204. }
  205. }
  206. // 存储象素值,输出
  207. for(j = 0; j < lHeight; j++)
  208. {
  209. // 列
  210. for(i = 0; i < lWidth; i++)
  211. {
  212. // 二值图象
  213.     temp = pnBinary[j * lLineBytes + i] ;
  214. // 指向位图i行j列象素的指针
  215. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i;
  216. // 更新源图像
  217. if(temp != 0)
  218. * (lpSrc) = 0;
  219. else
  220. * (lpSrc) = 255;
  221. }
  222. }
  223. delete pnBinary;
  224. return true;
  225. }
  226. /*************************************************************************
  227.  *
  228.  * 函数名称:
  229.  *   DIBMOMENT()
  230.  *
  231.  * 参数:
  232.  *   CDib * pDib        - 指向CDib类的指针
  233.  *
  234.  * 返回值:
  235.  *   BOOL               - 成功返回True,否则返回False。
  236.  *
  237.  * 说明:
  238.  *   该函数计算图象的力矩。
  239.  *
  240.  *************************************************************************/
  241. BOOL DIBMOMENT(CDib *pDib)
  242. {
  243. // 指向源图像的指针
  244. BYTE * lpSrc;
  245. //图象的宽度和高度
  246. LONG    lWidth;
  247. LONG    lHeight;
  248. // 图像每行的字节数
  249. LONG lLineBytes;
  250. //得到图象的宽度和高度
  251. CSize   SizeDim;
  252. SizeDim = pDib->GetDimensions();
  253. lWidth  = SizeDim.cx;
  254. lHeight = SizeDim.cy;
  255. //得到实际的Dib图象存储大小
  256. CSize   SizeRealDim;
  257. SizeRealDim = pDib->GetDibSaveDim();
  258. // 计算图像每行的字节数
  259. lLineBytes = SizeRealDim.cx;
  260. //图像数据的指针
  261. LPBYTE  lpDIBBits = pDib->m_lpImage;
  262. // 图象的矩
  263. long nImageMoment;
  264. // 循环变量
  265. int i,j;
  266. int ip,jq;
  267. // 临时变量
  268. double temp;
  269. nImageMoment = 0;
  270. // 计算一阶矩
  271. ip = jq = 1;
  272. // 力矩的计算
  273. for (j = 0; j < lHeight; j++)
  274. {
  275. for(i = 0; i < lWidth; i++)
  276. {
  277. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  278. temp = pow((double)i,ip)*pow(double(j),jq);
  279. temp = temp * (*lpSrc);
  280. nImageMoment = nImageMoment + (int)temp;
  281. }
  282. }
  283. // 将结果进行输出
  284. CString CView;
  285. CView.Format("图象的力矩为:%d",nImageMoment);
  286. MessageBox(NULL,CView, "计算结果" , MB_ICONINFORMATION | MB_OK);
  287. return true;
  288. }
  289. /*************************************************************************
  290.  *
  291.  * 函数名称:
  292.  *   DIBBARYCENTERMOMENT()
  293.  *
  294.  * 参数:
  295.  *   CDib * pDib        - 指向CDib类的指针
  296.  *
  297.  * 返回值:
  298.  *   BOOL               - 成功返回True,否则返回False。
  299.  *
  300.  * 说明:
  301.  *   该函数计算图象的重心矩。
  302.  *
  303.  *************************************************************************/
  304. BOOL DIBBARYCENTERMOMENT(CDib *pDib)
  305. {
  306. // 指向源图像的指针
  307. BYTE * lpSrc;
  308. //图象的宽度和高度
  309. LONG    lWidth;
  310. LONG    lHeight;
  311. // 图像每行的字节数
  312. LONG lLineBytes;
  313. //得到图象的宽度和高度
  314. CSize   SizeDim;
  315. SizeDim = pDib->GetDimensions();
  316. lWidth  = SizeDim.cx;
  317. lHeight = SizeDim.cy;
  318. //得到实际的Dib图象存储大小
  319. CSize   SizeRealDim;
  320. SizeRealDim = pDib->GetDibSaveDim();
  321. // 计算图像每行的字节数
  322. lLineBytes = SizeRealDim.cx;
  323. //图像数据的指针
  324. LPBYTE  lpDIBBits = pDib->m_lpImage;
  325. // 图象象素值
  326. int  nPixelValue;
  327. // 图象重心矩
  328. long nBarycenterMoment;
  329. // 0次矩m00,x方向的一次矩m01和y方向的一次矩m10
  330. long m00, m10, m01;
  331. // 重心x,y坐标值
  332. int nBarycenterX,nBarycenterY;
  333. // 循环变量
  334. int i,j;
  335. // 临时变量
  336. double temp;
  337. // 赋初值为零
  338. m00 = 0;
  339. m01 = 0;
  340. m10 = 0;
  341. nBarycenterMoment = 0;
  342. // 求0次矩m00,x方向的一次矩m01和y方向的一次矩m10
  343. for (j = 0; j < lHeight; j++)
  344. {
  345. for(i = 0; i < lWidth; i++)
  346. {
  347. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  348. nPixelValue = *lpSrc;
  349. m00 = m00 + nPixelValue;
  350. temp = i * nPixelValue;
  351. m01  = m01 + temp;
  352. temp = j * nPixelValue;
  353. m10  = m10 + temp;
  354. }
  355. }
  356. // 重心x,y坐标值
  357. nBarycenterX = (int)(m01 / m00 + 0.5);
  358. nBarycenterY = (int)(m10 / m00 + 0.5);
  359. // 计算重心矩
  360. for (j = 0; j < lHeight; j++)
  361. {
  362. for(i = 0; i < lWidth; i++)
  363. {
  364. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  365. nPixelValue = *lpSrc;
  366. temp = (i - nBarycenterX) * (j - nBarycenterY);
  367. temp = temp * nPixelValue;
  368. nBarycenterMoment = nBarycenterMoment + (int)temp;
  369. }
  370. }
  371. // 将结果进行输出
  372. CString CView;
  373. CView.Format("图象的重心矩为(%d,%d),重心矩为%d"
  374. ,nBarycenterX,nBarycenterY,nBarycenterMoment);
  375. MessageBox(NULL,CView, "计算结果" , MB_ICONINFORMATION | MB_OK);
  376. return true;
  377. }
  378. /*************************************************************************
  379.  *
  380.  * 函数名称:
  381.  *   DIBSTREETDIS()
  382.  *
  383.  * 参数:
  384.  *   CDib * pDib        - 指向CDib类的指针
  385.  *
  386.  * 返回值:
  387.  *   BOOL               - 成功返回True,否则返回False。
  388.  *
  389.  * 说明:
  390.  *   该函数利用棋盘距离对图象进行变换。
  391.  *
  392.  *************************************************************************/
  393. BOOL DIBSTREETDIS(CDib *pDib)
  394. {
  395. // 指向源图像的指针
  396. BYTE * lpSrc;
  397. //图象的宽度和高度
  398. LONG    lWidth;
  399. LONG    lHeight;
  400. // 图像每行的字节数
  401. LONG lLineBytes;
  402. //得到图象的宽度和高度
  403. CSize   SizeDim;
  404. SizeDim = pDib->GetDimensions();
  405. lWidth  = SizeDim.cx;
  406. lHeight = SizeDim.cy;
  407. //得到实际的Dib图象存储大小
  408. CSize   SizeRealDim;
  409. SizeRealDim = pDib->GetDibSaveDim();
  410. // 计算图像每行的字节数
  411. lLineBytes = SizeRealDim.cx;
  412. //图像数据的指针
  413. LPBYTE  lpDIBBits = pDib->m_lpImage;
  414. // 循环和临时变量
  415. int i,j;
  416. int temp, s;
  417. // 存储象素值的数组
  418. int *pnBinary, *pnStore;
  419. int nImageValue;
  420. pnBinary = new int[lHeight*lLineBytes];
  421. pnStore  = new int[lHeight*lLineBytes];
  422. // 将图象二值化
  423. for (j = 0; j < lHeight; j++)
  424. {
  425. for(i = 0; i < lWidth; i++)
  426. {
  427. // 指向源图像倒数第j行,第i个象素的指针
  428. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  429. // 白色象素为背景,存成0
  430. if(*lpSrc > 200)
  431. {
  432. pnBinary[lLineBytes * j + i] = 0;
  433. pnStore [lLineBytes * j + i] = 0;
  434. }
  435. // 黑象素存成1
  436. else
  437. {
  438. pnBinary[lLineBytes * j + i] = 1;
  439. pnStore [lLineBytes * j + i] = 1;
  440. }
  441. }
  442. }
  443. s = 1;
  444. while(s == 1)
  445. {
  446. s = 0;
  447. // 进行距离的累加
  448. for (j = 1; j < lHeight - 1; j++)
  449. {
  450. for(i = 1; i < lWidth - 1; i++)
  451. {
  452. nImageValue = pnBinary[lLineBytes * j + i];
  453. // 如果是背景,进行下一个循环
  454. if(nImageValue == 0)
  455. continue;
  456. // 如果当前象素值和四周的值一样,象素值增加一
  457. if(nImageValue==pnBinary[lLineBytes * (j-1) + i] && nImageValue==pnBinary[lLineBytes * (j+1) + i])
  458. if(nImageValue==pnBinary[lLineBytes * j + i-1] && nImageValue==pnBinary[lLineBytes * j + i+1])
  459. {
  460. pnStore[lLineBytes * j + i]++;
  461. s=1;
  462. }
  463. }
  464. }
  465. // 在进行下一轮循环前将当前的结果储存
  466. for (j = 0; j < lHeight; j++)
  467. for(i = 1; i < lWidth; i++)
  468. pnBinary[lLineBytes * j + i] = pnStore[lLineBytes * j + i];
  469. }
  470. // 存储象素值,输出
  471. for(j = 0; j < lHeight; j++)
  472. {
  473. // 列
  474. for(i = 0; i < lWidth; i++)
  475. {
  476. // 骨架的象素值
  477.     temp = pnStore[j * lLineBytes + i] ;
  478. // 指向位图i行j列象素的指针
  479. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i;
  480. // 更新源图像
  481. * (lpSrc) = (BYTE)((25 - temp) * 10 + 5);
  482. }
  483. }
  484. delete pnStore;
  485. delete pnBinary;
  486. return true;
  487. }
  488. /*************************************************************************
  489.  *
  490.  * 函数名称:
  491.  *   DIBFREAMEWORK()
  492.  *
  493.  * 参数:
  494.  *   CDib * pDib        - 指向CDib类的指针
  495.  *
  496.  * 返回值:
  497.  *   BOOL               - 成功返回True,否则返回False。
  498.  *
  499.  * 说明:
  500.  *   该函数利用棋盘距离,生成图象的骨架。
  501.  *
  502.  *************************************************************************/
  503. BOOL DIBFREAMEWORK(CDib *pDib)
  504. {
  505. // 指向源图像的指针
  506. BYTE * lpSrc;
  507. //图象的宽度和高度
  508. LONG    lWidth;
  509. LONG    lHeight;
  510. // 图像每行的字节数
  511. LONG lLineBytes;
  512. //得到图象的宽度和高度
  513. CSize   SizeDim;
  514. SizeDim = pDib->GetDimensions();
  515. lWidth  = SizeDim.cx;
  516. lHeight = SizeDim.cy;
  517. //得到实际的Dib图象存储大小
  518. CSize   SizeRealDim;
  519. SizeRealDim = pDib->GetDibSaveDim();
  520. // 计算图像每行的字节数
  521. lLineBytes = SizeRealDim.cx;
  522. //图像数据的指针
  523. LPBYTE  lpDIBBits = pDib->m_lpImage;
  524. // 循环和临时变量
  525. int i,j;
  526. int temp, s;
  527. // 存储象素值的数组
  528. int *pnBinary, *pnStore;
  529. int nImageValue;
  530. pnBinary = new int[lHeight*lLineBytes];
  531. pnStore  = new int[lHeight*lLineBytes];
  532. // 将图象二值化
  533. for (j = 0; j < lHeight; j++)
  534. {
  535. for(i = 0; i < lWidth; i++)
  536. {
  537. // 指向源图像倒数第j行,第i个象素的指针
  538. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  539. // 白色象素为背景,存成0
  540. if(*lpSrc > 200)
  541. {
  542. pnBinary[lLineBytes * j + i] = 0;
  543. pnStore [lLineBytes * j + i] = 0;
  544. }
  545. // 黑象素存成1
  546. else
  547. {
  548. pnBinary[lLineBytes * j + i] = 1;
  549. pnStore [lLineBytes * j + i] = 1;
  550. }
  551. }
  552. }
  553. s = 1;
  554. while(s == 1)
  555. {
  556. s = 0;
  557. // 进行距离的累加
  558. for (j = 1; j < lHeight - 1; j++)
  559. {
  560. for(i = 1; i < lWidth - 1; i++)
  561. {
  562. nImageValue = pnBinary[lLineBytes * j + i];
  563. // 如果是背景,进行下一个循环
  564. if(nImageValue == 0)
  565. continue;
  566. // 如果当前象素值和四周的值一样,象素值增加一
  567. if(nImageValue==pnBinary[lLineBytes * (j-1) + i] && nImageValue==pnBinary[lLineBytes * (j+1) + i])
  568. if(nImageValue==pnBinary[lLineBytes * j + i-1] && nImageValue==pnBinary[lLineBytes * j + i+1])
  569. {
  570. pnStore[lLineBytes * j + i]++;
  571. s=1;
  572. }
  573. }
  574. }
  575. // 在进行下一轮循环前将当前的结果储存
  576. for (j = 0; j < lHeight; j++)
  577. for(i = 1; i < lWidth; i++)
  578. pnBinary[lLineBytes * j + i] = pnStore[lLineBytes * j + i];
  579. }
  580. for (j = 0; j < lHeight; j++)
  581. for(i = 0; i < lWidth; i++)
  582. pnStore[lLineBytes * j + i] = 0;
  583. // 如果当前的象素值比周围的都要高,做为骨架
  584. for (j = 1; j < lHeight - 1; j++)
  585. for(i = 1; i < lWidth - 1; i++)
  586. {
  587. nImageValue = pnBinary[lLineBytes * j + i] + 1;
  588. // 在四连通域进行比较
  589. if(nImageValue!=pnBinary[lLineBytes * (j-1) + i] && nImageValue!=pnBinary[lLineBytes * (j+1) + i])
  590. if(nImageValue!=pnBinary[lLineBytes * j + i-1] && nImageValue!=pnBinary[lLineBytes * j + i+1])
  591. pnStore[lLineBytes * j + i] = pnBinary[lLineBytes * j + i];
  592. }
  593. // 存储象素值,输出
  594. for(j = 0; j < lHeight; j++)
  595. {
  596. // 列
  597. for(i = 0; i < lWidth; i++)
  598. {
  599. // 骨架的象素值
  600.     temp = pnStore[j * lLineBytes + i] ;
  601. // 指向位图i行j列象素的指针
  602. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i;
  603. // 更新源图像,并将象素值进行变换,以便输出
  604. if(temp != 0)
  605. * (lpSrc) = temp;
  606. else
  607. * (lpSrc) = 255;
  608. }
  609. }
  610. delete pnStore;
  611. delete pnBinary;
  612. return true;
  613. }
  614. /*************************************************************************
  615.  *
  616.  * 函数名称:
  617.  *   DIBCHESSBOARDDISRESTORE()
  618.  *
  619.  * 参数:
  620.  *   CDib * pDib        - 指向CDib类的指针
  621.  *
  622.  * 返回值:
  623.  *   BOOL               - 成功返回True,否则返回False。
  624.  *
  625.  * 说明:
  626.  *   该函数利用骨架对原图象进行恢复。
  627.  *
  628.  *************************************************************************/
  629. BOOL DIBCHESSBOARDDISRESTORE(CDib *pDib)
  630. {
  631. // 指向源图像的指针
  632. BYTE * lpSrc;
  633. //图象的宽度和高度
  634. LONG    lWidth;
  635. LONG    lHeight;
  636. // 图像每行的字节数
  637. LONG lLineBytes;
  638. //得到图象的宽度和高度
  639. CSize   SizeDim;
  640. SizeDim = pDib->GetDimensions();
  641. lWidth  = SizeDim.cx;
  642. lHeight = SizeDim.cy;
  643. //得到实际的Dib图象存储大小
  644. CSize   SizeRealDim;
  645. SizeRealDim = pDib->GetDibSaveDim();
  646. // 计算图像每行的字节数
  647. lLineBytes = SizeRealDim.cx;
  648. //图像数据的指针
  649. LPBYTE  lpDIBBits = pDib->m_lpImage;
  650. // 循环变量
  651. int i, j, n, m;
  652. // 临时变量
  653. int temp, s;
  654. // 用来存放象素值的数组
  655. int *pnBinary, *pnStore;
  656. int nImageValue;
  657. pnBinary = new int[lHeight*lLineBytes];
  658. pnStore  = new int[lHeight*lLineBytes];
  659. // 数组赋值
  660. for (j = 0; j < lHeight; j++)
  661. {
  662. for(i = 0; i < lWidth; i++)
  663. {
  664. // 指向源图像倒数第j行,第i个象素的指针
  665. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  666. pnBinary[lLineBytes * j + i] = 0;
  667. if((*lpSrc) != 255)
  668. pnStore [lLineBytes * j + i] = (*lpSrc);
  669. else
  670. pnStore [lLineBytes * j + i] = 0;
  671. }
  672. }
  673. // 进行图象的恢复
  674. for (j = 1; j < lHeight - 1; j++)
  675. {
  676. for(i = 1; i < lWidth - 1; i++)
  677. {
  678. nImageValue = pnStore[lLineBytes * j + i];
  679. if(nImageValue == 0)
  680. continue;
  681. if(nImageValue == 1)
  682. {
  683. pnBinary[lLineBytes * j + i] = 1;
  684. continue;
  685. }
  686. // 如果象素值大于等于2,将以(2×nImageValue)+1的菱形范围的象素值赋1
  687. s = nImageValue;
  688. // 菱形的主轴
  689. for(m = -s; m <= s; m++)
  690. {
  691. pnBinary[lLineBytes * j + i + m] = 1;
  692. }
  693. // 菱形的上半部分
  694. for(n = -s; n < 0; n++)
  695. for(m = -s - n; m <=s + n; m++)
  696. pnBinary[lLineBytes * (j+n) + i+m] = 1;
  697. // 菱形的下半部分
  698. for(n = 1; n <= s; n++)
  699. for(m = -s + n; m <= s - n; m++)
  700. pnBinary[lLineBytes * (j+n) + i+m] = 1;
  701. }
  702. }
  703. // 存储象素值,输出
  704. for(j = 0; j < lHeight; j++)
  705. {
  706. // 列
  707. for(i = 0; i < lWidth; i++)
  708. {
  709. // 骨架的象素值
  710.     temp = pnBinary[j * lLineBytes + i] ;
  711. // 指向位图i行j列象素的指针
  712. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * j + i;
  713. // 更新源图像
  714. if(temp != 0)
  715. // 黑色象素输出
  716. * (lpSrc) = 0;
  717. else
  718. // 白色象素输出
  719. * (lpSrc) = 255;
  720. }
  721. }
  722. delete pnStore;
  723. delete pnBinary;
  724. return true;
  725. }
  726. /*************************************************************************
  727.  *
  728.  * 函数名称:
  729.  *   DIBOUTLINE()
  730.  *
  731.  * 参数:
  732.  *   CDib * pDib        - 指向CDib类的指针
  733.  *
  734.  * 返回值:
  735.  *   BOOL               - 成功返回True,否则返回False。
  736.  *
  737.  * 说明:
  738.  *   该函数对二值图象进行轮廓检出。
  739.  *
  740.  *************************************************************************
  741.  */
  742. BOOL DIBOUTLINE(CDib *pDib)
  743. {
  744. // 指向源图像的指针
  745. BYTE * lpSrc;
  746. //图象的宽度和高度
  747. LONG    lWidth;
  748. LONG    lHeight;
  749. // 图像每行的字节数
  750. LONG lLineBytes;
  751. //得到图象的宽度和高度
  752. CSize   SizeDim;
  753. SizeDim = pDib->GetDimensions();
  754. lWidth  = SizeDim.cx;
  755. lHeight = SizeDim.cy;
  756. //得到实际的Dib图象存储大小
  757. CSize   SizeRealDim;
  758. SizeRealDim = pDib->GetDibSaveDim();
  759. // 计算图像每行的字节数
  760. lLineBytes = SizeRealDim.cx;
  761. //图像数据的指针
  762. LPBYTE  lpDIBBits = pDib->m_lpImage;
  763. // 循环变量
  764. int i, j;
  765. int nPixelValue;
  766. int n1,n2,n3,n4,n5,n6,n7,n8;
  767. // 用来存放象素值的数组
  768. int *pnBinary;
  769. pnBinary = new int[lHeight*lLineBytes];
  770. // 将图象二值化
  771. for (j = 0; j < lHeight; j++)
  772. {
  773. for(i = 0; i < lWidth; i++)
  774. {
  775. // 指向源图像倒数第j行,第i个象素的指针
  776. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  777. // 白色象素为背景,存成0
  778. if(*lpSrc > 200)
  779. {
  780. pnBinary[lLineBytes * j + i] = 0;
  781. }
  782. // 黑象素存成1
  783. else
  784. {
  785. pnBinary[lLineBytes * j + i] = 1;
  786. }
  787. }
  788. }
  789. for (j = 1; j < lHeight - 1; j++)
  790. {
  791. for(i = 1; i < lWidth - 1; i++)
  792. {
  793. nPixelValue = pnBinary[lLineBytes * j + i];
  794. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  795. // 如果当前象素是白色,进入下一个循环
  796. if(nPixelValue == 0)
  797. {
  798. // 将相应的象素值改成零
  799. *lpSrc = 255;
  800. continue;
  801. }
  802. // 如果当前象素是黑色
  803. else
  804. {
  805. // 检查周边的8连通域
  806. n1 = pnBinary[lLineBytes * (j+1) + i + 1];
  807. n2 = pnBinary[lLineBytes * (j+1) + i - 1];
  808. n3 = pnBinary[lLineBytes * (j+1) + i];
  809. n4 = pnBinary[lLineBytes * (j-1)+ i + 1];
  810. n5 = pnBinary[lLineBytes * (j-1) + i - 1];
  811. n6 = pnBinary[lLineBytes * (j-1) + i];
  812. n7 = pnBinary[lLineBytes * j + i + 1];
  813. n8 = pnBinary[lLineBytes * j + i - 1];
  814. //如果相邻的八个点都是黑点
  815. if(n1&&n2&&n3&&n4&&n5&&n6&&n7&&n8 == 1)
  816. {
  817. *lpSrc = (unsigned char)255;
  818. }
  819. }
  820. }
  821. }
  822. delete pnBinary;
  823. // 返回
  824. return TRUE;
  825. }
  826. /*************************************************************************
  827.  *
  828.  * 函数名称:
  829.  *   DIBTrace()
  830.  *
  831.  * 参数:
  832.  *   CDib * pDib        - 指向CDib类的指针
  833.  *
  834.  * 返回值:
  835.  *   BOOL               - 成功返回True,否则返回False。
  836.  *
  837.  * 说明:
  838.  * 该函数用于对图像进行轮廓跟踪运算。
  839.  *
  840.  *************************************************************************
  841.  */
  842. BOOL WINAPI DIBTrace(CDib *pDib)
  843. {
  844. // 指向源图像的指针
  845. BYTE * lpSrc;
  846. //图象的宽度和高度
  847. LONG    lWidth;
  848. LONG    lHeight;
  849. // 图像每行的字节数
  850. LONG lLineBytes;
  851. //得到图象的宽度和高度
  852. CSize   SizeDim;
  853. SizeDim = pDib->GetDimensions();
  854. lWidth  = SizeDim.cx;
  855. lHeight = SizeDim.cy;
  856. //得到实际的Dib图象存储大小
  857. CSize   SizeRealDim;
  858. SizeRealDim = pDib->GetDibSaveDim();
  859. // 计算图像每行的字节数
  860. lLineBytes = SizeRealDim.cx;
  861. //图像数据的指针
  862. LPBYTE  lpDIBBits = pDib->m_lpImage;
  863. //循环变量
  864. long i;
  865. long j;
  866. //像素值
  867. int nPixelValue;
  868. //是否找到起始点及回到起始点
  869. bool bFindStartPoint;
  870. //是否扫描到一个边界点
  871. bool bFindPoint;
  872. // 用来边界起点和所有边界点的数组
  873. int nStartPointX, nStartPointY;
  874. int *nCurrPointX, *nCurrPointY;
  875. // 边界点的数目
  876. long lNum;
  877. // 用来存储二值象素的数组
  878. int *pnBinary;
  879. //八个方向和起始扫描方向
  880. int Direction[8][2]={{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0}};
  881. int BeginDirect;
  882. // 分配内存
  883. pnBinary =new int[lLineBytes*lHeight];
  884. nCurrPointX = new int[lLineBytes*lHeight/4];
  885. nCurrPointY = new int[lLineBytes*lHeight/4];
  886. // 将图象二值化
  887. for (j = 0; j < lHeight; j++)
  888. {
  889. for(i = 0; i < lWidth; i++)
  890. {
  891. // 指向源图像倒数第j行,第i个象素的指针
  892. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * j + i;
  893. // 白色象素为背景,存成0
  894. if(*lpSrc > 200)
  895. {
  896. pnBinary[lLineBytes * j + i] = 0;
  897. }
  898. // 黑象素存成1
  899. else
  900. {
  901. pnBinary[lLineBytes * j + i] = 1;
  902. }
  903. // 将已经扫描过的象素存成白色背景
  904. *lpSrc = 255;
  905. }
  906. }
  907. //先找到最左上方的边界点
  908. bFindStartPoint = false;
  909. for (j = 0; j < lHeight; j++)
  910. {
  911. for(i = 0;i < lWidth ;i++)
  912. {
  913. nPixelValue = pnBinary[lLineBytes * j + i];
  914. if(nPixelValue == 1)
  915. {
  916. bFindStartPoint = true;
  917. // 储存边界起始点
  918. nStartPointY = j;
  919. nStartPointX  = i;
  920. // 跳出循环
  921. j = lHeight;
  922. i = lLineBytes ;
  923. }
  924. }
  925. }
  926. // 没有起始点,跳出
  927. if(bFindStartPoint == false)
  928. return false;
  929. //由于起始点是在左上方,起始扫描沿右侧方向
  930. BeginDirect = 0;
  931. //跟踪边界
  932. bFindStartPoint = false;
  933. //从初始点开始扫描
  934. lNum = 0;
  935. nCurrPointY[0] = nStartPointY;
  936. nCurrPointX[0] = nStartPointX;
  937. while(!bFindStartPoint)
  938. {
  939. bFindPoint = false;
  940. while(!bFindPoint)
  941. {
  942. nPixelValue = pnBinary[(nCurrPointY[lNum] + Direction[BeginDirect][1])*lLineBytes
  943. + nCurrPointX[lNum] + Direction[BeginDirect][0]];
  944. // 找到下一个边界点
  945. if(nPixelValue == 1)
  946. {
  947. bFindPoint = true;
  948. // 位置存储
  949. nCurrPointY[lNum+1] = nCurrPointY[lNum] + Direction[BeginDirect][1];
  950. nCurrPointX[lNum+1] = nCurrPointX[lNum] + Direction[BeginDirect][0];
  951. lNum ++;
  952. if(nCurrPointY[lNum] == nStartPointY && nCurrPointX[lNum] == nStartPointX)
  953. {
  954. bFindStartPoint = true;
  955. }
  956. //扫描的方向逆时针旋转两格
  957. BeginDirect--;
  958. if(BeginDirect == -1)
  959. BeginDirect = 7;
  960. BeginDirect--;
  961. if(BeginDirect == -1)
  962. BeginDirect = 7;
  963. }
  964. else
  965. {
  966. //扫描方向顺时针旋转一格
  967. BeginDirect++;
  968. if(BeginDirect == 8)
  969. BeginDirect = 0;
  970. }
  971. }
  972. }
  973. // 存储显示边界点
  974. for(i = 0; i <= lNum; i++)
  975. {
  976. lpSrc  = (unsigned char *)lpDIBBits + nCurrPointY[i] *lLineBytes  + nCurrPointX[i];
  977. *lpSrc = 0;
  978. }
  979. delete pnBinary;
  980. // 返回
  981. return TRUE;
  982. }