- 浏览: 223668 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
synack:
写的很好,图文并茂,语言简单清晰,赞!
SkipList 跳表 -
king_c:
jiandandecaicai 写道你好,请教一下是如何通过E ...
从Hadoop URL 中读取数据 -
jiandandecaicai:
你好,请教一下是如何通过Eclipse来连接Hadop机群的, ...
从Hadoop URL 中读取数据
图像特征检测综述(Image Feature Detection)
作者:王先荣
前言
图像特征提取是计算机视觉和图像处理中的一个概念。它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征。本文主要探讨如何提取图像中的“角点”这一特征,及其相关的内容。而诸如直方图、边缘、区域等内容在前文中有所提及,请查看相关文章。OpenCv(EmguCv)中实现了多种角点特征的提取方法,包括:Harris角点、ShiTomasi角点、亚像素级角点、SURF角点、Star关键点、FAST关键点、Lepetit关键点等等,本文将逐一介绍如何检测这些角点。在此之前将会先介绍跟角点检测密切相关的一些变换,包括Sobel算子、拉普拉斯算子、Canny算子、霍夫变换。另外,还会介绍一种广泛使用而OpenCv中并未实现的SIFT角点检测,以及最近在OpenCv中实现的MSER区域检测。所要讲述的内容会很多,我这里尽量写一些需要注意的地方及实现代码,而参考手册及书本中有的内容将一笔带过或者不会提及。
Sobel算子
Sobel算子用多项式计算来拟合导数计算,可以用OpenCv中的cvSobel函数或者EmguCv中的Image<TColor,TDepth>.Sobel方法来进行计算。需要注意的是,xorder和yorder中必须且只能有一个为非零值,即只能计算x方向或者y反向的导数;如果将方形滤波器的宽度设置为特殊值CV_SCHARR(-1),将使用Scharr滤波器代替Sobel滤波器。
使用Sobel滤波器的示例代码如下:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> //Sobel算子 private string SobelFeatureDetect() { //获取参数 int xOrder = int.Parse((string)cmbSobelXOrder.SelectedItem); int yOrder = int.Parse((string)cmbSobelYOrder.SelectedItem); int apertureSize = int.Parse((string)cmbSobelApertureSize.SelectedItem); if ((xOrder == 0 && yOrder == 0) || (xOrder != 0 && yOrder != 0)) return "Sobel算子,参数错误:xOrder和yOrder中必须且只能有一个非零。\r\n"; //计算 Stopwatch sw = new Stopwatch(); sw.Start(); Image<Gray, Single> imageDest = imageSourceGrayscale.Sobel(xOrder, yOrder, apertureSize); sw.Stop(); //显示 pbResult.Image = imageDest.Bitmap; //释放资源 imageDest.Dispose(); //返回 return string.Format("·Sobel算子,用时{0:F05}毫秒,参数(x方向求导阶数:{1},y方向求导阶数:{2},方形滤波器宽度:{3})\r\n", sw.Elapsed.TotalMilliseconds, xOrder, yOrder, apertureSize); }
拉普拉斯算子
拉普拉斯算子可以用作边缘检测;可以用OpenCv中的cvLaplace函数或者EmguCv中的Image<TColor,TDepth>.Laplace方法来进行拉普拉斯变换。需要注意的是:OpenCv的文档有点小错误,apertureSize参数值不能为CV_SCHARR(-1)。
使用拉普拉斯变换的示例代码如下:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> //拉普拉斯变换 private string LaplaceFeatureDetect() { //获取参数 int apertureSize = int.Parse((string)cmbLaplaceApertureSize.SelectedItem); //计算 Stopwatch sw = new Stopwatch(); sw.Start(); Image<Gray, Single> imageDest = imageSourceGrayscale.Laplace(apertureSize); sw.Stop(); //显示 pbResult.Image = imageDest.Bitmap; //释放资源 imageDest.Dispose(); //返回 return string.Format("·拉普拉斯变换,用时{0:F05}毫秒,参数(方形滤波器宽度:{1})\r\n", sw.Elapsed.TotalMilliseconds, apertureSize); }
Canny算子
Canny算子也可以用作边缘检测;可以用OpenCv中的cvCanny函数或者EmguCv中的Image<TColor,TDepth>.Canny方法来进行Canny边缘检测。所不同的是,Image<TColor,TDepth>.Canny方法可以用于检测彩色图像的边缘,但是它只能使用apertureSize参数的默认值3;
而cvCanny只能处理灰度图像,不过可以自定义apertureSize。cvCanny和Canny的方法参数名有点点不同,下面是参数对照表。
Image<TColor,TDepth>.Canny CvInvoke.cvCanny
thresh lowThresh
threshLinking highThresh
3 apertureSize
值得注意的是,apertureSize只能取3,5或者7,这可以在cvcanny.cpp第87行看到:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> aperture_size &= INT_MAX; if( (aperture_size & 1) == 0 || aperture_size < 3 || aperture_size > 7 ) CV_ERROR( CV_StsBadFlag, "" );
使用Canny算子的示例代码如下:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> //Canny算子 private string CannyFeatureDetect() { //获取参数 double lowThresh = double.Parse(txtCannyLowThresh.Text); double highThresh = double.Parse(txtCannyHighThresh.Text); int apertureSize = int.Parse((string)cmbCannyApertureSize.SelectedItem); //计算 Stopwatch sw = new Stopwatch(); sw.Start(); Image<Gray, Byte> imageDest = null; Image<Bgr, Byte> imageDest2 = null; if (rbCannyUseCvCanny.Checked) { imageDest = new Image<Gray, byte>(imageSourceGrayscale.Size); CvInvoke.cvCanny(imageSourceGrayscale.Ptr, imageDest.Ptr, lowThresh, highThresh, apertureSize); } else imageDest2 = imageSource.Canny(new Bgr(lowThresh, lowThresh, lowThresh), new Bgr(highThresh, highThresh, highThresh)); sw.Stop(); //显示 pbResult.Image = rbCannyUseCvCanny.Checked ? imageDest.Bitmap : imageDest2.Bitmap; //释放资源 if (imageDest != null) imageDest.Dispose(); if (imageDest2 != null) imageDest2.Dispose(); //返回 return string.Format("·Canny算子,用时{0:F05}毫秒,参数(方式:{1},阀值下限:{2},阀值上限:{3},方形滤波器宽度:{4})\r\n", sw.Elapsed.TotalMilliseconds, rbCannyUseCvCanny.Checked ? "cvCanny" : "Image<TColor, TDepth>.Canny", lowThresh, highThresh, apertureSize); }
另外,在http://www.china-vision.net/blog/user2/15975/archives/2007/804.html有一种自动获取Canny算子高低阀值的方法,作者提供了用C语言实现的代码。我将其改写成了C#版本,代码如下:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> /// <summary> /// 计算图像的自适应Canny算子阀值 /// </summary> /// <param name="imageSrc">源图像,只能是256级灰度图像</param> /// <param name="apertureSize">方形滤波器的宽度</param> /// <param name="lowThresh">阀值下限</param> /// <param name="highThresh">阀值上限</param> unsafe void AdaptiveFindCannyThreshold(Image<Gray, Byte> imageSrc, int apertureSize, out double lowThresh, out double highThresh) { //计算源图像x方向和y方向的1阶Sobel算子 Size size = imageSrc.Size; Image<Gray, Int16> imageDx = new Image<Gray, short>(size); Image<Gray, Int16> imageDy = new Image<Gray, short>(size); CvInvoke.cvSobel(imageSrc.Ptr, imageDx.Ptr, 1, 0, apertureSize); CvInvoke.cvSobel(imageSrc.Ptr, imageDy.Ptr, 0, 1, apertureSize); Image<Gray, Single> image = new Image<Gray, float>(size); int i, j; DenseHistogram hist = null; int hist_size = 255; float[] range_0 = new float[] { 0, 256 }; double PercentOfPixelsNotEdges = 0.7; //计算边缘的强度,并保存于图像中 float maxv = 0; float temp; byte* imageDataDx = (byte*)imageDx.MIplImage.imageData.ToPointer(); byte* imageDataDy = (byte*)imageDy.MIplImage.imageData.ToPointer(); byte* imageData = (byte*)image.MIplImage.imageData.ToPointer(); int widthStepDx = imageDx.MIplImage.widthStep; int widthStepDy = widthStepDx; int widthStep = image.MIplImage.widthStep; for (i = 0; i < size.Height; i++) { short* _dx = (short*)(imageDataDx + widthStepDx * i); short* _dy = (short*)(imageDataDy + widthStepDy * i); float* _image = (float*)(imageData + widthStep * i); for (j = 0; j < size.Width; j++) { temp = (float)(Math.Abs(*(_dx + j)) + Math.Abs(*(_dy + j))); *(_image + j) = temp; if (maxv < temp) maxv = temp; } } //计算直方图 range_0[1] = maxv; hist_size = hist_size > maxv ? (int)maxv : hist_size; hist = new DenseHistogram(hist_size, new RangeF(range_0[0], range_0[1])); hist.Calculate<Single>(new Image<Gray, Single>[] { image }, false, null); int total = (int)(size.Height * size.Width * PercentOfPixelsNotEdges); double sum = 0; int icount = hist.BinDimension[0].Size; for (i = 0; i < icount; i++) { sum += hist[i]; if (sum > total) break; } //计算阀值 highThresh = (i + 1) * maxv / hist_size; lowThresh = highThresh * 0.4; //释放资源 imageDx.Dispose(); imageDy.Dispose(); image.Dispose(); hist.Dispose(); }
霍夫变换
霍夫变换是一种在图像中寻找直线、圆及其他简单形状的方法,在OpenCv中实现了霍夫线变换和霍夫圆变换。值得注意的地方有以下几点:(1)HoughLines2需要先计算Canny边缘,然后再检测直线;(2)HoughLines2计算结果的获取随获取方式的不同而不同;(3)HoughCircles检测结果似乎不正确。
使用霍夫变换的示例代码如下所示:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> //霍夫线变换 private string HoughLinesFeatureDetect() { //获取参数 HOUGH_TYPE method = rbHoughLinesSHT.Checked ? HOUGH_TYPE.CV_HOUGH_STANDARD : (rbHoughLinesPPHT.Checked ? HOUGH_TYPE.CV_HOUGH_PROBABILISTIC : HOUGH_TYPE.CV_HOUGH_MULTI_SCALE); double rho = double.Parse(txtHoughLinesRho.Text); double theta = double.Parse(txtHoughLinesTheta.Text); int threshold = int.Parse(txtHoughLinesThreshold.Text); double param1 = double.Parse(txtHoughLinesParam1.Text); double param2 = double.Parse(txtHoughLinesParam2.Text); MemStorage storage = new MemStorage(); int linesCount = 0; StringBuilder sbResult = new StringBuilder(); //计算,先运行Canny边缘检测(参数来自Canny算子属性页),然后再用计算霍夫线变换 double lowThresh = double.Parse(txtCannyLowThresh.Text); double highThresh = double.Parse(txtCannyHighThresh.Text); int apertureSize = int.Parse((string)cmbCannyApertureSize.SelectedItem); Image<Gray, Byte> imageCanny = new Image<Gray, byte>(imageSourceGrayscale.Size); CvInvoke.cvCanny(imageSourceGrayscale.Ptr, imageCanny.Ptr, lowThresh, highThresh, apertureSize); Stopwatch sw = new Stopwatch(); sw.Start(); IntPtr ptrLines = CvInvoke.cvHoughLines2(imageCanny.Ptr, storage.Ptr, method, rho, theta, threshold, param1, param2); Seq<LineSegment2D> linesSeq = null; Seq<PointF> linesSeq2 = null; if (method == HOUGH_TYPE.CV_HOUGH_PROBABILISTIC) linesSeq = new Seq<LineSegment2D>(ptrLines, storage); else linesSeq2 = new Seq<PointF>(ptrLines, storage); sw.Stop(); //显示 Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>(); if (linesSeq != null) { linesCount = linesSeq.Total; foreach (LineSegment2D line in linesSeq) { imageResult.Draw(line, new Bgr(255d, 0d, 0d), 4); sbResult.AppendFormat("{0}-{1},", line.P1, line.P2); } } else { linesCount = linesSeq2.Total; foreach (PointF line in linesSeq2) { float r = line.X; float t = line.Y; double a = Math.Cos(t), b = Math.Sin(t); double x0 = a * r, y0 = b * r; int x1 = (int)(x0 + 1000 * (-b)); int y1 = (int)(y0 + 1000 * (a)); int x2 = (int)(x0 - 1000 * (-b)); int y2 = (int)(y0 - 1000 * (a)); Point pt1 = new Point(x1, y1); Point pt2 = new Point(x2, y2); imageResult.Draw(new LineSegment2D(pt1, pt2), new Bgr(255d, 0d, 0d), 4); sbResult.AppendFormat("{0}-{1},", pt1, pt2); } } pbResult.Image = imageResult.Bitmap; //释放资源 imageCanny.Dispose(); imageResult.Dispose(); storage.Dispose(); //返回 return string.Format("·霍夫线变换,用时{0:F05}毫秒,参数(变换方式:{1},距离精度:{2},弧度精度:{3},阀值:{4},参数1:{5},参数2:{6}),找到{7}条直线\r\n{8}", sw.Elapsed.TotalMilliseconds, method.ToString("G"), rho, theta, threshold, param1, param2, linesCount, linesCount != 0 ? (sbResult.ToString() + "\r\n") : ""); } //霍夫圆变换 private string HoughCirclesFeatureDetect() { //获取参数 double dp = double.Parse(txtHoughCirclesDp.Text); double minDist = double.Parse(txtHoughCirclesMinDist.Text); double param1 = double.Parse(txtHoughCirclesParam1.Text); double param2 = double.Parse(txtHoughCirclesParam2.Text); int minRadius = int.Parse(txtHoughCirclesMinRadius.Text); int maxRadius = int.Parse(txtHoughCirclesMaxRadius.Text); StringBuilder sbResult = new StringBuilder(); //计算 Stopwatch sw = new Stopwatch(); sw.Start(); CircleF[][] circles = imageSourceGrayscale.HoughCircles(new Gray(param1), new Gray(param2), dp, minDist, minRadius, maxRadius); sw.Stop(); //显示 Image<Bgr, Byte> imageResult = imageSourceGrayscale.Convert<Bgr, Byte>(); int circlesCount = 0; foreach (CircleF[] cs in circles) { foreach (CircleF circle in cs) { imageResult.Draw(circle, new Bgr(255d, 0d, 0d), 4); sbResult.AppendFormat("圆心{0}半径{1},", circle.Center, circle.Radius); circlesCount++; } } pbResult.Image = imageResult.Bitmap; //释放资源 imageResult.Dispose(); //返回 return string.Format("·霍夫圆变换,用时{0:F05}毫秒,参数(累加器图像的最小分辨率:{1},不同圆之间的最小距离:{2},边缘阀值:{3},累加器阀值:{4},最小圆半径:{5},最大圆半径:{6}),找到{7}个圆\r\n{8}", sw.Elapsed.TotalMilliseconds, dp, minDist, param1, param2, minRadius, maxRadius, circlesCount, sbResult.Length > 0 ? (sbResult.ToString() + "\r\n") : ""); }
Harris角点
cvCornerHarris函数检测的结果实际上是一幅包含Harris角点的浮点型单通道图像,可以使用类似下面的代码来计算包含Harris角点的图像:
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> //Harris角点 private string CornerHarrisFeatureDetect() { //获取参数 int blockSize = int.Parse(txtCornerHarrisBlockSize.Text); int apertureSize = int.Parse(txtCornerHarrisApertureSize.Text); double k = double.Parse(txtCornerHarrisK.Text); //计算 Image<Gray, Single> imageDest = <span sty发表评论
-
openface 人脸识别开放平台
2014-08-10 17:27 1773using System; using System.Co ... -
新中新二代身份证dll调用,报尝试读取或写入受保护的内存,这通常指示其他内存已损坏 这个错
2014-06-26 04:04 913新中新二代身份证dll调用问题: ... -
【OpenCV学习笔记】2.3 OpenCV2.2摄像头读取视频的问题和解决(VS2010)
2014-06-18 16:38 3941摄像头读取视频这一块研究了很长时间,终于弄好了。刚开始 ... -
C# 4.0 并行计算部分 [转发]
2014-05-03 15:24 1062沿用微软的写法,System.Threading.Task ... -
vector 转换成 数组 - [C++]
2013-12-13 18:06 4728参考: http://topic.csdn.n ... -
convert file into byte array
2012-05-12 23:16 923private byte [] StreamFile(s ... -
使用.NET中的XML注释-- 创建帮助文档入门篇
2012-04-07 11:24 1499一.摘要 在本系列 ... -
C#访问和操作MYSQL数据库
2012-03-23 09:59 1611这里介绍下比较简单的方式,引用MySql.Data.dll ... -
C#访问和操作MYSQL数据库
2012-03-23 09:58 1这里介绍下比较简单的方式,引用MySql.Data.dll ... -
http://www.microsoft.com/china/MSDN/library/langtool/VCSharp/USgetstart_vcsharp.
2012-03-22 21:26 1200http://www.microsoft.com/china/ ... -
使用Signature Tool自动生成P/Invoke调用Windows API的C#函数声明
2012-03-17 22:47 1286在网上看到很多网友在.NET程序中调用Win32 API, ... -
MarshalAs
2012-03-17 22:04 1346MarshalAs是提供向非托管代码封送数据时的规则。比如S ... -
Timeout expired. The timeout period elapsed prior ..
2012-02-26 19:13 1677关于这个问题,要 ... -
c#winform编程中获取cpu个数的方法 详细出处参考:http://www.ityoudao.com/Web/Csharp_590_1542.html
2012-02-23 18:44 969前些时间,为了配置合更加快速有效地制作Sphinx分词搜 ... -
C# socket 服务端实例
2011-12-08 19:50 1062IPAddress ipAddress; ... -
C# 文件操作
2011-12-08 19:40 760文件读取: Console.W ... -
C# 多线程处理相关说明: WaitHandle,waitCallback, ThreadPool.QueueUserWorkItem
2011-09-03 15:33 4099最近接触C#的一个项目,里面用到了多线程处理,这里做个备 ... -
c#的ThreadPool使用笔记(一)
2011-09-03 15:27 1898摘要:系列文章,从 ... -
C# 调用C++ DLL编码问题
2011-08-29 14:25 1536今天用C#调用C++写的一个DLL 死活不成功 ... -
关于global.asax 总结经验
2011-08-25 14:13 14071. 关于global.asax 总结 ...
相关推荐
在图像处理领域,特征检测是一项核心任务,它用于识别图像中的关键点、边缘或特定模式。这些特征可以是角点、线段、圆形、纹理等,对于计算机视觉应用至关重要,如对象识别、图像拼接、追踪和3D重建。本项目名为...
图像边缘检测是图像处理中的关键步骤,旨在找出图像中不同特征区域间的边界,这在图像分析和理解中至关重要。边缘是图像中灰度值发生显著变化的地方,通常代表目标与背景的分界。由于图像的噪声和模糊,边缘检测需要...
面向视频图像的烟雾检测算法有效克服了传统烟雾探测器靠近火源才能工作的不足,但是由于场景的复杂性和环境因素的不确定性,面向视频图像的烟雾检测算法仍然面临着巨大的挑战。首先简单介绍了烟雾检测技术的基本流程,...
根据提供的文件信息,以下是基于深度学习的图像边缘检测算法综述相关的知识点。 首先,边缘检测是计算机视觉领域的基础技术,它涉及从图像中提取边缘信息。边缘通常是指图像中亮度变化最为显著的位置,边缘检测算法...
图像检测图像检测图像检测图像检测图像检测图像检测图像检测图像检测图像检测图像检测 图像检测图像检测图像检测图像检测图像检测图像检测图像检测图像检测图像检测图像检测 图像检测图像检测图像检测图像检测图像...
图像边缘检测入门必看综述,介绍了用于边缘检测的常用算子算法,很适合对图像边缘检测了解的同学
《图像局部特征点检测算法综述》 图像特征检测在计算机视觉领域中占有核心地位,尤其是在图像分析、识别和目标追踪等应用中。图像特征包括颜色、纹理、形状和局部特征点等多种类型,其中局部特征点由于其稳定性和抗...
义出能够描述并区分不同重采样痕迹的两个特征量,将待测图像重叠分块,计算每块的特征量,然后利用特征量的不一致性检测定 位篡改区域。实验结果表明,该方法能够区分旋转与缩放的操作历史痕迹,进行篡改伪造图像的...
【图像局部特征点检测算法综述】 图像处理和计算机视觉领域中,图像特征点的检测是至关重要的一步,尤其在图像识别、匹配和追踪等应用中。局部特征点具有较高的稳定性和鲁棒性,不易受光照变化、旋转、噪声等因素的...
图像特征检测与匹配是计算机视觉领域中的重要研究方向,它涉及从图像中提取关键信息,并在此基础上实现图像间的对比、匹配、检索等功能。以下是图像特征检测与匹配方法研究的主要知识点。 1. 图像稀疏化与特征点...
3. 图像检测:确定哪些点是边缘,常用的方法是设置梯度幅值阈值,超过阈值的点被认为是边缘点。 4. 图像定位:精确确定边缘的位置,有时还需要进行子像素级别的定位。 边缘检测方法有很多种,其中经典微分边缘算子...
图像边缘检测是计算机视觉和图像处理中的关键技术,用于识别图像中目标与背景的界限,以及目标内部或之间的特征变化。边缘检测的结果对于后续的图像分析、分割、特征提取和模式识别至关重要。本文将概述边缘检测的...
在图像处理领域,边缘检测和特征提取是两个关键步骤,它们在计算机视觉、机器学习以及人工智能等应用中占据着重要地位。本程序采用VC++语言编写,专门针对这两个任务进行优化,为用户提供了一套高效且实用的解决方案...
然后,重点从候选区域、回归和anchor-free方法的角度对现有经典的图像目标检测模型进行综述;最后,根据在公共数据集上的检测结果分析模型的优势和缺点,总结了图像目标检测研究中存在的问题并对未来发展做出展望。