文章目錄
- 亞像素級别角點檢測
- 示範像素坐标檢測
亞像素級别角點檢測
亞像素:在生成數字圖像處理時(拍照等)我們是将實體世界中連續的圖像進行了離散化處理。現實世界中顔色為連續的且有無數種類,成像到像素面上每一個像素點隻代表其附近的顔色,我們常使用的3通道圖像顔色種類(255*255*255)代表,至于“附近”到什麼程度?就很困難解釋。兩個像素之間有5.2微米的距離,在宏觀上可以看作是連在一起的。但是在微觀上,它們之間還有無限的更小的東西存在。這個更小的東西我們稱它為“亞像素”。實際上“亞像素”應該是存在的,隻是硬體上沒有個細微的傳感器把它檢測出來。于是軟體上把它近似地計算出來。
亞像素級别角點檢測,提高檢測精準度;由于理論與現實總是不一緻的,實際情況下幾乎所有的角點不會是一個真正的準确像素點。例如(100, 5) 實際上(100.234, 5.789)。
特别是在:跟蹤,三維重建,相機校正方面,為了擷取更加精準的角點,這樣一來就需要亞像素級别角點檢測。
亞像素定位方法
- 插值方法
- 基于圖像矩計算
- 曲線拟合方法 -(高斯曲面、多項式、橢圓曲面)
除了利用 Harris和 Shi-Tomasi方法進行角點檢測 外, 還可以使用cornerEigenValsAndVecs() 函數和 cornerMinEigenVal() 函數自定義角點檢測函數。
如果對角點的精度有更高的要求,可以用 cornerSubPix() 函數将角點定位到子像素,進而取得亞像素級别的角點檢測效果。
函數簡介
函數goodFeaturesToTrack()函數隻能提供簡單的像素的整數坐标值,若需要實數坐标值則需要使用cornerSubPix()函數,用于尋找亞像素角點的位置:
InputArray image, 輸入圖像;
InputOutputArray corners, 初始化輸入角點與精确的輸出坐标
Size winSize, 搜尋視窗半徑。若Size(5,5),表示(5*2+1)*(5*2+1)=11*11大小的搜尋視窗。
Size zeroZone, 表示死區的一半尺寸。為不對搜尋區的中央位置做求和運算,用來避免自相關矩陣出現的某些可能的奇異性。值為(-1,-1)表示沒有死區。
TermCriteria criteria 求角點的疊代過程的終止條件。
);
-
其中:
cv::TerCriteria::MAX_ITER :疊代終止條件為達到最大疊代次數終止
cv::TerCriteria::EPS : 疊代到門檻值終止
cv::TerCriteria::MAX_ITER+cv::TerCriteria::EPS :兩者都作為疊代終止條件
頭檔案
image_feature_all.h
:聲明類與公共函數
#pragma once
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
class ImageFeature {
public:
void subpixel_corner_demo(Mat& image);
};
主函數
main.cpp
調用該類的公共成員函數
#include "image_feature_all.h"
int main(int argc, char** argv) {
const char* img_path = "D:\\Desktop\\jianzhu.jpg";
Mat image = imread(img_path);
if (image.empty()) {
cout << "圖像資料為空,讀取檔案失敗!" << endl;
}
ImageFeature imgfeature;
imgfeature.subpixel_corner_demo(image);
imshow("image", image);
waitKey(0);
destroyAllWindows();
return 0;
}
示範像素坐标檢測
檢測出角點,再拟合亞像素級别角點位置
static void on_subpixel(int num_corner, void* userdata) {
Mat image = *((Mat*)userdata);
Mat gray_src;
cvtColor(image, gray_src, COLOR_BGR2GRAY);
if (num_corner < 5) { num_corner = 5; }
//角點檢測Shi-Tomasi
vector<Point2f> corners;
double qualityLevel = 0.03;
double minDistance = 10;
int blockSize = 3;
bool userHarris = false;
double k = 0.04;
goodFeaturesToTrack(gray_src, corners, num_corner,
qualityLevel, minDistance, Mat(), blockSize, userHarris, k);
cout << "corners.size() = " << corners.size() << endl;
//可視化
RNG rng(12345);
Mat resultImg = gray_src.clone();
cvtColor(resultImg, resultImg, COLOR_GRAY2BGR);
for (size_t i = 0; i < corners.size(); i++){
Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
circle(resultImg, corners[i], 2, color, 1, 8, 0);
}
imshow("subpixel", resultImg);
//拟合亞像素角點位置并計算亞像素角點位置
Size winSize = Size(5, 5);
Size zerozone = Size(-1, -1);
TermCriteria tc = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001);
cornerSubPix(gray_src, corners, winSize, zerozone, tc);
//列印精細坐标
for (size_t i = 0; i < corners.size(); i++){
cout << (i + 1) << ".point[x,y]\t" << corners[i].x << "," << corners[i].y << endl;
}
return;
}
void ImageFeature::subpixel_corner_demo(Mat& image) {
cv::namedWindow("subpixel", WINDOW_NORMAL);
int num_corner = 100;
int max_corner = 500;
createTrackbar("CorNum", "subpixel", &num_corner, max_corner, on_subpixel, (void*)&image);
on_subpixel(0, &image);
}