opencv学习_13 (trajkovic 角点检测)
来源:http://blog.csdn.net/songzitea/article/details/13614977
背景引言
本节主要内容来源于是由 Miroslav Trajkovic和Mark Hedley[1]在1998年提出Trajkovic算子,其论文为FastCorner Detection.和Trajkovic Operator (4-Neighbours)[3](注:本节图片主要是来源于此)。Trajkovic算子角点提取方法存在价值是在角点提取的效果上,它优于同时期的其他角点(如Moravec角点,Harris角点)提取方法,同时,从算法的运行速度角度而言,它比同是期的其他角点提取方法要快很多。
基本理论
Figure 1: Notation for Trajkovic Operator
C(x,y)表示的是图像I上,任意一点(x,y)处的角点量。这个公式能断出是否是角点。点(x,y)在图像目的位置有四种情况。如下图所示:
根据上面的分析,Trajkovic 受噪声的影响比较大,所以,可以先实现高斯平滑去噪再使用Trajkovic算子进行角点检测。
角点量的计算方法
目前,关于Trajkovic计算角点量的并未具体介绍如何时计算。首先,如下图2所示,水平方向的灰度值变化量rA,垂直方向的灰度值变化量rB很容易计算。
如何计算任意一个方向上灰度值的变化程度呢?首先,我们角点量就取其最小值即可:
Figure 2: Interpixel positions Figure3: Interpixel approximation for a 3x3 window using 4-neighbours
现在,我们可将问题可以转换为,任意一条通过点C 的直线与圆的交点是P,P',Q,Q'即可:
把公式(2)代入公式(1) 中即可:
那么,最小值是即可结论是
多格算法(Multigrid Algorithm)
角点可以分为两类:几何角点和纹理角点。几何角点是由图像中物体边缘的相交。而纹理角点有由物体表面的纹理产生的角点(如:草地,衣服的纹理等)。通常情况下,一幅图像中的几何角点的数量要远少于纹理角点。多格算法的目的是希望能多检测到几何角点,少检测到纹理点。因Trajkovic 认为几何角点比纹理角点更加的稳定。所以,从实践使用来看,减少纹理角点是合理的。
经过观察发现,纹理角点一般都是非常的密集,并且是在一个很小区域内灰度值发生变化,所以,采用把原图缩小以后,再来提取角点,通过缩小图像,可以消除区域内灰度值的变换。缩小图像的方法不是使用插值法,而是使用平均法。如下图所示:
Trajkovic角点检测,首先使用多格法对原如图像进行缩小,这样不仅能够减少检测到纹理角点数目,而且加快了Trajkovic角点检测的速度,在Trajkovic角点检测缩小版的图像上,使用角为简单的角点量计算公式初步判断是不是侯选角点。如果是,再到原始图像上进一步判定。
Figure 4: Corner points detected at different image resolutions
如图4所示,原始的大小是256*256,图像中有一片草地,而草地上的角点,对于我们进行角点匹配时,是没有什么意义。当把图像缩小到128*128时,草地上的角点已经消除了。当然,图像也不能缩小太多,否则,几何角点也会消失,当缩小到64*64时,部分几何角点也消失了。
算法流程
代码:
- #include <iostream>
- #include "cv.h"
- #include "highgui.h"
- #include "cxcore.h"
- using namespace std;
- void getTrajkovic4NCorner(IplImage* src,IplImage* srcResize , float T1 , float T2 ,CvSeq* corners,int maximumSize)
- {
- int x,y,maxChar=255,scaleX = src->width/srcResize->width,scaleY = src->height/srcResize->height;
- IplImage* srcResizeMap ,*srcMap;
- srcResizeMap = cvCreateImage(cvGetSize(srcResize),8,1); // 用来保存缩小图像的角点量
- srcMap = cvCreateImage(cvGetSize(src),32,1); // 用来保存源图像计算得到的角点量
- cvZero(srcMap);
- cvZero(srcResizeMap);
- for( y=1;y<srcResize->height-1;y++)
- {
- uchar* preRow = (uchar*)(srcResize->imageData + (y-1)*srcResize->widthStep);
- uchar* curRow = (uchar*)(srcResize->imageData + y*srcResize->widthStep);
- uchar* nextRow = (uchar*)(srcResize->imageData + (y+1)*srcResize->widthStep);
- uchar* MapData = (uchar*)(srcResizeMap->imageData + y*srcResizeMap->widthStep);
- for(x=1;x<srcResize->width-1;x++)
- {
- int IC,IA,IB,IAA,IBB;
- int rA,rB,C_Simple;
- // curRow[x]是uchar型,而IC是int型,如果直接赋值int类型的其它三个字节可能会产生随机值
- IC = curRow[x]&maxChar;
- IA = curRow[x+1]&maxChar;
- IAA = curRow[x-1]&maxChar;
- IB = preRow[x]&maxChar;
- IBB = nextRow[x]&maxChar;
- rA = (IA-IC)*(IA-IC) + (IAA-IC)*(IAA-IC);
- rB = (IB-IC)*(IB-IC) + (IBB-IC)*(IBB-IC);
- C_Simple = rA < rB ? rA : rB;
- if(C_Simple > T1)
- {
- MapData[x]=1;
- }
- }
- }
- for( y=1;y<srcResize->height-1;y++)
- {
- uchar* srcResizeMapData = (uchar*)(srcResizeMap->imageData + y*srcResizeMap->widthStep);
- //uchar* srcMapData = (uchar*)(srcMap->imageData + y*srcMap->widthStep);
- for(x=1;x<srcResize->width-1;x++)
- {
- if(srcResizeMapData[x]==0)
- {
- continue;
- }
- int originX,originY,IC,IA,IB,IAA,IBB;
- int rA,rB,C_Simple;
- originX = x*scaleX;
- originY = y*scaleY;
- uchar* srcPreRow = (uchar*)(src->imageData + (originY-1)*src->widthStep);
- uchar* srcCurRow = (uchar*)(src->imageData + originY*src->widthStep);
- uchar* srcNextRow = (uchar*)(src->imageData + (originY+1)*src->widthStep);
- IC = srcCurRow[originX]&maxChar;
- IA = srcCurRow[originX+1]&maxChar;
- IAA = srcCurRow[originX-1]&maxChar;
- IB = srcPreRow[x]&maxChar;
- IBB = srcNextRow[x]&maxChar;
- rA = (IA-IC)*(IA-IC) + (IAA-IC)*(IAA-IC);
- rB = (IB-IC)*(IB-IC) + (IBB-IC)*(IBB-IC);
- C_Simple = rA < rB ? rA : rB;
- if(C_Simple>T2)
- {
- float B1,B2,C,A,B,C_InterPixel;
- B1 = (IB-IA)*(IA-IC)+(IBB-IAA)*(IAA-IC);
- B2 = (IB-IAA)*(IAA-IC)+(IBB-IA)*(IA-IC);
- C = rA;
- B = B1<B2 ? B1 : B2;
- A = rB-rA-2*B;
- if(B<0 &&(A+B)>0)
- {
- C_InterPixel = C-(B*B)/A;
- }
- else
- {
- C_InterPixel=C_Simple;
- }
- if(C_InterPixel>T2)
- {
- float* srcMapData = (float*)(srcMap->imageData + originY*srcMap->widthStep);
- srcMapData[originX]=C_InterPixel;
- //cvSetReal2D(srcMap,originY,originX,C_InterPixel);
- }
- }
- }
- }
- //计算局部极大值 及 极大值是否大于阈值
- int beginY,endY,beginX,endX;
- int halfWinSize = maximumSize/2;
- beginY = halfWinSize;
- endY = srcMap->height - halfWinSize;
- beginX = halfWinSize;
- endX = srcMap->width - halfWinSize;
- for(y=beginY;y<endY;)
- {
- for(x=beginX;x<endX;)
- {
- //寻找局部极大值 及其位置信息
- float maxValue=0;
- int flag = 0 ;
- CvPoint maxLoc;
- maxLoc.x = -1;
- maxLoc.y = -1;
- //首先计算以点(x,y)位中心的maximumSize*maximumSize的窗口内部的局部极大值
- for(int winy=-halfWinSize;winy<=halfWinSize;winy++)
- {
- for(int winx=-halfWinSize;winx<=halfWinSize;winx++)
- {
- float value ;
- value = cvGetReal2D(srcMap,y+winy,x+winx);
- //计算该窗口内 最大值 保存到max 并保存其坐标到maxLoc
- if(value>maxValue)
- {
- maxValue = value;
- maxLoc.x = x+winx;
- maxLoc.y = y+winy;
- flag = 1;
- }
- }
- }
- //如果找到局部极大值 并且该值大于预先设定的阈值 则认为是角点
- if(flag==1 && maxValue>T2)
- {
- cvSeqPush(corners,&maxLoc);
- }
- x = x+halfWinSize;
- }
- y = y + halfWinSize;
- }
- cvReleaseImage(&srcResizeMap);
- cvReleaseImage(&srcMap);
- }
- int main(int argc,char* argv[])
- {
- //相关变量
- int scale = 2;
- IplImage* src,*srcGray,*srcGrayResize;
- CvMemStorage* mem = cvCreateMemStorage(0);
- CvSeq* TrajkovicPoints;
- src = cvLoadImage("E:\\study_opencv_video\\lesson17_2\\2.jpg");//源图像
- srcGray = cvCreateImage(cvGetSize(src),8,1);
- if(!src)
- {
- cout << "src is null" << endl;
- return 0;
- }
- cvCvtColor(src,srcGray,CV_BGR2GRAY);
- srcGrayResize = cvCreateImage(cvSize(srcGray->width/scale,srcGray->height/scale),8,1);
- cvResize(srcGray,srcGrayResize);//请将resize修改为多格算法
- //Trajkovic 4 邻域角点角点保存的空间 角点坐标保存在一个序列中
- TrajkovicPoints = cvCreateSeq(0,sizeof(CvSeq),sizeof(CvPoint),mem);
- //进行Trajkovic 4 邻域角点检测
- int T1=120,T2=150,localArea = 8; // localArea 是局部极大值抑制时窗口的大小
- getTrajkovic4NCorner(srcGray,srcGrayResize,T1,T2,TrajkovicPoints,localArea);
- //获取每一个角点的坐标
- for(int x=0;x<TrajkovicPoints->total;x++)
- {
- //获取第x个角点的坐标
- CvPoint* pt = (CvPoint*)cvGetSeqElem(TrajkovicPoints,x);
- //以角点坐标为中心 绘制一个半径为5的圆
- cvCircle(src,*pt,2,cvScalar(255,0,255,0));
- }
- //显示图像
- cvNamedWindow("dst");
- cvShowImage("dst",src);
- cvWaitKey(0);
- //释放资源
- cvReleaseImage(&src);
- cvReleaseImage(&srcGray);
- cvReleaseImage(&srcGrayResize);
- cvReleaseMemStorage(&mem);
- return 0;
- }
英文链接: http://kiwi.cs.dal.ca/~dparks/CornerDetection/trajkovic.htm
opencv学习_13 (trajkovic 角点检测)相关推荐
- OpenCV与图像处理学习十三——Harris角点检测(含代码)
OpenCV与图像处理学习十三--Harris角点检测(含代码) 一.角点的概念 二.Harris角点检测的实现过程 三.Harris代码应用 一.角点的概念 角点: 在现实世界中, 角点对应于物体的 ...
- cv2.cornerHarris()详解 python+OpenCV 中的 Harris 角点检测
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/8763369.html 参考文献----------OpenCV-Python-Toturial ...
- Python+OpenCV:图像快速角点检测算法(FAST Algorithm for Corner Detection)
Python+OpenCV:图像快速角点检测算法(FAST Algorithm for Corner Detection) 理论 Feature Detection using FAST Select ...
- Python+OpenCV:图像Harris角点检测(Harris Corner Detection)
Python+OpenCV:图像Harris角点检测(Harris Corner Detection) 理论 corners are regions in the image with large v ...
- 【OpenCV 例程 300篇】240. OpenCV 中的 Shi-Tomas 角点检测
『youcans 的 OpenCV 例程300篇 - 总目录』 [youcans 的 OpenCV 例程 300篇]240. OpenCV 中的 Shi-Tomas 角点检测 角是直线方向的快速变化. ...
- OpenCV 图像特征提取——Harris角点检测
OpenCV 图像特征提取 Harris 角点检测 文章目录 1.什么是角点 2.如何区分角点.边界和平面 3.角点公式推导 4.OpenCV相关函数 5.角点检测程序实现 最后 1.什么是角点 ...
- opencv学习—简单方法用于斑马线检测(Python)
opencv学习-简单方法用于斑马线检测(Python) 目录 opencv学习-简单方法用于斑马线检测(Python) 1.读取原图像并将图像灰度化 2.通过高斯滤波去除噪声信息 3.阈值分割 4. ...
- Opencv java模板匹配-角点检测(11)
函数 在opencv中有模板匹配的方法, Imgproc.matchTemplate(src, template, result, Imgproc.TM_CCOEFF); 这个方法输入的参数分别是: ...
- 【opencv 学习笔记】harris焦点检测和原理学习笔记
参考博客: 1.https://blog.csdn.net/with__sunshine/article/details/88954489 2.https://www.cnblogs.com/djrc ...
最新文章
- How Tomcat works — 四、tomcat启动(3)
- Java基础语法纯小白入门
- 成功人士的十个故事- -
- SpringBoot框架(4)-- 类装配及Bean装配监听器
- 史上最详细的客服系统产品落地|后台产品经理的工作实例,有那么苦吗?
- Elasticsearch script使用详解
- 代码习惯---打印参数
- 使用MvcContrib的FormHelper
- 预编译头文件来自编译器的早期版本,或者预编译头为 C++ 而在 C 中使用它(或相反)...
- 线程池及其实现文章一
- 如何使用CANape实现XCP/CCP“Measurement测量”和“Calibration标定”变量
- MMKV_Android数据持久化方案调研-MMKV SP REALM ROOM WCDB...
- Eucalyptus使用注意事项
- 讲解制作“Icon”
- Matlab中semilogy函数使用
- SVN冲突的原因和解决
- 【CSDN2012年度博客之星】喜欢本博客的读者,投票赠送《visual C++2010开发权威指南》电子稿--感谢支持 ~(截至到2012年12月30日)
- Windows驱动的加载顺序
- pyinstaller spec文件详解
- LeetCode,无它,唯手熟尔(四)
热门文章
- 《CS专业宝典》一张图速览美国CS专业申请
- 程序员如何实现财务自由?狼叔回复
- 找鞍点(C语言实现)
- 基于神经网络给图识物
- 医疗图像的数据增强心得
- 如何夸一个女人,漂亮的,不漂亮的,皮肤好的,皮肤不好的
- Minecraft 1.16.5 生化8 模组 2.0版本 故事书+更多枪械
- Ubuntu18.04 RTX2070 显卡驱动、Cuda、cudnn和Pytorch深度学习环境配置——亲测可用
- 如何用word2010画组织结构图
- 有甲乙二人乙对甲盯梢matlab,甲、乙二人同时上山砍柴,甲花6小时砍了一担柴,乙砍了一段时间后觉得刀比较钝, - 问答库...