• OpenCV探索之路(十五):角点检测


    角点检测是计算机视觉系统中用来获取图像特征的一种方法。我们都常说,这幅图像很有特点,但是一问他到底有哪些特点,或者这幅图有哪些特征可以让你一下子就识别出该物体,你可能就说不出来了。其实说图像的特征,你可以尝试说一下这幅图有几个矩形啊几个圆形啊,有几条直线啊,当然啦,你也可以说一下有几个角点。

    什么是角点?

    角点通常被定义为两条边的交点。比如,三角形有三个角,矩形有四个角,这些就是角点,也是他们叫做矩形、三角形的特征,我们看到一些几何图形具有三个角,那么我们便可以脱口而出说这是一个三角形。

    上面所说的是严格意义上的角点,但是从广义来说,角点指的是拥有特定特征的图像点,这些特征点在图像中有具体的坐标,并具有某些数学特征(比如局部最大或最小的灰度)。

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

    • 边缘
    • 角点(感兴趣关键点)
    • 斑点(感兴趣区域)

    角点是个很特殊的存在。如果某一点在任意方向的一个微小的变动都会引起灰度很大的变化,那么我们就可以把该点看做是角点。

    Harris 角点检测

    Harris角点检测是一种直接基于灰度图的角点提取算法,稳定性高,尤其对L型角点(也就是直角)检测精度高。缺点也是明显的,就是运算速度慢。

    OpenCV使用的相应函数是

    void cornerHarris( InputArray src, OutputArray dst, int blockSize,int ksize,
                        double k, int borderType = BORDER_DEFAULT );
    

    下面给出相应的检测代码。

    #include <opencv2/opencv.hpp>  
    #include "opencv2/highgui/highgui.hpp"  
    #include "opencv2/imgproc/imgproc.hpp"  
    
    using namespace cv;
    using namespace std;
     
    
    Mat g_srcImage, g_srcImage1, g_grayImage;
    int thresh = 30; //当前阈值  
    int max_thresh = 175; //最大阈值  
    
    void on_CornerHarris(int, void*);//回调函数  
    
    int main(int argc, char** argv)
    {
    	g_srcImage = imread("lol19.jpg", 1);
    	if (!g_srcImage.data)
    	{
    		printf("读取图片错误! 
    ");
    		return -1;
    	}
    	imshow("原始图", g_srcImage);
    	g_srcImage1 = g_srcImage.clone();
    
    	//存留一张灰度图  
    	cvtColor(g_srcImage1, g_grayImage, CV_BGR2GRAY);
    
    	//创建窗口和滚动条  
    	namedWindow("角点检测", CV_WINDOW_AUTOSIZE);
    	createTrackbar("阈值: ", "角点检测", &thresh, max_thresh, on_CornerHarris);
    
    	//调用一次回调函数,进行初始化  
    	on_CornerHarris(0, 0);
    
    	waitKey(0);
    	return(0);
    }
    
    
    void on_CornerHarris(int, void*)
    {
    	Mat dstImage;//目标图  
    	Mat normImage;//归一化后的图  
    	Mat scaledImage;//线性变换后的八位无符号整型的图  
    
    	//置零当前需要显示的两幅图,即清除上一次调用此函数时他们的值  
    	dstImage = Mat::zeros(g_srcImage.size(), CV_32FC1);
    	g_srcImage1 = g_srcImage.clone();
    
    	//进行角点检测  
    	//第三个参数表示邻域大小,第四个参数表示Sobel算子孔径大小,第五个参数表示Harris参数
    	cornerHarris(g_grayImage, dstImage, 2, 3, 0.04, BORDER_DEFAULT);
    
    	// 归一化与转换  
    	normalize(dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
    	convertScaleAbs(normImage, scaledImage);//将归一化后的图线性变换成8位无符号整型   
    
    	// 将检测到的,且符合阈值条件的角点绘制出来  
    	for (int j = 0; j < normImage.rows; j++)
    	{
    		for (int i = 0; i < normImage.cols; i++)
    		{
    			//Mat::at<float>(j,i)获取像素值,并与阈值比较
    			if ((int)normImage.at<float>(j, i) > thresh + 80)
    			{
    				circle(g_srcImage1, Point(i, j), 5, Scalar(10, 10, 255), 2, 8, 0);
    				circle(scaledImage, Point(i, j), 5, Scalar(0, 10, 255), 2, 8, 0);
    			}
    		}
    	}
    	
    	imshow("角点检测", g_srcImage1);
    	imshow("角点检测2", scaledImage);
    
    }
    

    先看看原始图

    开始检测,我把阈值设为30,检测到角点还挺多的。

    我把阈值进一步提高,角点变少了。认真观察一下,是不是检测到的点都是一些亮度明显变化的临界点?比如由黑变白的边界点。

    Shi-Tomasi角点检测

    除了上述的Harris角点检测方法,我们还可以采用Shi-Tomasi方法进行角点检测。Shi-Tomsi算法是Harris算法的加强版,性能当然也有相应的提高。

    #include "opencv2/highgui/highgui.hpp"
    #include "opencv2/imgproc/imgproc.hpp"
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    
    using namespace cv;
    using namespace std;
    
    Mat src, src_gray;
    
    int maxCorners = 23;
    int maxTrackbar = 100;
    
    RNG rng(12345);  //RNG:random number generator,随机数产生器
    char* source_window = "Image";
    
    void goodFeaturesToTrack_Demo(int, void*);
    
    int main()
    {
    	//转化为灰度图
    	src = imread("lol19.jpg", 1);
    	cvtColor(src, src_gray, CV_BGR2GRAY);
    
    	namedWindow(source_window, CV_WINDOW_AUTOSIZE);
    
    	//创建trackbar
    	createTrackbar("MaxCorners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo);
    
    	imshow(source_window, src);
    
    	goodFeaturesToTrack_Demo(0, 0);
    
    	waitKey(0);
    	return(0);
    }
    
    void goodFeaturesToTrack_Demo(int, void*)
    {
    	if (maxCorners < 1) { maxCorners = 1; }
    
    	//初始化 Shi-Tomasi algorithm的一些参数
    	vector<Point2f> corners;
    	double qualityLevel = 0.01;
    	double minDistance = 10;
    	int blockSize = 3;
    	bool useHarrisDetector = false;
    	double k = 0.04;
    
    	//给原图做一次备份
    	Mat copy;
    	copy = src.clone();
    
    	// 角点检测
    	goodFeaturesToTrack(src_gray,corners,maxCorners,qualityLevel,minDistance,Mat(),blockSize,useHarrisDetector,k);
    
    	//画出检测到的角点
    	cout << "** Number of corners detected: " << corners.size() << endl;
    	int r = 4;
    	for (int i = 0; i < corners.size(); i++)
    	{
    		circle(copy, corners[i], r, Scalar(rng.uniform(0, 255), rng.uniform(0, 255),
    			rng.uniform(0, 255)), -1, 8, 0);
    	}
    
    	namedWindow(source_window, CV_WINDOW_AUTOSIZE);
    	imshow(source_window, copy);
    }
    

  • 相关阅读:
    区块链技术驱动金融.mobi
    ProcessExplorer 工具下载
    免费的论文查重网站
    接口可以继承接口吗?
    比较中的自动拆装箱
    Java语言中的异常处理
    Java类加载过程
    通过反射访问父类的私有成员
    final关键字详解
    MVC 控制台 +log4net 存入数据库
  • 原文地址:https://www.cnblogs.com/skyfsm/p/6899627.html
Copyright © 2020-2023  润新知