OpenCV算法學習筆記之形狀檢測

此系列的其他文章:
OpenCV算法學習筆記之初識OpenCV
OpenCV算法學習筆記之幾何變換
OpenCV算法學習筆記之對比度增強
OpenCV算法學習筆記之平滑算法
OpenCV算法學習筆記之閾值分割
OpenCV算法學習筆記之形態(tài)學處理
OpenCV算法學習筆記之邊緣檢測(一)
OpenCV算法學習筆記之邊緣處理(二)

更多文章可以訪問我的博客Aengus | Blog

霍夫直線檢測

原理

對于?中的任意一條直線元媚,我們以下圖為例:

xoy平面中的直線

?是直線的正切角罢防,?是直線的截距,?是原點的直線的垂線晰洒,?幔荒;則直線的方程可以用以下方程表示:

所以如果知道平面內(nèi)的一條直線糊闽,那么可以計算出唯一的?和?梳玫,使得此直線與?一一對應,所以我們就完成了?平面中的直線到霍夫空間的映射墓怀。因此如果我們想判斷?平面上一連串的點?是否在一條直線上汽纠,只需判斷他們映射在?平面上的曲線?是否相交于一個點即可,如果相交于一點傀履,則共線。

而對于較為復雜的情況莉炉,可能會出現(xiàn)點?所對應的?平面上的曲線有多個相交點的情況钓账,針對這種問題,我們可以設(shè)置一個投票器絮宁,選擇相交曲線最多的點梆暮,那么這些相交曲線所對應的?即是共線的。

API

OpenCV對二值圖提供霍夫檢測函數(shù):

void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0)

其中rho代表\rho的步長(分辨率)绍昂,theta代表\theta的步長(分辨率)啦粹,這是因為\theta o \rho平面中有無數(shù)個點,而計算機實現(xiàn)時只能取有限個點窘游,所以需要指定步長唠椭,像素為單位,一般取1忍饰;threshold代表投票器的閾值贪嫂,只有大于這個值才會被認為在一條線上;而srnstn則分別是多通道圖片的rhotheta艾蓝。

標準霍夫直線檢測內(nèi)存消耗較大力崇,執(zhí)行時間也比較短,采用概率霍夫直線檢測可以緩解這一問題赢织,它隨機地從邊緣二值圖中選擇前景像素點亮靴,確定檢測直線的兩個參數(shù),本質(zhì)上還是標準的霍夫直線檢測于置。其函數(shù)為:

void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLenght=0, double maxLineGap=0)

其中minLineLenght代表最短直線的長度茧吊;maxLineGap代表同一直線上的兩個點所允許的最大間隙。

霍夫圓形檢測

標準霍夫圓形檢測

原理

標準霍夫圓形檢測的思想與霍夫直線檢測類似俱两。

霍夫圓形檢測的問題可以簡述為:已知xoy平面上的點(x_1,y_1),(x_2,y_2),...,(x_n,y_n)在多個圓上饱狂,那么哪些點在同一個圓上,并計算出圓心坐標宪彩。

上述問題可以通過此步驟解決:首先固定一個半徑r休讳,然后分別以點(x_1,y_1),(x_2,y_2),...,(x_n,y_n)為圓心,r為半徑畫圓尿孔,若(x_1,y_1),(x_2,y_2),...,(x_n,y_n)在同一個圓上俊柔,那么以它們?yōu)閳A心畫的圓的交點就是所求圓的圓心筹麸,且其半徑就是r。具體實現(xiàn)時雏婶,可以首先確定一個r的范圍物赶,然后依次畫圓并按照霍夫直線檢測的思想對交點進行投票,票數(shù)最多的即為目標圓圓心坐標留晚,此時的r為目標圓半徑酵紫。

xoy平面中的任意一個圓都可以表示為(x-a)^2 + (y-b)^2 = r^2,可以利用圓的極坐標公式a=x - r\cos\theta,b=y - r \sin \theta對圓心進行計算错维。

Python實現(xiàn)

def hough_circle(image, min_r, max_r, vote_thresh=100):
    """
    :param image 輸入圖像
    :param min_r 最小半徑
    :param max_r 最大半徑
    :param vote_thresh 投票閾值奖地,小于此值則將此目標圓丟棄
    :return 包含目標圓(半徑,橫坐標赋焕,縱坐標)的list
    """
    # 寬参歹,高
    h, w = image.shape
    # 歸為整數(shù)
    minr = round(min_r) + 1
    maxr = round(max_r) + 1
    # 初始化三維計數(shù)器
    r_num = int(maxr - minr + 1)    # 半徑
    a_num = int(w - 1 + maxr + maxr + 1)    # 圓心橫坐標
    b_num = int(h - 1 + maxr + maxr + 1)    # 圓心縱坐標
    accumulator = np.zeros((r_num, b_num, a_num), np.int32)
    # 投票計數(shù)
    for y in range(h):
        for x in range(w):
            if image[y][x] == 255: # 只對邊緣進行霍夫變換
                for k in range(r_num):
                    for theta in np.linspace(0, 360, 180):
                        # 計算對應的a,b
                        a = x - (minr+k)*math.cos(theta/180.0*math.pi)
                        b = y - (minr+k)*math.sin(theta/180.0*math.pi)
                        # 取整
                        a = int(round(a))
                        b = int(round(b))
                        # 投票
                        accumulator[k, b, a] += 1
    # 篩選投票數(shù)大于vote_thresh的圓
    circles = []
    for k in range(r_num):
        for b in range(b_num):
            for a in range(a_num):
                if accumulator[k, b, a] > vote_thresh:
                    circles.append((k+minr, b, a))
    return circles

基于梯度的霍夫圓形檢測

原理

如果已知圓幾條切線的方向,那么對其做垂線隆判,垂線相交的點即是圓的圓心犬庇。通過這種方法,若得到一張圖邊緣二值圖侨嘀,對其中的直線做垂線就可以得到目標圓的圓心臭挽。對于r的確認,也可以通過“投票”的思想飒炎,如果n條切線距離圓心的距離為r_1埋哟,m條切線距離圓心的距離為r_2,有n>m郎汪,就以r_1作為最終的半徑赤赊。

API

OpenCV提供函數(shù):

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

其中circles是一個vector<Vec3f>,每一個都代表(x,y,radius)煞赢;mehod目前只有CV_HOUGH_GRADIENT抛计,代表梯度;dp是計數(shù)器分辨率照筑;minDsit是圓心間的最小距離吹截;param1是Canny邊緣檢測的雙閾值中的高閾值,低閾值默認是高閾值的一半凝危;param2代表最小投票數(shù)波俄;minRadius是需要檢測的圓的最小半徑;maxRadius是需要檢測圓的最大半徑蛾默。

角點檢測

角點可以簡單的認為是兩條線的交點懦铺,也就是一個物體的“角”。角點處的梯度值和梯度變化率都十分明顯支鸡,所以這也是大部分角點檢測算法入手的地方冬念。

Harris角點檢測

原理

Harris角點檢測就是利用角點的梯度值變化較大的這個特點進行檢測趁窃。

其步驟如下:

步驟一:計算分別圖像I(x,y)在水平方向和垂直方向上的梯度I_xI_y
I_x = I \times \left[ \begin{matrix} -1&0&1 \end{matrix} \right] \\ I_y = I \times \left[ \begin{matrix} -1&0&1 \end{matrix} \right]^T
步驟二:計算兩個梯度方向上的乘積,注意*代表點乘
I_x^2=I_x*I_x\\I_y^2=I_y*I_y\\I_xI_y=I_x*I_y
步驟三:使用高斯函數(shù)對I_x^2,I_y^2,I_xI_y進行高斯加權(quán)(取\sigma=2急前,ksize=3)醒陆,計算中心點為(x,y)的窗口W對應的協(xié)方差矩陣M
A=\sum_{(x,y)\in W}g(I_x^2)=\sum_{(x,y)\in W}I_x^2*w(x,y) \\ B=\sum_{(x,y)\in W}g(I_y^2)=\sum_{(x,y)\in W}I_y^2*w(x,y) \\ C = \sum_{(x,y)\in W}g(I_xI_y)=\sum_{(x,y)\in W}I_xI_y*w(x,y)
M=\left[\begin{matrix} A&C\\C&B\end{matrix}\right]

步驟四:計算每個像素點(x,y)處的Harris響應值Rk為經(jīng)驗參數(shù)):
R=det(M)-k(trace(M))^2
步驟五:過濾大于某一閾值t的Harris響應值R裆针,得到的結(jié)果就是角點刨摩;

API

OpenCV提供函數(shù):

void cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, int borderType = BORDER_DEFAULT)

實現(xiàn)Harris角點檢測,其中blockSize代表滑塊窗口的尺寸据块,也就是窗口W的尺寸码邻;ksize代表Sobel核的大小,所以此API會對圖像進行Sobel邊緣檢測另假;k是Harris中間參數(shù),經(jīng)驗值0.04~0.06怕犁。

Shi-Tomasi角點檢測

原理

Shi-Tomasi 算法是Harris 算法的改進边篮,主要不同在最后兩個步驟中,Harris 算法最原始的定義是將矩陣 M 的行列式值與 M 的跡相減奏甫,再將差值同預先給定的閾值進行比較戈轿。后來Shi 和Tomasi 提出改進的方法,若兩個特征值中較小的一個大于最小閾值阵子,則會得到強角點思杯。Shi 和Tomasi 的方法比較充分,并且在很多情況下可以得到比使用Harris 算法更好的結(jié)果挠进。

API

OpenCV提供函數(shù):

void goodFeaturesToTrack(InputArray image, OutputArray corners, int maxCorners, double qualityLevel, double minDistance, InputArray mask=noArray(), int blockSize=3, bool useHarrisDetector=false, double k=0.04);

其中maxCorners代表可以檢測到的最大角點數(shù)量色乾;qualityLevel代表檢測到的角點的質(zhì)量等級,角點特征值小于qualityLevel最大特征值的點將被舍棄领突;minDistance是兩個角點間最小間距暖璧,以像素為單位;mask是指定檢測區(qū)域君旦,若檢測整幅圖像澎办,mask置為空Mat()blockSize是計算協(xié)方差矩陣M時窗口大薪鹂场局蚀;useHarrisDetector是否使用Harris角點檢測,為false恕稠,則使用Shi-Tomasi算子琅绅;k留給Harris角點檢測算子用的中間參數(shù),一般取經(jīng)驗值0.04~0.06谱俭,useHarrisDetector=false時奉件,該參數(shù)不起作用宵蛀。

參考

《OpenCV算法精解——基于Python和C++》(張平)第九章

角點檢測詳細總結(jié)及代碼示例

第十一節(jié)、Harris角點檢測原理(附源碼)

OpenCV——角點檢測原理分析(Harris县貌,Shi-Tomasi术陶、亞像素級角點檢測)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市煤痕,隨后出現(xiàn)的幾起案子梧宫,更是在濱河造成了極大的恐慌,老刑警劉巖摆碉,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件塘匣,死亡現(xiàn)場離奇詭異,居然都是意外死亡巷帝,警方通過查閱死者的電腦和手機忌卤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來楞泼,“玉大人驰徊,你說我怎么就攤上這事《槔” “怎么了棍厂?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長超陆。 經(jīng)常有香客問我牺弹,道長,這世上最難降的妖魔是什么时呀? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任张漂,我火速辦了婚禮,結(jié)果婚禮上退唠,老公的妹妹穿的比我還像新娘鹃锈。我一直安慰自己,他們只是感情好瞧预,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布屎债。 她就那樣靜靜地躺著,像睡著了一般垢油。 火紅的嫁衣襯著肌膚如雪盆驹。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天滩愁,我揣著相機與錄音躯喇,去河邊找鬼。 笑死,一個胖子當著我的面吹牛廉丽,可吹牛的內(nèi)容都是我干的倦微。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼正压,長吁一口氣:“原來是場噩夢啊……” “哼欣福!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起焦履,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤拓劝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嘉裤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體郑临,經(jīng)...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年屑宠,在試婚紗的時候發(fā)現(xiàn)自己被綠了厢洞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡典奉,死狀恐怖犀变,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秋柄,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布蠢正,位于F島的核電站骇笔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏嚣崭。R本人自食惡果不足惜笨触,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望雹舀。 院中可真熱鬧芦劣,春花似錦、人聲如沸说榆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽签财。三九已至串慰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間唱蒸,已是汗流浹背邦鲫。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留神汹,地道東北人庆捺。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓古今,卻偏偏與公主長得像,于是被迫代替她去往敵國和親滔以。 傳聞我的和親對象是個殘疾皇子捉腥,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

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