目标检测之harr---角点检测harr 的opencv实现-程序员宅基地

技术标签: 人工智能  c/c++  

  • 本系列文章由@浅墨_毛星云 出品,转载请注明出处。

     

    文章链接: http://blog.csdn.net/poem_qianmo/article/details/29356187

     

    作者:毛星云(浅墨) 微博:http://weibo.com/u/1723155442

    知乎:http://www.zhihu.com/people/mao-xing-yun

    邮箱: [email protected]

    写作当前博文时配套使用的OpenCV版本:  2.4.9

     

     

    本篇文章中,我们一起探讨了OpenCV中Harris角点检测相关的知识点,学习了OpenCV中实现Harris角点检测的cornerHarris函数的使用方法。此博文一共有两个配套的麻雀虽小但五脏俱全的示例程序,其经过浅墨详细注释过的代码都在文中贴出,且文章最后提供了综合示例程序的下载。

    依然是先看看程序运行截图:

    \ \

     

     

     

     

     

    一、引言:关于兴趣点(interest points)

     

     

     

    在图像处理和与计算机视觉领域,兴趣点(interest points),或称作关键点(keypoints)、特征点(feature points) 被大量用于解决物体识别,图像识别、图像匹配、视觉跟踪、三维重建等一系列的问题。我们不再观察整幅图,而是选择某些特殊的点,然后对他们进行局部有的放矢的分析。如果能检测到足够多的这种点,同时他们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就有使用价值。

     

    图像特征类型可以被分为如下三种:

     

    <1>边缘<2>角点 (感兴趣关键点)<3>斑点(Blobs)(感兴趣区域)

     

    其中,角点是个很特殊的存在。他们在图像中可以轻易地定位,同时,他们在人造物体场景,比如门、窗、桌等出随处可见。因为角点位于两条边缘的交点处,代表了两个边缘变化的方向上的点,,所以他们是可以精确定位的二维特征,甚至可以达到亚像素的精度。且其图像梯度有很高的变化,这种变化是可以用来帮助检测角点的。需要注意的是,角点与位于相同强度区域上的点不同,与物体轮廓上的点也不同,因为轮廓点难以在相同的其他物体上精确定位。

     

     

     

     

     

    二、角点检测算法的分类

     

     

     

    在当前的图像处理领域,角点检测算法可归纳为三类:

     

    <1>基于灰度图像的角点检测<2>基于二值图像的角点检测<3>基于轮廓曲线的角点检测

    而基于灰度图像的角点检测又可分为基于梯度、基于模板和基于模板梯度组合三类方法,其中基于模板的方法主要考虑像素领域点的灰度变化,即图像亮度的变化,将与邻点亮度对比足够大的点定义为角点。常见的基于模板的角点检测算法有Kitchen-Rosenfeld角点检测算法,Harris角点检测算法、KLT角点检测算法及SUSAN角点检测算法。和其他角点检测算法相比,SUSAN角点检测算法具有算法简单、位置准确、抗噪声能力强等特点。

     

     

     

     

    三、角点的定义

     

     

    “如果某一点在任意方向的一个微小变动都会引起灰度很大的变化,那么我们就把它称之为角点”

    角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中。也称为特征点检测。

    角点通常被定义为两条边的交点,更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界。而实际应用中,大多数所谓的角点检测方法检测的是拥有特定特征的图像点,而不仅仅是“角点”。这些特征点在图像中有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征等。

    现有的角点检测算法并不是都十分的健壮。很多方法都要求有大量的训练集和冗余数据来防止或减少错误特征的出现。另外,角点检测方法的一个很重要的评价标准是其对多幅图像中相同或相似特征的检测能力,并且能够应对光照变化、图像旋转等图像变化。

    在我们解决问题时,往往希望找到特征点,“特征”顾名思义,指能描述物体本质的东西,还有一种解释就是这个特征微小的变化都会对物体的某一属性产生重大的影响。而角点就是这样的特征。

    观察日常生活中的“角落”就会发现,“角落”可以视为所有平面的交汇处,或者说是所有表面的发起处。假设我们要改变一个墙角的位置,那么由它而出发的平面势必都要有很大的变化。所以,这就引出了图像角点的定义。

     

    我们知道,特征检测与匹配是计算机视觉应用中非常重要的一部分,这需要寻找图像之间的特征建立对应关系。图像中的点作为图像的特殊位置,是很常用的一类特征,点的局部特征也可以叫做“关键特征点”(keypoint feature),或“兴趣点”(interest point),或“角点”(conrner)。

     

    另外,关于角点的具体描述可以有几种:

    一阶导数(即灰度的梯度)的局部最大所对应的像素点;两条及两条以上边缘的交点;图像中梯度值和梯度方向的变化速率都很高的点;角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。

     

     

     

     

    四、cornerHarris函数详解

     

     

    cornerHarris 函数用于在OpenCV中运行Harris角点检测算子处理图像。和cornerMinEigenVal( )以及cornerEigenValsAndVecs( )函数类似,cornerHarris 函数对于每一个像素(x,y)在\邻域内,计算2x2梯度的协方差矩阵\,接着它计算如下式子:

     

    \

     

    即可以找出输出图中的局部最大值,即找出了角点。

     

    其函数原型和参数解析:

     

    1. C++: void cornerHarris(InputArray src,OutputArray dst, int blockSize, int ksize, double k, intborderType=BORDER_DEFAULT )

     

     

     

    第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像。第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放Harris角点检测的输出结果,和源图片有一样的尺寸和类型。第三个参数,int类型的blockSize,表示邻域的大小,更多的详细信息在cornerEigenValsAndVecs()中有讲到。第四个参数,int类型的ksize,表示Sobel()算子的孔径大小。第五个参数,double类型的k,Harris参数。第六个参数,int类型的borderType,图像像素的边界模式,注意它有默认值BORDER_DEFAULT。更详细的解释,参考borderInterpolate( )函数。

     

    接着我们一起过一遍稍后需要用到的Threshold函数的解析,然后看一个以cornerHarris为核心的示例程序。

     

     

     

     

    五、Threshold函数详解

     

     

    函数Threshold( ) 对单通道数组应用固定阈值操作。该函数的典型应用是对灰度图像进行阈值操作得到二值图像。(另外,compare( )函数也可以达到此目的) 或者是去掉噪声,例如过滤很小或很大象素值的图像点。

     

    1. C++: double threshold(InputArray src,OutputArray dst, double thresh, double maxval, int type)

     

    第一个参数,InputArray类型的src,输入数组,填单通道 , 8或32位浮点类型的Mat即可。第二个参数,OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放输出结果,且和第一个参数中的Mat变量有一样的尺寸和类型。第三个参数,double类型的thresh,阈值的具体值。第四个参数,double类型的maxval,当第五个参数阈值类型type取 CV_THRESH_BINARY 或CV_THRESH_BINARY_INV 阈值类型时的最大值.第五个参数,int类型的type,阈值类型,。threshold( )函数支持的对图像取阈值的方法由其确定,具体用法如下图:

     

     

    \

     

     


     

    而图形化的阈值描述如下图:

     

    \

     

     

    讲解完这两个函数,让我们看一个调用示例程序:

     

    01. //-----------------------------------【头文件包含部分】--------------------------------------- 
    02. //      描述:包含程序所依赖的头文件 
    03. //----------------------------------------------------------------------------------------------  
    04. #include <opencv2/opencv.hpp> 
    05. #include <opencv2/imgproc/imgproc.hpp> 
    06.  
    07. //-----------------------------------【命名空间声明部分】--------------------------------------- 
    08. //      描述:包含程序所使用的命名空间 
    09. //-----------------------------------------------------------------------------------------------  
    10. using namespace cv; 
    11.  
    12. int main() 
    13.
    14. //以灰度模式载入图像并显示
    15. Mat srcImage = imread("1.jpg"0); 
    16. imshow("原始图", srcImage); 
    17.  
    18. //进行Harris角点检测找出角点
    19. Mat cornerStrength; 
    20. cornerHarris(srcImage, cornerStrength, 230.01);
    21.  
    22. //对灰度图进行阈值操作,得到二值图并显示 
    23. Mat harrisCorner; 
    24. threshold(cornerStrength, harrisCorner, 0.00001255, THRESH_BINARY); 
    25. imshow("角点检测后的二值效果图", harrisCorner); 
    26.  
    27. waitKey(0); 
    28. return 0
    29. }

     

     

    运行截图:

    \ \

     

     

     

     

     

     

     

     

    六、本文相关核心函数在OpenCV中的实现源代码

     

     

    这个部分贴出OpenCV中本文相关函数的源码实现细节,来给想了解实现细节的小伙伴们参考。浅墨暂时不在源码的细节上挖深作详细注释。

     

     

    6.1 OpenCV2.X中cornerHarris函数源代码

     

    源码路径: …opencvsourcesmodulesimgprocsrccorner.cpp

     

    1. void cv::cornerHarris( InputArray _src,OutputArray _dst, int blockSize, int ksize, double k, int borderType )
    2. {
    3. Mat src = _src.getMat();
    4. _dst.create( src.size(), CV_32F );
    5. Mat dst = _dst.getMat();
    6. cornerEigenValsVecs( src, dst, blockSize, ksize, HARRIS, k, borderType);
    7. }

     

     

    可见cornerHarris内部其实是调用了cornerEigenValsVecs函数,我们看看其实现源码:

     

    01. static void
    02. cornerEigenValsVecs( const Mat& src,Mat& eigenv, int block_size,
    03. int aperture_size, intop_type, double k=0.,
    04. intborderType=BORDER_DEFAULT )
    05. {
    06. #ifdef HAVE_TEGRA_OPTIMIZATION
    07. if (tegra::cornerEigenValsVecs(src, eigenv, block_size, aperture_size,op_type, k, borderType))
    08. return;
    09. #endif
    10.  
    11. int depth = src.depth();
    12. double scale = (double)(1 << ((aperture_size > 0 ?aperture_size : 3) - 1)) * block_size;
    13. if( aperture_size < 0 )
    14. scale *= 2.;
    15. if( depth == CV_8U )
    16. scale *= 255.;
    17. scale = 1./scale;
    18.  
    19. CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );
    20.  
    21. Mat Dx, Dy;
    22. if( aperture_size > 0 )
    23. {
    24. Sobel( src, Dx, CV_32F, 10, aperture_size, scale, 0, borderType );
    25. Sobel( src, Dy, CV_32F, 01, aperture_size, scale, 0, borderType );
    26. }
    27. else
    28. {
    29. Scharr( src, Dx, CV_32F, 10, scale, 0, borderType );
    30. Scharr( src, Dy, CV_32F, 01, scale, 0, borderType );
    31. }
    32.  
    33. Size size = src.size();
    34. Mat cov( size, CV_32FC3 );
    35. int i, j;
    36.  
    37. for( i = 0; i < size.height; i++ )
    38. {
    39. float* cov_data = (float*)(cov.data + i*cov.step);
    40. const float* dxdata = (const float*)(Dx.data + i*Dx.step);
    41. const float* dydata = (const float*)(Dy.data + i*Dy.step);
    42.  
    43. for( j = 0; j < size.width; j++ )
    44. {
    45. float dx = dxdata[j];
    46. float dy = dydata[j];
    47.  
    48. cov_data[j*3] = dx*dx;
    49. cov_data[j*3+1] = dx*dy;
    50. cov_data[j*3+2] = dy*dy;
    51. }
    52. }
    53.  
    54. boxFilter(cov, cov, cov.depth(), Size(block_size, block_size),
    55. Point(-1,-1), false, borderType );
    56.  
    57. if( op_type == MINEIGENVAL )
    58. calcMinEigenVal( cov, eigenv );
    59. else if( op_type == HARRIS )
    60. calcHarris( cov, eigenv, k );
    61. else if( op_type == EIGENVALSVECS )
    62. calcEigenValsVecs( cov, eigenv );
    63. }
    64.  
    65. }

     

     

     

     

    6.1 OpenCV2.X中Threshold函数源代码

     

    路径:…opencvsourcesmodulesimgprocsrc hresh.cpp

     

    01. double cv::threshold( InputArray _src,OutputArray _dst, double thresh, double maxval, int type )
    02. {
    03. Mat src = _src.getMat();
    04. bool use_otsu = (type & THRESH_OTSU) != 0;
    05. type &= THRESH_MASK;
    06.  
    07. if( use_otsu )
    08. {
    09. CV_Assert( src.type() == CV_8UC1 );
    10. thresh = getThreshVal_Otsu_8u(src);
    11. }
    12.  
    13. _dst.create( src.size(), src.type() );
    14. Mat dst = _dst.getMat();
    15.  
    16. if( src.depth() == CV_8U )
    17. {
    18. int ithresh = cvFloor(thresh);
    19. thresh = ithresh;
    20. int imaxval = cvRound(maxval);
    21. if( type == THRESH_TRUNC )
    22. imaxval = ithresh;
    23. imaxval = saturate_cast<uchar>(imaxval);
    24.  
    25. if( ithresh < 0 || ithresh >= 255 )
    26. {
    27. if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
    28. ((type == THRESH_TRUNC || type== THRESH_TOZERO_INV) && ithresh < 0) ||
    29. (type == THRESH_TOZERO&& ithresh >= 255) )
    30. {
    31. int v = type ==THRESH_BINARY ? (ithresh >= 255 0 : imaxval) :
    32. type ==THRESH_BINARY_INV ? (ithresh >= 255 ? imaxval : 0) :
    33. /*type == THRESH_TRUNC? imaxval :*/ 0;
    34. dst.setTo(v);
    35. }
    36. else
    37. src.copyTo(dst);
    38. return thresh;
    39. }
    40. thresh = ithresh;
    41. maxval = imaxval;
    42. }
    43. else if( src.depth() == CV_16S )
    44. {
    45. int ithresh = cvFloor(thresh);
    46. thresh = ithresh;
    47. int imaxval = cvRound(maxval);
    48. if( type == THRESH_TRUNC )
    49. imaxval = ithresh;
    50. imaxval = saturate_cast<short>(imaxval);
    51.  
    52. if( ithresh < SHRT_MIN || ithresh >= SHRT_MAX )
    53. {
    54. if( type == THRESH_BINARY || type == THRESH_BINARY_INV ||
    55. ((type == THRESH_TRUNC || type== THRESH_TOZERO_INV) && ithresh < SHRT_MIN) ||
    56. (type == THRESH_TOZERO&& ithresh >= SHRT_MAX) )
    57. {
    58. int v = type == THRESH_BINARY ?(ithresh >= SHRT_MAX ? 0 : imaxval) :
    59. type == THRESH_BINARY_INV ?(ithresh >= SHRT_MAX ? imaxval : 0) :
    60. /*type == THRESH_TRUNC ?imaxval :*/ 0;
    61. dst.setTo(v);
    62. }
    63. else
    64. src.copyTo(dst);
    65. return thresh;
    66. }
    67. thresh = ithresh;
    68. maxval = imaxval;
    69. }
    70. else if( src.depth() == CV_32F )
    71. ;
    72. else
    73. CV_Error( CV_StsUnsupportedFormat, "" );
    74.  
    75. parallel_for_(Range(0, dst.rows),
    76. ThresholdRunner(src, dst,thresh, maxval, type),
    77. dst.total()/(double)(1<<16));
    78. return thresh;
    79. }

     

     

    另外在贴上与之相关的自适应阈值操作函数的源码adaptiveThreshold:

     

    01. void cv::adaptiveThreshold( InputArray_src, OutputArray _dst, double maxValue,
    02. int method, inttype, int blockSize, double delta )
    03. {
    04. Mat src = _src.getMat();
    05. CV_Assert( src.type() == CV_8UC1 );
    06. CV_Assert( blockSize % 2 == 1 && blockSize > 1 );
    07. Size size = src.size();
    08.  
    09. _dst.create( size, src.type() );
    10. Mat dst = _dst.getMat();
    11.  
    12. if( maxValue < 0 )
    13. {
    14. dst = Scalar(0);
    15. return;
    16. }
    17.  
    18. Mat mean;
    19.  
    20. if( src.data != dst.data )
    21. mean = dst;
    22.  
    23. if( method == ADAPTIVE_THRESH_MEAN_C )
    24. boxFilter( src, mean, src.type(), Size(blockSize, blockSize),
    25. Point(-1,-1), true,BORDER_REPLICATE );
    26. else if( method == ADAPTIVE_THRESH_GAUSSIAN_C )
    27. GaussianBlur( src, mean, Size(blockSize, blockSize), 00,BORDER_REPLICATE );
    28. else
    29. CV_Error( CV_StsBadFlag, "Unknown/unsupported adaptive thresholdmethod" );
    30.  
    31. int i, j;
    32. uchar imaxval = saturate_cast<uchar>(maxValue);
    33. int idelta = type == THRESH_BINARY ? cvCeil(delta) : cvFloor(delta);
    34. uchar tab[768];
    35.  
    36. if( type == CV_THRESH_BINARY )
    37. for( i = 0; i < 768; i++ )
    38. tab[i] = (uchar)(i - 255 > -idelta ? imaxval : 0);
    39. else if( type == CV_THRESH_BINARY_INV )
    40. for( i = 0; i < 768; i++ )
    41. tab[i] = (uchar)(i - 255 <= -idelta ? imaxval : 0);
    42. else
    43. CV_Error( CV_StsBadFlag, "Unknown/unsupported threshold type");
    44.  
    45. if( src.isContinuous() && mean.isContinuous() &&dst.isContinuous() )
    46. {
    47. size.width *= size.height;
    48. size.height = 1;
    49. }
    50.  
    51. for( i = 0; i < size.height; i++ )
    52. {
    53. const uchar* sdata = src.data + src.step*i;
    54. const uchar* mdata = mean.data + mean.step*i;
    55. uchar* ddata = dst.data + dst.step*i;
    56.  
    57. for( j = 0; j < size.width; j++ )
    58. ddata[j] = tab[sdata[j] - mdata[j] + 255];
    59. }
    60. }

     

     

     

     

     

     

    七、综合示例部分

     

     

     

    本次综合示例为调节滚动条来控制阈值,以控制的harris检测角点的数量。一共有三个图片窗口,分别为显示原始图的窗口,包含滚动条的彩色效果图窗口,以及灰度图效果图窗口。

    废话不多说,让我们一起来欣赏详细注释过后的完整源代码:

     

    001. //-----------------------------------【程序说明】----------------------------------------------
    002. //      程序名称::《【OpenCV入门教程之十六】OpenCV角点检测之Harris角点检测》 博文配套源码
    003. //      开发所用IDE版本:Visual Studio 2010
    004. //      开发所用OpenCV版本:   2.4.9
    005. //      2014年6月8日 Created by 浅墨
    006. //      浅墨的微博:@浅墨_毛星云 http://weibo.com/1723155442
    007. //      浅墨的知乎:http://www.zhihu.com/people/mao-xing-yun
    008. //      浅墨的豆瓣:http://www.douban.com/people/53426472/
    009. //----------------------------------------------------------------------------------------------
    010.  
    011. //-----------------------------------【头文件包含部分】---------------------------------------
    012. //      描述:包含程序所依赖的头文件
    013. //----------------------------------------------------------------------------------------------
    014. #include <opencv2/opencv.hpp>
    015. #include "opencv2/highgui/highgui.hpp"
    016. #include "opencv2/imgproc/imgproc.hpp"
    017.  
    018. //-----------------------------------【命名空间声明部分】--------------------------------------
    019. //      描述:包含程序所使用的命名空间
    020. //-----------------------------------------------------------------------------------------------
    021. using namespace cv;
    022. using namespace std;
    023.  
    024. //-----------------------------------【宏定义部分】-------------------------------------------- 
    025. //  描述:定义一些辅助宏 
    026. //------------------------------------------------------------------------------------------------ 
    027. #define WINDOW_NAME1 "【程序窗口1】"        //为窗口标题定义的宏 
    028. #define WINDOW_NAME2 "【程序窗口2】"        //为窗口标题定义的宏 
    029.  
    030. //-----------------------------------【全局变量声明部分】--------------------------------------
    031. //      描述:全局变量声明
    032. //-----------------------------------------------------------------------------------------------
    033. Mat g_srcImage, g_srcImage1,g_grayImage;
    034. int thresh = 30//当前阈值
    035. int max_thresh = 175//最大阈值
    036.  
    037.  
    038. //-----------------------------------【全局函数声明部分】--------------------------------------
    039. //      描述:全局函数声明
    040. //-----------------------------------------------------------------------------------------------
    041. void on_CornerHarris( intvoid* );//回调函数
    042. static void ShowHelpText();
    043.  
    044. //-----------------------------------【main( )函数】--------------------------------------------
    045. //      描述:控制台应用程序的入口函数,我们的程序从这里开始执行
    046. //-----------------------------------------------------------------------------------------------
    047. int main( int argc, char** argv )
    048. {
    049. //【0】改变console字体颜色
    050. system("color 3F"); 
    051.  
    052. //【0】显示帮助文字
    053. ShowHelpText();
    054.  
    055. //【1】载入原始图并进行克隆保存
    056. g_srcImage = imread( "1.jpg"1 );
    057. if(!g_srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~!
    058. "); return false; } 
    059. imshow("原始图",g_srcImage);
    060. g_srcImage1=g_srcImage.clone( );
    061.  
    062. //【2】存留一张灰度图
    063. cvtColor( g_srcImage1, g_grayImage, CV_BGR2GRAY );
    064.  
    065. //【3】创建窗口和滚动条
    066. namedWindow( WINDOW_NAME1, CV_WINDOW_AUTOSIZE );
    067. createTrackbar( "阈值: ", WINDOW_NAME1, &thresh, max_thresh, on_CornerHarris );
    068.  
    069. //【4】调用一次回调函数,进行初始化
    070. on_CornerHarris( 00 );
    071.  
    072. waitKey(0);
    073. return(0);
    074. }
    075.  
    076. //-----------------------------------【on_HoughLines( )函数】--------------------------------
    077. //      描述:回调函数
    078. //----------------------------------------------------------------------------------------------
    079.  
    080. void on_CornerHarris( intvoid* )
    081. {
    082. //---------------------------【1】定义一些局部变量-----------------------------
    083. Mat dstImage;//目标图
    084. Mat normImage;//归一化后的图
    085. Mat scaledImage;//线性变换后的八位无符号整型的图
    086.  
    087. //---------------------------【2】初始化---------------------------------------
    088. //置零当前需要显示的两幅图,即清除上一次调用此函数时他们的值
    089. dstImage = Mat::zeros( g_srcImage.size(), CV_32FC1 );
    090. g_srcImage1=g_srcImage.clone( );
    091.  
    092. //---------------------------【3】正式检测-------------------------------------
    093. //进行角点检测
    094. cornerHarris( g_grayImage, dstImage, 230.04, BORDER_DEFAULT );
    095.  
    096. // 归一化与转换
    097. normalize( dstImage, normImage, 0255, NORM_MINMAX, CV_32FC1, Mat() );
    098. convertScaleAbs( normImage, scaledImage );//将归一化后的图线性变换成8位无符号整型
    099.  
    100. //---------------------------【4】进行绘制-------------------------------------
    101. // 将检测到的,且符合阈值条件的角点绘制出来
    102. forint j = 0; j < normImage.rows ; j++ )
    103. forint i = 0; i < normImage.cols; i++ )
    104. {
    105. if( (int) normImage.at<float>(j,i) > thresh+80 )
    106. {
    107. circle( g_srcImage1, Point( i, j ), 5,  Scalar(10,10,255), 280 );
    108. circle( scaledImage, Point( i, j ), 5,  Scalar(0,10,255), 280 );
    109. }
    110. }
    111. }
    112. //---------------------------【4】显示最终效果---------------------------------
    113. imshow( WINDOW_NAME1, g_srcImage1 );
    114. imshow( WINDOW_NAME2, scaledImage );
    115.  
    116. }
    117.  
    118. //-----------------------------------【ShowHelpText( )函数】----------------------------------
    119. //      描述:输出一些帮助信息
    120. //----------------------------------------------------------------------------------------------
    121. static void ShowHelpText()
    122. {
    123. //输出一些帮助信息
    124. printf("
    125.  
    126.  
    127. 【欢迎来到Harris角点检测示例程序~】
    128.  
    129. "); 
    130. printf("
    131.  
    132.  
    133. 请调整滚动条观察图像效果~
    134.  
    135. ");
    136. printf("
    137.  
    138. by浅墨"
    139. );
    140. }

     

     

     

    放出一些运行效果图。

    首先是原始图,非常美丽的异域建筑群:

    \

     

    第一组阈值效果图:

    \ \

    第二组阈值效果图:

    \ \

    第三组阈值效果图:

    \ \

    第四组阈值效果图:

    \ \

     

     


     

    本篇文章的配套源代码请点击这里下载:

     

    【浅墨OpenCV入门教程之十六】配套源代码下载

     


    \

     

    OK,今天的内容大概就是这些,我们下篇文章见:)
 
 
 
http://www.cnblogs.com/xrwang/archive/2010/03/03/1677515.html 综合实现!!!
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_34129145/article/details/86387593

智能推荐

opencv自动裁切_[原]opencv图像裁剪-程序员宅基地

文章浏览阅读663次。在图像处理中,我们经常根据需要截取图像中某一区域做处理,而不是针对整幅图像,这样会提高运算速度。当然,opencv有现成的截取函数供我们调用,但是考虑的运行平台不同(DSP芯片移植等),直接调用函数不现实。小生针对这一情况做了以下工作,不调用相关函数,截取到指定位置指定大小的图像,希望大家批评指正。c++代码:#include "stdafx.h"#include "cv.h"#include "..._opencvsharp 自动裁剪

JQuery 高级-程序员宅基地

文章浏览阅读224次。1. speed:动画的速度。三个预定义的值("slow","normal", "fast")或表示动画时长的毫秒数值(如:1000)2. easing:用来指定切换效果,默认是"swing",可用参数"linear"回调函数也是一个函数,与一般函数直接调用区别在于,回调函数是一个函数将另一个函数作为参数调用,被调用者就是回调函数。* swing:动画执行时效果是 先慢,中间快,最后又慢。3. fn:在动画完成时执行的函数,每个元素执行一次。对全局方法扩展2个方法,扩展min方法:求2个值的最小值;_jquery 高级

“地震波还有61秒到达”,08年筹建的技术,在这次四川地震中立功了_高新减灾系统接入费用多少-程序员宅基地

文章浏览阅读590次。文章发布于公号【数智物语】(ID:decision_engine),关注公号不错过每一篇干货。来源 | 量子位(公众号 ID: QbitAI)作者 |地应栗 郭一璞救命技术,紧急时刻立功了。6 月 17 日 22 点 55 分,地震频发的四川又发生了一场大地震,震中位于四川省宜宾市长宁县,震级达到 6.0 级,震源深度 16..._高新减灾系统接入费用多少

Ubuntu 18.04 opencv+vtk+anaconda+pycharm Environment Configuration_ubuntu编译vtk和python支持-程序员宅基地

文章浏览阅读675次。每次重新装ubuntu之后都得各处搜罗教程,这次打算自己写篇环境搭建的document以便之后查看。这次的环境搭建主要是用于三位重建,vtk用来进行suraface rendering。目录Anaconda+PyCharmVTK+OpenCVVTKAnaconda+PyCharm直接在官网下载anaconda 最新版本,用bash filepath执行.sh文件。一路默认直至安装完成。Py..._ubuntu编译vtk和python支持

MatchZoo 文本匹配工具包_文本匹配插件-程序员宅基地

文章浏览阅读932次。MatchZoo是封装了一系列文本匹配的框架包含以下算法:官网地址:https://github.com/kouunn/MatchZooModel Detail:1. DRMMthis model is an implementation ofA Deep Relevance Matching Model for Ad-hoc Retrieval.model file: mo..._文本匹配插件

计算机组成原理课设模板,计算机组成原理课习题.doc-程序员宅基地

文章浏览阅读100次。文档介绍:卒顽碴再束膛效策篆缺恋酉渗蒋绑淹讥徐悯壳猩箩惧坠爆励晴蛾臃船羚顷撤茶焊珐偷峻统钓炸呆脉诱英苑虾吱砚谦史半湛访勘贬闯仿摄疾叫痈靳煌够顶龋广晨寨鸵躲椎地弛镰科委捐漫般船剥敞治唤委骂桨邯秀寇眩蚀憨骄寅担坤塔鼎哨疆径争胁妹肪嘉积襟旭蝶领笔澜潞真碴坚噬嚎话行戊眺豌屎归妹讨废判痰浪褂焚锦认屈爹倍臀畦冗眉践专归详临尘瓢彤胯淑沸搁劈违助如助垢雀曙天庞忆手颓狂版踌痰坪版严拙沮障怒愁逼轴皂疾辉畦痛沂牌似腰郑..._pc机硬件在逻辑上主要由cpu、主存储器、__________、输入/输出设备、系统总线与i/

随便推点

PHP的substr_replace函数用于将指定位置之间的字符替换为指定的字符串_php 字符串指定位置替换-程序员宅基地

文章浏览阅读86次。PHP的substr_replace函数用于将指定位置之间的字符替换为指定的字符串。在本篇文章中,我将详细介绍如何使用substr_replace函数来实现这一功能,并提供相应的源代码。通过使用substr_replace函数,我们可以方便地将指定位置之间的字符替换为任意字符串,从而实现对字符串的部分替换操作。函数,将原始字符串中的指定位置之间的字符替换为星号字符串。语句将替换后的结果输出到屏幕上,结果为"Hello, *****!需要注意的是,如果不指定替换的字符数。,即”*****“。_php 字符串指定位置替换

Scratch案例——弹球游戏_scratch弹球游戏为啥接不住-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏32次。游戏介绍:一个小球在屏幕中移动,碰到边缘反弹回来,下面有一块板在左右移动,接到球之后就反弹,没有接到球的话,则失败。角色准备针对这样的一个游戏介绍,我们首先来确定游戏角色:小球、弹板。角色之弹板的编程三个角色中,弹板是最简单的,只需要左右移动就可以了,我们首先来针对弹板写一段程序:1、角色区选中Paddle:2、脚本区控制弹板,让弹板的X坐标跟随鼠标的X坐标变换。(小贴士:积木块的..._scratch弹球游戏为啥接不住

电脑自学c语言需要下载什么软件吗,我想学C语言,在自己的电脑上练习,要安装什么软件呢?...-程序员宅基地

文章浏览阅读525次。希望能对你有所帮助:1。 C语言学习系统 3。2C语言是一门非常有用高级语言,是您踏上计算机学习之路的必修课,几乎所有的计算机考试dl。pconline。com。cn/html/1/9/dlid=6199&dltypeid=1&pn=0&。html2。 C语言学习系统 3。2C语言是一门非常有用高级语言,是您踏上计算机学习之路的必修课,几乎所有的计算机考试3。 C语言程序设..._c语言学习需要下载什么

Android VTS 8.1 TEST 源码结构分析_android vts源码路径-程序员宅基地

文章浏览阅读2.6k次。之前看过关于VTS的东西,一直在采坑,网上能搜索到的资源也有限,基本都是环境搭建之类的,那些就不重复。如果你搭建好环境,并且跑起来了,一下是我对源码的一些简析:一 、Where to find VTS test cases源码介绍:https://android.googlesource.com/platform/test/vts/二、vts测试用例代码结构:1.kern..._android vts源码路径

二叉树的递归算法例题_递归算法统计二叉树的宽度-程序员宅基地

文章浏览阅读1.9k次,点赞18次,收藏63次。二叉树递归算法:1. 统计二叉树中,度为0的结点个数2. 统计二叉树中,度为1的结点个数3. 统计二叉树中,度为2的结点个数4. 统计二叉树高度5. 统计二叉树宽度度6. 删除二叉树中所有叶子节点7. 交换每个节点的左右子女8. 判断一棵树是否为二叉排序树9. 找出给定结点在二叉树中的层次10. 判断二叉树是否为平衡二叉树首先,创建二叉树BiTre..._递归算法统计二叉树的宽度

命令行导入导出数据文件-程序员宅基地

文章浏览阅读245次。 为支撑数据量,引入了MyCat做为分库,分表的代理持久层代理,MyCat在语法上不支持Mysql的语法。 Mycat数据导入需要带有插入声明的列:导出命令:1.通过doc进入到mysql目录下如:C:\Program Files (x86)\MySQL\MySQL Server 5.1\bin&gt;mysqldump -ur..._如何在cmd命令窗口将一个数据表导入本方案

推荐文章

热门文章

相关标签