OpenCV二值圖像分析之尋找缺失與靶心
點(diǎn)擊上方“小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)
引子
大家好,今天給大家分享兩個(gè)來自O(shè)penCV研習(xí)社提問的帖子,都是很經(jīng)典的圖像處理與分析問題,希望通過這兩個(gè)例子,大家能夠得到更多的啟發(fā),從而想到更好的解決類似問題的思路。
01
問題一:尋找靶心

圖一
02
問題二:尋找其中的缺失點(diǎn)

圖二
解決方法
01
尋找靶心
仔細(xì)觀察圖一,可以看到兩個(gè)最直接的是靶心有十字交叉線,而在OpenCV形態(tài)學(xué)處理中,支持十字交叉結(jié)構(gòu)元素,所以我們可以先檢測(cè)兩條線,然后獲取十字交叉結(jié)構(gòu),最后對(duì)結(jié)構(gòu)進(jìn)行輪廓分析,獲取中心點(diǎn),即可獲得最終的靶心位置,最終尋找到的靶心位置圖示如下:

獲取水平與垂直線如下:

獲取十字交叉線如下:

代碼實(shí)現(xiàn)如下:
1image?=?cv.imread("D:/images/zsxq/cross.jpg")
2cv.imshow("input",?image)
3gray?=?cv.cvtColor(image,?cv.COLOR_BGR2GRAY)
4ret,?binary?=?cv.threshold(gray,?0,?255,?cv.THRESH_OTSU?|?cv.THRESH_BINARY_INV)
5se1?=?cv.getStructuringElement(cv.MORPH_CROSS,?(50,?1))
6se2?=?cv.getStructuringElement(cv.MORPH_CROSS,?(1,?50))
7hline?=?cv.morphologyEx(binary,?cv.MORPH_OPEN,?se1)
8vline?=?cv.morphologyEx(binary,?cv.MORPH_OPEN,?se2)
9contours,?hireachy?=?cv.findContours(hline,?cv.RETR_EXTERNAL,?cv.CHAIN_APPROX_SIMPLE)
10mask?=?np.zeros_like(hline)
11max?=?-1
12index?=?0
13for?cnt?in?range(len(contours)):
14????x,?y,?w,?h?=?cv.boundingRect(contours[cnt])
15????if?max?16????????max?=?w
17????????index?=?cnt
18cv.drawContours(mask,?contours,?index,?(255),?-1,?8)
19
20cv.imshow("vline",?vline)
21contours,?hireachy?=?cv.findContours(vline,?cv.RETR_EXTERNAL,?cv.CHAIN_APPROX_SIMPLE)
22max?=?-1
23index?=?0
24for?cnt?in?range(len(contours)):
25????x,?y,?w,?h?=?cv.boundingRect(contours[cnt])
26????if?max?and?x?1]*0.75):
27????????max?=?h
28????????index?=?cnt
29
30cv.drawContours(mask,?contours,?index,?(255),?-1,?8)
31cv.imshow("mask",?mask)
32
33se3?=?cv.getStructuringElement(cv.MORPH_CROSS,?(13,?13))
34mask?=?cv.morphologyEx(mask,?cv.MORPH_OPEN,?se3)
35cv.imshow("corss",?mask)
36contours,?hireachy?=?cv.findContours(mask,?cv.RETR_EXTERNAL,?cv.CHAIN_APPROX_SIMPLE)
37for?cnt?in?range(len(contours)):
38????x,?y,?w,?h?=?cv.boundingRect(contours[cnt])
39????print(x,?y,?w,?h)
40????cx?=?(x?+?w//2)
41????cy?=?(y?+?h//2)
42????cv.circle(image,?(cx,?cy),?4,?(0,?0,?255),?4,?8,?0)
43cv.imshow("result",?image)
44cv.imwrite("D:/find_cross.png",?image)
45cv.waitKey(0)
46cv.destroyAllWindows()02
尋找缺失
仔細(xì)觀察圖二,缺失是偶發(fā)情況,針對(duì)這種情況下,要完成計(jì)數(shù)與缺失位置標(biāo)定!我感覺我的密集恐懼癥已經(jīng)開始犯了!首先需要獲取這些位置,通過二值話與輪廓發(fā)現(xiàn)搞定,然后根據(jù)這些輪廓位置,重新繪制統(tǒng)一的圓形標(biāo)記,輪廓發(fā)現(xiàn)對(duì)每個(gè)圓形標(biāo)記進(jìn)行上下左右位置最近領(lǐng)搜索,返回間隔距離,-1表示邊界,根據(jù)間隔距離設(shè)置閾值查找缺失,最終運(yùn)行結(jié)果如下:

從原圖得到的標(biāo)記圖如下:

代碼實(shí)現(xiàn)如下:
1image?=?cv.imread("D:/images/zsxq/zsxq_40.png")
2gray?=?cv.cvtColor(image,?cv.COLOR_BGR2GRAY)
3ret,?binary?=?cv.threshold(gray,?0,?255,?cv.THRESH_OTSU?|?cv.THRESH_BINARY_INV)
4cv.imshow("binary",?binary)
5contours,?hireachy?=?cv.findContours(binary,?cv.RETR_EXTERNAL,?cv.CHAIN_APPROX_SIMPLE)
6mask?=?np.zeros_like(binary)
7for?cnt?in?range(len(contours)):
8????area?=?cv.contourArea(contours[cnt])
9????if?area?50:
10????????continue
11????x,?y,?w,?h?=?cv.boundingRect(contours[cnt])
12????if?(y?+?h)?>?(binary.shape[0]?-?10):
13????????continue
14????cx?=?(x?+?w//2)
15????cy?=?(y?+?h//2)
16????cv.circle(mask,?(cx,?cy),?4,?(255),?4,?8,?0)
17cv.imshow("mask",?mask)
18contours,?hireachy?=?cv.findContours(mask,?cv.RETR_EXTERNAL,?cv.CHAIN_APPROX_SIMPLE)
19for?cnt?in?range(len(contours)):
20????x,?y,?w,?h?=?cv.boundingRect(contours[cnt])
21????cx?=?(x?+?w//2)
22????cy?=?(y?+?h//2)
23????left?=?find_neighborhood(mask,?cx,?cy,?1)
24????right?=?find_neighborhood(mask,?cx,?cy,?2)
25????#?top?=?find_neighborhood(mask,?cx,?cy,?3)
26????#?bottom?=?find_neighborhood(mask,?cx,?cy,?4)
27????if?left?==?-1?or?right?==?-1:?#?or?top?==?-1?or?bottom?==?-1:
28????????continue
29????dx?=?right?-?left
30????#?dy?=?top?-?bottom
31????#?print(dx,?dy)
32????if?dx?>?15:
33????????cv.circle(image,?(cx?+?left?+?10,?cy),?4,?(0,?0,?255),?4,?8,?0)
34
35cv.imshow("test",?image)
36cv.imwrite("D:/find_miss.png",?image)
37cv.waitKey(0)
38cv.destroyAllWindows()