OpenCV图像特征提取与检测C++(二)Harris角点检测、Shi-Tomasi 角点检测、亚像素级别角点检测

图像特征类型可以分为三种:
边缘,角点,斑点。
其中,角点是个很特殊的存在,他们在图像中可以轻松定位,因为角点位于两条边缘的交点,代表了两条边缘变化的方向上的点,所以他们是可以精确定位的二维特征,甚至可以达到亚像素精度。
角点定义:如果某一点在任意方向的一个微小变动都会引起灰度很大的变化,则称为角点。
角点通常被定义为两条边的交点,更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界
1,一阶导数(灰度的梯度)的局部最大化所对应的像素点
2,两天及两条以上边缘的交点
3,图像中梯度值和梯度方向的变化速率都很高的点
4,角点处的一阶导数最大,二阶导数为0,指示物体边缘变化不连续的方向

角点检测算法分为三类:
1,基于灰度图像的角点检测
2,基于二值图像的角点检测
3,基于轮廓曲线的角点检测
角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中。也称为特征点检测。
角点响应函数R为:
R=λ1*λ2-k(λ1+λ2)的平方,k在0.04-0.06之间
Harris角点检测:
角点响应函数R为:
R=λ1*λ2-k(λ1+λ2)的平方,k在0.04-0.06之间
API:

void cornerHarris(InputArray src,   源图像,填Mat类的对象即可,且需为单通道8位或者浮点型图像
OutputArray dst,     这个参数用于存放Harris角点检测的输出结果,和源图片有一样的尺寸和类型。
int blockSize,         领域的大小即计算y1y2时候矩阵的大小
int ksize,                 表示Sobel()算子的孔径大小
double k,               k在0.04-0.06之间
intborderType=BORDER_DEFAULT  图像像素的边界模式
)

步骤:

  • 转为灰度图像
  • 角点检测找出角点
  • 转为二值图像

代码:

#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;

Mat src,graysrc;
int thresh_v = 130;
int thresh_max = 255;

void m_harris(int, void*) {
    Mat dst,nordst,scadst,retdst;
    dst = Mat::zeros(src.size(), CV_32FC1);
    cornerHarris(graysrc, dst, 2, 3, 0.04);
    normalize(dst, nordst, 0, 255, NORM_MINMAX,CV_32FC1 );// 检测出的元素值范围不确定,而且有正有负,归一化
    convertScaleAbs(nordst, scadst, 1, 0);// 将元素值取绝对值,且将输出图像深度变为 CV_8U
    retdst = src.clone();
    for (int row = 0; row < retdst.rows; row++) {
        uchar* curRow = scadst.ptr(row);
        for (int col = 0; col < retdst.cols; col++) {
            int value = (int)*curRow;
            if (value > thresh_v) {  // 过滤,角点响应值 大于 阈值才显示
                circle(retdst, Point(col, row), 2, Scalar(0, 0, 255), 2);
            }
            curRow++;
        }
    }
    imshow("output", retdst);
}

int main() {

    src = imread("C:/Users/Administrator/Desktop/pic/1-H.jpg");
    cvtColor(src, graysrc, CV_BGR2GRAY);
    imshow("input", src);
    m_harris(0, 0);
    createTrackbar("yuzhi", "output", &thresh_v, thresh_max, m_harris);

    waitKey(0);
}

结果:
这里写图片描述

Shi-Tomasi 角点检测
Shi-Tomasi 算法是Harris 算法的改进。Harris 算法最原始的定义是将矩阵 M 的行列式值与 M 的迹相减,再将差值同预先给定的阈值进行比较。后来Shi 和Tomasi 提出改进的方法,若两个特征值中较小的一个大于最小阈值,则会得到强角点。
唯一不同的是在使用矩阵 特征值 λ1 λ2 计算角度响应的时候
R = min(λ1, λ2)
API:

void goodFeaturesToTrack( // Shi-Tomasi角点检测
InputArray image,  // 灰度图像
OutputArray corners, // 检测出来的角点在输入图像的Point
int maxCorners, // -maxCorners 表示返回角点的数目,如果检测出来的角点数目大于最大数目则返回响应值最强前maxCorners数目。
double qualityLevel, // -qualityLevel表示最小可接受的向量值1500, 0.01, 15
double minDistance, // -minDistance两个角点之间的最小距离(欧几里得距离)
InputArray mask = noArray(),
int blockSize = 3, // -blockSize 计算导数微分不同的窗口大小
bool useHarrisDetector = false, // -useHarrisDetector是否使用Harris角点检测,设置为false的时候 下一个参数 k 无效
double k = 0.04 // 最好 0.04~0.06
);

代码:

#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;

Mat src, graysrc;
int thresh_v = 5;
int thresh_max = 255;

void shi_tomasi(int, void*) {
    vector<Point2f>corners;
    Mat dst = src.clone();
    goodFeaturesToTrack(graysrc, corners, thresh_v, 0.01, 10);
    for (int i = 0; i < corners.size(); i++) {
        circle(dst, corners[i], 2, Scalar(255, 0, 233), 2);
    }
    imshow("output", dst);
}

int main() {
    src = imread("C:/Users/Administrator/Desktop/pic/1-H.jpg");
    imshow("input", src);
    cvtColor(src, graysrc, CV_BGR2GRAY);
    shi_tomasi(0, 0);
    createTrackbar("yuhzi", "output", &thresh_v, thresh_max, shi_tomasi);
    waitKey(0);
}

结果:
这里写图片描述

亚像素级别角点检测
提高检测精准度
理论与现实总是不一致的,实际情况下几乎所有的角点不会是一个真正的准确像素点。
检测出的点(100, 5) 实际上可能是(100.234, 5.789),可以使用亚像素定位确定准确位置
- 跟踪
- 三维重建
- 相机校正
亚像素定位方法
- 插值方法
- 基于图像矩计算
- 曲线拟合方法 -(高斯曲面(最常用)、多项式、椭圆曲面)

代码:

#include <opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
#include <string> 
#include<fstream> 
using namespace cv;
using namespace std;

Mat src, graysrc;
int thresh_v = 50;
int thresh_max = 255;

void sub_dip(int, void*) {
    vector<Point2f>corners;
    goodFeaturesToTrack(graysrc, corners, thresh_v, 0.01, 10);
    cout << "corner_size:" << corners.size() << endl;
    Mat dst = src.clone();
    for (int i = 0; i < corners.size(); i++) {
        cout << i << ".point[x,y]=" << corners[i].x << "," << corners[i].y << endl;
        circle(dst, corners[i], 2, Scalar(0, 255, 255), 2);
    }
    imshow("output", dst);
    Size winsize = Size(5, 5);//窗口不要太大,不然亚像素可能会被干扰
    Size zerozone = Size(-1, -1);// 拟合时使用 零区域
     //TermCriteria类是用来作为迭代算法的终止条件的,参数:类型(EPS表示迭代到阈值终止),
    //第二个参数为迭代的最大次数,最后一个是特定的阈值
    TermCriteria tc = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001);
    cornerSubPix(graysrc, corners, winsize, zerozone, tc);//亚像素定位,为后续计算提供更高精确度的值
    cout << "subpix corner_size:" << corners.size() << endl;
    for (size_t i = 0; i < corners.size(); i++) {
        cout << i << ".point[x,y]=" << corners[i].x << "," << corners[i].y << endl;// 亚像素定位出来的,精确度较高,浮点值
    }
}

结果:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_26907755/article/details/81742160