SongpingWang 2021-08-15 03:06:51 阅读数:910
關於詳情查看 OpenCV—python 角點特征檢測之二(SIFT、SURF、ORB)
SIFT 是用於描述圖像中的局部特征,在空間尺度(使用高斯卷積核實現多尺度空間)中尋找極值點(LoG近似DoG找到關鍵點),並且提取出其比特置、尺度、旋轉不變量,因此具有尺度和旋轉不變的性質。
與sift的算法相似,只是sift算法更加穩定,檢測得到的特征點更多。但是surf的運算簡單,運算時間更短一些。
surf最大的特點是采用 HARR 特征以及積分圖像。
方向梯度直方圖。用來錶示圖像的物體特征,算法流程如下:
【圖像預處理:伽馬校正和灰度化】 -> 【計算每一個像素點的梯度值,得到梯度圖】 -> 【計算梯度直方圖】 -> 【對16*16大小的block歸一化】 -> 【得到HOG特征向量】
Haar特征是一種反映圖像的灰度變化的,像素分模塊求差值的一種特征。它分為三類:邊緣特征、線性特征、中心特征和對角線特征。用黑白兩種矩形框組合成特征模板,矩形特征只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述在特定方向(水平、垂直、對角)上有明顯像素模塊梯度變化的圖像結構。
詳情查看:https://blog.csdn.net/lanxuecc/article/details/52222369
LBP(Local Binary Pattern,局部二值模式)是一種用來描述圖像局部紋理特征的算子;它具有旋轉不變性和灰度不變性等顯著的優點。它是首先由T. Ojala, M.Pietikäinen, 和D. Harwood 在1994年提出,用於紋理特征提取。而且,提取的特征是圖像的局部的紋理特征;
詳情查看:https://blog.csdn.net/xidianzhimeng/article/details/19634573
KAZE Features 算法是由法國學者在在2012年的ECCV會議 (論文) 中提出的, 是一種比SIFT更穩定的特征檢測算法。KAZE特征檢測是在圖像域中進行非線性擴散處理的過程。
SITF、SURF算法是通過線性尺度空間,在線性尺度空間來檢測特征點的,容易造成邊界模糊和細節丟失;而KAZE算法是通過構造非線性尺度空間,並在非線性尺度空間來檢測特征點,保留了更多的圖像細節。
KAZE算法主要包括以下步驟:
(1) 非線性尺度空間的構建;
(2) 特征點的檢測與精確定比特;
(3) 特征點主方向的確定;
(4) 特征描述子的生成。
關於詳情查看:https://www.cnblogs.com/xinyuyuanm/archive/2013/03/25/2980817.html
AKAZE是KAZE的加速版本。KAZE在構建非線性空間的過程中很耗時。
在非線性擴散濾波方面:AKAZE中將Fast Explicit Diffusion(FED)加入到金字塔框架可以dramatically speed-up。
在描述子方面:AKAZE使用了更高效的Modified Local Difference Binary(M-LDB),可以從非線性空間中利用梯度信息gradient information。M-LDB是旋轉和尺度不變的,並且對內存的要求更低。
詳情鏈接:https://blog.csdn.net/zcg1942/article/details/84570068
論文及github地址:http://www.robesafe.com/personal/pablo.alcantarilla/kaze.html
在AKAZE算法中默認使用二進制描述符,故漢明距離進行比較
Binary Robust Invariant Scalable Keypoints。它是一種二進制的特征描述算子。它具有較好的旋轉不變性、尺度不變性,較好的魯棒性等。在對有較大模糊的圖像配准時,BRISK算法在其中錶現最為出色。
在圖像配准應用中,速度比較:SIFT<SURF<BRISK<FREAK<ORB。
詳情查看:https://www.cnblogs.com/welen/articles/6088639.html、https://blog.csdn.net/Daker_Huang/article/details/84960704
算法流程:
圖像特征描述子用於: Detection、Description、Matching
1988 年的文章《A CombinedCorner and Edge Detector》中就已經提出了焦點檢測的方法,被稱為Harris 角點檢測。
關於理論詳情請查看:OpenCV—python 角點特征檢測之一(cornerHarris、Shi-Tomasi、FAST)
角度響應:
R = det ( M ) − k ( t r a c e ( M ) ) 2 det ( M ) = λ 1 ∗ λ 2 t r a c e ( M ) = λ 1 + λ 2 R = \det(M)-k(trace(M))^2\\ ~\\ \det(M) = \lambda_1 * \lambda_2\\ trace(M) = \lambda_1 + \lambda_2 R=det(M)−k(trace(M))2 det(M)=λ1∗λ2trace(M)=λ1+λ2
頭文件 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;
}
源文件 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);
}
跟Harris角點檢測的理論幾乎完全一致,唯一不同的是在使用矩陣特征值 λ 1 , λ 2 \lambda_1, \lambda_2 λ1,λ2 計算角度響應的時候
角度響應: R = min ( λ 1 , λ 2 ) R = \min(\lambda_1 , \lambda_2) R=min(λ1,λ2)
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檢測子。
函數簡介:
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);
}
版权声明:本文为[SongpingWang]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/08/20210815030634223W.html