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。即
。同理由图可得
,
,
,
。在它们中,值最大的为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日更新:
2015年9月16日更新:
2.使用HARRIS、SIFT、SURF提取特征点时,CFeatures类不能正确析构,初步判断是dll和EXE堆释放错误,
而且出错点很可能是 m_vecPoints向量问题
/************************************************************************************************************************************/
2015年9月10上传
以下是我实现的Hausdorff distance距离匹配 C++ 类,构造函数如下:
- CHausdorff(IplImage *srcImg, IplImage *modelImge,
- int xInterval = 1, int yInterval = 1,
- double frontRange = 0.8, double backRange = 0.7);
- 当frontRange = 1,backRange = 1,并使用sort()函数时,该类退化成原始Hausforff distance定义的匹配方法
- 当frontRange ,backRange 取值为0~1之间,并使用sort函数时,该类为改进型hausdorff distance:部分hausdorff distance.
- 当frontRange ,backRange 取值任意,并使用meanDistance()函数时,该类为改进型hausdorff distance:平均hausdorff distance.
以下C++代码在VS2010 + OpenCV2.4.8下调试通过,
附上代码:
CHausdorff类定义如下:
CHausdorff.h 文件:
- /******************************************
- * Copyright (C) 2015 HolaMirai(HolaMirai@163.com)
- * All rights reserved.
- *
- * 文件名:hausdorff.h
- * 摘要:寻找Hausdorff Distance度量的最匹配位置和最匹配位置的距离
- * 当前版本:<V1.0>,<完成日期:2015年9月7日>,<HolaMirai>,<创建该文件>
- * 历史记录:...
- ******************************************/
- /*
- * 类定义说明
- */
- /********************************************
- * CHausforff类
- * CHausdorff类接受带匹配图、模板图的二值化图像或包含特征点二值化图像,参数都带有默认值
- * 使用match函数可以直接获取匹配结果
- * hausdorff distance 采用部分距离法,对遮挡、噪声效果良好,也可以采用平均距离法
- * 匹配过程分为粗匹配和精匹配个过程
- * 各函数已经解耦,可以单独调用某个函数以观察hausdorff distance 方法的各部分
- ********************************************/
- #ifndef CHAUSDORFF_H
- #define CHAUSDORFF_H
- /*
- * 宏定义
- */
- // 最大距离
- #define MAX_DISTANCE INT_MAX
- #include "cv.h"
- /*
- * 类定义
- */
- class CHausdorff
- {
- public:
- CHausdorff( IplImage *modelImge, IplImage *srcImg = NULL,
- int xInterval = 1, int yInterval = 1,
- double frontRange = 0.8, double backRange = 0.7);
- ~CHausdorff();
- public:
- void setSourceImage(IplImage *srcImg);
- //void setModelImage(IplImage *modelImg);
- void setScanInterval_X(int xInterval);
- void setScanInterval_Y(int yInterval);
- void setFrontRange(double Range);
- void setBackRange(double Range);
- double computeDirDistance(CvPoint Apoints[], CvPoint Bpoints[], int numA, int numB, double Range) const;
- double distance(CvPoint Apoints[], CvPoint Bpoints[], int numA, int numB) const;
- void match();
- void drawMatch(const char *name, IplImage *img = NULL);
- private:
- int searchPoints(IplImage *img, CvPoint pPoints[]) const;
- void sort(double a[],int n) const;
- double meanDistance(double a[], int n) const;
- void createTable();
- void freeTable();
- public:
- //记录匹配结果
- CvPoint m_matchPoint;
- double m_matchDistance;
- private:
- int m_xInterval;
- int m_yInterval;
- double m_frontRange;
- double m_backRange;
- //距离变换表指针
- double **m_disTable;
- public:
- IplImage *m_srcImg;
- IplImage *m_modelImg;
- };
- #endif
CHausdorff.cpp文件:
- /******************************************
- * Copyright (C) 2015 HolaMirai(HolaMirai@163.com)
- * All rights reserved.
- *
- * 文件名:hausdorff.cpp
- * 摘要:寻找Hausdorff Distance度量的最匹配位置和最匹配位置的距离
- * 当前版本:V2.1, 2015年9月11日,HolaMirai, 添加 createTable()、freeTable()函数,添加平均hausdorff距离方法,添加注释
- * 历史记录:V2.0, 2015年9月10日,HolaMirai, 调试完成该文件&添加meanDistance()函数
- * :V1.0, 2015年9月7日, HolaMirai, 创建该文件
- ******************************************/
- /*
- * TBD: 1.改用Voronoi图进行Hausdorff距离计算
- */
- #include "CHausdorff.h"
- #include "highgui.h"
- /*
- * 函数名称:CHausdorff
- * 函数功能:类构造函数
- * 函数入口:
- * 输入参数: 待匹配图、模板二值化图像,粗匹配横、纵坐标扫描间隔 xInterval,yInterval
- * 前向距离因子 frontRange,后向距离因子 backRange
- * 输出参数:无
- * 返 回 值:
- * 其它说明:
- */
- CHausdorff::CHausdorff(IplImage *modelImg, IplImage *srcImg, int xInterval, int yInterval, double frontRange, double backRange)
- {
- m_modelImg = cvCloneImage(modelImg);
- m_srcImg = cvCloneImage(srcImg);
- m_frontRange = frontRange;
- m_backRange = backRange;
- m_xInterval = xInterval;
- m_yInterval = yInterval;
- createTable();
- }
- CHausdorff::~CHausdorff()
- {
- freeTable();
- m_srcImg = NULL;
- cvReleaseImage(&m_modelImg);
- }
- /*
- * 函数名称:setSourceImage
- * 函数功能:设置待匹配图像
- * 函数入口:
- * 输入参数: 待匹配图像指针
- * 输出参数:
- * 返 回 值:void
- * 其它说明:
- */
- void CHausdorff::setSourceImage(IplImage *srcImg)
- {
- assert(srcImg->nChannels == 1);
- m_srcImg = srcImg;
- }
- /*
- * 函数名称:setModelImage
- * 函数功能:设置待模板图像
- * 函数入口:
- * 输入参数: 模板图像指针
- * 输出参数:
- * 返 回 值:void
- * 其它说明: 若是用查表法计算距离,请不要改变模板图,即不要调用该函数
- */
- /*
- void CHausdorff::setModelImage(IplImage *modelImg)
- {
- assert(modelImg->nChannels == 1);
- m_modelImg = modelImg;
- }
- */
- /*
- * 函数名称:setScanInterval_X
- * 函数功能:设置粗匹配X坐标扫描间隔
- * 函数入口:
- * 输入参数: 粗匹配横坐标扫描间隔 xInterval
- * 输出参数:无
- * 返 回 值:void
- * 其它说明:
- */
- void CHausdorff::setScanInterval_X(int xInterval)
- {
- m_xInterval = xInterval;
- }
- /*
- * 函数名称:setScanInterval_Y
- * 函数功能:设置粗匹配Y坐标扫描间隔
- * 函数入口:
- * 输入参数: 粗匹配横坐标扫描间隔 yInterval
- * 输出参数:无
- * 返 回 值:void
- * 其它说明:
- */
- void CHausdorff::setScanInterval_Y(int yInterval)
- {
- m_yInterval = yInterval;
- }
- /*
- * 函数名称:setFrontRange
- * 函数功能:设置前向匹配距离因子
- * 函数入口:
- * 输入参数: 前向匹配距离因子 Range
- * 输出参数:无
- * 返 回 值:void
- * 其它说明:
- */
- void CHausdorff::setFrontRange(double Range)
- {
- m_frontRange = Range;
- }
- /*
- * 函数名称:setFrontRange
- * 函数功能:设置后向匹配距离因子
- * 函数入口:
- * 输入参数: 前向匹配距离因子 Range
- * 输出参数:无
- * 返 回 值:void
- * 其它说明:
- */
- void CHausdorff::setBackRange(double Range)
- {
- m_backRange = Range;
- }
- /*
- * 函数名称:searchPoints
- * 函数功能:获得特征点坐标和特征点的个数
- * 函数入口:
- * 输入参数: 灰度图 img, 接受特征点的数组指针
- * 输出参数:无
- * 返 回 值: 特征点个数
- * 其它说明: 支持图片 ROI
- */
- int CHausdorff::searchPoints(IplImage *img, CvPoint pPoints[]) const
- {
- CvRect rect;
- if ( !img->roi)
- {
- rect.x = 0;
- rect.y = 0;
- rect.width = img->width;
- rect.height = img->height;
- }
- else
- {
- rect.x = img->roi->xOffset;
- rect.y = img->roi->yOffset;
- rect.width = img->roi->width;
- rect.height = img->roi->height;
- }
- //统计特征点
- uchar *ptr;
- int num = 0;
- for (int i = rect.y; i < rect.y + rect.height; i++)
- {
- ptr = (uchar *) (img->imageData + i * img->widthStep);
- for (int j = rect.x; j < rect.x + rect.width; j++)
- {
- if (ptr[j] != 0)
- {
- num++;
- }
- }
- }
- if (num == 0)
- {
- return 0;
- }
- num = 0;
- for (int i = rect.y; i < rect.y + rect.height; i++)
- {
- ptr = (uchar *) (img->imageData + i * img->widthStep);
- for (int j = rect.x; j < rect.x + rect.width; j++)
- {
- if (ptr[j] != 0)
- {
- pPoints[num].x = j - rect.x;
- pPoints[num].y = i - rect.y;
- num++;
- }
- }
- }
- //结果返回
- return num;
- }/*searchPoints()*/
- /*
- * 函数名称:match
- * 函数功能:利用 Hausdorff distance 值来匹配图片
- * 函数入口:
- * 输入参数:无
- * 输出参数:最佳匹配位置 和最佳匹配距离
- * 返 回 值: void
- * 其它说明:
- */
- void CHausdorff::match()
- {
- int ws, hs, wm, hm, numModel, numSrc;
- CvRect rect;
- double *matchDis = new double[100]; //假定最大会有100个最佳位置,这里并未实现,留着以后改进
- CvPoint *matchPoints = new CvPoint[100];
- double temp = MAX_DISTANCE;
- double dis = MAX_DISTANCE;
- int n = 0; //只有一个最佳位置,本文的假设前提
- ws = m_srcImg->width;
- hs = m_srcImg->height;
- wm = m_modelImg->width;
- hm = m_modelImg->height;
- // 存储模板特征点和原图像特征点
- CvPoint *pMPoints = new CvPoint[wm * hm];
- CvPoint *pSPoints = new CvPoint[wm * hm];
- //获得模板特征点
- numModel = searchPoints(m_modelImg,pMPoints);
- if (numModel == 0)
- {
- printf_s("find no points in model");
- return;
- }
- //搜索最佳匹配
- rect.width = wm;
- rect.height = hm;
- // 粗匹配
- //#pragma omp parallel for firstprivate(m_srcImg) //并行运算
- for (int i = 0; i < ws; i += m_xInterval)
- {
- rect.x = i;
- //#pragma omp parallel for
- for (int j = 0; j < hs; j += m_yInterval)
- {
- rect.y = j;
- cvSetImageROI(m_srcImg,rect);
- numSrc = searchPoints(m_srcImg,pSPoints);
- if (numSrc == 0)
- {
- continue;
- }
- // 特征点数据量相差太大则忽略该位置,可以依具体情况调整参数
- if (double(numSrc)/numModel < 0.8 || (double)numSrc/numModel > 1.25)
- {
- continue;
- }
- temp = distance(pMPoints, pSPoints, numModel, numSrc);
- // min
- if (temp < dis)
- {
- dis = temp;
- matchDis[n] = temp;
- matchPoints[n].x = i;
- matchPoints[n].y = j;
- }
- }
- }
- //精匹配
- for (int i = matchPoints[n].x - m_xInterval; i < matchPoints[n].x + m_xInterval; i++)
- {
- rect.x = i;
- for (int j = matchPoints[n].y - m_yInterval; j < matchPoints[n].y + m_yInterval; j++)
- {
- rect.y = j;
- cvSetImageROI(m_srcImg,rect);
- numSrc = searchPoints(m_srcImg,pSPoints);
- if (numSrc == 0)
- {
- continue;
- }
- temp = distance(pMPoints, pSPoints, numModel, numSrc);
- // min
- if (temp < dis)
- {
- dis = temp;
- matchDis[n] = temp;
- matchPoints[n].x = i;
- matchPoints[n].y = j;
- }
- }
- }
- m_matchPoint = matchPoints[0];
- m_matchDistance = matchDis[0];
- cvResetImageROI(m_srcImg);
- delete []pMPoints;
- delete []pSPoints;
- <span style="white-space:pre"> </span>delete []matchDis;
- <span style="white-space:pre"> </span>delete []matchPoints;
- }/* match() */
- /*
- * 函数名称:distance
- * 函数功能:获取某位置的Hausdorff distance值
- * 函数入口:
- * 输入参数:两组特征点数组指针,特征点个数 numA, numB
- * 输出参数:
- * 返 回 值: 该位置的Hausdorff distance值
- * 其它说明: 支持图片ROI
- */
- double CHausdorff::distance(CvPoint Apoints[], CvPoint Bpoints[], int numA, int numB) const
- {
- double hAB;
- double hBA;
- hAB = computeDirDistance(Apoints, Bpoints, numA, numB, m_frontRange);
- hBA = computeDirDistance(Bpoints, Apoints, numB, numA, m_backRange);
- // H(A, B) = max(h(A, B), h(B,A))
- return std::max(hAB, hBA);
- }/*distance()*/
- /*
- * 函数名称:computeDirDistance
- * 函数功能:计算单向 Hausdorff distance 值
- * 函数入口:
- * 输入参数:两组特征点数组指针 Apoints, Bpoints, 特征点个数numA, int numB, 单向距离因子 Range
- * 输出参数:
- * 返 回 值: 单向 Hausdorff distance 值
- * 其它说明:
- */
- double CHausdorff::computeDirDistance(CvPoint Apoints[], CvPoint Bpoints[], int numA, int numB, double Range) const
- {
- double *disA = new double[numA];
- double temp;
- double aB = MAX_DISTANCE;
- for (int i = 0; i < numA; i++)
- {
- for (int j = 0; j < numB; j++)
- {
- temp = (Apoints[i].x - Bpoints[j].x) * (Apoints[i].x - Bpoints[j].x)
- + (Apoints[i].y - Bpoints[j].y) * (Apoints[i].y - Bpoints[j].y);
- //或者使用查表法
- //temp = m_disTable[abs(Apoints[i].x - Bpoints[j].x)][abs(Apoints[i].y - Bpoints[j].y)];
- // while b in B, get min|| a - b ||
- aB = std::min(temp,aB);
- }
- disA[i] = aB;
- // 注意下面这条语句
- aB = MAX_DISTANCE;
- }
- sort(disA, numA);
- double dis;
- // hausdorff 距离改进版:部分hausdorff距离
- dis = disA[(int)(numA * Range) - 1];
- // 也可以尝试平均距离:meanDistance(),使用meanDistance()则不需要对距离数组排序
- // dis = meanDistance(disA, numA);
- delete []disA;
- return dis;
- }/*computeDirDistance()*/
- /*
- * 函数名称:drawMatch()
- * 函数功能:在待匹配图中画出匹配结果区域
- * 函数入口:
- * 输入参数: img指针默认指向m_srcImg,可以将待匹配图像的jpeg格式图像指针传入,以使结果更加直观
- * 输出参数:
- * 返 回 值: void
- * 其它说明:
- */
- void CHausdorff::drawMatch(const char *name, IplImage *img)
- {
- CvPoint pt;
- pt.x = m_matchPoint.x + m_modelImg->width;
- pt.y = m_matchPoint.y + m_modelImg->height;
- if (!img)
- {
- img = m_srcImg;
- }
- cvRectangle(img, m_matchPoint, pt, cvScalar(0,0,255));
- cvShowImage(name, img);
- }
- /*
- * 函数名称:sort
- * 函数功能:对数组进行升序排序
- * 函数入口:
- * 输入参数:待排序数组指针及数组个数
- * 输出参数:
- * 返 回 值: void
- * 其它说明:
- */
- void CHausdorff::sort(double a[],int n) const //升序
- {
- double temp;
- for(int i=0;i<n;i++)
- for(int j=i+1;j<n;j++)
- {
- if(a[i]>a[j])
- {
- temp=a[i];
- a[i]=a[j];
- a[j]=temp;
- }
- }
- }
- /*
- * 函数名称:meanDistance
- * 函数功能:对距离数组求平均值
- * 函数入口:
- * 输入参数:距离数组指针及数组个数
- * 输出参数:
- * 返 回 值: 距离数组的平均值
- * 其它说明:
- */
- double CHausdorff::meanDistance(double a[], int n) const
- {
- double sum = 0;
- for (int i = 0; i < n; i++)
- {
- sum += a[i];
- }
- sum /= n;
- return sum;
- }
- /*
- * 函数名称:createTable
- * 函数功能:创建距离变换表
- * 函数入口:
- * 输入参数:NULL
- * 输出参数:距离变换表的指针
- * 返 回 值: void
- * 其它说明:
- */
- void CHausdorff::createTable()
- {
- int wm, hm, r;
- wm = m_modelImg->width;
- hm = m_modelImg->height;
- r = std::max(wm,hm);
- m_disTable = new double*[r];
- for (int i = 0; i < r; i++)
- {
- m_disTable[i] = new double[r];
- }
- for (int j = 0; j < r; j++)
- {
- for(int i = 0; i < r; i++)
- {
- m_disTable[j][i] = i*i + j*j;
- m_disTable[i][j] = m_disTable[j][i];
- }
- }
- }
- /*
- * 函数名称:freeTable
- * 函数功能:释放距离变换表内存
- * 函数入口:
- * 输入参数:
- * 输出参数:
- * 返 回 值: void
- * 其它说明:
- */
- void CHausdorff::freeTable()
- {
- int wm, hm, r;
- wm = m_modelImg->width;
- hm = m_modelImg->height;
- r = std::max(wm,hm);
- for (int i = 0; i < r; i++)
- {
- delete []m_disTable[i];
- }
- delete []m_disTable;
- }
CFeatures类定义
CFeatures.h文件
- /******************************************
- * Copyright (C) 2015 HolaMirai(HolaMirai@163.com)
- * All rights reserved.
- *
- * 文件名:CFeatures.h
- * 摘要:图像前置处理,用于获取特征点
- * 当前版本:V1.0,2015年9月13日,HolaMirai,创建该文件
- * 历史记录:...
- ******************************************/
- /*
- * BUG: 1.使用HARRIS、SIFT、SURF提取特征点时,Debug版本耗时非常长,release版本正常
- 2.使用HARRIS、SIFT、SURF提取特征点时,CFeatures类不能正确析构,初步判断是dll和EXE堆释放错误,
- 而且出错点很可能是 m_vecPoints向量问题
- */
- /*
- * 类定义说明
- */
- /********************************************
- * CFeatures类
- * CFeatures类接受一个int值,表示特征点类型
- * 使用getFeatures()函数可以得到特征点的二值化图像
- * 一个工程只需定义一个CFeatures类的实例
- ********************************************/
- #ifndef CFEATURES_H
- #define CFEATURES_H
- /*
- * 特征点类型
- */
- enum feature_type
- {
- FEATURE_CANNY, //特征点为CANNY边缘点
- FEATURE_HARRIS, //特征点为Harris特征点
- FEATURE_SIFT, //特征点为SIFT特征点
- FEATURE_SURF, //特征点为SURF特征点
- };
- #include "cv.h"
- #include <vector>
- /*
- * 类定义
- */
- class CFeatures
- {
- public:
- CFeatures(int feature_type);
- ~CFeatures();
- public:
- void getFeatures(IplImage *grayImg, IplImage *featuresImg);
- void drawFeatures(const char *name, IplImage *img);
- private:
- void vecPointsToImage(IplImage *featuresImg);
- public:
- IplImage *m_featuresImg;
- IplImage *m_imgShow;
- std::vector<cv::KeyPoint> m_vecPoints;
- private:
- int m_type;
- };
- #endif
- /******************************************
- * Copyright (C) 2015 HolaMirai(HolaMirai@163.com)
- * All rights reserved.
- *
- * 文件名:CFeatures.cpp
- * 摘要:图像前置处理,用于获取特征点
- * 当前版本:V2.0,2015年9月14日,HolaMirai,完成四种特征点获取方法
- * 历史记录:V1.0,2015年9月13日,HolaMirai,创建该文件
- ******************************************/
- #include "CFeatures.h"
- #include "highgui.h"
- #include <opencv2/nonfree/nonfree.hpp>
- using namespace cv;
- /***********************************************/
- /*
- * 函数名称:CFeatures
- * 函数功能:CFeatures类构造函数
- * 函数入口:
- * 输入参数: 需要获取的特征点的特征点类型,值为enum feature_type其中一个
- * 输出参数:无
- * 返 回 值:
- * 其它说明:
- */
- CFeatures::CFeatures(int feature_type)
- {
- m_type = feature_type;
- initModule_nonfree();//if use SIFT or SURF
- }
- /*
- * 函数名称:~CFeatures
- * 函数功能:CFeatures类析构函数
- * 函数入口:
- * 输入参数:
- * 输出参数:
- * 返 回 值:
- * 其它说明:
- */
- CFeatures::~CFeatures()
- {
- }
- /*
- * 函数名称:getFeatures
- * 函数功能:获取特征点
- * 函数入口:
- * 输入参数: 待搜索图像的灰度图 grayImg 指针, 接受特征点的灰度图像指针 featuresImg, featuresImg与 grayImg尺寸相同
- * 输出参数:特征点的灰度图像 featuresImg
- * 返 回 值:
- * 其它说明:
- */
- void CFeatures::getFeatures(IplImage *grayImg, IplImage *featuresImg)
- {
- switch (m_type)
- {
- case FEATURE_CANNY:
- {
- assert(grayImg->width == featuresImg->width &&
- grayImg->height == featuresImg->height &&
- grayImg->nChannels == grayImg->nChannels);
- cvCanny(grayImg,featuresImg,50,150);
- break;
- }
- case FEATURE_HARRIS:
- {
- Ptr<FeatureDetector> detector = FeatureDetector::create( "HARRIS" ); //特征点寻找
- detector->detect(grayImg, m_vecPoints);
- vecPointsToImage(featuresImg);
- break;
- }
- case FEATURE_SIFT:
- {
- Ptr<FeatureDetector> detector = FeatureDetector::create( "SIFT" ); //特征点寻找
- detector->detect(grayImg, m_vecPoints);
- vecPointsToImage(featuresImg);
- break;
- }
- case FEATURE_SURF:
- {
- Ptr<FeatureDetector> detector = FeatureDetector::create( "SURF" ); //特征点寻找
- detector->detect(grayImg, m_vecPoints);
- vecPointsToImage(featuresImg);
- break;
- }
- default:
- break;
- }
- } /*getFeatures()*/
- /*
- * 函数名称:vecPointsToImage
- * 函数功能:将vector类型的特征点变换成 IplImage 图像类型
- * 函数入口:
- * 输入参数: 特征点向量m_vecPoints, 接受特征点的灰度图像指针 featuresImg
- * 输出参数:特征点的灰度图像 featuresImg
- * 返 回 值:
- * 其它说明:
- */
- void CFeatures::vecPointsToImage(IplImage *featuresImg)
- {
- vector<KeyPoint>::iterator it;
- vector<KeyPoint>::iterator end_it = m_vecPoints.end();
- cvZero(featuresImg);
- int w,h;
- uchar *ptr;
- for (it = m_vecPoints.begin(); it != end_it; it++)
- {
- w= (int)it->pt.x;
- h = (int)it->pt.y;
- ptr = (uchar *)(featuresImg->imageData + h*featuresImg->widthStep + w);
- // 特征点置255,其他置0
- *ptr = 255;
- }
- ptr = NULL;
- }/*vecPointsToImage()*/
- /*
- * 函数名称:drawFeatures
- * 函数功能:画出特征点
- * 函数入口:
- * 输入参数: 显示窗口 name, 在哪副图像上画出特征点的图像指针 img
- * 输出参数:
- * 返 回 值:void
- * 其它说明:画出的是最近一次处理的图片的特征点
- */
- void CFeatures::drawFeatures(const char *name, IplImage *img)
- {
- IplImage *m_imgShow = cvCloneImage(img);
- vector<KeyPoint>::iterator it;
- vector<KeyPoint>::iterator end_it = m_vecPoints.end();
- CvPoint center;
- for (it = m_vecPoints.begin(); it != end_it; it++)
- {
- center.x = (int)it->pt.x;
- center.y = (int)it->pt.y;
- cvCircle(m_imgShow,center,3,cvScalar(rand()%255,rand()%255,rand()%255));
- }
- cvShowImage(name,m_imgShow);
- cvReleaseImage(&m_imgShow);
- }/*drawFeatures()*/
测试程序文件
huas.cpp代码
- /******************************************
- * Copyright (C) 2015 HolaMirai(HolaMirai@163.com)
- * All rights reserved.
- *
- * 文件名:haus.cpp
- * 摘要:包含main函数的主文件,用于测试CHausdorff类, CFeatures类
- * 当前版本:V2.0,2015年9月14日,添加CFeatures类,并使用CFeatures类来获取特征点
- * 历史记录:V1.0,2015年9月7日,HolaMirai,创建该文件
- ******************************************/
- #include "opencv2/opencv.hpp"
- #include "iostream"
- #include "CHausdorff.h"
- #include "CFeatures.h"
- #include "windows.h"
- using namespace std;
- using namespace cv;
- //单张图片匹配
- void main()
- {
- char srcName[] = "sg.jpg";
- char modelName[] = "sgt.jpg";
- IplImage *srcColor = cvLoadImage(srcName,1);
- IplImage *modelColor = cvLoadImage(modelName,1);
- IplImage *srcGray = cvLoadImage(srcName,0);
- IplImage *modelGray = cvLoadImage(modelName,0);
- IplImage *srcFeat = cvCreateImage(cvGetSize(srcGray),IPL_DEPTH_8U,1);
- IplImage *modelFeat = cvCreateImage(cvGetSize(modelGray),IPL_DEPTH_8U,1);
- CFeatures features(FEATURE_HARRIS);
- features.getFeatures(srcGray,srcFeat);
- features.drawFeatures("src",srcColor);
- features.getFeatures(modelGray,modelFeat);
- features.drawFeatures("model",modelColor);
- CHausdorff haus(modelFeat,srcFeat,8,8);
- DWORD start_t = GetTickCount();
- haus.match();
- DWORD end_t = GetTickCount();
- cout<<"匹配耗时:"<<end_t - start_t<<"ms"<<endl;
- haus.drawMatch("resultMatch",srcColor);
- cvWaitKey(0);
- //system("pause");
- cvReleaseImage(&srcColor);
- cvReleaseImage(&modelColor);
- cvReleaseImage(&srcGray);
- cvReleaseImage(&modelGray);
- cvReleaseImage(&srcFeat);
- cvReleaseImage(&modelFeat);
- cvDestroyAllWindows();
- }
- //从相机中获取图像连续匹配
- /*
- void main()
- {
- char modelName[] = "m1.jpg";
- CvCapture *capture = cvCreateCameraCapture(0);
- IplImage *srcColor = cvQueryFrame(capture);
- IplImage *modelColor = cvLoadImage(modelName,1);
- IplImage *srcGray = cvCreateImage(cvGetSize(srcColor),IPL_DEPTH_8U,1);
- IplImage *modelGray = cvLoadImage(modelName,0);
- IplImage *srcFeat = cvCreateImage(cvGetSize(srcColor),IPL_DEPTH_8U,1);
- IplImage *modelFeat = cvCreateImage(cvGetSize(modelColor),IPL_DEPTH_8U,1);
- CFeatures features(FEATURE_HARRIS);
- features.getFeatures(modelGray,modelFeat);
- char winSrc[] = "src";
- cvNamedWindow("src",1);
- CHausdorff haus(modelFeat,NULL,8,8);
- for (int i = 0; i < 30; i++)
- {
- srcColor = cvQueryFrame(capture);
- cvShowImage(winSrc,srcColor);
- cvWaitKey(30);
- }
- while (cvWaitKey(30) != 'q')
- {
- srcColor = cvQueryFrame(capture);
- cvCvtColor(srcColor,srcGray,CV_BGR2GRAY);
- features.getFeatures(srcGray,srcFeat);
- haus.setSourceImage(srcFeat);
- DWORD start_t = GetTickCount();
- haus.match();
- DWORD end_t = GetTickCount();
- cout<<"匹配耗时:"<<end_t - start_t<<"ms"<<endl;
- haus.drawMatch("resultMatch",srcColor);
- }
- cvWaitKey(0);
- //system("pause");
- cvReleaseImage(&srcColor);
- cvReleaseImage(&modelColor);
- cvReleaseImage(&srcGray);
- cvReleaseImage(&modelGray);
- cvReleaseImage(&srcFeat);
- cvReleaseImage(&modelFeat);
- cvDestroyAllWindows();
- }
- */
结果:
使用Harris特征点进行匹配,release版本耗时为203ms,基本可以满足实时性要求
输入带匹配图和模板图,结果如下图所示: