Dib.cpp
上传用户:pass2008
上传日期:2021-07-05
资源大小:3299k
文件大小:18k
源码类别:

Internet/IE编程

开发平台:

Visual C++

  1. #include "StdAfx.h"
  2. #include "Dib.h"
  3. #include "math.h"
  4. CDib::CDib(void)
  5. {
  6. m_pDib = NULL;
  7. }
  8. CDib::~CDib(void)
  9. {
  10. // 如果位图已经被加载,释放内存
  11. if (m_pDib != NULL)
  12. {
  13. delete[] m_pDib;
  14. }
  15. }
  16. BOOL CDib::imageLoadOperation(LPCTSTR lpszPathName, UINT nOperatorSel)
  17. {
  18. CxImage xImage;
  19. int imgForm = analysisImageFormat(lpszPathName);
  20. switch (imgForm) //先进行格式统一处理,调用cxImage图像处理库
  21. {
  22. case IMG_FORMAT_BMP:
  23. xImage.Load(lpszPathName, CXIMAGE_FORMAT_BMP);
  24. break;
  25. case IMG_FORMAT_JPEG:
  26. xImage.Load(lpszPathName, CXIMAGE_FORMAT_JPG);
  27. break;
  28. case IMG_FORMAT_GIF:
  29. xImage.Load(lpszPathName, CXIMAGE_FORMAT_GIF);
  30. break;
  31. case IMG_FORMAT_PNG:
  32. xImage.Load(lpszPathName, CXIMAGE_FORMAT_PNG);
  33. break;
  34. case IMG_FORMAT_TIFF:
  35. xImage.Load(lpszPathName, CXIMAGE_FORMAT_TIF);
  36. break;
  37. default:
  38. return FALSE;
  39. }
  40. CString lpszNewPathName = alterFileExtension(lpszPathName, imgForm);
  41. xImage.Save(lpszNewPathName, CXIMAGE_FORMAT_BMP); //先保存为位图格式
  42. xImage.Load(lpszNewPathName, CXIMAGE_FORMAT_BMP);
  43. if (xImage.IsValid())
  44. {
  45. if (xImage.GetBpp()>8)
  46. {
  47. xImage.DecreaseBpp(8, true);
  48. }
  49. else if (xImage.GetBpp()<8)
  50. {
  51. xImage.IncreaseBpp(8);
  52. }
  53. xImage.GrayScale();  //转存为8位灰度位图
  54. if (!xImage.IsGrayScale()) 
  55. {
  56. return FALSE;
  57. }
  58. }
  59. else
  60. {
  61. return FALSE;
  62. }
  63. xImage.Save(lpszNewPathName, CXIMAGE_FORMAT_BMP);
  64. loadIntoMemory(lpszNewPathName); //载入内存,自己编写边缘算子函数进行处理
  65. imageEdgeOperation(nOperatorSel);
  66. saveAfterProcess(lpszNewPathName);
  67. xImage.Load(lpszNewPathName, CXIMAGE_FORMAT_BMP);
  68. switch (imgForm)
  69. {
  70. case IMG_FORMAT_BMP:
  71. break;
  72. case IMG_FORMAT_JPEG:
  73. xImage.Save(lpszPathName, CXIMAGE_FORMAT_JPG);
  74. ::DeleteFile(lpszNewPathName);
  75. break;
  76. case IMG_FORMAT_GIF:
  77. xImage.Save(lpszPathName, CXIMAGE_FORMAT_GIF);
  78. ::DeleteFile(lpszNewPathName);
  79. break;
  80. case IMG_FORMAT_PNG:
  81. xImage.Save(lpszPathName, CXIMAGE_FORMAT_PNG);
  82. ::DeleteFile(lpszNewPathName);
  83. break;
  84. case IMG_FORMAT_TIFF:
  85. xImage.Save(lpszPathName, CXIMAGE_FORMAT_TIF);
  86. ::DeleteFile(lpszNewPathName);
  87. break;
  88. }
  89. return TRUE;
  90. }
  91. CString CDib::alterFileExtension(LPCTSTR lpszPathName, int nImgFormat)
  92. {
  93. CString strImgForm(lpszPathName);
  94. int index;
  95. switch (nImgFormat)
  96. {
  97. case IMG_FORMAT_BMP:
  98. break;
  99. case IMG_FORMAT_JPEG:
  100. strImgForm.Replace(_T(".jpg"), _T(".bmp"));
  101. strImgForm.Replace(_T(".jpeg"), _T(".bmp"));
  102. strImgForm.Replace(_T(".JPG"), _T(".BMP"));
  103. strImgForm.Replace(_T(".JPEG"), _T(".BMP"));
  104. break;
  105. case IMG_FORMAT_GIF:
  106. strImgForm.Replace(_T(".gif"), _T(".bmp"));
  107. strImgForm.Replace(_T(".GIF"), _T(".BMP"));
  108. break;
  109. case IMG_FORMAT_PNG:
  110. strImgForm.Replace(_T(".png"), _T(".bmp"));
  111. strImgForm.Replace(_T(".PNG"), _T(".BMP"));
  112. break;
  113. case IMG_FORMAT_TIFF:
  114. strImgForm.Replace(_T(".tif"), _T(".bmp"));
  115. strImgForm.Replace(_T(".tiff"), _T(".bmp"));
  116. strImgForm.Replace(_T(".TIF"), _T(".BMP"));
  117. strImgForm.Replace(_T(".TIFF"), _T(".BMP"));
  118. break;
  119. }
  120. return strImgForm;
  121. }
  122. int CDib::analysisImageFormat(LPCTSTR lpszPathName)
  123. {
  124. CString strImgForm(lpszPathName);
  125. int index;
  126. index = (((strImgForm.Find(_T(".bmp"))!=-1) || (strImgForm.Find(_T(".BMP"))!=-1)) ? 0 : -1);
  127. //index = strImgForm.Find(".bmp");
  128. if (index > -1)
  129. {
  130. return IMG_FORMAT_BMP;
  131. }
  132. index = (((strImgForm.Find(_T(".gif"))!=-1) || (strImgForm.Find(_T(".GIF"))!=-1)) ? 0 : -1);
  133. //index = strImgForm.Find(".gif");
  134. if (index > -1)
  135. {
  136. return IMG_FORMAT_GIF;
  137. }
  138. index = (((strImgForm.Find(_T(".png"))!=-1) || (strImgForm.Find(_T(".PNG"))!=-1)) ? 0 : -1);
  139. //index = strImgForm.Find(".png");
  140. if (index > -1)
  141. {
  142. return IMG_FORMAT_PNG;
  143. }
  144. index = (((strImgForm.Find(_T(".jpg"))!=-1) || (strImgForm.Find(_T(".jpeg"))!=-1) || (strImgForm.Find(_T(".JPG"))!=-1) || (strImgForm.Find(_T(".JPEG"))!=-1)) ? 0 : -1);
  145. if (index > -1)
  146. {
  147. return IMG_FORMAT_JPEG;
  148. }
  149. index = (((strImgForm.Find(_T(".tif"))!=-1) || (strImgForm.Find(_T(".tiff"))!=-1) || (strImgForm.Find(_T(".TIF"))!=-1) || (strImgForm.Find(_T(".TIFF"))!=-1)) ? 0 : -1);
  150. if (index > -1)
  151. {
  152. return IMG_FORMAT_TIFF;
  153. }
  154. return IMG_FORMAT_DEFAULT;
  155. }
  156. BOOL CDib::loadIntoMemory(LPCTSTR lpszPathName)
  157. {
  158. CFile imgFile;
  159. // 打开位图文件
  160. if (!imgFile.Open(lpszPathName, CFile::modeReadWrite | CFile::shareExclusive))
  161. {
  162. return FALSE;
  163. }
  164. // 获得位图文件大小,并减去BITMAPFILEHEADER的长度
  165. DWORD dwDibSize;
  166. dwDibSize = imgFile.GetLength() - sizeof(BITMAPFILEHEADER);
  167. // 为DIB位图分配内存
  168. unsigned char* pDib;
  169. pDib = new unsigned char[dwDibSize];
  170. if (pDib == NULL)
  171. {
  172. return FALSE;
  173. }
  174. BITMAPFILEHEADER BFH;
  175. // 读取位图文件数据
  176. try
  177. {
  178. // 文件格式是否正确有效
  179. if (imgFile.Read(&BFH, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER) ||
  180. BFH.bfType != 'MB' || 
  181. imgFile.Read(pDib, dwDibSize) != dwDibSize)
  182. {
  183. delete[] pDib;
  184. return FALSE;
  185. }
  186. }
  187. catch (CFileException* e)
  188. {
  189. e->Delete();
  190. delete[] pDib;
  191. return FALSE;
  192. }
  193. // delete先前加载的位图
  194. if (m_pDib != NULL)
  195. {
  196. delete m_pDib;
  197. }
  198. // 将临时Dib数据指针和Dib大小变量赋给类成员变量
  199. m_pDib = pDib;
  200. m_dwDibSize = dwDibSize;
  201. // 为相应类成员变量赋BITMAPINFOHEADER和调色板指针
  202. m_pBIH = (BITMAPINFOHEADER*)m_pDib;
  203. m_pPalette = (RGBQUAD*)&m_pDib[sizeof(BITMAPINFOHEADER)];
  204. m_Width = m_pBIH->biWidth;
  205. m_Height = m_pBIH->biHeight;
  206. // 计算调色板中实际颜色数量
  207. m_nPaletteEntries = 1 << (m_pBIH->biBitCount);
  208. if (m_pBIH->biBitCount >8)
  209. {
  210. m_nPaletteEntries = 0;
  211. }
  212. else if (m_pBIH->biClrUsed != 0)
  213. {
  214. m_nPaletteEntries = m_pBIH->biClrUsed;
  215. }
  216. // 为相应类成员变量赋image data指针
  217. m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER) + m_nPaletteEntries * sizeof(RGBQUAD)];
  218. // delete先前的调色板
  219. if (m_Palette.GetSafeHandle() != NULL)
  220. {
  221. m_Palette.DeleteObject();
  222. }
  223. // 如果位图中存在调色板,创建LOGPALETTE 及CPalette
  224. if (m_nPaletteEntries != 0)
  225. {
  226. LOGPALETTE* pLogPal = (LOGPALETTE*)new char[sizeof(LOGPALETTE) + m_nPaletteEntries * sizeof(PALETTEENTRY)];
  227. if (pLogPal != NULL)
  228. {
  229. pLogPal->palVersion = 0x300;
  230. pLogPal->palNumEntries = m_nPaletteEntries;
  231. for (int i = 0; i < m_nPaletteEntries; i++)
  232. {
  233. pLogPal->palPalEntry[i].peRed = m_pPalette[i].rgbRed;
  234. pLogPal->palPalEntry[i].peGreen = m_pPalette[i].rgbGreen;
  235. pLogPal->palPalEntry[i].peBlue = m_pPalette[i].rgbBlue;
  236. }
  237. //创建CPalette并释放LOGPALETTE的内存
  238. m_Palette.CreatePalette(pLogPal);
  239. delete[] pLogPal;
  240. }
  241. }
  242. return TRUE;
  243. }
  244. BOOL CDib::imageEdgeOperation(UINT nOperatorSel)
  245. {
  246. switch (nOperatorSel)
  247. {
  248. case 0:
  249. LaplaceOperator();
  250. break;
  251. case 1:
  252. CannyOperator(0.1, 0.9, 0.3);
  253. break;
  254. default:
  255. break;
  256. }
  257. return TRUE;
  258. }
  259. BOOL CDib::LaplaceOperator(void)
  260. {
  261. unsigned char* lpSrc0, *lpSrc1, *lpSrc2, *lpSrc3, *lpSrc4, *lpSrc5, *lpSrc6, *lpSrc7, *lpSrc8;
  262. BYTE* p_temp = new BYTE[m_Height * m_Width];
  263. memset(p_temp, 255, m_Height * m_Width);
  264. for(int i=1; i<m_Height-1; i++)
  265. {
  266. for(int j=1; j<m_Width-1; j++)
  267. {
  268. lpSrc0 = m_pDibBits + i * m_Width + j;
  269. lpSrc1 = m_pDibBits + i * m_Width + j - 1;
  270. lpSrc2 = m_pDibBits + i * m_Width + j + 1;
  271. lpSrc3 = m_pDibBits + (i-1) * m_Width + j;
  272. lpSrc4 = m_pDibBits + (i+1) * m_Width + j;
  273. lpSrc5 = m_pDibBits + (i-1) * m_Width + j - 1;
  274. lpSrc6 = m_pDibBits + (i-1) * m_Width + j + 1;
  275. lpSrc7 = m_pDibBits + (i+1) * m_Width + j - 1;
  276. lpSrc8 = m_pDibBits + (i+1) * m_Width + j + 1;
  277. p_temp[i * m_Width + j] = abs(*lpSrc0 * 8 + *lpSrc1 * (-1) + *lpSrc2 * (-1) +
  278. *lpSrc3 * (-1) + *lpSrc4 * (-1) + *lpSrc5 * (-1) +
  279. *lpSrc6 * (-1) + *lpSrc7 * (-1) + *lpSrc8 * (-1));
  280. }
  281. }
  282. memcpy(m_pDibBits, p_temp, m_Height * m_Width);
  283. delete[] p_temp;
  284. return TRUE;
  285. }
  286. void CDib::CreatGauss(double sigma, double** pdKernel, int* pnWidowSize)
  287. {
  288. LONG i;
  289. // 数组中心点
  290. int nCenter;
  291. // 数组中一点到中心点距离
  292. double dDis;
  293. // 中间变量
  294. double dValue;
  295. double dSum;
  296. dSum = 0;
  297. // [-3*sigma,3*sigma] 以内数据,会覆盖绝大部分滤波系数
  298. *pnWidowSize = (int)(1+2*ceil(3*sigma));
  299. nCenter = (*pnWidowSize)/2;
  300. *pdKernel = new double[*pnWidowSize];
  301. //生成高斯数据
  302. for (i=0; i<(*pnWidowSize); i++)
  303. {
  304. dDis = double(i - nCenter);
  305. dValue = exp(-(1/2)*dDis*dDis/(sigma*sigma))/(sqrt(2*3.1415926)*sigma);
  306. (*pdKernel)[i] = dValue;
  307. dSum += dValue;
  308. }
  309. //归一化
  310. for (i=0; i<(*pnWidowSize); i++)
  311. {
  312. (*pdKernel)[i] /= dSum;
  313. }
  314. }
  315. void CDib::GaussianSmooth(unsigned char* pResult, double sigma)
  316. {
  317. LONG x, y;
  318. LONG i;
  319. int nWindowSize; // 高斯滤波器长度
  320. int nLen; // 窗口长度
  321. double* pdKernel; // 一维高斯滤波器
  322. double dDotMul; // 高斯系数与图像数据的点乘
  323. double dWeightSum; // 滤波系数总和
  324. double* pdTemp = new double[m_Height*m_Width];
  325. //产生一维高斯数据
  326. CreatGauss(sigma, &pdKernel, &nWindowSize);
  327. nLen = nWindowSize/2;
  328. for (y=0; y<m_Height; y++) // x方向滤波
  329. {
  330. for (x=0; x<m_Width; x++)
  331. {
  332. dDotMul = 0;
  333. dWeightSum = 0;
  334. for (i=(-nLen); i<=nLen; i++)
  335. {
  336. //判断是否在图像内部
  337. if ((i+x)>=0 && (i+x)<m_Width)
  338. {
  339. dDotMul += (double)(*(m_pDibBits+y*m_Width+(i+x))) * pdKernel[nLen+i];
  340. dWeightSum += pdKernel[nLen+i];
  341. }
  342. }
  343. pdTemp[y*m_Width+x] = dDotMul/dWeightSum;
  344. }
  345. }
  346. for (x=0; x<m_Width; x++) // y方向滤波
  347. {
  348. for (y=0; y<m_Height; y++)
  349. {
  350. dDotMul = 0;
  351. dWeightSum = 0;
  352. for (i=(-nLen); i<=nLen; i++)
  353. {
  354. if ((i+y)>=0 && (i+y)<m_Height)
  355. {
  356. dDotMul += (double)pdTemp[(y+i)*m_Width+x]*pdKernel[nLen+i];
  357. dWeightSum += pdKernel[nLen+i];
  358. }
  359. }
  360. pResult[y*m_Width+x] = (unsigned char)dDotMul/dWeightSum;
  361. }
  362. }
  363. delete[] pdKernel;
  364. pdKernel = NULL;
  365. delete[] pdTemp;
  366. pdTemp = NULL;
  367. }
  368. void CDib::Grad(unsigned char* pGray, int* pGradX, int* pGradY, int* pMag)
  369. {
  370. LONG y, x;
  371. for (y=1; y<m_Height-1; y++) // x方向的方向导数
  372. {
  373. for (x=1; x<m_Width-1; x++)
  374. {
  375. pGradX[y*m_Width + x] = (int)(pGray[y*m_Width+x+1] - pGray[y*m_Width+x-1]);
  376. }
  377. }
  378. for (x=1; x<m_Width-1; x++) // y方向方向导数
  379. {
  380. for (y=1; y<m_Height-1; y++)
  381. {
  382. pGradY[y*m_Width + x] = (int)(pGray[(y+1)*m_Width+x] - pGray[(y-1)*m_Width+x]);
  383. }
  384. }
  385. //求梯度
  386. double dSqt1, dSqt2; //中间变量
  387. for (y=0; y<m_Height; y++)
  388. {
  389. for (x=0; x<m_Width; x++)
  390. {
  391. //二阶范数求梯度
  392. dSqt1 = pGradX[y*m_Width + x]*pGradX[y*m_Width + x];
  393. dSqt2 = pGradY[y*m_Width + x]*pGradY[y*m_Width + x];
  394. pMag[y*m_Width + x] = (int)(sqrt(dSqt1+dSqt2)+0.5);
  395. }
  396. }
  397. }
  398. //非最大抑制
  399. void CDib::NonmaxSuppress(int* pMag, int* pGradX, int* pGradY, unsigned char* pNSRst)
  400. {
  401. LONG y,x;
  402. int nPos;
  403. int gx, gy; // 梯度分量
  404. //中间变量
  405. int g1, g2, g3, g4;
  406. double weight;
  407. double dTmp, dTmp1, dTmp2;
  408. //设置图像边缘为不可能的分界点
  409. for (x=0; x<m_Width; x++)
  410. {
  411. pNSRst[x] = 0;
  412. pNSRst[(m_Height-1)*m_Width+x] = 0;
  413. }
  414. for (y=0; y<m_Height; y++)
  415. {
  416. pNSRst[y*m_Width] = 0;
  417. pNSRst[y*m_Width + m_Width - 1] = 0;
  418. }
  419. for (y=1; y<m_Height-1; y++)
  420. {
  421. for (x=1; x<m_Width-1; x++)
  422. {
  423. nPos = y*m_Width + x; //当前点
  424. if (pMag[nPos] == 0) // 如果当前像素梯度幅度为0,则不是边界点
  425. {
  426. pNSRst[nPos] = 0;
  427. }
  428. else
  429. {
  430. dTmp = pMag[nPos]; // 当前点的梯度幅度
  431. //x,y方向导数
  432. gx = pGradX[nPos];
  433. gy = pGradY[nPos];
  434. if (abs(gy) > abs(gx)) //如果方向导数y分量比x分量大,说明导数方向趋向于y分量
  435. {
  436. weight = fabs((double)gx)/fabs((double)gy); // 计算插值比例
  437. g2 = pMag[nPos-m_Width];
  438. g4 = pMag[nPos+m_Width];
  439. //如果x,y两个方向导数的符号相同
  440. //C 为当前像素,与g1-g4 的位置关系为:
  441. //g1 g2
  442. //            C
  443. //             g4 g3
  444. if(gx*gy>0)
  445. {
  446. g1 = pMag[nPos-m_Width-1];
  447. g3 = pMag[nPos+m_Width+1];
  448. }
  449. //如果x,y两个方向的方向导数方向相反
  450. //C是当前像素,与g1-g4的关系为:
  451. //             g2 g1
  452. //              C
  453. //          g3 g4
  454. else
  455. {
  456. g1 = pMag[nPos-m_Width+1];
  457. g3 = pMag[nPos+m_Width-1];
  458. }
  459. }
  460. else // 如果方向导数x分量比y分量大,说明导数的方向趋向于x分量
  461. {
  462. weight = fabs((double)gy)/fabs((double)gx); // 插值比例
  463. g2 = pMag[nPos+1];
  464. g4 = pMag[nPos-1];
  465. //如果x,y两个方向的方向导数符号相同
  466. //当前像素C与 g1-g4的关系为
  467. //        g3
  468. //        g4 C g2
  469. //             g1
  470. if(gx * gy > 0)
  471. {
  472. g1 = pMag[nPos+m_Width+1];
  473. g3 = pMag[nPos-m_Width-1];
  474. }
  475. //如果x,y两个方向导数的方向相反
  476. // C与g1-g4的关系为
  477. //         g1
  478. //          g4 C g2
  479. //           g3
  480. else
  481. {
  482. g1 = pMag[nPos-m_Width+1];
  483. g3 = pMag[nPos+m_Width-1];
  484. }
  485. }
  486. //利用 g1-g4 对梯度进行插值
  487. {
  488. dTmp1 = weight*g1 + (1-weight)*g2;
  489. dTmp2 = weight*g3 + (1-weight)*g4;
  490. //当前像素的梯度是局部的最大值
  491. //该点可能是边界点
  492. if(dTmp>=dTmp1 && dTmp>=dTmp2)
  493. {
  494. pNSRst[nPos] = 128;
  495. }
  496. else
  497. {
  498. //不可能是边界点
  499. pNSRst[nPos] = 0;
  500. }
  501. }
  502. }
  503. }
  504. }
  505. }
  506. void CDib::EstimateThreshold(int* pMag, int* pThrHigh, int* pThrLow, unsigned char* pGray, double dRatHigh, double dRatLow)
  507. {
  508. LONG y, x, k;
  509. int nHist[256]; //该数组的大小和梯度值的范围有关,如果采用本程序的算法那么梯度的范围不会超过pow(2,10)
  510. int nEdgeNum; // 可能边界数
  511. int nMaxMag; // 最大梯度数
  512. int nHighCount;
  513. nMaxMag = 0;
  514. for (k=0; k<256; k++) // 初始化
  515. {
  516. nHist[k] = 0;
  517. }
  518. for (y=0; y<m_Height; y++) // 统计直方图,利用直方图计算阈值
  519. {
  520. for (x=0; x<m_Width; x++)
  521. {
  522. if (pGray[y*m_Width+x]==128)
  523. {
  524. nHist[pMag[y*m_Width+x]]++;
  525. }
  526. }
  527. }
  528. nEdgeNum = nHist[0];
  529. nMaxMag = 0;
  530. for (k=1; k<256; k++) //统计经过“非最大值抑制”后有多少像素
  531. {
  532. if (nHist[k] != 0)
  533. {
  534. nMaxMag = k;
  535. }
  536. //梯度为0的点是不可能为边界点的
  537. //经过non-maximum suppression后有多少像素
  538. nEdgeNum += nHist[k];
  539. }
  540. nHighCount = (int)(dRatHigh * nEdgeNum + 0.5); // 梯度比高阈值*pThrHigh 小的像素点总书目
  541. k=1;
  542. nEdgeNum = nHist[1];
  543. while ((k<(nMaxMag-1)) && (nEdgeNum<nHighCount)) //计算高阈值
  544. {
  545. k++;
  546. nEdgeNum += nHist[k];
  547. }
  548. *pThrHigh = k;
  549. *pThrLow = (int)((*pThrHigh) * dRatLow + 0.5); //低阈值
  550. }
  551. //利用函数寻找边界起点
  552. void CDib::Hysteresis(int* pMag, double dRatLow, double dRatHigh, unsigned char* pResult)
  553. {
  554. LONG y,x;
  555. int nThrHigh, nThrLow;
  556. int nPos;
  557. EstimateThreshold(pMag, &nThrHigh, &nThrLow, pResult, dRatHigh, dRatLow); //估计TraceEdge 函数需要的低阈值,以及Hysteresis函数使用的高阈值
  558. //寻找大于dThrHigh的点,这些点用来当作边界点,
  559. //然后用TraceEdge函数跟踪该点对应的边界
  560. for (y=0; y<m_Height; y++)
  561. {
  562. for (x=0; x<m_Width; x++)
  563. {
  564. nPos = y*m_Width + x;
  565. //如果该像素是可能的边界点,并且梯度大于高阈值,该像素作为一个边界的起点
  566. if ((pResult[nPos]==128) && (pMag[nPos]>=nThrHigh))
  567. {
  568. //设置该点为边界点
  569. pResult[nPos] = 255;
  570. TraceEdge(y, x, nThrLow, pResult, pMag);
  571. }
  572. }
  573. }
  574. //其他点已经不可能为边界点
  575. for (y=0; y<m_Height; y++)
  576. {
  577. for (x=0; x<m_Width; x++)
  578. {
  579. nPos = y*m_Width + x;
  580. if (pResult[nPos] != 255)
  581. {
  582. pResult[nPos] = 0;
  583. }
  584. }
  585. }
  586. }
  587. //根据Hysteresis 执行的结果,从一个像素点开始搜索,搜索以该像素点为边界起点的一条边界的
  588. //一条边界的所有边界点,函数采用了递归算法
  589. //             从(x,y)坐标出发,进行边界点的跟踪,跟踪只考虑pResult中没有处理并且可能是边界
  590. //        点的像素(=128),像素值为0表明该点不可能是边界点,像素值为255表明该点已经是边界点
  591. void CDib::TraceEdge(int y, int x, int nThrLow, unsigned char* pResult, int* pMag)
  592. {
  593. //对8邻域像素进行查询
  594. int xNum[8] = {1, 1, 0, -1, -1, -1, 0, 1};
  595. int yNum[8] = {0, 1, 1, 1, 0, -1, -1, -1};
  596. LONG yy, xx, k;
  597. for (k=0; k<8; k++)
  598. {
  599. yy = y+yNum[k];
  600. xx = x+xNum[k];
  601. if (pResult[yy*m_Width+xx]==128 && pMag[yy*m_Width+xx]>=nThrLow)
  602. {
  603. pResult[yy*m_Width+xx] = 255; // 该点设为边界点
  604. TraceEdge(yy, xx, nThrLow, pResult, pMag); // 以该点为中心再进行跟踪
  605. }
  606. }
  607. }
  608. // Canny算子
  609. BOOL CDib::CannyOperator(double sigma, double dRatLow, double dRatHigh)
  610. {
  611. unsigned char* pResult = new unsigned char[m_Height*m_Width];
  612. memset(pResult, 0, m_Height*m_Width);
  613. unsigned char* pGaussSmooth = new unsigned char[m_Height*m_Width]; // 经过高斯滤波后的图像
  614. memset(pGaussSmooth, 0, m_Height*m_Width);
  615. int* pGradX = new int[m_Height*m_Width]; // x方向导数的指针
  616. int* pGradY = new int[m_Height*m_Width]; // y方向
  617. int* pGradMag = new int[m_Height*m_Width]; // 梯度的幅度
  618. GaussianSmooth(pGaussSmooth, sigma); // 对原图高斯滤波
  619. Grad(pGaussSmooth, pGradX, pGradY, pGradMag); // 计算方向导数和梯度的幅度
  620. NonmaxSuppress(pGradMag, pGradX, pGradY, pResult); // 应用非最大抑制
  621. Hysteresis(pGradMag, dRatLow, dRatHigh, pResult); // 应用Hysteresis,找到所有边界
  622. delete[] pGradX;
  623. pGradX = NULL;
  624. delete[] pGradY;
  625. pGradY = NULL;
  626. delete[] pGradMag;
  627. pGradMag = NULL;
  628. delete[] pGaussSmooth;
  629. pGaussSmooth = NULL;
  630. memcpy(m_pDibBits, pResult, m_Height * m_Width);
  631. delete[] pResult;
  632. return TRUE;
  633. }
  634. BOOL CDib::saveAfterProcess(LPCTSTR lpszPathName)
  635. {
  636. if (m_pDib == NULL)
  637. {
  638. return FALSE;
  639. }
  640. CFile imgFile;
  641. if (!imgFile.Open(lpszPathName, CFile::modeCreate | CFile::modeWrite))
  642. {
  643. return FALSE;
  644. }
  645. try
  646. {
  647. BITMAPFILEHEADER BFH;
  648. memset(&BFH, 0, sizeof(BITMAPFILEHEADER));
  649. BFH.bfType = 'MB';
  650. BFH.bfSize = sizeof(BITMAPFILEHEADER) + m_dwDibSize;
  651. BFH.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + m_nPaletteEntries * sizeof(RGBQUAD);
  652. imgFile.Write(&BFH, sizeof(BITMAPFILEHEADER));
  653. imgFile.Write(m_pDib, m_dwDibSize);
  654. }
  655. catch (CFileException* e)
  656. {
  657. e->Delete();
  658. return FALSE;
  659. }
  660. return TRUE;
  661. }