FreTrans.cpp
上传用户:panpan8800
上传日期:2013-06-29
资源大小:274k
文件大小:34k
源码类别:

图形图像处理

开发平台:

Visual C++

  1. #include "stdafx.h"
  2. #include "GlobalApi.h"
  3. #include "Cdib.h"
  4. #include <math.h>
  5. #include <direct.h>
  6. #include <complex>
  7. using namespace std;
  8. // FOURBYTES就是用来计算离4最近的整倍数
  9. #define FOURBYTES(bits)    (((bits) + 31) / 32 * 4)
  10. /**************************************************************************
  11.  *  文件名:FreTrans.cpp
  12.  *
  13.  *  正交变换API函数库:
  14.  *
  15.  *  THREECROSS() - 将实对称矩阵化作三对角矩阵
  16.  *  BSTQ()     - 求三对角对称矩阵的特征值和特征向量
  17.  *  FFT_1D() - 快速一维傅立叶变换
  18.  *  IFFT_1D() - 快速一维傅立叶反变换
  19.  *  IFFT_2D() - 快速二维傅立叶反变换
  20.  *  DCT() - 离散余弦变换
  21.  * IDCT() - 离散余弦反变换
  22.  *  WALSH() - 沃尔什-哈达玛变换
  23.  *  IWALSH() - 沃尔什-哈达玛反变换
  24.  *
  25.  *
  26.  *  DIBFFT_2D() - 图象的二维离散傅立叶快速变换
  27.  *  DIBDFT_2D() - 图象的二维离散傅立叶变换
  28.  *  DIBHOTELLING() - 图象的霍特林变换
  29.  *  DIBDct() - 图像的离散余弦变换
  30.  *  DIBWalsh() - 图像的沃尔什-哈达玛变换
  31.  *
  32.  ************************************************************************
  33. */
  34.  
  35. /*************************************************************************
  36.  *
  37.  * 函数名称:
  38.  *   FFT_1D()
  39.  *
  40.  * 输入参数:
  41.  *   complex<double> * pCTData - 指向时域数据的指针,输入的需要变换的数据
  42.  *   complex<double> * pCFData - 指向频域数据的指针,输出的经过变换的数据
  43.  *   nLevel -傅立叶变换蝶形算法的级数,2的幂数,
  44.  *
  45.  * 返回值:
  46.  *   无
  47.  *
  48.  * 说明:
  49.  *   一维快速傅立叶变换。
  50.  *
  51.  *************************************************************************
  52.  */
  53. VOID WINAPI FFT_1D(complex<double> * pCTData, complex<double> * pCFData, int nLevel)
  54. {
  55. // 循环控制变量
  56. int i;
  57. int     j;
  58. int     k;
  59. double PI = 3.1415926; 
  60. // 傅立叶变换点数
  61. int nCount =0 ;
  62. // 计算傅立叶变换点数
  63. nCount =(int)pow(2,nLevel) ;
  64. // 某一级的长度
  65. int nBtFlyLen;
  66. nBtFlyLen = 0 ;
  67. // 变换系数的角度 =2 * PI * i / nCount
  68. double dAngle;
  69. complex<double> *pCW ;
  70. // 分配内存,存储傅立叶变化需要的系数表
  71. pCW  = new complex<double>[nCount / 2];
  72.     // 计算傅立叶变换的系数
  73. for(i = 0; i < nCount / 2; i++)
  74. {
  75. dAngle = -2 * PI * i / nCount;
  76. pCW[i] = complex<double> ( cos(dAngle), sin(dAngle) );
  77. }
  78. // 变换需要的工作空间
  79. complex<double> *pCWork1,*pCWork2; 
  80. // 分配工作空间
  81. pCWork1 = new complex<double>[nCount];
  82. pCWork2 = new complex<double>[nCount];
  83. // 临时变量
  84. complex<double> *pCTmp;
  85. // 初始化,写入数据
  86. memcpy(pCWork1, pCTData, sizeof(complex<double>) * nCount);
  87. // 临时变量
  88. int nInter; 
  89. nInter = 0;
  90. // 蝶形算法进行快速傅立叶变换
  91. for(k = 0; k < nLevel; k++)
  92. {
  93. for(j = 0; j < (int)pow(2,k); j++)
  94. {
  95. //计算长度
  96. nBtFlyLen = (int)pow( 2,(nLevel-k) );
  97. //倒序重排,加权计算
  98. for(i = 0; i < nBtFlyLen/2; i++)
  99. {
  100. nInter = j * nBtFlyLen;
  101. pCWork2[i + nInter] = 
  102. pCWork1[i + nInter] + pCWork1[i + nInter + nBtFlyLen / 2];
  103. pCWork2[i + nInter + nBtFlyLen / 2] =
  104. (pCWork1[i + nInter] - pCWork1[i + nInter + nBtFlyLen / 2]) 
  105. * pCW[(int)(i * pow(2,k))];
  106. }
  107. }
  108. // 交换 pCWork1和pCWork2的数据
  109. pCTmp   = pCWork1 ;
  110. pCWork1 = pCWork2 ;
  111. pCWork2 = pCTmp ;
  112. }
  113. // 重新排序
  114. for(j = 0; j < nCount; j++)
  115. {
  116. nInter = 0;
  117. for(i = 0; i < nLevel; i++)
  118. {
  119. if ( j&(1<<i) )
  120. {
  121. nInter += 1<<(nLevel-i-1);
  122. }
  123. }
  124. pCFData[j]=pCWork1[nInter];
  125. }
  126. // 释放内存空间
  127. delete pCW;
  128. delete pCWork1;
  129. delete pCWork2;
  130. pCW = NULL ;
  131. pCWork1 = NULL ;
  132. pCWork2 = NULL ;
  133. }
  134. /*************************************************************************
  135.  *
  136.  * 函数名称:
  137.  *    IFFT_1D()
  138.  *
  139.  * 输入参数:
  140.  *   complex<double> * pCTData - 指向时域数据的指针,输入的需要反变换的数据
  141.  *   complex<double> * pCFData - 指向频域数据的指针,输出的经过反变换的数据
  142.  *   nLevel -傅立叶变换蝶形算法的级数,2的幂数,
  143.  *
  144.  * 返回值:
  145.  *   无
  146.  *
  147.  * 说明:
  148.  *   一维快速傅立叶反变换。
  149.  *
  150.  ************************************************************************
  151.  */
  152. VOID WINAPI IFFT_1D(complex<double> * pCFData, complex<double> * pCTData, int nLevel)
  153. {
  154. // 循环控制变量
  155. int i;
  156. // 傅立叶反变换点数
  157. int nCount;
  158. // 计算傅立叶变换点数
  159. nCount = (int)pow(2,nLevel) ;
  160. // 变换需要的工作空间
  161. complex<double> *pCWork;
  162. // 分配工作空间
  163. pCWork = new complex<double>[nCount];
  164. // 将需要反变换的数据写入工作空间pCWork
  165. memcpy(pCWork, pCFData, sizeof(complex<double>) * nCount);
  166. // 为了利用傅立叶正变换,可以把傅立叶频域的数据取共轭
  167. // 然后直接利用正变换,输出结果就是傅立叶反变换结果的共轭
  168. for(i = 0; i < nCount; i++)
  169. {
  170. pCWork[i] = complex<double> (pCWork[i].real(), -pCWork[i].imag());
  171. }
  172. // 调用快速傅立叶变换实现反变换,结果存储在pCTData中
  173. FFT_1D(pCWork, pCTData, nLevel);
  174. // 求时域点的共轭,求得最终结果
  175. // 根据傅立叶变换原理,利用这样的方法求得的结果和实际的时域数据
  176. // 相差一个系数nCount
  177. for(i = 0; i < nCount; i++)
  178. {
  179. pCTData[i] = 
  180. complex<double> (pCTData[i].real() / nCount, -pCTData[i].imag() / nCount);
  181. }
  182. // 释放内存
  183. delete pCWork;
  184. pCWork = NULL;
  185. }
  186. /*************************************************************************
  187.  *
  188.  * 函数名称:
  189.  *   FFT_2D()
  190.  *
  191.  * 输入参数:
  192.  *   complex<double> * pCTData - 图像数据
  193.  *   int    nWidth - 数据宽度
  194.  *   int    nHeight - 数据高度
  195.  *   complex<double> * pCFData - 傅立叶变换后的结果
  196.  *
  197.  * 返回值:
  198.  *   无
  199.  *
  200.  * 说明:
  201.  *   二维傅立叶变换。
  202.  *
  203.  ************************************************************************
  204.  */
  205. VOID WINAPI DIBFFT_2D(complex<double> * pCTData, int nWidth, int nHeight, complex<double> * pCFData)
  206. {
  207. // 循环控制变量
  208. int x;
  209. int y;
  210. // 临时变量
  211. double dTmpOne;
  212. double  dTmpTwo;
  213. // 进行傅立叶变换的宽度和高度,(2的整数次幂)
  214. // 图像的宽度和高度不一定为2的整数次幂
  215. int nTransWidth;
  216. int  nTransHeight;
  217. // 计算进行傅立叶变换的宽度 (2的整数次幂)
  218. dTmpOne = log(nWidth)/log(2);
  219. dTmpTwo = ceil(dTmpOne)    ;
  220. dTmpTwo = pow(2,dTmpTwo)    ;
  221. nTransWidth = (int) dTmpTwo    ;
  222. // 计算进行傅立叶变换的高度 (2的整数次幂)
  223. dTmpOne = log(nHeight)/log(2);
  224. dTmpTwo = ceil(dTmpOne)    ;
  225. dTmpTwo = pow(2,dTmpTwo)    ;
  226. nTransHeight = (int) dTmpTwo    ;
  227. // x,y(行列)方向上的迭代次数
  228. int nXLev;
  229. int nYLev;
  230. // 计算x,y(行列)方向上的迭代次数
  231. nXLev = (int) ( log(nTransWidth)/log(2) +  0.5 );
  232. nYLev = (int) ( log(nTransHeight)/log(2) + 0.5 );
  233. for(y = 0; y < nTransHeight; y++)
  234. {
  235. // x方向进行快速傅立叶变换
  236. FFT_1D(&pCTData[nTransWidth * y], &pCFData[nTransWidth * y], nXLev);
  237. }
  238. // pCFData中目前存储了pCTData经过行变换的结果
  239. // 为了直接利用FFT_1D,需要把pCFData的二维数据转置,再一次利用FFT_1D进行
  240. // 傅立叶行变换(实际上相当于对列进行傅立叶变换)
  241. for(y = 0; y < nTransHeight; y++)
  242. {
  243. for(x = 0; x < nTransWidth; x++)
  244. {
  245. pCTData[nTransHeight * x + y] = pCFData[nTransWidth * y + x];
  246. }
  247. }
  248. for(x = 0; x < nTransWidth; x++)
  249. {
  250. // 对x方向进行快速傅立叶变换,实际上相当于对原来的图象数据进行列方向的
  251. // 傅立叶变换
  252. FFT_1D(&pCTData[x * nTransHeight], &pCFData[x * nTransHeight], nYLev);
  253. }
  254. // pCFData中目前存储了pCTData经过二维傅立叶变换的结果,但是为了方便列方向
  255. // 的傅立叶变换,对其进行了转置,现在把结果转置回来
  256. for(y = 0; y < nTransHeight; y++)
  257. {
  258. for(x = 0; x < nTransWidth; x++)
  259. {
  260. pCTData[nTransWidth * y + x] = pCFData[nTransHeight * x + y];
  261. }
  262. }
  263. memcpy(pCTData, pCFData, sizeof(complex<double>) * nTransHeight * nTransWidth );
  264. }
  265. /*************************************************************************
  266.  *
  267.  * 函数名称:
  268.  *   IFFT_2D()
  269.  *
  270.  * 输入参数:
  271.  *   complex<double> * pCFData - 频域数据
  272.  *   complex<double> * pCTData - 时域数据
  273.  *   int    nWidth - 图像数据宽度
  274.  *   int    nHeight - 图像数据高度
  275.  *
  276.  * 返回值:
  277.  *   无
  278.  *
  279.  * 说明:
  280.  *   二维傅立叶反变换。
  281.  *
  282.  ************************************************************************
  283.  */
  284. VOID WINAPI IFFT_2D(complex<double> * pCFData, complex<double> * pCTData, int nWidth, int nHeight)
  285. {
  286. // 循环控制变量
  287. int x;
  288. int y;
  289. // 临时变量
  290. double dTmpOne;
  291. double  dTmpTwo;
  292. // 进行傅立叶变换的宽度和高度,(2的整数次幂)
  293. // 图像的宽度和高度不一定为2的整数次幂
  294. int nTransWidth;
  295. int  nTransHeight;
  296. // 计算进行傅立叶变换的宽度 (2的整数次幂)
  297. dTmpOne = log(nWidth)/log(2);
  298. dTmpTwo = ceil(dTmpOne)    ;
  299. dTmpTwo = pow(2,dTmpTwo)    ;
  300. nTransWidth = (int) dTmpTwo    ;
  301. // 计算进行傅立叶变换的高度 (2的整数次幂)
  302. dTmpOne = log(nHeight)/log(2);
  303. dTmpTwo = ceil(dTmpOne)    ;
  304. dTmpTwo = pow(2,dTmpTwo)    ;
  305. nTransHeight = (int) dTmpTwo    ;
  306. // 分配工作需要的内存空间
  307. complex<double> *pCWork= new complex<double>[nTransWidth * nTransHeight];
  308. //临时变量
  309. complex<double> *pCTmp ;
  310. // 为了利用傅立叶正变换,可以把傅立叶频域的数据取共轭
  311. // 然后直接利用正变换,输出结果就是傅立叶反变换结果的共轭
  312. for(y = 0; y < nTransHeight; y++)
  313. {
  314. for(x = 0; x < nTransWidth; x++)
  315. {
  316. pCTmp = &pCFData[nTransWidth * y + x] ;
  317. pCWork[nTransWidth * y + x] = complex<double>( pCTmp->real() , -pCTmp->imag() );
  318. }
  319. }
  320. // 调用傅立叶正变换
  321. ::DIBFFT_2D(pCWork, nWidth, nHeight, pCTData) ;
  322. // 求时域点的共轭,求得最终结果
  323. // 根据傅立叶变换原理,利用这样的方法求得的结果和实际的时域数据
  324. // 相差一个系数
  325. for(y = 0; y < nTransHeight; y++)
  326. {
  327. for(x = 0; x < nTransWidth; x++)
  328. {
  329. pCTmp = &pCTData[nTransWidth * y + x] ;
  330. pCTData[nTransWidth * y + x] = 
  331. complex<double>( pCTmp->real()/(nTransWidth*nTransHeight),
  332.  -pCTmp->imag()/(nTransWidth*nTransHeight) );
  333. }
  334. }
  335. delete pCWork ;
  336. pCWork = NULL ;
  337. }
  338. /*************************************************************************
  339.  *
  340.  * 函数名称:
  341.  *   DCT()
  342.  *
  343.  * 参数:
  344.  *   double * dpf - 指向时域值的指针
  345.  *   double * dpF - 指向频域值的指针
  346.  *   r -2的幂数
  347.  *
  348.  * 返回值:
  349.  *   无。
  350.  *
  351.  * 说明:
  352.  *   实现一维快速离散余弦变换。
  353.  *
  354.  ***********************************************************************
  355. */
  356. VOID WINAPI DCT(double *dpf, double *dpF, int r)
  357. {
  358. double PI = 3.1415926; 
  359. // 离散余弦变换点数
  360. LONG lNum;
  361. // 循环变量
  362. int i;
  363. // 中间变量
  364. double dTemp;
  365. complex<double> *comX;
  366. // 离散余弦变换点数
  367. lNum = 1<<r;
  368. // 分配内存
  369. comX = new complex<double>[lNum*2];
  370. // 赋初值0
  371. memset(comX, 0, sizeof(complex<double>) * lNum * 2);
  372. // 将时域点转化为复数形式
  373. for(i=0;i<lNum;i++)
  374. {
  375. comX[i] = complex<double> (dpf[i], 0);
  376. }
  377. // 调用快速付立叶变换
  378. FFT_1D(comX,comX,r+1);
  379. // 调整系数
  380. dTemp = 1/sqrt(lNum);
  381. // 求dpF[0]
  382. dpF[0] = comX[0].real() * dTemp;
  383. dTemp *= sqrt(2);
  384. // 求dpF[u]
  385. for(i = 1; i < lNum; i++)
  386. {
  387. dpF[i]=(comX[i].real() * cos(i*PI/(lNum*2)) 
  388. + comX[i].imag() * sin(i*PI/(lNum*2))) * dTemp;
  389. }
  390. // 释放内存
  391.     delete comX;
  392. }
  393. /*************************************************************************
  394.  *
  395.  * 函数名称:
  396.  *   IDCT()
  397.  *
  398.  * 参数:
  399.  *   double * dpF - 指向频域值的指针
  400.  *   double * dpf - 指向时域值的指针
  401.  *   r -2的幂数
  402.  *
  403.  * 返回值:
  404.  *   无。
  405.  *
  406.  * 说明:
  407.  *   实现一维快速离散余弦反变换。
  408.  *
  409.  ************************************************************************/
  410. VOID WINAPI IDCT(double *dpF, double *dpf, int r)
  411. {
  412. double PI = 3.1415926; 
  413. // 离散余弦反变换点数
  414. LONG lNum;
  415. // 计算离散余弦变换点数
  416. lNum = 1<<r;
  417. // 循环变量
  418. int i;
  419. // 中间变量
  420. double dTemp, d0;
  421. complex<double> *comX;
  422.     // 给复数变量分配内存
  423. comX = new complex<double>[lNum*2];
  424. // 赋初值0
  425. memset(comX, 0, sizeof(complex<double>) * lNum * 2);
  426. // 将频域变换后点写入数组comX
  427. for(i=0;i<lNum;i++)
  428. {
  429. comX[i] = complex<double> (cos(i*PI/(lNum*2)) * dpF[i], sin(i*PI/(lNum*2) * dpF[i]));
  430. }
  431. // 调用快速付立叶反变换
  432. IFFT_1D(comX,comX,r+1);
  433. // 调整系数
  434. dTemp = sqrt(2.0/lNum);
  435. d0 = (sqrt(1.0/lNum) - dTemp) * dpF[0];
  436. // 计算dpf(x)
  437. for(i = 0; i < lNum; i++)
  438. {
  439. dpf[i] = d0 + 2 * lNum * comX[i].real()* dTemp ;
  440. }
  441. // 释放内存
  442. delete comX;
  443. }
  444. /*************************************************************************
  445.  *
  446.  * 函数名称:
  447.  *   WALSH()
  448.  *
  449.  * 参数:
  450.  *   double * dpf - 指向时域值的指针
  451.  *   double * dpF - 指向频域值的指针
  452.  *   r -2的幂数
  453.  *
  454.  * 返回值:
  455.  *   无。
  456.  *
  457.  * 说明:
  458.  *   该函数用来实现一维快速沃尔什-哈达玛变换。
  459.  *
  460.  ***********************************************************************
  461. */
  462. VOID WINAPI WALSH(double *dpf, double *dpF, int r)
  463. {
  464. // 沃尔什-哈达玛变换点数
  465. LONG lNum;
  466. // 快速沃尔什变换点数
  467. lNum = 1 << r;
  468. // 循环变量
  469. int i,j,k;
  470. // 中间变量
  471. int nTemp,m;
  472. double *X1,*X2,*X;
  473. // 分配运算所需的数组
  474. X1 = new double[lNum];
  475. X2 = new double[lNum];
  476. // 将时域点写入数组X1
  477. memcpy(X1, dpf, sizeof(double) * lNum);
  478. for(k = 0; k < r; k++)
  479. {
  480. for(j = 0; j < 1<<k; j++)
  481. {
  482. // 按照蝶形运算图进行运算
  483. nTemp = 1 << (r-k);
  484. for(i = 0; i < nTemp / 2; i++)
  485. {
  486. m = j * nTemp;
  487. X2[i + m] = X1[i + m] + X1[i + m + nTemp / 2];
  488. X2[i + m + nTemp / 2] = X1[i + m] - X1[i + m + nTemp / 2];
  489. }
  490. }
  491. // 互换  
  492. X = X2;
  493. X2 = X1;
  494. X1 = X;
  495. }
  496. // 对系数做调整
  497. for(j = 0; j < lNum; j++)
  498. {
  499. m = 0;
  500. for(i = 0; i < r; i++)
  501. {
  502. if (j & (1<<i))
  503. {
  504. m += 1 << (r-i-1);
  505. }
  506. }
  507. dpF[j] = X1[m] / lNum;
  508. }
  509. // 释放内存
  510. delete X1;
  511. delete X2;
  512. }
  513. /*************************************************************************
  514.  *
  515.  * 函数名称:
  516.  *   THREECROSS()
  517.  *
  518.  * 参数:
  519.  *   double  *Matrix     - 用来存放矩阵A
  520.  *   int     Rank        - 矩阵A的阶数
  521.  *   double  *QMatrix    - 返回householder变换的矩阵Q
  522.  *   double  *MainCross  - 对称三角阵中的主对角元素
  523.  *   double  *HypoCross  - 对称三角阵中的次对角元素
  524.  *
  525.  * 返回值:
  526.  *   BOOL                - 成功返回TRUE,否则返回FALSE。
  527.  *
  528.  * 说明:
  529.  *   该函数用householder变换将n阶实对称矩阵化为对称三角阵
  530.  *
  531.  *
  532.  ***********************************************************************
  533. */
  534. BOOL WINAPI THREECROSS(double *Matrix, int Rank, double *QMatrix, 
  535.     double *MainCross, double *HypoCross)
  536. {
  537. //   循环变量
  538. int i, j, k, u;
  539.     double h, f, g, h2;
  540.     
  541. // 对矩阵QMatrix赋值
  542. for(i = 0; i <= Rank-1; i++)
  543. for(j = 0; j <= Rank-1; j++)
  544. {
  545. u = i*Rank + j; 
  546. QMatrix[u] = Matrix[u];
  547. }
  548.     for (i = Rank-1; i >= 1; i--)
  549.     {
  550. h = 0.0;
  551.         if (i > 1)
  552.           for (k = 0; k <= i-1; k++)
  553.           {
  554.   u = i*Rank + k; 
  555.   h = h + QMatrix[u]*QMatrix[u];
  556.   }
  557.         
  558. // 如果一行全部为零
  559. if (h + 1.0 == 1.0)
  560.         {
  561. HypoCross[i] = 0.0;
  562.             if (i == 1) 
  563. HypoCross[i] = QMatrix[i*Rank+i-1];
  564.             MainCross[i] = 0.0;
  565.         }
  566.         
  567. // 否则进行householder变换,求正交矩阵的值
  568. else
  569.         {
  570. // 求次对角元素的值
  571. HypoCross[i] = sqrt(h);
  572.             
  573. // 判断i行i-1列元素是不是大于零
  574. u = i*Rank + i - 1;
  575.             if (QMatrix[u] > 0.0) 
  576. HypoCross[i] = -HypoCross[i];
  577.             
  578. h = h - QMatrix[u]*HypoCross[i];
  579.             QMatrix[u] = QMatrix[u] - HypoCross[i];
  580.             f = 0.0;
  581.             
  582. // householder变换
  583.     for (j = 0; j <= i-1; j++)
  584.             { 
  585. QMatrix[j*Rank+i] = QMatrix[i*Rank+j] / h;
  586.                 g = 0.0;
  587.                 
  588. for (k = 0; k <= j; k++)
  589.                   g = g + QMatrix[j*Rank+k]*QMatrix[i*Rank+k];
  590.                 
  591. if (j+1 <= i-1)
  592.                   for (k = j+1; k <= i-1; k++)
  593.                     g = g + QMatrix[k*Rank+j]*QMatrix[i*Rank+k];
  594.                 
  595. HypoCross[j] = g / h;
  596.                 f = f + g*QMatrix[j*Rank+i];
  597.             }
  598.             
  599. h2 = f / (h + h);
  600.             
  601. // 求正交矩阵的值
  602. for (j = 0; j <= i-1; j++)
  603.             {
  604. f = QMatrix[i*Rank + j];
  605.                 g = HypoCross[j] - h2*f;
  606.                 HypoCross[j] = g;
  607.                 
  608. for (k = 0; k <= j; k++)
  609.                 {
  610. u = j*Rank + k;
  611.                     QMatrix[u] = QMatrix[u] - f*HypoCross[k] - g*QMatrix[i*Rank + k];
  612.                  }
  613.             }
  614.             MainCross[i] = h;
  615.          }
  616.     }
  617.     // 赋零值
  618.     for (i = 0; i <= Rank-2; i++) 
  619. HypoCross[i] = HypoCross[i + 1];
  620.     HypoCross[Rank - 1] = 0.0;
  621.     MainCross[0]        = 0.0;
  622.     
  623. for (i = 0; i <= Rank-1; i++)
  624.     { 
  625. // 主对角元素的计算
  626. if ((MainCross[i] != 0.0) && (i-1 >= 0))
  627. for (j = 0; j <= i-1; j++)
  628. {
  629. g = 0.0;
  630. for (k = 0; k <= i-1; k++)
  631. g = g + QMatrix[i*Rank + k]*QMatrix[k*Rank + j];
  632. for (k = 0; k <= i-1; k++)
  633. u = k*Rank + j;
  634. QMatrix[u] = QMatrix[u] - g*QMatrix[k*Rank + i];
  635. }
  636. }
  637.         // 将主对角线的元素进行存储,以便返回
  638. u = i*Rank + i;
  639.         MainCross[i] = QMatrix[u]; 
  640. QMatrix[u]   = 1.0;
  641.         
  642. // 将三对角外所有的元素赋零值
  643. if (i-1 >= 0)
  644.           for (j = 0; j <= i-1; j++)
  645.           { 
  646.   QMatrix[i*Rank + j] = 0.0; 
  647.   QMatrix[j*Rank+i]   = 0.0;
  648.   }
  649.     }
  650.     
  651. // 返回值
  652. return(TRUE);
  653. }
  654. /*************************************************************************
  655.  *
  656.  * 函数名称:
  657.  *   BSTQ()
  658.  *
  659.  * 参数:
  660.  *   int     Rank        - 矩阵A的阶数
  661.  *   double  *MainCross  - 对称三角阵中的主对角元素,返回时存放A的特征值
  662.  *   double  *HypoCross  - 对称三角阵中的次对角元素
  663.  *  double  *Matrix     - 返回对称矩阵A的特征向量
  664.  *   double Eps          - 控制精度
  665.  *   int MaxT            - 最大迭代次数
  666.  *
  667.  * 返回值:
  668.  *   BOOL                - 成功返回TRUE,否则返回FALSE。
  669.  *
  670.  * 说明:
  671.  *   该函数用变形QR方法计算实对称三角矩阵的全部特征值以及相应的特征向量
  672.  *
  673.  *
  674.  ***********************************************************************
  675. */
  676. BOOL WINAPI BSTQ(int Rank, double *MainCross, double *HypoCross, 
  677.   double *Matrix, double Eps, int MaxT)
  678. {
  679. // 变量的定义
  680. int i, j, k, m, it, u, v;
  681.     double d, f, h, g, p, r, e, s;
  682. // 赋零值
  683.     HypoCross[Rank - 1] = 0.0; 
  684. d = 0.0; 
  685. f = 0.0;
  686.     
  687. for(j = 0; j <= Rank-1; j++)
  688.     {
  689. //  迭代精度的控制
  690. it = 0;
  691.         h = Eps * (fabs(MainCross[j]) + fabs(HypoCross[j]));
  692.         if(h > d) 
  693. d = h;
  694.         m = j;
  695.         
  696. while((m <= Rank-1) && (fabs(HypoCross[m]) > d)) 
  697. m = m + 1;
  698.         
  699. if(m != j)
  700.         {
  701. // 进行迭代,求得矩阵A的特征值和特征向量
  702. do
  703.             {
  704. // 超过迭代次数,返回迭代失败
  705. if(it == MaxT)
  706. return(FALSE);
  707.                 it = it + 1;
  708.                 g = MainCross[j];
  709.                 p = (MainCross[j + 1] - g) / (2.0 * HypoCross[j]);
  710.                 r = sqrt(p*p + 1.0);
  711.                 
  712. // 如果p大于0
  713. if (p >= 0.0)
  714. MainCross[j] = HypoCross[j]/(p + r);
  715.                 else
  716. MainCross[j] = HypoCross[j]/(p - r);
  717.                 
  718. h = g - MainCross[j];
  719.                 
  720. //  计算主对角线的元素
  721. for (i = j + 1; i <= Rank - 1; i++)
  722.                   MainCross[i] = MainCross[i] - h;
  723.                 
  724. // 赋值
  725. f = f + h;
  726. p = MainCross[m];
  727. e = 1.0; s = 0.0;
  728.                 
  729. for(i = m - 1; i >= j; i--)
  730.                 {
  731. g = e * HypoCross[i];
  732. h = e * p;
  733.                     
  734. //  主对角线元素的绝对值是否大于次对角线元素的
  735. if(fabs(p) >= fabs(HypoCross[i]))
  736.                     {
  737. e = HypoCross[i] / p;
  738. r = sqrt(e*e + 1.0);
  739.                         HypoCross[i + 1] = s*p*r; 
  740. s = e / r;  e = 1.0 / r;
  741.                      }
  742.                     else
  743. {
  744. e = p / HypoCross[i]; 
  745. r = sqrt(e*e + 1.0);
  746.                         HypoCross[i+1] = s * HypoCross[i] * r;
  747.                         s = 1.0 / r; e = e / r;
  748.                       }
  749.                     
  750. p = e*MainCross[i] - s*g;
  751.                     MainCross[i + 1] = h + s*(e*g + s*MainCross[i]);
  752.                     
  753. // 重新存储特征向量
  754. for(k = 0; k <= Rank - 1; k++)
  755.                     {
  756. u = k*Rank + i + 1; v = u - 1;
  757.                         h = Matrix[u]; 
  758. Matrix[u] = s*Matrix[v] + e*h;
  759.                         Matrix[v] = e*Matrix[v] - s*h;
  760.                     }
  761.                 
  762. }
  763.                 
  764. // 将主对角线和次对角线元素重新赋值
  765. HypoCross[j] = s * p; 
  766. MainCross[j] = e * p;
  767.             
  768. }
  769.             while (fabs(HypoCross[j]) > d);
  770.         }
  771.         MainCross[j] = MainCross[j] + f;
  772.     }
  773.     
  774. // 返回A的特征值
  775. for (i = 0; i <= Rank-1; i++)
  776.     {
  777. k = i; p = MainCross[i];
  778.         
  779. // 将A特征值赋给p
  780. if(i+1 <= Rank-1)
  781.         {
  782. j = i + 1;
  783.             while((j <= Rank-1) && (MainCross[j] <= p))
  784.             { k = j; 
  785.   p = MainCross[j]; 
  786.   j = j+1;
  787. }
  788.         }
  789.         
  790. // 存储A的特征值和特征向量
  791. if (k != i)
  792.         {
  793. MainCross[k] = MainCross[i];
  794. MainCross[i] = p;
  795.             for(j = 0; j <= Rank-1; j++)
  796.             {
  797. u = j*Rank + i; 
  798. v = j*Rank + k;
  799.                 p = Matrix[u]; 
  800. Matrix[u] = Matrix[v];
  801. Matrix[v] = p;
  802.             }
  803.         }
  804.     }
  805.   // 返回值
  806.   return(TRUE);
  807. }
  808. /*************************************************************************
  809.  *
  810.  * 函数名称:
  811.  *   IWALSH()
  812.  *
  813.  * 参数:
  814.  *   double * dpF - 指向频域值的指针
  815.  *   double * dpf - 指向时域值的指针
  816.  *   n -2的幂数
  817.  *
  818.  * 返回值:
  819.  *   无。
  820.  *
  821.  * 说明:
  822.  *   该函数用来实现一维快速沃尔什-哈达玛反变换。
  823.  *
  824.  ***********************************************************************
  825.  */
  826. VOID WINAPI IWALSH(double *dpF, double *dpf, int n)
  827. {
  828. // 变换点数
  829. LONG lNum;
  830. // 循环变量
  831. int i;
  832. // 计算变换点数
  833. lNum = 1 << n;
  834. // 用快速沃尔什-哈达玛变换进行反变换
  835. WALSH(dpF, dpf, n);
  836. // 对系数进行调整
  837. for(i = 0; i < lNum; i++)
  838. {
  839. dpf[i] *= lNum;
  840. }
  841. }
  842. /*************************************************************************
  843.  *
  844.  * 函数名称:
  845.  *   DFT_2D()
  846.  *
  847.  * 输入参数:
  848.  *   CDib * pDib - 指向CDib类的指针,含有图像数据
  849.  *   double * pTrRstRpart - 指向傅立叶系数实部的指针
  850.  *   double * pTrRstIpart - 指向傅立叶系数虚部的指针
  851.  *
  852.  * 返回值:
  853.  *   无
  854.  *
  855.  * 说明:
  856.  *   二维傅立叶变换。
  857.  *
  858.  *************************************************************************
  859.  */
  860. VOID WINAPI DIBDFT_2D(CDib * pDib,double * pTrRstRpart, double * pTrRstIpart)
  861. {
  862. double PI = 3.14159;
  863. //遍历图象的纵坐标
  864. int y;
  865. //遍历图象的横坐标
  866. int x;
  867. //频域的横坐标
  868. int m;
  869. //频域的纵坐标
  870. int n; 
  871. //图象的长宽大小
  872. CSize sizeImage = pDib->GetDimensions();
  873. int nWidth = sizeImage.cx ;
  874. int nHeight = sizeImage.cy ;
  875. //图像在计算机在存储中的实际大小
  876. CSize sizeImageSave = pDib->GetDibSaveDim();
  877. int nSaveWidth = sizeImageSave.cx;
  878. //图像数据的指针
  879. LPBYTE  pImageData = pDib->m_lpImage;
  880. //初始化结果数据
  881. for(n=0; n<nHeight ; n++ )
  882. for(m=0 ; m<nWidth ; m++ )
  883. {
  884. *( pTrRstRpart + n*nWidth + m ) =0;
  885. *( pTrRstIpart + n*nWidth + m ) =0;
  886. }
  887. double fCosTable;
  888. double fSinTable;
  889. int   nPxValue;
  890. fCosTable=0 ;
  891. nPxValue =0;
  892. double fTmpRstR;
  893. double fTmpRstI;
  894. for(n=0; n<nHeight ; n++ )
  895. for(m=0 ; m<nWidth ; m++ )
  896. {
  897. fTmpRstR=0;
  898. fTmpRstI=0;
  899. for(y=0; y<nHeight ; y++ )
  900. for(x=0 ; x<nWidth ; x++ )
  901. {
  902. fCosTable= 
  903. cos( 2*PI*( ((double)m*x)/nWidth + ((double)n*y)/nHeight) ) ;
  904. fSinTable= 
  905. sin( -2*PI*( ((double)m*x)/nWidth + ((double)n*y)/nHeight) ) ;
  906. nPxValue = *(pImageData+ y*nSaveWidth + x ) ;
  907. fTmpRstR+=fCosTable* nPxValue ;
  908. fTmpRstI+=fSinTable* nPxValue ;
  909. }
  910. *( pTrRstRpart + nWidth * n + m ) = fTmpRstR;
  911. *( pTrRstIpart + nWidth * n + m ) = fTmpRstI;
  912. }
  913. }
  914. /*************************************************************************
  915.  *
  916.  * 函数名称:
  917.  *   IDFT_2D()
  918.  *
  919.  * 输入参数:
  920.  *   CDib * pDib - 指向CDib类的指针,含有图像数据
  921.  *   double * pTrRstRpart - 指向傅立叶系数实部的指针
  922.  *   double * pTrRstIpart - 指向傅立叶系数虚部的指针
  923.  *
  924.  * 返回值:
  925.  *   无
  926.  *
  927.  * 说明:
  928.  *   二维傅立叶反变换。
  929.  *
  930.  *************************************************************************
  931.  */
  932. VOID WINAPI IDFT_2D(CDib * pDib,double * pTrRstRpart, double * pTrRstIpart)
  933. {
  934. double PI = 3.1415926;
  935. //遍历图象的纵坐标
  936. int y;
  937. //遍历图象的横坐标
  938. int x;
  939. //频域的横坐标
  940. int m;
  941. //频域的纵坐标
  942. int n; 
  943. //图象的长宽大小
  944. CSize sizeImage = pDib->GetDimensions();
  945. int nWidth = sizeImage.cx ;
  946. int nHeight = sizeImage.cy ;
  947. //图像在计算机在存储中的实际大小
  948. CSize sizeImageSave = pDib->GetDibSaveDim();
  949. int nSaveWidth = sizeImageSave.cx;
  950. //图像数据的指针
  951. LPBYTE  pImageData = pDib->m_lpImage;
  952. // 正弦和余弦值
  953. double fCosTable;
  954. double fSinTable;
  955. fCosTable=0 ;
  956. fSinTable=0 ;
  957. // 临时变量
  958. double fTmpPxValue;
  959. double fRpartValue;
  960. double fIpartValue;
  961. fTmpPxValue=0;
  962. fRpartValue=0;
  963. fIpartValue=0;
  964. for(y=0; y<nHeight ; y++ )
  965. for(x=0 ; x<nWidth ; x++ )
  966. {
  967. fTmpPxValue=0;
  968. for(n=0; n<nHeight ; n++ )
  969. for(m=0 ; m<nWidth ; m++ )
  970. {
  971. // 生成正弦和余弦值
  972. fCosTable= 
  973. cos( 2*PI*( ((double)m*x)/nWidth + ((double)n*y)/nHeight) ) ;
  974. fSinTable= 
  975. sin( 2*PI*( ((double)m*x)/nWidth + ((double)n*y)/nHeight) ) ;
  976. // 傅立叶变化的实部与虚部
  977. fRpartValue=*(pTrRstRpart+ n*nHeight + m ) ;
  978. fIpartValue=*(pTrRstIpart+ n*nHeight + m ) ;
  979. // 加权相加
  980. fTmpPxValue+=fCosTable* fRpartValue-fSinTable*fIpartValue;
  981. }
  982. // 傅立叶系数变换对要求除以(nHeight*nWidth)
  983. fTmpPxValue=fTmpPxValue/(nHeight*nWidth);
  984. *( pImageData + nSaveWidth * y + x) = (unsigned char) fTmpPxValue ;
  985. }
  986. }
  987. /*************************************************************************
  988.  *
  989.  * 函数名称:
  990.  *   DIBWalsh()
  991.  *
  992.  * 参数:
  993.  *   CDib  *pDib       - 指向CDib类的指针
  994.  *
  995.  * 返回值:
  996.  *   BOOL               - 成功返回TRUE,否则返回FALSE。
  997.  *
  998.  * 说明:
  999.  *   该函数用来对图像进行二维快速沃尔什-哈达玛变换。
  1000.  *
  1001.  ***********************************************************************
  1002.  */
  1003. BOOL WINAPI DIBWalsh(CDib * pDib)
  1004. {
  1005. // 指向源图像的指针
  1006. unsigned char *lpSrc;
  1007. //图象的宽度和高度
  1008. LONG    lWidth;
  1009. LONG    lHeight;
  1010. // 循环变量
  1011. LONG i;
  1012. LONG j;
  1013. // 实际进行付立叶变换的宽度和高度
  1014. LONG lW = 1;
  1015. LONG lH = 1;
  1016. int wp = 0;
  1017. int hp = 0;
  1018. // 中间变量
  1019. double dTemp;
  1020. //得到图象的宽度和高度
  1021. CSize   SizeDim;
  1022. SizeDim = pDib->GetDimensions();
  1023. lWidth = SizeDim.cx;
  1024. lHeight = SizeDim.cy;
  1025. //得到实际的图象存储大小
  1026. CSize   SizeRealDim;
  1027. SizeRealDim = pDib->GetDibSaveDim();
  1028. // 图像每行的字节数
  1029. LONG lLineBytes;
  1030. // 计算图像每行的字节数
  1031. lLineBytes = SizeRealDim.cx;
  1032. //图像数据的指针
  1033. LPBYTE  lpDIBBits = pDib->m_lpImage;
  1034. // 保证离散余弦变换的宽度和高度为2的整数次方
  1035. while(lW * 2 <= lWidth)
  1036. {
  1037. lW = lW * 2;
  1038. wp++;
  1039. }
  1040. while(lH * 2 <= lHeight)
  1041. {
  1042. lH = lH * 2;
  1043. hp++;
  1044. }
  1045. // 分配内存
  1046. double *dpf = new double[lW * lH];
  1047. double *dpF = new double[lW * lH];
  1048. // 时域赋值
  1049. for(i = 0; i < lH; i++)
  1050. {
  1051. // 列
  1052. for(j = 0; j < lW; j++)
  1053. {
  1054. // 指向DIBi行j列象素的指针
  1055. lpSrc = lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  1056. // 将象素值赋值给时域数组
  1057. dpf[j + i * lW] = *(lpSrc);
  1058. }
  1059. }
  1060. for(i = 0; i < lH; i++)
  1061. // 对y方向进行沃尔什-哈达玛变换
  1062. WALSH(dpf + lW * i, dpF + lW * i, wp);
  1063. // 保存计算结果
  1064. for(i = 0; i < lH; i++)
  1065. {
  1066. for(j = 0; j < lW; j++)
  1067. {
  1068. dpf[j * lH + i] = dpF[j + lW * i];
  1069. }
  1070. }
  1071. for(j = 0; j < lW; j++)
  1072. // 对x方向进行沃尔什-哈达玛变换
  1073. WALSH(dpf + j * lH, dpF + j * lH, hp);
  1074. // 行
  1075. for(i = 0; i < lH; i++)
  1076. {
  1077. // 列
  1078. for(j = 0; j < lW; j++)
  1079. {
  1080. // 计算频谱
  1081. dTemp = fabs(dpF[j * lH + i] * 1000);
  1082. if (dTemp > 255)
  1083. {
  1084. // 超过255直接设置为255
  1085. dTemp = 255;
  1086. }
  1087. // 指向DIBi行j列象素的指针
  1088. lpSrc = lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  1089. // 更新源图像
  1090. * (lpSrc) = (BYTE)(dTemp);
  1091. }
  1092. }
  1093. //释放内存
  1094. delete dpf;
  1095. delete dpF;
  1096. // 返回
  1097. return TRUE;
  1098. }
  1099. /*************************************************************************
  1100.  *
  1101.  * 函数名称:
  1102.  *   DIBDct()
  1103.  *
  1104.  * 参数:
  1105.  *   CDib  *pDib       - 指向CDib类的指针
  1106.  *
  1107.  * 返回值:
  1108.  *   BOOL               - 成功返回TRUE,否则返回FALSE。
  1109.  *
  1110.  * 说明:
  1111.  *   该函数用来对图像进行二维离散余弦变换。
  1112.  *
  1113.  ***********************************************************************
  1114.  */
  1115. BOOL WINAPI DIBDct(CDib *pDib)
  1116. {
  1117. // 指向源图像的指针
  1118. unsigned char* lpSrc;
  1119. //图象的宽度和高度
  1120. LONG    lWidth;
  1121. LONG    lHeight;
  1122. // 循环变量
  1123. LONG i;
  1124. LONG j;
  1125. // 离散余弦变换的宽度和高度,必须为2的整数次方
  1126. LONG lW = 1;
  1127. LONG lH = 1;
  1128. int wp = 0;
  1129. int hp = 0;
  1130. // 中间变量
  1131. double dTemp;
  1132. //得到图象的宽度和高度
  1133. CSize   SizeDim;
  1134. SizeDim = pDib->GetDimensions();
  1135. lWidth = SizeDim.cx;
  1136. lHeight = SizeDim.cy;
  1137. // 图像每行的字节数
  1138. LONG lLineBytes;
  1139. //得到实际的Dib图象存储大小
  1140. CSize   SizeRealDim;
  1141. SizeRealDim = pDib->GetDibSaveDim();
  1142. // 计算图像每行的字节数
  1143. lLineBytes = SizeRealDim.cx;
  1144.    //图像数据的指针
  1145. LPBYTE  lpDIBBits = pDib->m_lpImage;
  1146. // 保证离散余弦变换的宽度和高度为2的整数次方
  1147. while(lW * 2 <= lWidth)
  1148. {
  1149. lW = lW * 2;
  1150. wp++;
  1151. }
  1152. while(lH * 2 <= lHeight)
  1153. {
  1154. lH = lH * 2;
  1155. hp++;
  1156. }
  1157. // 分配内存
  1158. double *dpf = new double[lW * lH];
  1159. double *dpF = new double[lW * lH];
  1160. // 时域赋值
  1161. for(i = 0; i < lH; i++)
  1162. {
  1163. for(j = 0; j < lW; j++)
  1164. {
  1165. // 指针指向位图i行j列的象素
  1166. lpSrc = lpDIBBits + lLineBytes * ( i) + j;
  1167. // lpSrc = lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  1168. // 将象素值赋给时域数组
  1169. dpf[j + i * lW] = *(lpSrc);
  1170. }
  1171. }
  1172. for(i = 0; i < lH; i++)
  1173. // y方向进行离散余弦变换
  1174. DCT(&dpf[lW * i], &dpF[lW * i], wp);
  1175. // 保存计算结果
  1176. for(i = 0; i < lH; i++)
  1177. for(j = 0; j < lW; j++)
  1178. dpf[j * lH + i] = dpF[j + lW * i];
  1179. for(j = 0; j < lW; j++)
  1180. // x方向进行离散余弦变换
  1181. DCT(&dpf[j * lH], &dpF[j * lH], hp);
  1182. // 频谱的计算
  1183. for(i = 0; i < lH; i++)
  1184. {
  1185. for(j = 0; j < lW; j++)
  1186. {
  1187. dTemp = fabs(dpF[j*lH+i]);
  1188. // 是否超过255
  1189. if (dTemp > 255)
  1190. // 如果超过,设置为255
  1191. dTemp = 255;
  1192. // 指针指向位图i行j列的象素
  1193. lpSrc = lpDIBBits + lLineBytes * ( i) + j;
  1194. // lpSrc = lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  1195. // 更新源图像
  1196. * (lpSrc) = (BYTE)(dTemp);
  1197. }
  1198. }
  1199. // 释放内存
  1200. delete dpf;
  1201. delete dpF;
  1202. // 返回
  1203. return TRUE;
  1204. }
  1205. /*************************************************************************
  1206.  *
  1207.  * 函数名称:
  1208.  *   DIBOHOTELLING()
  1209.  *
  1210.  * 参数:
  1211.  *   CDib  *pDib       - 指向CDib类的指针
  1212.  *
  1213.  * 返回值:
  1214.  *   BOOL               - 成功返回TRUE,否则返回FALSE。
  1215.  *
  1216.  * 说明:
  1217.  *   该函数用霍特林变换来对图像进行旋转。
  1218.  *
  1219.  ***********************************************************************
  1220.  */
  1221. BOOL WINAPI DIBHOTELLING(CDib *pDib)
  1222. {
  1223. // 指向源图像的指针
  1224. unsigned char*  lpSrc;
  1225. // 循环变量
  1226. LONG i;
  1227. LONG j;
  1228. //图象的宽度和高度
  1229. LONG    lWidth;
  1230. LONG    lHeight;
  1231. // 图像每行的字节数
  1232. LONG lLineBytes;
  1233. // 经过变换后图象最大可能范围
  1234. LONG    lMaxRange;
  1235. //  物体坐标的均值
  1236.     LONG    AverEx;
  1237. LONG    AverEy;
  1238. //  物体总的象素数
  1239. LONG    ToaCount;
  1240. // 坐标值的协方差矩阵
  1241. double  Matr4C[2][2];
  1242. // 存放协方差矩阵的特征向量
  1243. double  QMatrix[2][2];
  1244. //  三对角阵的主对角和次对角线元素
  1245. double  MainCross[2];
  1246. double  HypoCross[2];
  1247. // 中间变量
  1248. double dTemp;
  1249. LONG    lTempI;
  1250. LONG    lTempJ;
  1251. //得到图象的宽度和高度
  1252. CSize   SizeDim;
  1253. SizeDim = pDib->GetDimensions();
  1254. lWidth = SizeDim.cx;
  1255. lHeight = SizeDim.cy;
  1256. //得到实际的Dib图象存储大小
  1257. CSize   SizeRealDim;
  1258. SizeRealDim = pDib->GetDibSaveDim();
  1259. // 计算图像每行的字节数
  1260. lLineBytes = SizeRealDim.cx;
  1261.    //图像数据的指针
  1262. LPBYTE  lpDIBBits = pDib->m_lpImage;
  1263. // 估计图象经过旋转后可能最大的宽度和高度
  1264. if(lWidth>lHeight)
  1265. lMaxRange = lWidth;
  1266. else
  1267. lMaxRange =lHeight;
  1268. // 赋初值
  1269. AverEx=0.0;
  1270. AverEy=0.0;
  1271. ToaCount = 0;
  1272. Matr4C[0][0] = Matr4C[0][1] = Matr4C[1][0] = Matr4C[1][1] = 0.0;
  1273. // 分配内存
  1274. double *F = new double[lWidth*lHeight];
  1275. // 行
  1276. for(i = 0; i < lHeight; i++)
  1277. {
  1278. // 列
  1279. for(j = 0; j < lWidth; j++)
  1280. {
  1281. // 给旋转后坐标轴的每个点赋零值(灰度值255对应显示白色)
  1282. F[i*lWidth + j] = 255;
  1283. // 指向位图i行j列象素的指针
  1284. lpSrc = lpDIBBits + lLineBytes*i + j;
  1285. // 值小于255(非背景色白色)的象素认为物体的一部分
  1286. // 并将其坐标值x和y看作二维随机矢量
  1287. if((*lpSrc) < 255)
  1288. {
  1289. // 属于物体象素的Y坐标和X坐标累计值
  1290. AverEx=AverEx+i;
  1291. AverEy=AverEy+j;
  1292. // 物体总的象素数加一
  1293. ToaCount++;
  1294.                    
  1295.                 // 随机矢量协方差矩阵的累计值
  1296. Matr4C[0][0] = Matr4C[0][0] + i*i;
  1297.                 Matr4C[0][1] = Matr4C[0][1] + i*j;
  1298. Matr4C[1][0] = Matr4C[1][0] + j*i;
  1299. Matr4C[1][1] = Matr4C[1][1] + j*j;
  1300. }
  1301. }
  1302. }
  1303. // 计算随机矢量的均值
  1304. AverEx = AverEx/ToaCount;
  1305. AverEy = AverEy/ToaCount;
  1306. //  计算随机矢量的协方差矩阵
  1307.     Matr4C[0][0] = Matr4C[0][0]/ToaCount - AverEx*AverEx;
  1308. Matr4C[0][1] = Matr4C[0][1]/ToaCount - AverEx*AverEy;
  1309. Matr4C[1][0] = Matr4C[1][0]/ToaCount - AverEx*AverEy;
  1310. Matr4C[1][1] = Matr4C[1][1]/ToaCount - AverEy*AverEy;
  1311.     // 规定迭代的计算精度
  1312. double Eps = 0.000001;
  1313. // 将协方差矩阵化作三对角对称阵
  1314.     THREECROSS(*Matr4C, 2, *QMatrix, MainCross, HypoCross);
  1315. // 求协方差矩阵的特征值和特征矢向量
  1316. BSTQ(2, MainCross,HypoCross, *Matr4C, Eps, 50);
  1317.     
  1318. // 将特征列向量转化称特征列向量
  1319.     dTemp = Matr4C[0][1];
  1320. Matr4C[0][1] = Matr4C[1][0];
  1321. Matr4C[1][0] = dTemp;
  1322. // 对特征列向量进行归一化
  1323. for(i=0;i<=1;i++)
  1324. {
  1325. dTemp = pow(Matr4C[i][0],2) + pow(Matr4C[i][1],2);
  1326. dTemp = sqrt(dTemp);
  1327. Matr4C[i][0] = Matr4C[i][0]/dTemp;
  1328. Matr4C[i][1] = Matr4C[i][1]/dTemp;
  1329. }
  1330. // 查找经霍特林变换后的坐标点在原坐标系中的坐标    
  1331.     for(i = -lMaxRange+1; i < lMaxRange; i++)
  1332. {
  1333. for(j = -lMaxRange+1; j < lMaxRange; j++)
  1334. {
  1335. //  将新坐标值映射到旧的坐标系
  1336. int Cx = (int)(i*Matr4C[0][0]-j*Matr4C[0][1])+AverEx;
  1337. int Cy = (int)(-i*Matr4C[1][0]+j*Matr4C[1][1])+AverEy;
  1338. //  映射值是否属于源图象
  1339. if( Cx>=0 && Cx<lHeight && Cy>=0 && Cy<lWidth )
  1340. {
  1341. lpSrc = lpDIBBits + lLineBytes*Cx + Cy;
  1342. // 映射值是否属于原来的物体
  1343. if(*(lpSrc)<255)
  1344. {
  1345. //  将新坐标系原点平移到中心,以便显示
  1346. lTempI=(LONG)(lHeight/2)+j;
  1347. lTempJ=(LONG)(lWidth/2)+i;
  1348. // 看如果能够进行显示,赋值给数组,进行存储
  1349. if( lTempI>=0 && lTempI<lHeight && lTempJ>=0 && lTempJ<lWidth )
  1350. F[lTempJ+ (lTempI) * lWidth]=*(lpSrc);
  1351. }
  1352. }
  1353. }
  1354. }
  1355. // 行
  1356. for(i = 0; i < lMaxRange; i++)
  1357. {
  1358. // 列
  1359. for(j = 0; j < lMaxRange; j++)
  1360. {
  1361. // 霍特林变换后的象素值
  1362.     dTemp = F[i * lMaxRange + j] ;
  1363. // 指向位图i行j列象素的指针
  1364. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  1365. // 更新源图像
  1366. * (lpSrc) = (BYTE)(dTemp);
  1367. }
  1368. }
  1369. // 释放内存
  1370. delete F;
  1371. // 返回
  1372. return TRUE;
  1373. }