PlateLocateMethod.cpp
上传用户:sgmlaoniu
上传日期:2013-03-16
资源大小:403k
文件大小:27k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /**************************************************************************
  2. *  文件名:PlateLocateMethod.cpp
  3. *
  4. *  车牌定位函数库:
  5. *  
  6. *  ConvertToGrayScale();   - 24位真彩色图转换成灰度图
  7. *************************************************************************/
  8. #include "stdafx.h"
  9. #include "PlateLocateMethod.h"
  10. #include "math.h"
  11. /*************************************************************************
  12. *
  13. * 函数名称:
  14. *   ConvertToGrayScale()
  15. *
  16. * 参数:
  17. *   LPSTR lpDIB - 指向源DIB图像指针
  18. *   
  19. * 返回值:
  20. *   BOOL - 成功返回TRUE,否则返回FALSE。
  21. *
  22. * 说明:
  23. *   该函数将24位真彩色图转换成256级灰度图
  24. *
  25. ************************************************************************/
  26. BOOL WINAPI ConvertToGrayScale(LPSTR lpDIB)   
  27. {
  28. LPSTR lpDIBBits;                //指向DIB的象素的指针
  29. LPSTR lpNewDIBBits;             //指向DIB灰度图图像(新图像)开始处象素的指针
  30.     LONG lLineBytes;
  31. unsigned char * lpSrc;          //指向原图像象素点的指针
  32. unsigned char * lpdest;         //指向目标图像象素点的指针
  33.     unsigned  char *ired,*igreen,*iblue;
  34.     long lWidth;                    //图像宽度和高度
  35. long lHeight;
  36. long i,j;           //循环变量
  37. lWidth = ::DIBWidth(lpDIB);   //DIB 宽度
  38. lHeight = ::DIBHeight(lpDIB); //DIB 高度
  39. RGBQUAD  *lpRGBquad;
  40. lpRGBquad = (RGBQUAD *)&lpDIB[sizeof(BITMAPINFOHEADER)]; //INFOHEADER后为调色板
  41.     if(::DIBNumColors(lpDIB) == 256)  //256色位图不作任何处理
  42. {
  43. return TRUE;
  44.     }
  45. if(::DIBNumColors(lpDIB) != 256)  //非256色位图将它灰度化
  46. {
  47. lLineBytes = WIDTHBYTES(lWidth*8*3);//真彩色一个象素为3个字节
  48. lpdest=  new  BYTE[lHeight*lWidth];
  49. lpDIBBits = (LPSTR)lpDIB + sizeof(BITMAPINFOHEADER);//指向DIB象素
  50. for(i = 0;i < lHeight; i++)
  51. for(j = 0;j < lWidth*3; j+=3)//每个象素3个字节
  52. {
  53. ired   =  (unsigned  char*)lpDIBBits + lLineBytes * i + j + 2;
  54. igreen =  (unsigned  char*)lpDIBBits + lLineBytes * i + j + 1;
  55. iblue  =  (unsigned  char*)lpDIBBits + lLineBytes * i + j ;
  56. lpdest[i*lWidth + j/3]  = (unsigned  char)((*ired)*0.299 + (*igreen)*0.588 + (*iblue)*0.114);
  57. }
  58. //需要做三件事情:1、修改INFOHEADER 2、增加调色板 3、修改原图像灰度值
  59. LPBITMAPINFOHEADER  lpBI;
  60. lpBI  =  (LPBITMAPINFOHEADER)lpDIB;
  61. lpBI->biBitCount = 8;
  62. //设置灰度调色板
  63. for(i = 0;i < 256;i++)
  64. {
  65. lpRGBquad[i].rgbRed   = (unsigned char)i;
  66. lpRGBquad[i].rgbGreen = (unsigned char)i;
  67. lpRGBquad[i].rgbBlue  = (unsigned char)i;
  68. lpRGBquad[i].rgbReserved = 0;
  69. }
  70. lpNewDIBBits= ::FindDIBBits(lpDIB);  //找到DIB图像象素起始位置
  71. lLineBytes=WIDTHBYTES(lWidth  *  8);
  72. //修改灰度值
  73. for(i = 0;i < lHeight; i++)
  74. for(j = 0;j < lWidth; j++)
  75. {
  76. lpSrc = (unsigned  char*)lpNewDIBBits + lLineBytes * i+ j ;
  77. *lpSrc=lpdest[i*lWidth+j];
  78. }
  79. delete  lpdest;
  80. }
  81. return true;
  82. }
  83. /*************************************************************************
  84.  *
  85.  * 函数名称:
  86.  *   InteEqualize()
  87.  *
  88.  * 参数:
  89.  *   LPSTR lpDIBBits    - 指向源DIB图像指针
  90.  *   LONG  lWidth       - 源图像宽度(象素数)
  91.  *   LONG  lHeight      - 源图像高度(象素数)
  92.  *
  93.  * 返回值:
  94.  *   BOOL               - 成功返回TRUE,否则返回FALSE。
  95.  *
  96.  * 说明:
  97.  *   该函数用来对图像进行直方图均衡。
  98.  *
  99.  ************************************************************************/
  100. BOOL WINAPI InteEqualize(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
  101. {
  102. // 指向源图像的指针
  103. unsigned char* lpSrc;
  104. // 临时变量
  105. LONG lTemp;
  106. // 循环变量
  107. LONG i;
  108. LONG j;
  109. // 灰度映射表
  110. BYTE bMap[256];
  111. // 灰度映射表
  112. LONG lCount[256];
  113. // 图像每行的字节数
  114. LONG lLineBytes;
  115. // 计算图像每行的字节数
  116. lLineBytes = WIDTHBYTES(lWidth * 8);
  117. // 重置计数为0
  118. for (i = 0; i < 256; i ++)
  119. {
  120. // 清零
  121. lCount[i] = 0;
  122. }
  123. // 计算各个灰度值的计数
  124. for (i = 0; i < lHeight; i ++)
  125. {
  126. for (j = 0; j < lWidth; j ++)
  127. {
  128. lpSrc = (unsigned char *)lpDIBBits + lLineBytes * i + j;
  129. // 计数加1
  130. lCount[*(lpSrc)]++;
  131. }
  132. }
  133. // 计算灰度映射表
  134. for (i = 0; i < 256; i++)
  135. {
  136. // 初始为0
  137. lTemp = 0;
  138. for (j = 0; j <= i ; j++)
  139. {
  140. lTemp += lCount[j];
  141. }
  142. // 计算对应的新灰度值
  143. bMap[i] = (BYTE) (lTemp * 255 / (lHeight * lWidth));
  144. }
  145. // 每行
  146. for(i = 0; i < lHeight; i++)
  147. {
  148. // 每列
  149. for(j = 0; j < lWidth; j++)
  150. {
  151. // 指向DIB第i行,第j个象素的指针
  152. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  153. // 计算新的灰度值
  154. *lpSrc = bMap[*lpSrc];
  155. }
  156. }
  157. // 返回
  158. return TRUE;
  159. }
  160. /*************************************************************************
  161.  *
  162.  * 函数名称:
  163.  *   RobertDIB()
  164.  *
  165.  * 参数:
  166.  *   LPSTR lpDIBBits    - 指向源DIB图像指针
  167.  *   LONG  lWidth       - 源图像宽度(象素数,必须是4的倍数)
  168.  *   LONG  lHeight      - 源图像高度(象素数)
  169.  * 返回值:
  170.  *   BOOL               - 边缘检测成功返回TRUE,否则返回FALSE。
  171.  *
  172.  * 说明:
  173.  * 该函数用Robert边缘检测算子对图像进行边缘检测运算。
  174.  * 
  175.  * 要求目标图像为灰度图像。
  176.  ************************************************************************/
  177. BOOL WINAPI RobertDIB(LPSTR lpDIBBits, LONG lWidth, LONG lHeight)
  178. {
  179. // 指向源图像的指针
  180. LPSTR lpSrc;
  181. // 指向缓存图像的指针
  182. LPSTR lpDst;
  183. // 指向缓存DIB图像的指针
  184. LPSTR lpNewDIBBits;
  185. HLOCAL hNewDIBBits;
  186. //循环变量
  187. long i;
  188. long j;
  189. //像素值
  190. double result;
  191. unsigned char pixel[4];
  192. // 暂时分配内存,以保存新图像
  193. hNewDIBBits = LocalAlloc(LHND, lWidth * lHeight);
  194. if (hNewDIBBits == NULL)
  195. {
  196. // 分配内存失败
  197. return FALSE;
  198. }
  199. // 锁定内存
  200. lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
  201. // 初始化新分配的内存,设定初始值为255
  202. lpDst = (char *)lpNewDIBBits;
  203. memset(lpDst, (BYTE)255, lWidth * lHeight);
  204. //使用水平方向的结构元素进行腐蚀
  205. for(j = lHeight-1; j > 0; j--)
  206. {
  207. for(i = 0;i <lWidth-1; i++)
  208. {
  209. //由于使用2×2的模板,为防止越界,所以不处理最下边和最右边的两列像素
  210. // 指向源图像第j行,第i个象素的指针
  211. lpSrc = (char *)lpDIBBits + lWidth * j + i;
  212. // 指向目标图像第j行,第i个象素的指针
  213. lpDst = (char *)lpNewDIBBits + lWidth * j + i;
  214. //取得当前指针处2*2区域的像素值,注意要转换为unsigned char型
  215. pixel[0] = (unsigned char)*lpSrc;
  216. pixel[1] = (unsigned char)*(lpSrc + 1);
  217. pixel[2] = (unsigned char)*(lpSrc - lWidth);
  218. pixel[3] = (unsigned char)*(lpSrc - lWidth + 1);
  219. //计算目标图像中的当前点
  220.  result = sqrt(( pixel[0] - pixel[3] )*( pixel[0] - pixel[3] ) + 
  221.   ( pixel[1] - pixel[2] )*( pixel[1] - pixel[2] ));
  222. *lpDst = (unsigned char)result;
  223. }
  224. }
  225. // 复制腐蚀后的图像
  226. memcpy(lpDIBBits, lpNewDIBBits, lWidth * lHeight);
  227. // 释放内存
  228. LocalUnlock(hNewDIBBits);
  229. LocalFree(hNewDIBBits);
  230. // 返回
  231. return TRUE;
  232. }
  233. /*************************************************************************
  234. *
  235. * 函数名称:
  236. *   ThresholdTrans()
  237. *
  238. * 参数:
  239. *   LPSTR lpDIBBits    - 指向源DIB图像指针
  240. *   LONG  lWidth       - 源图像宽度(象素数)
  241. *   LONG  lHeight      - 源图像高度(象素数)
  242. *   BYTE  bThre     - 阈值
  243. *
  244. * 返回值:
  245. *   BOOL               - 成功返回TRUE,否则返回FALSE。
  246. *
  247. * 说明:
  248. *   该函数用来对图像进行阈值变换。对于灰度值小于阈值的象素直接设置
  249. * 灰度值为0;灰度值大于阈值的象素直接设置为255。
  250. *
  251. ************************************************************************/
  252. BOOL WINAPI ThresholdTrans(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, BYTE bThre)
  253. {
  254. // 指向源图像的指针
  255. unsigned char* lpSrc;
  256. // 循环变量
  257. LONG i;
  258. LONG j;
  259. // 图像每行的字节数
  260. LONG lLineBytes;
  261. // 计算图像每行的字节数
  262. lLineBytes = WIDTHBYTES(lWidth * 8);
  263. // 每行
  264. for(i = 0; i < lHeight; i++)
  265. {
  266. // 每列
  267. for(j = 0; j < lWidth; j++)
  268. {
  269. // 指向DIB第i行,第j个象素的指针
  270. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  271. // 判断是否小于阈值
  272. if ((*lpSrc) < bThre)
  273. {
  274. // 直接赋值为0
  275. *lpSrc = 0;
  276. }
  277. else
  278. {
  279. // 直接赋值为255
  280. *lpSrc = 255;
  281. }
  282. }
  283. }
  284. // 返回
  285. return TRUE;
  286. }
  287. /*************************************************************************
  288. *
  289. * 函数名称:
  290. *   myHprojectDIB()
  291. *
  292. * 参数:
  293. *   LPSTR lpDIBBits    - 指向源DIB图像指针
  294. *   LONG  lWidth       - 源图像宽度(象素数)
  295. *   LONG  lHeight      - 源图像高度(象素数)
  296. *   INT*  iTop         - 车牌上边缘
  297. *   INT*  iBottom      - 车牌下边缘
  298. * 返回值:
  299. *   BOOL               - 成功返回TRUE,否则返回FALSE。
  300. *
  301. * 说明:
  302. *   该函数用于对含车牌图像进行水平投影运算,求取车牌子图像的上下边缘位置
  303. *
  304. ************************************************************************/
  305. BOOL WINAPI myHprojectDIB(LPSTR lpDIB, LONG lWidth, LONG lHeight, 
  306.   int* iTop, int* iBottom) 
  307. {
  308. LPSTR lpDIBBits;                   //指向DIB的象素的指针
  309.     LONG lLineBytes;                   // 图像每行的字节数
  310. unsigned char * lpSrc;             //指向原图像象素点的指针
  311. unsigned char pixel; //像素值
  312. int i,j;
  313. // 计算结果
  314. INT* iResult;
  315. INT pzBottom,pzTop;
  316. bool findPZ=false;
  317. // 找到DIB图像象素起始位置
  318. lpDIBBits = ::FindDIBBits(lpDIB);
  319. // 计算图像每行的字节数
  320. lLineBytes = WIDTHBYTES(lWidth * 8);
  321. iResult=new INT[lHeight];
  322. for(i=0;i<lHeight;i++)
  323. iResult[i]=0;
  324. for(j=lHeight/7;j<lHeight*0.8;j++)
  325. {
  326. iResult[j]=0;
  327. for(i=0;i<lWidth;i++)
  328. {
  329. lpSrc=(unsigned char*)lpDIBBits+lLineBytes*j+i;
  330. pixel=(unsigned char)(*lpSrc);
  331. if(pixel==255)
  332. {
  333. iResult[j]++;
  334. }
  335. }
  336. if((!findPZ)&&iResult[j]>12)
  337. {
  338. pzBottom=j;
  339. findPZ=true;
  340. continue;
  341. }
  342. if(findPZ&&iResult[j]<12)
  343. {
  344. pzTop=j;
  345. break;
  346. }
  347. }
  348. if(pzTop - pzBottom < 40)
  349. {
  350. pzTop=pzTop+55;
  351. pzBottom=pzBottom-20;   //微量调整
  352. }
  353. *iBottom=lHeight-pzBottom;
  354. //*iBottom=pzBottom;
  355. *iTop=lHeight-pzTop;
  356. //*iTop=pzTop;
  357. return true;
  358. }
  359. /*************************************************************************
  360. *
  361. * 函数名称:
  362. *   myVprojectDIB()
  363. *
  364. * 参数:
  365. *   LPSTR lpDIBBits    - 指向源DIB图像指针
  366. *   LONG  lWidth       - 源图像宽度(象素数)
  367. *   LONG  lHeight      - 源图像高度(象素数)
  368. *   INT*  iLeft        - 车牌左边缘
  369. *   INT*  iRight       - 车牌右边缘
  370. * 返回值:
  371. *   BOOL               - 成功返回TRUE,否则返回FALSE。
  372. *
  373. * 说明:
  374. *   该函数用于对含车牌图像进行垂直投影运算,求取车牌子图像的左右边缘位置
  375. *
  376. ************************************************************************/
  377. BOOL WINAPI myVprojectDIB(LPSTR lpDIB, LONG lWidth, LONG lHeight, 
  378.   int* iLeft, int* iRight) 
  379. {
  380. LPSTR lpDIBBits;                   //指向DIB的象素的指针
  381.     LONG lLineBytes;                   // 图像每行的字节数
  382. unsigned char * lpSrc;             //指向原图像象素点的指针
  383. unsigned char pixel; //像素值
  384. int i,j;
  385. // 计算结果
  386. INT* iResult;
  387. INT pzLeft,pzRight;
  388. bool findPZ=false;
  389. // 找到DIB图像象素起始位置
  390. lpDIBBits = ::FindDIBBits(lpDIB);
  391. // 计算图像每行的字节数
  392. lLineBytes = WIDTHBYTES(lWidth * 8);
  393. iResult=new INT[lWidth];
  394. for(i=0;i<lWidth;i++)
  395. iResult[i]=0;
  396. for(i=lWidth/7;i<lWidth*0.8;i++)
  397. {
  398. iResult[i]=0;
  399. for(j=0;j<lHeight;j++)
  400. {
  401. lpSrc=(unsigned char*)lpDIBBits+lLineBytes*j+i;
  402. pixel=(unsigned char)(*lpSrc);
  403. if(pixel==255)
  404. {
  405. iResult[i]++;
  406. }
  407. }
  408. if((!findPZ)&&iResult[i]>12)
  409. {
  410. pzLeft=i;
  411. findPZ=true;
  412. continue;
  413. }
  414. pzRight=pzLeft+150;
  415. }
  416. *iLeft=pzLeft-10;
  417. *iRight=pzRight+10;
  418. return true;
  419. }
  420. /*************************************************************************
  421. *
  422. * 函数名称:
  423. *   Template()
  424. *
  425. * 参数:
  426. *   LPSTR lpDIBBits    - 指向源DIB图像指针
  427. *   LONG  lWidth       - 源图像宽度(象素数)
  428. *   LONG  lHeight      - 源图像高度(象素数)
  429. *   int   iTempH - 模板的高度
  430. *   int   iTempW - 模板的宽度
  431. *   int   iTempMX - 模板的中心元素X坐标 ( < iTempW - 1)
  432. *   int   iTempMY - 模板的中心元素Y坐标 ( < iTempH - 1)
  433. *  FLOAT * fpArray - 指向模板数组的指针
  434. *  FLOAT fCoef - 模板系数
  435. *
  436. * 返回值:
  437. *   BOOL               - 成功返回TRUE,否则返回FALSE。
  438. *
  439. * 说明:
  440. *   该函数用指定的模板(任意大小)来对图像进行操作,参数iTempH指定模板
  441. * 的高度,参数iTempW指定模板的宽度,参数iTempMX和iTempMY指定模板的中心
  442. * 元素坐标,参数fpArray指定模板元素,fCoef指定系数。
  443. *
  444. ************************************************************************/
  445. BOOL WINAPI myTemplate(LPSTR lpDIB)
  446. {
  447. // 指向复制图像的指针
  448. LPSTR lpNewDIBBits;
  449. HLOCAL hNewDIBBits;
  450. // 指向要复制区域的指针
  451. unsigned char* lpDst;
  452. LPSTR lpDIBBits;                   //指向DIB的象素的指针
  453.     LONG lLineBytes;                   // 图像每行的字节数
  454. unsigned char * lpSrc;             //指向原图像象素点的指针
  455.     long lWidth;                       //图像宽度和高度
  456. long lHeight;
  457. // 计算结果
  458. INT fResult1;
  459. INT fResult2;
  460. INT fResult;
  461. // 找到DIB图像象素起始位置
  462. lpDIBBits = ::FindDIBBits(lpDIB);
  463. lWidth = ::DIBWidth(lpDIB);   //DIB 宽度
  464. lHeight = ::DIBHeight(lpDIB); //DIB 高度
  465. // 计算图像每行的字节数
  466. lLineBytes = WIDTHBYTES(lWidth * 8);
  467. // 暂时分配内存,以保存新图像
  468. hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight);
  469. // 判断是否内存分配失败
  470. if (hNewDIBBits == NULL)
  471. {
  472. // 分配内存失败
  473. return false;
  474. }
  475. // 锁定内存
  476. lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
  477. // 初始化图像为原始图像
  478. memcpy(lpNewDIBBits, lpDIBBits, lLineBytes * lHeight);
  479. long i,j;           //循环变量
  480. //
  481. //不对边缘进行处理
  482. for(i = 0; i < lHeight; i++)
  483. {
  484. // 每列
  485. for(j = 0; j < lWidth; j++)
  486. {
  487. // 指向新DIB第i行,第j个象素的指针
  488. lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  489. // 指向DIB第i行,第j个象素的指针
  490. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  491. fResult1=abs((*lpSrc)-(*(lpSrc+1)));
  492. fResult2=abs((*lpSrc)-(*(lpSrc+lWidth)));
  493. if(fResult1 < fResult2)
  494. fResult = fResult2;
  495. else fResult = fResult1;
  496. // 取绝对值
  497. if(fResult<0) fResult=-fResult;
  498. // 判断是否超过255
  499. if(fResult > 255)
  500. {
  501. // 直接赋值为255
  502. * lpDst = 255;
  503. }
  504. else
  505. {
  506. // 赋值
  507. * lpDst = (unsigned char) (fResult + 0.5);
  508. }
  509. }
  510. }
  511. // 复制变换后的图像
  512. memcpy(lpDIBBits, lpNewDIBBits, lLineBytes * lHeight);
  513. // 释放内存
  514. LocalUnlock(hNewDIBBits);
  515. LocalFree(hNewDIBBits);
  516. // 返回
  517. return TRUE;
  518. }
  519. /*************************************************************************
  520. *
  521. * 函数名称:
  522. *   myCropDIB()
  523. *
  524. * 参数:
  525. *   HDIB hDIB          - 指向源DIB图像句柄
  526. *   LPRECT lpRect      - 指向要剪裁的矩形区域
  527. *
  528. * 返回值:
  529. *   HDIB               - 返回裁剪后的矩形区域图像句柄。
  530. *
  531. * 说明:
  532. * 该函数用于对指定图像进行指定区域裁剪操作。
  533. * 要求目标图像为255个灰度值的灰度图像。
  534. ************************************************************************/
  535. HDIB WINAPI myCropDIB(HDIB hDIB, LPRECT lpRect)
  536. {
  537. LPBITMAPINFO lpbmi = NULL; 
  538.     LPBYTE       lpSourceBits, lpTargetBits, lpResult; 
  539.     HDC  hDC = NULL, hSourceDC, hTargetDC; 
  540.     HBITMAP      hSourceBitmap, hTargetBitmap, hOldTargetBitmap, hOldSourceBitmap; 
  541.     DWORD        dwSourceBitsSize, dwTargetBitsSize, dwTargetHeaderSize; 
  542. int  nWidth, nHeight;
  543. HDIB  hNewDIB;
  544. DWORD  dwSize;
  545. // Get DIB pointer
  546. if (! hDIB)
  547. {
  548. return NULL;
  549. }
  550. LPBITMAPINFO lpSrcDIB = (LPBITMAPINFO)GlobalLock(hDIB);
  551. if (! lpSrcDIB)
  552. {
  553. return NULL;
  554. }
  555.     // Allocate and fill out a BITMAPINFO struct for the new DIB 
  556.     dwTargetHeaderSize = sizeof( BITMAPINFOHEADER ) + PaletteSize((LPSTR)lpSrcDIB); 
  557.     lpbmi = (LPBITMAPINFO)malloc( dwTargetHeaderSize ); 
  558. memcpy(lpbmi, lpSrcDIB, dwTargetHeaderSize);
  559. nWidth = RECTWIDTH(lpRect);
  560. nHeight = RECTHEIGHT(lpRect);
  561.     lpbmi->bmiHeader.biWidth = nWidth; 
  562.     lpbmi->bmiHeader.biHeight = nHeight; 
  563.     // Gonna use DIBSections and BitBlt() to do the conversion, so make 'em 
  564. hDC = ::GetDC( NULL ); 
  565.     hTargetBitmap = CreateDIBSection( hDC, lpbmi, DIB_RGB_COLORS, (VOID **)&lpTargetBits, NULL, 0 ); 
  566.     hSourceBitmap = CreateDIBSection( hDC, lpSrcDIB, DIB_RGB_COLORS, (VOID **)&lpSourceBits, NULL, 0 ); 
  567.     hSourceDC = CreateCompatibleDC( hDC ); 
  568.     hTargetDC = CreateCompatibleDC( hDC ); 
  569.     // Flip the bits on the source DIBSection to match the source DIB 
  570.     dwSourceBitsSize = lpSrcDIB->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpSrcDIB->bmiHeader)); 
  571.     dwTargetBitsSize = lpbmi->bmiHeader.biHeight * BytesPerLine((LPBYTE)&(lpbmi->bmiHeader)); 
  572.     memcpy( lpSourceBits, FindDIBBits((LPSTR)lpSrcDIB), dwSourceBitsSize ); 
  573.     lpbmi->bmiHeader.biSizeImage = dwTargetBitsSize; 
  574.     // Select DIBSections into DCs 
  575.     hOldSourceBitmap = (HBITMAP)SelectObject( hSourceDC, hSourceBitmap ); 
  576.     hOldTargetBitmap = (HBITMAP)SelectObject( hTargetDC, hTargetBitmap ); 
  577. // put old bitmap in new bitmap 
  578.     BitBlt(hTargetDC, 0, 0, nWidth, nHeight, hSourceDC, lpRect->left, lpRect->top, SRCCOPY); 
  579.     // Clean up and delete the DCs 
  580.     SelectObject( hSourceDC, hOldSourceBitmap ); 
  581.     SelectObject( hTargetDC, hOldTargetBitmap ); 
  582.     DeleteDC( hSourceDC ); 
  583.     DeleteDC( hTargetDC ); 
  584.     ::ReleaseDC( NULL, hDC ); 
  585.     // Flush the GDI batch, so we can play with the bits 
  586.     GdiFlush(); 
  587.     // Allocate enough memory for the new CF_DIB, and copy bits 
  588. dwSize = dwTargetHeaderSize + dwTargetBitsSize;
  589. hNewDIB =(HDIB)GlobalAlloc(GHND, dwSize);
  590.     lpResult = (LPBYTE)GlobalLock(hNewDIB);//malloc( dwTargetHeaderSize + dwTargetBitsSize ); 
  591.     memcpy( lpResult, lpbmi, dwTargetHeaderSize ); 
  592.     memcpy( FindDIBBits( (LPSTR)lpResult ), lpTargetBits, dwTargetBitsSize ); 
  593.     // final cleanup 
  594.     DeleteObject( hTargetBitmap ); 
  595.     DeleteObject( hSourceBitmap ); 
  596.     free( lpbmi ); 
  597. GlobalUnlock(hDIB);
  598. GlobalUnlock(hNewDIB);
  599.     return hNewDIB;
  600. }
  601. /*************************************************************************
  602. *
  603. * 函数名称:
  604. *   MedianFilter()
  605. *
  606. * 参数:
  607. *   LPSTR lpDIBBits - 指向源DIB图像指针
  608. *   LONG  lWidth - 源图像宽度(象素数)
  609. *   LONG  lHeight - 源图像高度(象素数)
  610. *   int   iFilterH - 滤波器的高度
  611. *   int   iFilterW - 滤波器的宽度
  612. *   int   iFilterMX - 滤波器的中心元素X坐标
  613. *   int   iFilterMY - 滤波器的中心元素Y坐标
  614. *
  615. * 返回值:
  616. *   BOOL - 成功返回TRUE,否则返回FALSE。
  617. *
  618. * 说明:
  619. *   该函数对DIB图像进行中值滤波。
  620. *
  621. ************************************************************************/
  622. BOOL WINAPI myMedianFilter(LPSTR lpDIBBits, LONG lWidth, LONG lHeight, 
  623.    int iFilterH, int iFilterW, 
  624.    int iFilterMX, int iFilterMY)
  625. {
  626. // 指向源图像的指针
  627. unsigned char* lpSrc;
  628. // 指向要复制区域的指针
  629. unsigned char* lpDst;
  630. // 指向复制图像的指针
  631. LPSTR lpNewDIBBits;
  632. HLOCAL hNewDIBBits;
  633. // 指向滤波器数组的指针
  634. unsigned char * aValue;
  635. HLOCAL hArray;
  636. // 循环变量
  637. LONG i;
  638. LONG j;
  639. LONG k;
  640. LONG l;
  641. // 图像每行的字节数
  642. LONG lLineBytes;
  643. // 计算图像每行的字节数
  644. lLineBytes = WIDTHBYTES(lWidth * 8);
  645. // 暂时分配内存,以保存新图像
  646. hNewDIBBits = LocalAlloc(LHND, lLineBytes * lHeight);
  647. // 判断是否内存分配失败
  648. if (hNewDIBBits == NULL)
  649. {
  650. // 分配内存失败
  651. return FALSE;
  652. }
  653. // 锁定内存
  654. lpNewDIBBits = (char * )LocalLock(hNewDIBBits);
  655. // 初始化图像为原始图像
  656. memcpy(lpNewDIBBits, lpDIBBits, lLineBytes * lHeight);
  657. // 暂时分配内存,以保存滤波器数组
  658. hArray = LocalAlloc(LHND, iFilterH * iFilterW);
  659. // 判断是否内存分配失败
  660. if (hArray == NULL)
  661. {
  662. // 释放内存
  663. LocalUnlock(hNewDIBBits);
  664. LocalFree(hNewDIBBits);
  665. // 分配内存失败
  666. return FALSE;
  667. }
  668. // 锁定内存
  669. aValue = (unsigned char * )LocalLock(hArray);
  670. // 开始中值滤波
  671. // 行(除去边缘几行)
  672. for(i = iFilterMY; i < lHeight - iFilterH + iFilterMY + 1; i++)
  673. {
  674. // 列(除去边缘几列)
  675. for(j = iFilterMX; j < lWidth - iFilterW + iFilterMX + 1; j++)
  676. {
  677. // 指向新DIB第i行,第j个象素的指针
  678. lpDst = (unsigned char*)lpNewDIBBits + lLineBytes * (lHeight - 1 - i) + j;
  679. // 读取滤波器数组
  680. for (k = 0; k < iFilterH; k++)
  681. {
  682. for (l = 0; l < iFilterW; l++)
  683. {
  684. // 指向DIB第i - iFilterMY + k行,第j - iFilterMX + l个象素的指针
  685. lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i + iFilterMY - k) + j - iFilterMX + l;
  686. // 保存象素值
  687. aValue[k * iFilterW + l] = *lpSrc;
  688. }
  689. }
  690. // 获取中值
  691. * lpDst = myGetMedianNum(aValue, iFilterH * iFilterW);
  692. }
  693. }
  694. // 复制变换后的图像
  695. memcpy(lpDIBBits, lpNewDIBBits, lLineBytes * lHeight);
  696. // 释放内存
  697. LocalUnlock(hNewDIBBits);
  698. LocalFree(hNewDIBBits);
  699. LocalUnlock(hArray);
  700. LocalFree(hArray);
  701. // 返回
  702. return TRUE;
  703. }
  704. /*************************************************************************
  705. *
  706. * 函数名称:
  707. *   GetMedianNum()
  708. *
  709. * 参数:
  710. *   unsigned char * bpArray - 指向要获取中值的数组指针
  711. *   int   iFilterLen - 数组长度
  712. *
  713. * 返回值:
  714. *   unsigned char      - 返回指定数组的中值。
  715. *
  716. * 说明:
  717. *   该函数用冒泡法对一维数组进行排序,并返回数组元素的中值。
  718. *
  719. ************************************************************************/
  720. unsigned char WINAPI myGetMedianNum(unsigned char * bArray, int iFilterLen)
  721. {
  722. // 循环变量
  723. int i;
  724. int j;
  725. // 中间变量
  726. unsigned char bTemp;
  727. // 用冒泡法对数组进行排序
  728. for (j = 0; j < iFilterLen - 1; j ++)
  729. {
  730. for (i = 0; i < iFilterLen - j - 1; i ++)
  731. {
  732. if (bArray[i] > bArray[i + 1])
  733. {
  734. // 互换
  735. bTemp = bArray[i];
  736. bArray[i] = bArray[i + 1];
  737. bArray[i + 1] = bTemp;
  738. }
  739. }
  740. }
  741. // 计算中值
  742. if ((iFilterLen & 1) > 0)
  743. {
  744. // 数组有奇数个元素,返回中间一个元素
  745. bTemp = bArray[(iFilterLen + 1) / 2];
  746. }
  747. else
  748. {
  749. // 数组有偶数个元素,返回中间两个元素平均值
  750. bTemp = (bArray[iFilterLen / 2] + bArray[iFilterLen / 2 + 1]) / 2;
  751. }
  752. // 返回中值
  753. return bTemp;
  754. }
  755. /***************************************************************************
  756. ***************************************************************************/
  757. BOOL WINAPI myFindRightAngle(CDC* pDC,LPSTR lpDIB,int* iLeft,int* iTop,int* iRight,int* iBottom)
  758. {
  759. LPSTR lpDIBBits;                   //指向DIB的象素的指针
  760.     LONG lLineBytes;                   // 图像每行的字节数
  761. unsigned char * lpSrc;             //指向原图像象素点的指针
  762. unsigned char pixel = 0; //像素值
  763. long lWidth;                       //图像宽度和高度
  764. long lHeight;
  765. int i = 0,j = 0;
  766. int lineRequired = 12;//确定一条直线至少要18个象素
  767. int lineLimited  = 20;//为确定一条直线应该扫描25个象素
  768. int linePixelCount = 0;//已扫描到的灰度值为255的象素点
  769. int pixelCount = 0;//扫描象素时的循环变量
  770. CPen newRedPen(PS_SOLID,2,RGB(255,0,0));
  771. pDC->SelectObject(newRedPen);
  772. HGDIOBJ brush=GetStockObject(NULL_BRUSH);
  773. pDC->SelectObject((HBRUSH)GetStockObject(NULL_BRUSH));
  774.     //INT pzBottom,pzTop,pzLeft,pzRight;
  775. struct topLeftCorner {
  776. int pzTop;
  777. int pzLeft;
  778. }topLeft[1000];
  779. struct bottomRightCorner {
  780. int pzBottom;
  781. int pzRight;
  782. }bottomRight[1000];
  783. int  tlCount = 0;//左上角数组的索引
  784. int  brCount = 0;//右下角数组的索引
  785. bool findTL=false;                  //是否找到左上角
  786. bool findBR=false;                  //是否找到右下角
  787. // 找到DIB图像象素起始位置
  788. lpDIBBits = ::FindDIBBits(lpDIB);
  789. lWidth = ::DIBWidth(lpDIB);   //DIB 宽度
  790. lHeight = ::DIBHeight(lpDIB); //DIB 高度
  791. // 计算图像每行的字节数
  792. lLineBytes = WIDTHBYTES(lWidth * 8);
  793. for(i = 0;i < 100;i++)
  794. {
  795. topLeft[i].pzTop = 0;
  796. topLeft[i].pzLeft = 0;
  797. }
  798. for(i = 0;i < 100;i++)
  799. {
  800. bottomRight[i].pzBottom = 0;
  801. bottomRight[i].pzRight = 0;
  802. }
  803.     //计算左上角的位置,可能有多个,保存在topLeft数组中
  804. for(i = 30;i < lHeight - 30;i++)//考虑到车牌的大小,在边缘一定范围内可以不考虑
  805. {
  806. linePixelCount = 0;
  807. for(j = 30;j < lWidth - 30 ;j++)
  808. {
  809. linePixelCount = 0;
  810. for(pixelCount = j;pixelCount < (j + lineLimited);pixelCount++)//计算直线
  811. {
  812. lpSrc=(unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + pixelCount;
  813.     pixel=(unsigned char)(*lpSrc);
  814.     if(pixel == 255)
  815. {
  816.     linePixelCount++;
  817. //pDC->MoveTo(j,i);
  818.     //pDC->LineTo(j,i);
  819. }
  820. }
  821. /*if(linePixelCount >= lineRequired)
  822. {
  823. pDC->MoveTo(j,i);
  824. pDC->LineTo(j,i);
  825. }*/
  826. if(linePixelCount >= lineRequired)
  827. {
  828. linePixelCount = 0;
  829. for(pixelCount = i;pixelCount < (i + lineLimited);pixelCount++)
  830. {
  831. lpSrc=(unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - pixelCount) + j;
  832.         pixel=(unsigned char)(*lpSrc);
  833.         if(pixel == 255)
  834. {
  835.         linePixelCount++;
  836. //pDC->MoveTo(j,i);
  837.         //pDC->LineTo(j,i);
  838. }
  839. }
  840. }
  841. if(linePixelCount >= lineRequired)
  842. {
  843. findTL = true;
  844. }
  845. if(findTL)
  846. {
  847. findTL = false;
  848. linePixelCount = 0;
  849. topLeft[tlCount].pzTop = i;
  850. topLeft[tlCount].pzLeft = j;
  851. pDC->MoveTo(j,i);
  852. pDC->LineTo(j,i);
  853. tlCount++;
  854. }
  855. }
  856. }
  857.     CPen newGreenPen(PS_SOLID,2,RGB(0,255,0));
  858. pDC->SelectObject(newGreenPen);
  859. //计算右下角的位置,可能有多个,保存在bottomRight数组中
  860. linePixelCount = 0;//重新初始化计数器
  861. for(i = 10;i < lHeight - 10;i++)//考虑到车牌的大小,在边缘一定范围内可以不考虑
  862. {
  863. linePixelCount = 0;
  864. for(j = 20;j < lWidth - 20;j++)
  865. {
  866. linePixelCount = 0;
  867. for(pixelCount = j;pixelCount < (j + lineLimited);pixelCount++)//计算直线
  868. {
  869. lpSrc=(unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - i) + pixelCount;
  870.     pixel=(unsigned char)(*lpSrc);
  871.     if(pixel == 255)
  872. {
  873.     linePixelCount++;
  874. }
  875. }
  876. if(linePixelCount >= lineRequired)
  877. {
  878. linePixelCount = 0;
  879. for(pixelCount = i;pixelCount > (i - lineLimited);pixelCount--)
  880. {
  881. lpSrc=(unsigned char*)lpDIBBits + lLineBytes * (lHeight - 1 - pixelCount) + lineRequired + j;
  882.         pixel=(unsigned char)(*lpSrc);
  883.         if(pixel == 255)
  884. {
  885.         linePixelCount++;
  886. }
  887. }
  888. if(linePixelCount >= lineRequired)
  889. {
  890. findBR = true;
  891. }
  892. }
  893. if(findBR)
  894. {
  895. findBR = false;
  896. linePixelCount = 0;
  897. bottomRight[brCount].pzBottom = i;
  898. bottomRight[brCount].pzRight = j + lineRequired;
  899. pDC->MoveTo(j + lineRequired,i);
  900. pDC->LineTo(j + lineRequired,i);
  901. brCount++;
  902. }
  903. }
  904. }
  905.     
  906.     //计算车牌的位置
  907. int plateUpHeight = 50;
  908. int plateDownHeight = 30;
  909. int plateUpWidth = 100;
  910. int plateDownWidth = 80;
  911. bool plateFind = false;
  912. for(i = 0;i < tlCount;i++)
  913. {
  914. for(j = brCount - 1 ;j >= 0;j--)
  915. {
  916. if((bottomRight[j].pzBottom - topLeft[i].pzTop > plateDownHeight) &&
  917. (bottomRight[j].pzBottom - topLeft[i].pzTop < plateUpHeight) && 
  918. (bottomRight[j].pzRight - topLeft[i].pzLeft > plateDownWidth) && 
  919. (bottomRight[j].pzRight - topLeft[i].pzLeft < plateUpWidth) &&
  920. (double(bottomRight[j].pzRight - topLeft[i].pzLeft) / (bottomRight[j].pzBottom - topLeft[i].pzTop)) > 2)
  921. {
  922. *iTop = topLeft[i].pzTop;
  923. *iLeft = topLeft[i].pzLeft;
  924. *iBottom = bottomRight[j].pzBottom + 10;
  925. *iRight = bottomRight[j].pzRight + 15;
  926. plateFind = true;
  927. break;
  928. }
  929. else
  930. {
  931. //i++;
  932. //j--;
  933. }
  934. }
  935. if(plateFind) break;
  936. }
  937. /**iTop = topLeft[0].pzTop;
  938. *iLeft = topLeft[0].pzLeft;
  939. *iBottom = bottomRight[0].pzBottom;
  940. *iRight = bottomRight[0].pzRight;*/
  941. return true;
  942. }
  943. /*************************************************************************
  944. *在图像上画一个矩形
  945. *
  946. *
  947. *
  948. *************************************************************************/
  949. BOOL WINAPI DrawRectangle(CDC* pDC,int iLeft,int iTop,int iRight,int iBottom)
  950. {
  951. CPen newPen(PS_SOLID,2,RGB(255,0,0));
  952. pDC->SelectObject(newPen);
  953. HGDIOBJ brush=GetStockObject(NULL_BRUSH);
  954. pDC->SelectObject((HBRUSH)GetStockObject(NULL_BRUSH));
  955. pDC->Rectangle(iLeft,iTop,iRight,iBottom);
  956. return true;
  957. }