文章目录
一、常用图像特征描述
- SIFT、SURF、HOG、Haar、LBP、KAZE、AKAZE、BRISK
关于详情查看 OpenCV—python 角点特征检测之二(SIFT、SURF、ORB) SIFT 是用于描述图像中的局部特征,在空间尺度(使用高斯卷积核实现多尺度空间)中寻找极值点(LoG近似DoG找到关键点),并且提取出其位置、尺度、旋转不变量,因此具有尺度和旋转不变的性质。
SURF
与sift的算法相似,只是sift算法更加稳定,检测得到的特征点更多。但是surf的运算简单,运算时间更短一些。
surf最大的特点是采用 HARR 特征以及积分图像。
HOG
方向梯度直方图。用来表示图像的物体特征,算法流程如下:
【图像预处理:伽马校正和灰度化】 -> 【计算每一个像素点的梯度值,得到梯度图】 -> 【计算梯度直方图】 -> 【对16*16大小的block归一化】 -> 【得到HOG特征向量】
Haar
Haar特征是一种反映图像的灰度变化的,像素分模块求差值的一种特征。它分为三类:边缘特征、线性特征、中心特征和对角线特征。用黑白两种矩形框组合成特征模板,矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述在特定方向(水平、垂直、对角)上有明显像素模块梯度变化的图像结构。
LBP
LBP(Local Binary Pattern,局部二值模式)是一种用来描述图像局部纹理特征的算子;它具有旋转不变性和灰度不变性等显著的优点。它是首先由T. Ojala, M.Pietikäinen, 和D. Harwood 在1994年提出,用于纹理特征提取。而且,提取的特征是图像的局部的纹理特征;
KAZE
KAZE Features 算法是由法国学者在在2012年的ECCV会议 (论文) 中提出的, 是一种比SIFT更稳定的特征检测算法。KAZE特征检测是在图像域中进行非线性扩散处理的过程。
SITF、SURF算法是通过线性尺度空间,在线性尺度空间来检测特征点的,容易造成边界模糊和细节丢失;而KAZE算法是通过构造非线性尺度空间,并在非线性尺度空间来检测特征点,保留了更多的图像细节。
KAZE算法主要包括以下步骤:
(1) 非线性尺度空间的构建;
(2) 特征点的检测与精确定位;
(3) 特征点主方向的确定;
(4) 特征描述子的生成。
AKAZE
AKAZE是KAZE的加速版本。KAZE在构建非线性空间的过程中很耗时。
在非线性扩散滤波方面:AKAZE中将Fast Explicit Diffusion(FED)加入到金字塔框架可以dramatically speed-up。 在描述子方面:AKAZE使用了更高效的Modified Local Difference Binary(M-LDB),可以从非线性空间中利用梯度信息gradient information。M-LDB是旋转和尺度不变的,并且对内存的要求更低。 github地址:http://www.robesafe.com/personal/pablo.alcantarilla/kaze.html 在AKAZE算法中默认使用二进制描述符,故汉明距离进行比较
BRISK
Binary Robust Invariant Scalable Keypoints。它是一种二进制的特征描述算子。它具有较好的旋转不变性、尺度不变性,较好的鲁棒性等。在对有较大模糊的图像配准时,BRISK算法在其中表现最为出色。
在图像配准应用中,速度比较:SIFT<SURF<BRISK<FREAK<ORB。 算法流程:
- 特征点检测(建立尺度空间、特征点检测、非极大值抑制、亚像素插值)
- 特征点描述(高斯滤波、局部梯度计算、特征描述符)
- 匹配方法(汉明距离进行比较)
图像特征描述子用于: Detection、Description、Matching
二、Harris角点检测
1988 年的文章《A CombinedCorner and Edge Detector》中就已经提出了焦点检测的方法,被称为Harris 角点检测。
关于理论详情请查看:OpenCV—python 角点特征检测之一(cornerHarris、Shi-Tomasi、FAST)
角度响应:
InputArray src, 输入图像
OutputArray dst, 输出图像
int blockSize, 计算时候的矩阵大小
int ksize, 窗口大小
double k, 阈值:计算角度响应时候的参数大小,默认在0.04~0.06
int borderType = BORDER_DEFAULT 边界处理
)
头文件 image_feature_all.h
:声明类与公共函数
#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
class ImageFeature {
public:
void harris_demo(Mat& image);
void shi_tomasi_demo(Mat& image);
void custome_corner_demo(Mat& image);
};
主函数main.cpp
调用该类的公共成员函数
#include "image_feature_all.h"
int main(int argc, char** argv) {
const char* img_path = "D:\\Desktop\\xiaomuren.jpg";
Mat image = imread(img_path);
if (image.empty()) {
cout << "图像数据为空,读取文件失败!" << endl;
}
ImageFeature imgfeature;
imgfeature.harris_demo(image);
imgfeature.shi_tomasi_demo(image);
imgfeature.custome_corner_demo(image);
imshow("image", image);
waitKey(0);
destroyAllWindows();
return 0;
}
演示Harris角点检测
源文件 feature_extract.cpp
:实现类与公共函数
#include "image_feature_all.h"
void ImageFeature::harris_demo(Mat& image) {
Mat gray_img;
cvtColor(image, gray_img, COLOR_BGR2GRAY);
int thresh_ = 80;
Mat dst = Mat::zeros(gray_img.size(), CV_32FC1);
Mat norm_dst, norm_scale_dst;
int blocksize = 2;
int ksize = 3;
double k = 0.04;
cornerHarris(gray_img, dst, blocksize, ksize, k, BORDER_DEFAULT);
normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
convertScaleAbs(norm_dst, norm_scale_dst);
cout << "norm_scale_dst.type()=" << norm_scale_dst.type() << endl;
Mat result_img = image.clone();
for (int row = 0; row < result_img.rows; row++) {
uchar* row_ptr = norm_scale_dst.ptr(row);
for (int col = 0; col < result_img.cols; col++) {
int value = (int)*row_ptr++;
if (value > thresh_) {
circle(result_img, Point(col, row), 2, Scalar(0, 0, 255), 1, 8, 0);
}
}
}
imwrite("D:\\Desktop\\harris_"+ to_string(thresh_)+".jpg", result_img);
}
三、Shi-Tomasi角点检测
跟Harris角点检测的理论几乎完全一致,唯一不同的是在使用矩阵特征值
角度响应:
InputArray
image, 输入图像
OutputArray corners, 输出角点vector<point2d>
int maxCorners, 返回角点的数目,若检测角点数目大于maxCorners,则返回前maxCorners数目。
double qualityLevel, 最小可接受的向量值 0.01,
double minDistance, 两个角点之间的最小距离(欧几里得距离)
InputArray mask = noArray(),
int blockSize = 3, 导数微分不同的窗口大小
bool useHarrisDetector = false, 是否使用Harris角点检测
double k = 0.04
);
void ImageFeature::shi_tomasi_demo(Mat& image) {
Mat gray_img;
cvtColor(image, gray_img, COLOR_BGR2GRAY);
int num_colors[] = { 10,20,40,80 };
double qualityLevel = 0.01;
double minDistance = 10;
int blockSize = 3;
bool useHarris = false;
double k = 0.04;
RNG rng(1125);
for (size_t i = 0; i < 4; i++)
{
Mat result_img = image.clone();
vector<Point2f> corners;
corners.reserve(num_colors[i]);
goodFeaturesToTrack(gray_img, corners, num_colors[i], qualityLevel, minDistance, Mat(), blockSize, useHarris, k);
// 可视化角点
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
for (size_t i = 0; i < corners.size(); i++) {
circle(result_img, corners[i], 2, color, 2, 8);
}
imshow("result_img"+to_string(num_colors[i]), result_img);
}
}
四、自定义角点检测器
基于Harris与Shi-Tomasi角点检测
- 首先通过计算矩阵得到
- 然后自己设置阈值实现计算出阈值得到有效响应值的角点位置
使用 OpenCV 函数 cornerEigenValsAndVecs 来计算像素对应的本征值和本征向量来确定其是否是角点。
使用OpenCV 函数 cornerMinEigenVal 通过最小化本征值来进行角点检测。
用上述两个函数实现一个定制化的Harris detector,类似Shi-Tomasi检测子。
函数简介:
InputArray src,
OutputArray dst,
int blockSize,
int ksize,
int borderType = BORDER_DEFAULT
)
InputArray src,
OutputArray dst,
int blockSize,
int ksize = 3,
int borderType = BORDER_DEFAULT
)
void ImageFeature::custome_corner_demo(Mat& image) {
Mat gray_dst;
cvtColor(image, gray_dst, COLOR_BGR2GRAY);
// 自定义harris角点检测:计算本征值本征向量,获取其最大最小值。
int blockSize = 3;
int kSize = 3;
double k = 0.04;
Mat harris_dst = Mat::zeros(image.size(), CV_32FC1);
Mat harris_tmp = Mat::zeros(image.size(), CV_32FC(6));
cornerEigenValsAndVecs(gray_dst, harris_tmp, blockSize, kSize, 4);
for (size_t row = 0; row < gray_dst.rows; row++) {
Vec6f* harris_tmp_ptr = harris_tmp.ptr<Vec6f>(row);
float* harris_dst_ptr = harris_dst.ptr<float>(row);
for (size_t col = 0; col < gray_dst.cols; col++) {
double lambda1 = harris_tmp_ptr[col][0];
double lambda2 = harris_tmp_ptr[col][1];
*harris_dst_ptr++ = (float)(lambda1 * lambda2 - k * pow((lambda1 + lambda2), 2));
}
}
double harris_minVal = 0, harris_maxVal = 0;
minMaxLoc(harris_dst, &harris_minVal, &harris_maxVal, 0, 0, Mat());
// 自定义harris角点检测:可视化
int qualityLevel = 40; //修改该参数,显示不同效果。
int max_qualityLevel = 100;
Mat Harris_copy = image.clone();
float t = harris_minVal + (((double)qualityLevel / max_qualityLevel) * (harris_maxVal - harris_minVal));
RNG rng;
for (size_t row = 0; row < image.rows; row++) {
float* harris_dst_ptr = harris_dst.ptr<float>(row);
for (size_t col = 0; col < image.cols; col++) {
float v = *harris_dst_ptr++;
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
if (v > t) {
circle(Harris_copy, Point(col, row), 1, color, 2, 8, 0);
}
}
}
imshow("custom_Harris", Harris_copy);
// 自定义Shi-Tomas角点检测: 最小化本征值来进行角点检测
double ShiTomas_minVal = 0, ShiTomas_maxVal = 0;
Mat ShiTomas_dst = Mat::zeros(image.size(), CV_32FC1);
cornerMinEigenVal(gray_dst, ShiTomas_dst, blockSize, kSize, 4);
minMaxLoc(ShiTomas_dst, &ShiTomas_minVal, &ShiTomas_maxVal, 0, 0, Mat());
// 自定义Shi-Tomas角点检测:可视化
float t2 = ShiTomas_minVal + (((double)qualityLevel / max_qualityLevel) * (ShiTomas_maxVal - ShiTomas_minVal));
Mat ShiTomasi_copy = image.clone();
for (int row = 0; row < gray_dst.rows; row++){
float* ShiTomas_dst_ptr = ShiTomas_dst.ptr<float>(row);
for (int col = 0; col < gray_dst.cols; col++){
float val = *ShiTomas_dst_ptr++;
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
if (val > t2) {
circle(ShiTomasi_copy, Point(col, row), 4, color, -1, 8, 0);
}
}
}
imshow("custom_ShiTomasi", ShiTomasi_copy);
}