iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 9
0
自我挑戰組

我的影像視覺定位學習筆記系列 第 9

day9-圖像特徵(FAST實作)

  • 分享至 

  • xImage
  •  

這邊我想講一些圖像特徵中"特徵點偵測"的部分,有很多演算法想辦法從圖像中獲取有意義的特徵,
比方說角點、物體的邊緣,一些紋理強烈的部分。而這篇提到的FAST主要在於偵測角點的部分。
演算法的細節可以參考openCV的講解。
https://docs.opencv.org/master/df/d0c/tutorial_py_fast.html

而FAST的演算法只提供找尋有意義的特徵,並沒有為該特徵計算它的描述符用以辨識不同特徵的差異性。
如果我們未來想用FAST的特徵來做特徵匹配的部分,就會需要搭配其他演算法來計算特徵的描述符。
我想把這部分留到日後的內容。

具體的程式碼由opencv的範例改寫
https://docs.opencv.org/3.4/d7/d66/tutorial_feature_detection.html
我原先想直接示範SURF的特徵點偵測,但是當初在cmake的時候似乎漏掉了 OPENCV_ENABLE_NONFREE的選項,
有些演算法有專利,而opencv需要把這些演算法的實作搬移到當初下載sources code 的extra modules裡面。
看起來又要重新編譯sources code了呢............/images/emoticon/emoticon02.gif

#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
#include <opencv2/imgproc.hpp>/*putText*/
#include <string>

int main() {
	cv::Mat image01 = cv::imread("box.png", -1);

	cv::imshow("box", image01);
	cv::waitKey(0);


	//-- Step 1: Detect the keypoints using FAST Detector
	int 	threshold = 10;
	bool 	nonmaxSuppression = true;
	int 	type = cv::FastFeatureDetector::TYPE_9_16;
	cv::Ptr<cv::FastFeatureDetector> detectorFAST = cv::FastFeatureDetector::create();
	std::vector<cv::KeyPoint> FASTkeypoints;
	detectorFAST->detect(image01, FASTkeypoints);

/*
	int minHessian = 400;
	cv::Ptr<cv::xfeatures2d::SURF> detector = cv::xfeatures2d::SURF::create(minHessian);
	std::vector<cv::KeyPoint> keypoints;
	detector->detect(image01, keypoints);
*/
	//-- Draw keypoints
	cv::Mat img_keypoints;
	cv::drawKeypoints(image01, FASTkeypoints, img_keypoints);
	cv::waitKey();

	for (unsigned int j = 0; j < FASTkeypoints.size(); j+=100) {
		std::string kpPosition = std::to_string(j)+"th Scale: " + std::to_string(image01.at<uchar>(cv::Point(FASTkeypoints.at(j).pt.x, FASTkeypoints.at(j).pt.y)));
		cv::putText(img_keypoints, kpPosition,cv::Point(FASTkeypoints.at(j).pt.x, FASTkeypoints.at(j).pt.y),0,0.5, cv::Scalar(255,255  ,255 ),1);
	}

	//-- Show detected (drawn) keypoints
	imshow("FAST Keypoints", img_keypoints);
	cv::waitKey();
	return 0;
}

第一步當然就是先讀入一張影像,你可以使用你自己的影像(但是要注意FAST只適用灰階影像),
所以你可能需要改變imread的參數,或是讀入彩色影像之後再轉灰階。

也可以從sources code的資料夾裡面的samples/data找到我這邊使用的box.png 。
首先先創建偵測特徵的FAST,用cv::Ptr<>包起來,我們就不需要花心思去思考該Detector甚麼時候要delete。
而create裡面有三個可以修改的選項,不用賦值也沒關係它有預設值,這三個選項會改變FAST演算法的變數,
你可以理解完演算法再來做你想要的修改。

而Detector需要我們準備一個KeyPoint由vector包起來的容器,來儲存偵測出來的特徵點的位置,
之後我們想要將偵測出來的特徵點在原本的圖像上標記起來可以使用 cv::drawKeypoints來標記,

	for (unsigned int j = 0; j < FASTkeypoints.size(); j+=100) {
		std::string kpPosition = std::to_string(j)+"th Scale: " + std::to_string(image01.at<uchar>(cv::Point(FASTkeypoints.at(j).pt.x, FASTkeypoints.at(j).pt.y)));
		cv::putText(img_keypoints, kpPosition,cv::Point(FASTkeypoints.at(j).pt.x, FASTkeypoints.at(j).pt.y),0,0.5, cv::Scalar(255,255  ,255 ),1);
	}

最後你可以透過KeyPoint裡面的所記錄特徵點在影像中的位子(x,y),回去讀影像該特徵點的灰階值,並將結果表示在影像上。
https://ithelp.ithome.com.tw/upload/images/20190925/2012112702xENmbp9t.png
而由於FAST 偵測出來的特徵點有很多,如果要每個特徵點的都畫出來的話,整個圖像反而變得難以辨識,
所以你可以修改for裡面的變數來讓畫面更簡潔有意義。
而未來要如何將這麼多的特徵點過濾出比較有高辨識度的點,就是圖像匹配主要的工作。

最後KeyPoint在vector的順序是有其意義的,未來再做特徵匹配的時候,會跟描述符的順序一起看。你如果想對vector裡面的資料做變動,請確定你的操作不會破壞所對應的描述符的意義。


上一篇
day8-從影像中如何獲得3D點座標
下一篇
day10-特徵描述符與匹配過濾
系列文
我的影像視覺定位學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言