OpenCV C++(九)----幾何形狀的檢測和擬合

9.1田晚、點集的最小外包

點集是坐標(biāo)點的集返弹。

9.1.1、最小外包旋轉(zhuǎn)矩形

//點集
Mat points = (Mat_<float>(5, 2) << 1, 1, 5, 1, 1, 10, 5, 10, 2, 5);
//計算點集的最小外包旋轉(zhuǎn)矩陣
RotatedRect rRect = minAreaRect(points);
//打印旋轉(zhuǎn)矩形的信息
cout << "旋轉(zhuǎn)矩形的角度" << rRect.angle << endl;
cout << "旋轉(zhuǎn)矩形的中心" << rRect.center << endl;
cout << "旋轉(zhuǎn)矩形的尺寸" << rRect.size << endl;

9.1.2沐兰、旋轉(zhuǎn)矩形的四個頂點

OpenCV3新特性

void boxPoints(RotatedRect box,OutputArray points)

便于計算旋轉(zhuǎn)矩形的四個頂點,這樣就可以使用函數(shù)line畫出四個頂點的連線蔽挠,從而畫出旋轉(zhuǎn)矩形住闯。

9.1.3、最小外包圓

void minEnclosingCircle( InputArray points,CV_OUT Point2f& center, CV_OUT float& radius );

9.1.4澳淑、最小外包直立矩形

Rect boundingRect( InputArray points );

9.1.5比原、最小凸包

凸包是將最外層的點連接起來構(gòu)成的凸多邊形,它能包含點集的所有點杠巡。

void convexHull( InputArray points, OutputArray hull,
                              bool clockwise = false, bool returnPoints = true );

利用該函數(shù)求出的凸包量窘,坐標(biāo)點的順序不是隨機(jī)排列的,而是按照某順序排列的氢拥,也就是把這些點依次相連就可以得到連線蚌铜。

9.1.6、最小外包三角形

OpenCV3新特性

double minEnclosingTriangle( InputArray points, CV_OUT OutputArray triangle );

    //5行2列的單通道Mat
    Mat point = (Mat_<int>(5, 2) << 1, 1, 5, 1, 1, 10, 5, 10, 2, 5);
    //轉(zhuǎn)換為雙通道矩陣
    point = point.reshape(2, 5);
    //存儲三角形的三個頂點
    vector<Point> triangle;
    //點集的最小外包三角形
    double area;
    area = minEnclosingTriangle(point, triangle);
    //打印結(jié)果
    cout << "三角形的三個頂點";
    for (int i = 0; i < 3; i++)
    {
        cout << triangle[i] << ",";
    }
    cout << "面積" << area << endl;

9.2嫩海、霍夫直線檢測

如果知道原點到一條直線的代數(shù)距離ρ和與x軸的夾角θ冬殃,則直線方程可由以下方式表示:

image.png

當(dāng)然, 反過來也可以出革, 如果知道平面內(nèi)的一條直線造壮, 那么可以計算出唯一的ρ和θ渡讼, 即xoy平面內(nèi)的任意一條直線對應(yīng)參數(shù)空間(或稱霍夫空間) θoρ中的一點(ρ骂束, θ) 。

image.png
image.png

Hough直線檢測的基本原理在于利用點與線的對偶性成箫≌瓜洌霍夫變換運用兩個坐標(biāo)空間之間的變換,將在一個空間中具有相同形狀的曲線或直線映射到另一個坐標(biāo)空間的一個點上形成峰值蹬昌,從而把檢測任意形狀的問題轉(zhuǎn)化為統(tǒng)計峰值問題混驰。

結(jié)論:判斷xoy平面內(nèi)哪些點是共線的,首先求出每一個點對應(yīng)到霍夫空間的曲線,然后判斷哪幾條曲線相交于一點栖榨,最后將相交于一點的曲線反過來對應(yīng)到xoy平面內(nèi)的點昆汹,這些點是共線的。

在理論上婴栽,一個點對應(yīng)無數(shù)條直線或者說任意方向的直線(在參數(shù)空間中坐標(biāo)軸表示的斜率k或者說θ有無數(shù)個)满粗,但在實際應(yīng)用中,我們必須限定直線的數(shù)量(即有限數(shù)量的方向)才能夠進(jìn)行計算愚争。

因此映皆,我們將直線的方向θ離散化為有限個等間距的離散值,參數(shù)ρ也就對應(yīng)離散化為有限個值轰枝,于是參數(shù)空間不再是連續(xù)的捅彻,而是被離散量化為一個個等大小網(wǎng)格單元。將圖像空間(直角坐標(biāo)系)中每個像素點坐標(biāo)值變換到參數(shù)空間(極坐標(biāo)系)后鞍陨,所得值會落在某個網(wǎng)格內(nèi)步淹,使該網(wǎng)格單元的累加計數(shù)器加1。當(dāng)圖像空間中所有的像素都經(jīng)過霍夫變換后诚撵,對網(wǎng)格單元進(jìn)行檢查贤旷,累加計數(shù)值最大的網(wǎng)格,其坐標(biāo)值(ρ0, θ0)就對應(yīng)圖像空間中所求的直線砾脑。

如下圖解

image.png

總結(jié):使用霍夫變換檢測直線具體步驟:
1.彩色圖像->灰度圖
2.去噪(高斯核)
3.邊緣提扔资弧(梯度算子、拉普拉斯算子韧衣、canny盅藻、sobel
4.二值化(判斷此處是否為邊緣點,就看灰度值==255)
5.映射到霍夫空間(準(zhǔn)備兩個容器畅铭,一個用來展示hough-space概況氏淑,一個數(shù)組hough-space用來儲存voting的值,因為投票過程往往有某個極大值超過閾值硕噩,多達(dá)幾千假残,不能直接用灰度圖來記錄投票信息)
6.取局部極大值,設(shè)定閾值炉擅,過濾干擾直線
7.繪制直線辉懒、標(biāo)定角點

優(yōu)點:Hough直線檢測的優(yōu)點是抗干擾能力強(qiáng),對圖像中直線的殘缺部分谍失、噪聲以及其它共存的非直線結(jié)構(gòu)不敏感眶俩,能容忍特征邊界描述中的間隙,并且相對不受圖像噪聲的影響

缺點:Hough變換算法的特點導(dǎo)致其時間復(fù)雜度和空間復(fù)雜度都很高快鱼,并且在檢測過程中只能確定直線方向颠印,丟失了線段的長度信息纲岭。由于霍夫檢測過程中進(jìn)行了離散化,因此檢測精度受參數(shù)離散間隔制約

OpenCV支持三種霍夫直線檢測算法:
1)Standard Hough Transform(SHT线罕,標(biāo)準(zhǔn)霍夫變換)
2)Multiscale Hough Transform(MSHT止潮,多尺度霍夫變換)
3)Progressive Probability Houth Transform(PPHT,漸進(jìn)概率式霍夫變換)

在OpenCV3.0及以上版本中钞楼,霍夫直線檢測算法定義了兩個函數(shù):HoughLines(1沽翔、2)、HoughLinesP(3)

CV_EXPORTS_W void HoughLines( InputArray image, OutputArray lines, 
  double rho, double theta, int threshold, 
  double srn = 0, double stn = 0, 
  double min_theta = 0, double max_theta = CV_PI );
  
  //InputArray image:輸入圖像窿凤,必須是8位單通道圖像仅偎。 
  //OutputArray lines:檢測到的線條參數(shù)集合。 
  //double rho:以像素為單位的距離步長雳殊。 
  //double theta:以弧度為單位的角度步長橘沥。 
  //int threshold:累加計數(shù)值的閾值參數(shù),當(dāng)參數(shù)空間某個交點的累加計數(shù)的值超過該閾值夯秃,則認(rèn)為該交點對應(yīng)了圖像空間的一條直線座咆。 
  //double srn:默認(rèn)值為0,用于在多尺度霍夫變換中作為參數(shù)rho的除數(shù)仓洼,rho=rho/srn介陶。 
  //double stn:默認(rèn)值為0,用于在多尺度霍夫變換中作為參數(shù)theta的除數(shù)色建,theta=theta/stn哺呜。
  //如果srn和stn同時為0,就表示HoughLines函數(shù)執(zhí)行標(biāo)準(zhǔn)霍夫變換箕戳,否則就是執(zhí)行多尺度霍夫變換某残。

CV_EXPORTS_W void HoughLinesP( InputArray image, OutputArray lines, 
  double rho, double theta, int threshold, 
  double minLineLength = 0, double maxLineGap = 0 ); 
  
  //InputArray image:輸入圖像,必須是8位單通道圖像陵吸。 
  //OutputArray lines:檢測到的線條參數(shù)集合玻墅。 
  //double rho:直線搜索時的距離步長,以像素為單位壮虫。 
  //double theta:直線搜索時的角度步長澳厢,以弧度為單位。 
  //int threshold:累加計數(shù)值的閾值參數(shù)囚似,當(dāng)參數(shù)空間某個交點的累加計數(shù)的值超過該閾值剩拢,則認(rèn)為該交點對應(yīng)了圖像空間的一條直線。 
  //double minLineLength:默認(rèn)值為0谆构,表示最小線段長度閾值(像素)裸扶。 
  //double maxLineGap:線段上最近兩點之間的閾值.默認(rèn)值為0框都,表示直線斷裂的最大間隔距離閾值搬素。即如果有兩條線段是在一條直線上呵晨,但它們之間有間隙,那么如果這個間隔距離小于該值熬尺,則被認(rèn)為是一條線段摸屠,否則認(rèn)為是兩條線段。 

注意:霍夫直線變換是一種用來在圖像空間尋找直線的方法粱哼,輸入圖像要求是二值圖像季二,同時為了提高檢測直線的效率和準(zhǔn)確率,在使用霍夫線變換之前揭措,最好對圖像進(jìn)行邊緣檢測生成邊緣二值圖像胯舷,這樣的檢測效果是最好的。

9.3绊含、霍夫圓檢測

9.3.2桑嘶、標(biāo)準(zhǔn)霍夫圓檢測

與霍夫直線檢測類似, 圖像的霍夫圓檢測就是檢測哪些前景或邊緣像素點在同一個 圓上躬充, 并給出對應(yīng)圓的圓心坐標(biāo)及圓的半徑逃顶; 而且仍然需要計數(shù)器來完成該過程, 只是 這里的計數(shù)器從二維變成了三維充甚。

9.3.2以政、基于梯度的霍夫圓檢測

步驟:首先定位圓心(兩個參數(shù)),然后計算半徑 (一個參數(shù))伴找。在代碼實現(xiàn)中盈蛮,首先構(gòu)造一個二維計數(shù)器,然后再構(gòu)造一個一維計數(shù)器技矮。

OpenCV提供的函數(shù)HoughCircles實現(xiàn)了基于梯度的霍夫圓檢測眉反, 在該函數(shù)的實現(xiàn)過 程中, 使用了Sobel算子且內(nèi)部實現(xiàn)了邊緣的二值圖穆役, 所以輸入的圖像不用像函數(shù) HoughLinesPHoughLines一樣必須是二值圖寸五。

CV_EXPORTS_W void HoughCircles( InputArray image, OutputArray circles,
                               int method, double dp, double minDist,
                               double param1 = 100, double param2 = 100,
                               int minRadius = 0, int maxRadius = 0 );

缺點是在不知道一些先驗知識的情況下, 需要多次調(diào)整參數(shù)才有可能得到我們想要的結(jié)果耿币。

對于霍夫變換不限于對直線梳杏、圓進(jìn)行檢測,也可以對橢圓等其他幾何形狀進(jìn)行擬合淹接。同時從原理中可以看出十性,霍夫變換的一個較大的優(yōu)點就是可以檢測出部分或者遮擋的直線和圓,當(dāng)然其他幾何形狀也可以塑悼。

9.4劲适、輪廓

9.4.1、查找厢蒜、擬制輪廓

輪廓:有序點集

CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours,
                              OutputArray hierarchy, int mode,
                              int method, Point offset = Point());

CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays contours,
                              int contourIdx, const Scalar& color,
                              int thickness = 1, int lineType = LINE_8,
                              InputArray hierarchy = noArray(),
                              int maxLevel = INT_MAX, Point offset = Point() );

9.4.2霞势、外包烹植、擬合輪廓

介紹了尋找圖像中輪廓的方法和點集的擬合, 那么這兩部分合起來愕贡, 就可以處理圖像目標(biāo)的定位問題了 草雕。

第一步: 對圖像邊緣檢測或者閾值分割得到二值圖,有時也需要對這些二值圖進(jìn)行形態(tài)學(xué)處理固以。
第二步: 利用函數(shù)findContours尋找二值圖中的多個輪廓墩虹。
第三步: 對于通過第二步得到的多個輪廓,其中每一個輪廓都可以作為函數(shù) convexHull憨琳、minAreaRect等的輸入?yún)?shù)诫钓,然后就可以擬合出包含這個輪廓的最小凸包、最小旋轉(zhuǎn)矩形等篙螟。

Mat img = imread("Koala.jpg", IMREAD_GRAYSCALE);
//step1:邊緣檢測尖坤,得到邊緣二值圖
GaussianBlur(img, img, Size(3, 3), 0.5);
Mat binaryImg;
Canny(img, binaryImg, 50, 200);
//step2:邊緣的輪廓
vector<vector<Point>> contours;
findContours(binaryImg, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
//step3:對每一個輪廓進(jìn)行擬合
for (int i = 0; i < contours.size(); i++)
{
    Rect rect = boundingRect(contours[i]);
    if (rect.area() > 500)
    {
        rectangle(img, rect, Scalar(255));
    }
}   

9.4.3、輪廓的周長和面積

用來計算點集所圍區(qū)域的周長:
參數(shù)closed是指點集是否首尾相接闲擦。

CV_EXPORTS_W double arcLength( InputArray curve, bool closed );

用來計算點集所圍區(qū)域的面積

CV_EXPORTS_W double contourArea( InputArray contour, bool oriented = false );

9.4.4慢味、點和輪廓的位置關(guān)系

點集可以圍成一個封閉的輪廓, 那么空間中任意一點和這個輪廓無非有三種關(guān)系: 點在輪廓外墅冷、 點在輪廓上纯路、 點在輪廓內(nèi)。

CV_EXPORTS_W double pointPolygonTest( InputArray contour, Point2f pt, bool measureDist );

注:measureDist是bool類型寞忿,當(dāng)其值為false時驰唬,函數(shù)pointPolygonTest的返回值有三種, 即+1腔彰、0叫编、-1, +1代表pt在點集圍成的輪廓內(nèi)霹抛,0代表pt在點集圍成的輪廓上搓逾,-1代表pt在點集圍成的輪廓外;當(dāng)其值為true時杯拐,則返回值為pt到輪廓的實際距離霞篡。

9.4.5、輪廓的凸包缺陷

用來衡量凸包的缺陷:

void convexityDefects( InputArray contour, InputArray convexhull, OutputArray convexityDefects );

convexityDefects代表返回的凸包缺陷的信息端逼,形式為vector< Vec4i>朗兵,每一個Vec4i代表一個缺陷,它的四個元素依次代表:缺陷的起點顶滩、終點余掖、最遠(yuǎn)點的索引及最遠(yuǎn)點到凸包的距離。

對凸包的缺陷檢測在判斷物體形狀等方面發(fā)揮著很重要的作用礁鲁,與凸包缺陷類似的還有如矩形度盐欺、橢圓度赁豆、 圓度等,它們均是衡量目標(biāo)物體形態(tài)的度量找田。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末歌憨,一起剝皮案震驚了整個濱河市着憨,隨后出現(xiàn)的幾起案子墩衙,更是在濱河造成了極大的恐慌,老刑警劉巖甲抖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漆改,死亡現(xiàn)場離奇詭異,居然都是意外死亡准谚,警方通過查閱死者的電腦和手機(jī)挫剑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柱衔,“玉大人樊破,你說我怎么就攤上這事∷纛恚” “怎么了哲戚?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長艾岂。 經(jīng)常有香客問我顺少,道長,這世上最難降的妖魔是什么王浴? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任脆炎,我火速辦了婚禮,結(jié)果婚禮上氓辣,老公的妹妹穿的比我還像新娘秒裕。我一直安慰自己,他們只是感情好钞啸,可當(dāng)我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布簇爆。 她就那樣靜靜地躺著,像睡著了一般爽撒。 火紅的嫁衣襯著肌膚如雪入蛆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天硕勿,我揣著相機(jī)與錄音哨毁,去河邊找鬼。 笑死源武,一個胖子當(dāng)著我的面吹牛扼褪,可吹牛的內(nèi)容都是我干的想幻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼话浇,長吁一口氣:“原來是場噩夢啊……” “哼脏毯!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起幔崖,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤食店,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后赏寇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吉嫩,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年嗅定,在試婚紗的時候發(fā)現(xiàn)自己被綠了自娩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡渠退,死狀恐怖忙迁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情碎乃,我是刑警寧澤姊扔,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站荠锭,受9級特大地震影響旱眯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜证九,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一删豺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧愧怜,春花似錦呀页、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至猜惋,卻和暖如春丸氛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背著摔。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工缓窜, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓禾锤,卻偏偏與公主長得像私股,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子恩掷,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容