橢圓檢測與擬合
歡迎到YangHan's Notebook 橢圓檢測與擬合 獲得更佳閱讀體驗饼记。
實驗目標
- 調(diào)?CvBox2D cvFitEllipse2( const CvArr* points )實現(xiàn)橢圓擬合
實驗環(huán)境
- Windows 10 1709
- OpenCV 3.3
實驗過程
實現(xiàn)了一個fitEllipse()
函數(shù),函數(shù)原型如下:
void fitEllipse(char* filename, int threshold);
傳入圖片路徑,然后顯示出圖片橢圓擬合之后的效果。
支持命令行解析圖片路徑參數(shù)。
FitEllipse.exe test.png
如果沒有路徑參數(shù),默認時當前目錄下的test.png
。
首先把圖片讀進來鹦肿,包括一份灰度圖和一份原圖。
Mat gray_img = imread(filename, IMREAD_GRAYSCALE);
Mat result = imread(filename);
把灰度圖二值化:
Mat binary_img = gray_img >= thresh;
然后使用findContours()
檢測二值化圖像的輪廓點辅柴。
findContours(binary_img, contours, RETR_LIST, CHAIN_APPROX_NONE);
其中箩溃,參數(shù)3可以取值為:
- RETR_EXTERNEL: 只檢測最外圍輪廓,包含在外圍輪廓內(nèi)的內(nèi)圍輪廓被忽略
- RETR_LIST: 檢測所有的輪廓碌嘀,包括內(nèi)圍涣旨、外圍輪廓,但是檢測到的輪廓不建立等級關系股冗,彼此之間獨立霹陡,沒有等級關系,這就意味著這個檢索模式下不存在父輪廓或內(nèi)嵌輪廓
- RETR_CCOMP: 檢測所有的輪廓止状,但所有輪廓只建立兩個等級關系烹棉,外圍為頂層,若外圍內(nèi)的內(nèi)圍輪廓還包含了其他的輪廓信息怯疤,則內(nèi)圍內(nèi)的所有輪廓均歸屬于頂層
- RETR_TREE: 檢測所有輪廓浆洗,所有輪廓建立一個等級樹結(jié)構。外層輪廓包含內(nèi)層輪廓集峦,內(nèi)層輪廓還可以繼續(xù)包含內(nèi)嵌輪廓伏社。
這里我們只選擇RETR_LIST
即可滿足橢圓擬合的要求。
參數(shù)4可以取值為:
- CHAIN_APPROX_NONE 保存物體邊界上所有連續(xù)的輪廓點到contours向量內(nèi)
- CHAIN_APPROX_SIMPLE 僅保存輪廓的拐點信息塔淤,把所有輪廓拐點處的點保存入contours向量內(nèi)摘昌,拐點與拐點之間直線段上的信息點不予保留
- CHAIN_APPROX_TC89_L1, CHAIN_APPROX_TC89_KCOS: 使用teh-Chin Chain 近似算法
這里直接選擇簡單的CHAIN_APPROX_NONE
。
然后對于檢測出的輪廓點高蜂,用橢圓去擬合:
for each (auto contour in contours)
{
if (contour.size() < 6) continue;
RotatedRect box = fitEllipse(contour);
ellipse(result, box, Scalar(0, 255, 255), 1, LINE_AA);
}
橢圓的擬合至少需要6個點聪黎,所以把少于6個點的檢測結(jié)果直接丟棄,然后對于剩下的點用cv2::fitEllipse()
來擬合备恤,然后把橢圓繪制在原圖上稿饰。
之后再保存結(jié)果就行了。
實驗結(jié)果
原圖:
test.png
結(jié)果:
result.png
可以看到橢圓基本上都檢測并擬合出來了烘跺。
心得體會
這次實驗就是先檢測出圖像的輪廓點,然后用fitEllipse()
函數(shù)來擬合橢圓脂崔,整體不是太難滤淳。然后注意到一點就是imread()
讀入圖片的時候第二個參數(shù)可以選擇讀入的模式,可以用IMREAD_GRAYSCALE
讓其讀入單通道的圖片矩陣數(shù)據(jù)砌左。
附:源代碼
// main.cpp
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
void fitEllipse(char* filename, int threshold);
int main(int argc, char** argv) {
char* filename;
if (argc == 2) {
filename = argv[1];
}
else {
filename = "test.png";
}
fitEllipse(filename, 150);
cvWaitKey(0);
destroyAllWindows();
return 0;
}
void fitEllipse(char* filename, int thresh) {
Mat gray_img = imread(filename, IMREAD_GRAYSCALE);
Mat result = imread(filename);
vector<vector<Point>> contours;
Mat binary_img = gray_img >= thresh;
findContours(binary_img, contours, RETR_LIST, CHAIN_APPROX_NONE);
for each (auto contour in contours)
{
if (contour.size() < 6) continue;
RotatedRect box = fitEllipse(contour);
ellipse(result, box, Scalar(0, 255, 255), 1, LINE_AA);
}
imwrite("result.png", result);
imshow(filename, gray_img);
imshow("result", result);
}