Hausdorff距离匹配算法及代码,特征点进行匹配得出目标区域,但是不具有区域自适应。

1、例说hausdorff距离

定欧氏空间中的两点集  ,Hausdorff距离就是用来衡量这两个点集间的距离。

  其中, , 。 称为双向Hausdorff距离, 称为从点集A到点集B的单向Hausdorff距离。相应地 称为从点集B到点集A的单向Hausdorff距离。

       下面从一个例子来理解Hausdorff距离。

   

  上图中,给出了A,B,C,D四条路径,其中路径A具体为(16-17-18-19-20),路径B具体为(1-2-3-4-9-10)。要求Hausdorff距离 ,则需要先求出单向Hausdorff距离  。

  对于 ,以A中的点16为例,在路径B中的所有点中,距离点16最近的是点1,距离为3。即 alt= 。同理由图可得 , , , 。在它们中,值最大的为3,故  。

  同理可得, 。

  所以 。

  同理可求出上图中四条路径间的单向Hausdorff距离如下表所示:

  

 

  双向Hausdorff距离 是单向Hausdorff距离 和 两者中的较大者,显然它度量了两个点集间的最大不匹配程度。

  

  当A,B都是闭集的时候,Hausdorff距离满足度量的三个定理:

  (1) ,当且仅当A=B时, 。

  (2)     

  (3)     

  

  若凸集A,B满足 且 ,并记 , 分别为A,B边界的点集合,则A,B的Hausdorff距离等于 , 的Hausdorff距离。

 

  Hausdorff距离易受到突发噪声的影响。

  

  当图像受到噪声污染或存在遮挡等情况时,原始的Haudorff距离容易造成误匹配。所以,在1933年,Huttenlocher提出了部分Hausdorff距离的概念。

  简单地说,包含q个点的集合B与集合A的部分Hausdorff距离就是选取B中的K( 且  )个点,然后求这K个点到A集合的最小距离并排序,则排序后的第K个值就是集合B到集合A的部分单向Hausdorff距离。定义公式如下:

  相应地,部分双向Hausdorff距离定义为:


     注意:

a、下面代码画出的目标区域的大小是不会自适应的,其大小是跟模板区域的大小;

b、这里的特征点距离匹配是不具有旋转不变性的,其实特征点、Hausdorf都具有旋转不变性,只是这两者的结合导致了这种结果,如果使用轮廓曲率跟Hausdorf的话是具有旋转不变性,其距离就是曲率值的大小差

c、其距离计算的temp = distance(pMPoints, pSPoints, numModel, numSrc);  里pSPoints是一个感兴趣区域,其大小跟pMPoints大小一样,这样在不断移动过


程中会得到一个最佳的位置。



2016年11月29日更新:

该代码已托管到GitHub,最新代码请从GitHub 下载
1. 修复了match()函数内一个导致内存泄漏的bug.

2015年9月16日更新:

添加CFeatures类,用于获取特征点,实现了CANNY、HARRIS、SIFT、SURF特征点的获取,添加了实时匹配例程。

已知BUG:
1.使用HARRIS、SIFT、SURF提取特征点时,Debug版本耗时非常长,release版本正常
2.使用HARRIS、SIFT、SURF提取特征点时,CFeatures类不能正确析构,初步判断是dll和EXE堆释放错误,
而且出错点很可能是 m_vecPoints向量问题

如有知道原因,还望不吝赐教。

/************************************************************************************************************************************/

2015年9月10上传

以下是我实现的Hausdorff  distance距离匹配 C++ 类,构造函数如下:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. CHausdorff(IplImage *srcImg, IplImage *modelImge,   
  2.         int xInterval = 1, int yInterval = 1,   
  3.         double frontRange = 0.8, double backRange = 0.7);  
  1. 当frontRange = 1,backRange = 1,并使用sort()函数时,该类退化成原始Hausforff distance定义的匹配方法
  2. 当frontRange ,backRange 取值为0~1之间,并使用sort函数时,该类为改进型hausdorff distance:部分hausdorff distance.
  3. 当frontRange ,backRange 取值任意,并使用meanDistance()函数时,该类为改进型hausdorff distance:平均hausdorff distance.

以下C++代码在VS2010 + OpenCV2.4.8下调试通过,

附上代码:

CHausdorff类定义如下:

CHausdorff.h 文件:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /****************************************** 
  2. * Copyright (C) 2015 HolaMirai(HolaMirai@163.com) 
  3. * All rights reserved. 
  4.  
  5. * 文件名:hausdorff.h 
  6. * 摘要:寻找Hausdorff Distance度量的最匹配位置和最匹配位置的距离 
  7. * 当前版本:<V1.0>,<完成日期:2015年9月7日>,<HolaMirai>,<创建该文件> 
  8. * 历史记录:... 
  9. ******************************************/  
  10.   
  11.   
  12. /* 
  13. * 类定义说明 
  14. */  
  15. /******************************************** 
  16. * CHausforff类 
  17. * CHausdorff类接受带匹配图、模板图的二值化图像或包含特征点二值化图像,参数都带有默认值 
  18. * 使用match函数可以直接获取匹配结果 
  19. * hausdorff distance 采用部分距离法,对遮挡、噪声效果良好,也可以采用平均距离法 
  20. * 匹配过程分为粗匹配和精匹配个过程 
  21. * 各函数已经解耦,可以单独调用某个函数以观察hausdorff distance 方法的各部分 
  22. ********************************************/  
  23.   
  24. #ifndef CHAUSDORFF_H  
  25. #define CHAUSDORFF_H  
  26.   
  27. /* 
  28. * 宏定义 
  29. */  
  30. // 最大距离  
  31. #define MAX_DISTANCE INT_MAX  
  32.   
  33. #include "cv.h"  
  34.   
  35. /* 
  36. *  类定义 
  37. */  
  38. class CHausdorff  
  39. {  
  40. public:  
  41.     CHausdorff( IplImage *modelImge, IplImage *srcImg = NULL,  
  42.                 int xInterval = 1, int yInterval = 1,   
  43.                 double frontRange = 0.8, double backRange = 0.7);  
  44.     ~CHausdorff();  
  45.   
  46. public:  
  47.     void setSourceImage(IplImage *srcImg);  
  48.     //void setModelImage(IplImage *modelImg);  
  49.   
  50.     void setScanInterval_X(int xInterval);  
  51.      void setScanInterval_Y(int yInterval);  
  52.   
  53.      void setFrontRange(double Range);  
  54.      void setBackRange(double Range);  
  55.   
  56.      double computeDirDistance(CvPoint Apoints[], CvPoint Bpoints[], int numA, int numB, double Range) const;  
  57.      double distance(CvPoint Apoints[], CvPoint Bpoints[], int numA, int numB) const;  
  58.        
  59.      void match();  
  60.      void drawMatch(const char *name, IplImage *img = NULL);  
  61.   
  62. private:  
  63.     int searchPoints(IplImage *img, CvPoint pPoints[]) const;  
  64.   
  65.     void sort(double a[],int n) const;  
  66.     double meanDistance(double a[], int n) const;  
  67.   
  68.     void createTable();  
  69.     void freeTable();  
  70.   
  71. public:  
  72.     //记录匹配结果  
  73.     CvPoint m_matchPoint;  
  74.     double  m_matchDistance;  
  75.   
  76. private:  
  77.     int m_xInterval;  
  78.     int m_yInterval;  
  79.     double m_frontRange;  
  80.     double m_backRange;  
  81.   
  82.     //距离变换表指针  
  83.     double **m_disTable;  
  84.   
  85. public:  
  86.     IplImage *m_srcImg;  
  87.     IplImage *m_modelImg;  
  88. };  
  89.   
  90. #endif  

CHausdorff.cpp文件:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /****************************************** 
  2. * Copyright (C) 2015 HolaMirai(HolaMirai@163.com) 
  3. * All rights reserved. 
  4.  
  5. * 文件名:hausdorff.cpp 
  6. * 摘要:寻找Hausdorff Distance度量的最匹配位置和最匹配位置的距离 
  7. * 当前版本:V2.1, 2015年9月11日,HolaMirai, 添加 createTable()、freeTable()函数,添加平均hausdorff距离方法,添加注释 
  8. * 历史记录:V2.0, 2015年9月10日,HolaMirai, 调试完成该文件&添加meanDistance()函数 
  9. *         :V1.0, 2015年9月7日, HolaMirai, 创建该文件 
  10. ******************************************/  
  11.   
  12. /* 
  13. * TBD:  1.改用Voronoi图进行Hausdorff距离计算 
  14. */  
  15.   
  16. #include "CHausdorff.h"  
  17. #include "highgui.h"  
  18.   
  19. /* 
  20. * 函数名称:CHausdorff 
  21. * 函数功能:类构造函数 
  22. * 函数入口:  
  23. * 输入参数: 待匹配图、模板二值化图像,粗匹配横、纵坐标扫描间隔 xInterval,yInterval  
  24. *            前向距离因子 frontRange,后向距离因子 backRange 
  25. * 输出参数:无 
  26. * 返 回 值: 
  27. * 其它说明:  
  28. */  
  29. CHausdorff::CHausdorff(IplImage *modelImg, IplImage *srcImg, int xInterval, int yInterval, double frontRange, double backRange)  
  30. {  
  31.     m_modelImg = cvCloneImage(modelImg);  
  32.     m_srcImg = cvCloneImage(srcImg);  
  33.   
  34.     m_frontRange = frontRange;  
  35.     m_backRange = backRange;  
  36.     m_xInterval = xInterval;  
  37.     m_yInterval = yInterval;  
  38.   
  39.     createTable();  
  40. }  
  41.   
  42. CHausdorff::~CHausdorff()  
  43. {  
  44.     freeTable();  
  45.   
  46.     m_srcImg = NULL;  
  47.     cvReleaseImage(&m_modelImg);  
  48.       
  49. }  
  50.   
  51. /* 
  52. * 函数名称:setSourceImage 
  53. * 函数功能:设置待匹配图像 
  54. * 函数入口:  
  55. * 输入参数: 待匹配图像指针 
  56. * 输出参数: 
  57. * 返 回 值:void 
  58. * 其它说明:  
  59. */  
  60. void CHausdorff::setSourceImage(IplImage *srcImg)  
  61. {  
  62.     assert(srcImg->nChannels == 1);  
  63.     m_srcImg = srcImg;  
  64. }  
  65.   
  66. /* 
  67. * 函数名称:setModelImage 
  68. * 函数功能:设置待模板图像 
  69. * 函数入口:  
  70. * 输入参数: 模板图像指针 
  71. * 输出参数: 
  72. * 返 回 值:void 
  73. * 其它说明: 若是用查表法计算距离,请不要改变模板图,即不要调用该函数 
  74. */  
  75. /* 
  76. void CHausdorff::setModelImage(IplImage *modelImg) 
  77. { 
  78.     assert(modelImg->nChannels == 1); 
  79.     m_modelImg = modelImg; 
  80. } 
  81. */  
  82. /* 
  83. * 函数名称:setScanInterval_X 
  84. * 函数功能:设置粗匹配X坐标扫描间隔 
  85. * 函数入口:  
  86. * 输入参数: 粗匹配横坐标扫描间隔 xInterval 
  87. * 输出参数:无 
  88. * 返 回 值:void 
  89. * 其它说明:  
  90. */  
  91. void CHausdorff::setScanInterval_X(int xInterval)  
  92. {  
  93.     m_xInterval = xInterval;  
  94. }  
  95.   
  96. /* 
  97. * 函数名称:setScanInterval_Y 
  98. * 函数功能:设置粗匹配Y坐标扫描间隔 
  99. * 函数入口:  
  100. * 输入参数: 粗匹配横坐标扫描间隔 yInterval 
  101. * 输出参数:无 
  102. * 返 回 值:void 
  103. * 其它说明:  
  104. */  
  105. void CHausdorff::setScanInterval_Y(int yInterval)  
  106. {  
  107.     m_yInterval = yInterval;  
  108. }  
  109.   
  110. /* 
  111. * 函数名称:setFrontRange 
  112. * 函数功能:设置前向匹配距离因子 
  113. * 函数入口:  
  114. * 输入参数: 前向匹配距离因子 Range 
  115. * 输出参数:无 
  116. * 返 回 值:void 
  117. * 其它说明:  
  118. */  
  119. void CHausdorff::setFrontRange(double Range)  
  120. {  
  121.     m_frontRange = Range;  
  122. }  
  123.   
  124. /* 
  125. * 函数名称:setFrontRange 
  126. * 函数功能:设置后向匹配距离因子 
  127. * 函数入口:  
  128. * 输入参数: 前向匹配距离因子 Range 
  129. * 输出参数:无 
  130. * 返 回 值:void 
  131. * 其它说明:  
  132. */  
  133. void CHausdorff::setBackRange(double Range)  
  134. {  
  135.     m_backRange = Range;  
  136. }  
  137.   
  138. /* 
  139. * 函数名称:searchPoints 
  140. * 函数功能:获得特征点坐标和特征点的个数 
  141. * 函数入口:  
  142. * 输入参数: 灰度图 img, 接受特征点的数组指针 
  143. * 输出参数:无 
  144. * 返 回 值: 特征点个数 
  145. * 其它说明: 支持图片 ROI 
  146. */  
  147. int CHausdorff::searchPoints(IplImage *img, CvPoint pPoints[]) const  
  148. {  
  149.     CvRect rect;  
  150.     if ( !img->roi)  
  151.     {  
  152.         rect.x = 0;  
  153.         rect.y = 0;  
  154.         rect.width = img->width;  
  155.         rect.height = img->height;  
  156.     }  
  157.     else  
  158.     {  
  159.         rect.x = img->roi->xOffset;  
  160.         rect.y = img->roi->yOffset;  
  161.         rect.width = img->roi->width;  
  162.         rect.height = img->roi->height;  
  163.     }  
  164.   
  165.     //统计特征点  
  166.     uchar *ptr;  
  167.     int num = 0;  
  168.     for (int i = rect.y; i < rect.y + rect.height; i++)  
  169.     {  
  170.         ptr = (uchar *) (img->imageData + i * img->widthStep);  
  171.         for (int j = rect.x; j < rect.x + rect.width; j++)  
  172.         {  
  173.             if (ptr[j] != 0)  
  174.             {  
  175.                 num++;  
  176.             }  
  177.         }  
  178.     }  
  179.   
  180.     if (num == 0)  
  181.     {  
  182.         return 0;  
  183.     }  
  184.   
  185.     num = 0;  
  186.     for (int i = rect.y; i < rect.y + rect.height; i++)  
  187.     {  
  188.         ptr = (uchar *) (img->imageData + i * img->widthStep);  
  189.         for (int j = rect.x; j < rect.x + rect.width; j++)  
  190.         {  
  191.             if (ptr[j] != 0)  
  192.             {  
  193.                 pPoints[num].x = j - rect.x;  
  194.                 pPoints[num].y = i - rect.y;  
  195.                 num++;  
  196.             }  
  197.         }  
  198.     }  
  199.   
  200.     //结果返回  
  201.     return num;  
  202. }/*searchPoints()*/  
  203.   
  204.   
  205. /* 
  206. * 函数名称:match 
  207. * 函数功能:利用 Hausdorff distance 值来匹配图片 
  208. * 函数入口:  
  209. * 输入参数:无 
  210. * 输出参数:最佳匹配位置 和最佳匹配距离 
  211. * 返 回 值: void 
  212. * 其它说明:  
  213. */  
  214. void CHausdorff::match()  
  215. {  
  216.     int ws, hs, wm, hm, numModel, numSrc;  
  217.     CvRect rect;  
  218.     double *matchDis = new double[100];  //假定最大会有100个最佳位置,这里并未实现,留着以后改进  
  219.     CvPoint *matchPoints = new CvPoint[100];  
  220.     double temp = MAX_DISTANCE;  
  221.     double dis = MAX_DISTANCE;  
  222.     int n = 0;  //只有一个最佳位置,本文的假设前提  
  223.   
  224.   
  225.     ws = m_srcImg->width;  
  226.     hs = m_srcImg->height;  
  227.     wm = m_modelImg->width;  
  228.     hm = m_modelImg->height;  
  229.   
  230.     // 存储模板特征点和原图像特征点  
  231.     CvPoint *pMPoints = new CvPoint[wm * hm];  
  232.     CvPoint *pSPoints = new CvPoint[wm * hm];  
  233.   
  234.     //获得模板特征点  
  235.     numModel = searchPoints(m_modelImg,pMPoints);  
  236.   
  237.     if (numModel == 0)  
  238.     {  
  239.         printf_s("find no points in model");  
  240.         return;  
  241.     }  
  242.   
  243.     //搜索最佳匹配  
  244.     rect.width = wm;  
  245.     rect.height = hm;  
  246.       
  247.     // 粗匹配  
  248.     //#pragma omp parallel for firstprivate(m_srcImg)     //并行运算  
  249.     for (int i = 0; i < ws; i += m_xInterval)  
  250.     {  
  251.         rect.x = i;  
  252.         //#pragma omp parallel for   
  253.         for (int j = 0; j < hs; j += m_yInterval)  
  254.         {  
  255.             rect.y = j;  
  256.             cvSetImageROI(m_srcImg,rect);  
  257.             numSrc = searchPoints(m_srcImg,pSPoints);  
  258.             if (numSrc == 0)  
  259.             {  
  260.                 continue;  
  261.             }  
  262.             // 特征点数据量相差太大则忽略该位置,可以依具体情况调整参数  
  263.             if (double(numSrc)/numModel < 0.8 || (double)numSrc/numModel > 1.25)  
  264.             {  
  265.                 continue;  
  266.             }  
  267.   
  268.             temp = distance(pMPoints, pSPoints, numModel, numSrc);  
  269.             // min  
  270.             if (temp < dis)  
  271.             {  
  272.                 dis = temp;  
  273.                 matchDis[n] = temp;  
  274.                 matchPoints[n].x = i;  
  275.                 matchPoints[n].y = j;  
  276.             }     
  277.         }  
  278.     }  
  279.   
  280.     //精匹配  
  281.     for (int i = matchPoints[n].x - m_xInterval; i < matchPoints[n].x + m_xInterval; i++)  
  282.     {  
  283.         rect.x = i;  
  284.         for (int j = matchPoints[n].y - m_yInterval; j < matchPoints[n].y + m_yInterval; j++)  
  285.         {  
  286.             rect.y = j;  
  287.             cvSetImageROI(m_srcImg,rect);  
  288.             numSrc = searchPoints(m_srcImg,pSPoints);  
  289.             if (numSrc == 0)  
  290.             {  
  291.                 continue;  
  292.             }  
  293.   
  294.             temp = distance(pMPoints, pSPoints, numModel, numSrc);  
  295.             // min  
  296.             if (temp < dis)  
  297.             {  
  298.                 dis = temp;  
  299.                 matchDis[n] = temp;  
  300.                 matchPoints[n].x = i;  
  301.                 matchPoints[n].y = j;  
  302.             }     
  303.         }  
  304.     }  
  305.   
  306.   
  307.     m_matchPoint = matchPoints[0];  
  308.     m_matchDistance = matchDis[0];  
  309.   
  310.     cvResetImageROI(m_srcImg);  
  311.   
  312.     delete []pMPoints;  
  313.     delete []pSPoints;  
  314. <span style="white-space:pre">  </span>delete []matchDis;  
  315. <span style="white-space:pre">  </span>delete []matchPoints;  
  316. }/* match() */  
  317.   
  318.   
  319. /* 
  320. * 函数名称:distance 
  321. * 函数功能:获取某位置的Hausdorff distance值 
  322. * 函数入口:  
  323. * 输入参数:两组特征点数组指针,特征点个数 numA, numB 
  324. * 输出参数: 
  325. * 返 回 值: 该位置的Hausdorff distance值 
  326. * 其它说明: 支持图片ROI 
  327. */  
  328. double CHausdorff::distance(CvPoint Apoints[], CvPoint Bpoints[], int numA, int numB) const  
  329. {  
  330.     double hAB;  
  331.     double hBA;  
  332.     hAB = computeDirDistance(Apoints, Bpoints, numA, numB, m_frontRange);  
  333.     hBA = computeDirDistance(Bpoints, Apoints, numB, numA, m_backRange);  
  334.   
  335.     // H(A, B) = max(h(A, B), h(B,A))  
  336.     return std::max(hAB, hBA);    
  337. }/*distance()*/  
  338.   
  339. /* 
  340. * 函数名称:computeDirDistance 
  341. * 函数功能:计算单向 Hausdorff distance 值 
  342. * 函数入口:  
  343. * 输入参数:两组特征点数组指针 Apoints, Bpoints, 特征点个数numA, int numB, 单向距离因子 Range 
  344. * 输出参数: 
  345. * 返 回 值: 单向 Hausdorff distance 值 
  346. * 其它说明: 
  347. */  
  348. double CHausdorff::computeDirDistance(CvPoint Apoints[], CvPoint Bpoints[], int numA, int numB, double Range) const  
  349. {  
  350.     double *disA = new double[numA];  
  351.   
  352.     double temp;  
  353.     double aB = MAX_DISTANCE;  
  354.     for (int i = 0; i < numA; i++)  
  355.     {  
  356.         for (int j = 0; j < numB; j++)  
  357.         {  
  358.             temp = (Apoints[i].x - Bpoints[j].x) * (Apoints[i].x - Bpoints[j].x)  
  359.                     + (Apoints[i].y - Bpoints[j].y) * (Apoints[i].y - Bpoints[j].y);  
  360.             //或者使用查表法  
  361.             //temp = m_disTable[abs(Apoints[i].x - Bpoints[j].x)][abs(Apoints[i].y - Bpoints[j].y)];  
  362.   
  363.             // while b in B, get min|| a - b ||  
  364.             aB = std::min(temp,aB);  
  365.         }  
  366.         disA[i] = aB;  
  367.         // 注意下面这条语句  
  368.         aB = MAX_DISTANCE;  
  369.     }  
  370.   
  371.     sort(disA, numA);  
  372.     double dis;  
  373.     // hausdorff 距离改进版:部分hausdorff距离  
  374.     dis = disA[(int)(numA * Range) - 1];  
  375.     // 也可以尝试平均距离:meanDistance(),使用meanDistance()则不需要对距离数组排序  
  376.     // dis = meanDistance(disA, numA);  
  377.   
  378.     delete []disA;  
  379.     return dis;  
  380. }/*computeDirDistance()*/  
  381.   
  382. /* 
  383. * 函数名称:drawMatch() 
  384. * 函数功能:在待匹配图中画出匹配结果区域 
  385. * 函数入口:  
  386. * 输入参数: img指针默认指向m_srcImg,可以将待匹配图像的jpeg格式图像指针传入,以使结果更加直观 
  387. * 输出参数: 
  388. * 返 回 值: void 
  389. * 其它说明:  
  390. */  
  391. void CHausdorff::drawMatch(const char *name, IplImage *img)  
  392. {  
  393.     CvPoint pt;  
  394.     pt.x = m_matchPoint.x + m_modelImg->width;  
  395.     pt.y = m_matchPoint.y + m_modelImg->height;  
  396.   
  397.     if (!img)  
  398.     {  
  399.         img = m_srcImg;  
  400.     }  
  401.   
  402.     cvRectangle(img, m_matchPoint, pt, cvScalar(0,0,255));  
  403.     cvShowImage(name, img);  
  404. }  
  405.   
  406. /* 
  407. * 函数名称:sort 
  408. * 函数功能:对数组进行升序排序 
  409. * 函数入口:  
  410. * 输入参数:待排序数组指针及数组个数 
  411. * 输出参数: 
  412. * 返 回 值: void 
  413. * 其它说明:  
  414. */  
  415. void CHausdorff::sort(double a[],int n) const //升序  
  416. {   
  417.     double temp;  
  418.     for(int i=0;i<n;i++)   
  419.         for(int j=i+1;j<n;j++)   
  420.         {   
  421.             if(a[i]>a[j])   
  422.             {    
  423.                 temp=a[i];   
  424.                 a[i]=a[j];   
  425.                 a[j]=temp;   
  426.             }   
  427.         }   
  428. }  
  429.   
  430. /* 
  431. * 函数名称:meanDistance 
  432. * 函数功能:对距离数组求平均值 
  433. * 函数入口:  
  434. * 输入参数:距离数组指针及数组个数 
  435. * 输出参数: 
  436. * 返 回 值: 距离数组的平均值 
  437. * 其它说明:  
  438. */  
  439. double CHausdorff::meanDistance(double a[], int n) const  
  440. {  
  441.     double sum = 0;  
  442.   
  443.     for (int i = 0; i < n; i++)  
  444.     {  
  445.         sum += a[i];  
  446.     }  
  447.     sum /= n;  
  448.     return sum;  
  449. }  
  450.   
  451. /* 
  452. * 函数名称:createTable 
  453. * 函数功能:创建距离变换表 
  454. * 函数入口:  
  455. * 输入参数:NULL 
  456. * 输出参数:距离变换表的指针 
  457. * 返 回 值: void 
  458. * 其它说明:  
  459. */  
  460. void CHausdorff::createTable()  
  461. {  
  462.     int wm, hm, r;  
  463.     wm = m_modelImg->width;  
  464.     hm = m_modelImg->height;  
  465.   
  466.     r = std::max(wm,hm);  
  467.   
  468.     m_disTable = new double*[r];  
  469.     for (int i = 0; i < r; i++)  
  470.     {  
  471.         m_disTable[i] = new double[r];  
  472.     }  
  473.   
  474.     for (int j = 0; j < r; j++)  
  475.     {  
  476.         for(int i = 0; i < r; i++)  
  477.         {  
  478.             m_disTable[j][i] = i*i + j*j;  
  479.             m_disTable[i][j] = m_disTable[j][i];  
  480.         }  
  481.     }  
  482. }  
  483.   
  484. /* 
  485. * 函数名称:freeTable 
  486. * 函数功能:释放距离变换表内存 
  487. * 函数入口:  
  488. * 输入参数: 
  489. * 输出参数: 
  490. * 返 回 值: void 
  491. * 其它说明:  
  492. */  
  493. void CHausdorff::freeTable()  
  494. {  
  495.     int wm, hm, r;  
  496.     wm = m_modelImg->width;  
  497.     hm = m_modelImg->height;  
  498.   
  499.     r = std::max(wm,hm);  
  500.   
  501.     for (int i = 0; i < r; i++)  
  502.     {  
  503.         delete []m_disTable[i];  
  504.     }  
  505.     delete []m_disTable;  
  506. }  

CFeatures类定义

CFeatures.h文件

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /****************************************** 
  2. * Copyright (C) 2015 HolaMirai(HolaMirai@163.com) 
  3. * All rights reserved. 
  4.  
  5. * 文件名:CFeatures.h 
  6. * 摘要:图像前置处理,用于获取特征点 
  7. * 当前版本:V1.0,2015年9月13日,HolaMirai,创建该文件 
  8. * 历史记录:... 
  9. ******************************************/  
  10.   
  11.   
  12. /* 
  13. * BUG:  1.使用HARRIS、SIFT、SURF提取特征点时,Debug版本耗时非常长,release版本正常 
  14.         2.使用HARRIS、SIFT、SURF提取特征点时,CFeatures类不能正确析构,初步判断是dll和EXE堆释放错误, 
  15.         而且出错点很可能是 m_vecPoints向量问题 
  16. */  
  17.   
  18.   
  19.   
  20.   
  21. /* 
  22. * 类定义说明 
  23. */  
  24. /******************************************** 
  25. * CFeatures类 
  26. * CFeatures类接受一个int值,表示特征点类型 
  27. * 使用getFeatures()函数可以得到特征点的二值化图像 
  28. * 一个工程只需定义一个CFeatures类的实例 
  29.  
  30.  
  31. ********************************************/  
  32.   
  33. #ifndef CFEATURES_H  
  34. #define CFEATURES_H  
  35.   
  36. /* 
  37. * 特征点类型 
  38. */  
  39. enum feature_type  
  40. {  
  41.     FEATURE_CANNY,      //特征点为CANNY边缘点  
  42.     FEATURE_HARRIS,     //特征点为Harris特征点  
  43.     FEATURE_SIFT,       //特征点为SIFT特征点  
  44.     FEATURE_SURF,       //特征点为SURF特征点  
  45. };  
  46.   
  47. #include "cv.h"  
  48. #include <vector>  
  49.   
  50. /* 
  51. * 类定义 
  52. */  
  53. class CFeatures  
  54. {  
  55. public:  
  56.     CFeatures(int feature_type);  
  57.     ~CFeatures();  
  58.   
  59. public:  
  60.     void getFeatures(IplImage *grayImg, IplImage *featuresImg);  
  61.     void drawFeatures(const char *name, IplImage *img);  
  62.   
  63. private:  
  64.     void vecPointsToImage(IplImage *featuresImg);  
  65.   
  66. public:  
  67.     IplImage *m_featuresImg;  
  68.     IplImage *m_imgShow;  
  69.     std::vector<cv::KeyPoint> m_vecPoints;  
  70.   
  71. private:  
  72.     int m_type;  
  73. };  
  74.   
  75. #endif  
CFeatures.cpp文件

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /****************************************** 
  2. * Copyright (C) 2015 HolaMirai(HolaMirai@163.com) 
  3. * All rights reserved. 
  4.  
  5. * 文件名:CFeatures.cpp 
  6. * 摘要:图像前置处理,用于获取特征点 
  7. * 当前版本:V2.0,2015年9月14日,HolaMirai,完成四种特征点获取方法 
  8. * 历史记录:V1.0,2015年9月13日,HolaMirai,创建该文件 
  9. ******************************************/  
  10.   
  11. #include "CFeatures.h"  
  12. #include "highgui.h"  
  13. #include <opencv2/nonfree/nonfree.hpp>    
  14. using namespace cv;  
  15.   
  16. /***********************************************/  
  17.   
  18. /* 
  19. * 函数名称:CFeatures 
  20. * 函数功能:CFeatures类构造函数 
  21. * 函数入口:  
  22. * 输入参数: 需要获取的特征点的特征点类型,值为enum feature_type其中一个 
  23. * 输出参数:无 
  24. * 返 回 值: 
  25. * 其它说明:  
  26. */  
  27. CFeatures::CFeatures(int feature_type)  
  28. {  
  29.     m_type = feature_type;  
  30.     initModule_nonfree();//if use SIFT or SURF  
  31. }  
  32.   
  33. /* 
  34. * 函数名称:~CFeatures 
  35. * 函数功能:CFeatures类析构函数 
  36. * 函数入口:  
  37. * 输入参数:  
  38. * 输出参数: 
  39. * 返 回 值: 
  40. * 其它说明:  
  41. */  
  42. CFeatures::~CFeatures()  
  43. {  
  44.   
  45. }  
  46.   
  47. /* 
  48. * 函数名称:getFeatures 
  49. * 函数功能:获取特征点 
  50. * 函数入口:  
  51. * 输入参数: 待搜索图像的灰度图 grayImg 指针, 接受特征点的灰度图像指针 featuresImg, featuresImg与 grayImg尺寸相同 
  52. * 输出参数:特征点的灰度图像 featuresImg 
  53. * 返 回 值: 
  54. * 其它说明:  
  55. */  
  56. void CFeatures::getFeatures(IplImage *grayImg, IplImage *featuresImg)  
  57. {  
  58.     switch (m_type)  
  59.     {  
  60.     case FEATURE_CANNY:  
  61.         {  
  62.             assert(grayImg->width == featuresImg->width &&  
  63.                 grayImg->height == featuresImg->height &&  
  64.                 grayImg->nChannels == grayImg->nChannels);  
  65.   
  66.             cvCanny(grayImg,featuresImg,50,150);  
  67.             break;  
  68.         }  
  69.     case FEATURE_HARRIS:  
  70.         {  
  71.             Ptr<FeatureDetector> detector = FeatureDetector::create( "HARRIS" );    //特征点寻找  
  72.             detector->detect(grayImg, m_vecPoints);  
  73.             vecPointsToImage(featuresImg);  
  74.             break;  
  75.         }  
  76.   
  77.     case FEATURE_SIFT:  
  78.         {  
  79.             Ptr<FeatureDetector> detector = FeatureDetector::create( "SIFT" );    //特征点寻找  
  80.             detector->detect(grayImg, m_vecPoints);  
  81.             vecPointsToImage(featuresImg);  
  82.             break;  
  83.         }  
  84.   
  85.     case FEATURE_SURF:  
  86.         {  
  87.             Ptr<FeatureDetector> detector = FeatureDetector::create( "SURF" );    //特征点寻找  
  88.             detector->detect(grayImg, m_vecPoints);  
  89.             vecPointsToImage(featuresImg);  
  90.             break;  
  91.         }  
  92.     default:  
  93.         break;  
  94.     }  
  95. /*getFeatures()*/  
  96.   
  97. /* 
  98. * 函数名称:vecPointsToImage 
  99. * 函数功能:将vector类型的特征点变换成 IplImage 图像类型 
  100. * 函数入口:  
  101. * 输入参数: 特征点向量m_vecPoints, 接受特征点的灰度图像指针 featuresImg 
  102. * 输出参数:特征点的灰度图像 featuresImg 
  103. * 返 回 值: 
  104. * 其它说明:  
  105. */  
  106. void CFeatures::vecPointsToImage(IplImage *featuresImg)  
  107. {  
  108.     vector<KeyPoint>::iterator it;  
  109.     vector<KeyPoint>::iterator end_it = m_vecPoints.end();  
  110.   
  111.     cvZero(featuresImg);  
  112.   
  113.     int w,h;  
  114.     uchar *ptr;  
  115.     for (it = m_vecPoints.begin(); it != end_it; it++)  
  116.     {  
  117.         w= (int)it->pt.x;  
  118.         h = (int)it->pt.y;  
  119.         ptr = (uchar *)(featuresImg->imageData + h*featuresImg->widthStep + w);  
  120.         // 特征点置255,其他置0  
  121.         *ptr = 255;  
  122.     }  
  123.     ptr = NULL;  
  124. }/*vecPointsToImage()*/  
  125.   
  126. /* 
  127. * 函数名称:drawFeatures 
  128. * 函数功能:画出特征点 
  129. * 函数入口:  
  130. * 输入参数: 显示窗口 name, 在哪副图像上画出特征点的图像指针 img 
  131. * 输出参数: 
  132. * 返 回 值:void 
  133. * 其它说明:画出的是最近一次处理的图片的特征点 
  134. */  
  135. void CFeatures::drawFeatures(const char *name, IplImage *img)  
  136. {  
  137.     IplImage *m_imgShow = cvCloneImage(img);  
  138.   
  139.     vector<KeyPoint>::iterator it;  
  140.     vector<KeyPoint>::iterator end_it = m_vecPoints.end();  
  141.   
  142.     CvPoint center;  
  143.     for (it = m_vecPoints.begin(); it != end_it; it++)  
  144.     {  
  145.         center.x = (int)it->pt.x;  
  146.         center.y  = (int)it->pt.y;  
  147.   
  148.         cvCircle(m_imgShow,center,3,cvScalar(rand()%255,rand()%255,rand()%255));  
  149.     }  
  150.     cvShowImage(name,m_imgShow);  
  151.     cvReleaseImage(&m_imgShow);  
  152. }/*drawFeatures()*/  


测试程序文件

huas.cpp代码

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. /****************************************** 
  2. * Copyright (C) 2015 HolaMirai(HolaMirai@163.com) 
  3. * All rights reserved. 
  4.  
  5. * 文件名:haus.cpp 
  6. * 摘要:包含main函数的主文件,用于测试CHausdorff类, CFeatures类 
  7. * 当前版本:V2.0,2015年9月14日,添加CFeatures类,并使用CFeatures类来获取特征点 
  8. * 历史记录:V1.0,2015年9月7日,HolaMirai,创建该文件 
  9. ******************************************/  
  10.   
  11. #include "opencv2/opencv.hpp"  
  12. #include "iostream"  
  13. #include "CHausdorff.h"  
  14. #include "CFeatures.h"  
  15. #include "windows.h"  
  16.   
  17. using namespace std;  
  18. using namespace cv;  
  19.   
  20. //单张图片匹配  
  21. void main()  
  22. {  
  23.     char srcName[] = "sg.jpg";  
  24.     char modelName[] = "sgt.jpg";  
  25.   
  26.     IplImage *srcColor = cvLoadImage(srcName,1);  
  27.     IplImage *modelColor = cvLoadImage(modelName,1);  
  28.   
  29.     IplImage *srcGray = cvLoadImage(srcName,0);  
  30.     IplImage *modelGray = cvLoadImage(modelName,0);  
  31.   
  32.     IplImage *srcFeat = cvCreateImage(cvGetSize(srcGray),IPL_DEPTH_8U,1);  
  33.     IplImage *modelFeat = cvCreateImage(cvGetSize(modelGray),IPL_DEPTH_8U,1);  
  34.   
  35.     CFeatures features(FEATURE_HARRIS);  
  36.   
  37.   
  38.     features.getFeatures(srcGray,srcFeat);  
  39.     features.drawFeatures("src",srcColor);  
  40.     features.getFeatures(modelGray,modelFeat);  
  41.     features.drawFeatures("model",modelColor);  
  42.       
  43.   
  44.     CHausdorff haus(modelFeat,srcFeat,8,8);  
  45.   
  46.     DWORD start_t = GetTickCount();   
  47.     haus.match();  
  48.     DWORD end_t = GetTickCount();  
  49.   
  50.     cout<<"匹配耗时:"<<end_t - start_t<<"ms"<<endl;  
  51.   
  52.     haus.drawMatch("resultMatch",srcColor);  
  53.   
  54.     cvWaitKey(0);  
  55.     //system("pause");  
  56.     cvReleaseImage(&srcColor);  
  57.     cvReleaseImage(&modelColor);  
  58.     cvReleaseImage(&srcGray);  
  59.     cvReleaseImage(&modelGray);  
  60.     cvReleaseImage(&srcFeat);  
  61.     cvReleaseImage(&modelFeat);  
  62.     cvDestroyAllWindows();  
  63.   
  64. }  
  65.   
  66.   
  67. //从相机中获取图像连续匹配  
  68. /* 
  69. void main() 
  70. { 
  71.     char modelName[] = "m1.jpg"; 
  72.  
  73.     CvCapture *capture = cvCreateCameraCapture(0); 
  74.     IplImage *srcColor = cvQueryFrame(capture); 
  75.     IplImage *modelColor = cvLoadImage(modelName,1); 
  76.  
  77.     IplImage *srcGray = cvCreateImage(cvGetSize(srcColor),IPL_DEPTH_8U,1); 
  78.     IplImage *modelGray = cvLoadImage(modelName,0); 
  79.  
  80.     IplImage *srcFeat = cvCreateImage(cvGetSize(srcColor),IPL_DEPTH_8U,1); 
  81.     IplImage *modelFeat = cvCreateImage(cvGetSize(modelColor),IPL_DEPTH_8U,1); 
  82.  
  83.     CFeatures features(FEATURE_HARRIS); 
  84.     features.getFeatures(modelGray,modelFeat); 
  85.  
  86.     char winSrc[] = "src"; 
  87.     cvNamedWindow("src",1); 
  88.  
  89.     CHausdorff haus(modelFeat,NULL,8,8); 
  90.  
  91.     for (int i = 0; i < 30; i++) 
  92.     { 
  93.         srcColor = cvQueryFrame(capture); 
  94.         cvShowImage(winSrc,srcColor); 
  95.         cvWaitKey(30); 
  96.     } 
  97.  
  98.     while (cvWaitKey(30) != 'q') 
  99.     { 
  100.         srcColor = cvQueryFrame(capture); 
  101.  
  102.         cvCvtColor(srcColor,srcGray,CV_BGR2GRAY); 
  103.         features.getFeatures(srcGray,srcFeat); 
  104.  
  105.         haus.setSourceImage(srcFeat); 
  106.  
  107.         DWORD start_t = GetTickCount();  
  108.         haus.match(); 
  109.         DWORD end_t = GetTickCount(); 
  110.  
  111.         cout<<"匹配耗时:"<<end_t - start_t<<"ms"<<endl; 
  112.  
  113.         haus.drawMatch("resultMatch",srcColor); 
  114.     } 
  115.  
  116.     cvWaitKey(0); 
  117.     //system("pause"); 
  118.     cvReleaseImage(&srcColor); 
  119.     cvReleaseImage(&modelColor); 
  120.     cvReleaseImage(&srcGray); 
  121.     cvReleaseImage(&modelGray); 
  122.     cvReleaseImage(&srcFeat); 
  123.     cvReleaseImage(&modelFeat); 
  124.     cvDestroyAllWindows(); 
  125.  
  126. } 
  127. */  



结果:

使用Harris特征点进行匹配,release版本耗时为203ms,基本可以满足实时性要求

输入带匹配图和模板图,结果如下图所示:




转载网址:Hausdorff距离匹配算法及代码



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值