【計(jì)算機(jī)視覺(五)】模板匹配

前請(qǐng)?zhí)嵋?/h2>

前三期(【計(jì)算機(jī)視覺(二)】常用顏色空間及其轉(zhuǎn)換)揩尸、【計(jì)算機(jī)視覺(三)】形態(tài)學(xué)處理侥袜、【計(jì)算機(jī)視覺(四)】輪廓檢測(cè))在介紹基本知識(shí)的同時(shí)穿插了一個(gè)很naive的檢測(cè)車牌位置的方法稠项,對(duì)參數(shù)設(shè)置有很強(qiáng)的依賴。后續(xù)會(huì)慢慢涉及到高級(jí)的方法窃躲。

本期內(nèi)容

本期作為一個(gè)引子介紹模板匹配法嫂伞,引出后來的Cascade檢測(cè)算法。

一聂抢、全等模板

car_test.jpg

假如我們要在上面這張固定的圖上找出左邊這輛車的位置钧嘶,一個(gè)很簡單的方法就是我們可以先人工把左邊這輛車用“截圖”工具裁剪出來。
template.jpg

然后拿著這張圖在大圖上找琳疏,一開始有决,我們把模板圖放到大圖的左上角,看它們是不是所有像素值都相等空盼,然后往右移一個(gè)像素书幕,再看是不是所有值相等,如此遍歷整幅圖揽趾,直到找到全等的位置台汇。
sw1.jpg

sw2.jpg

這樣的搜尋策略叫做滑動(dòng)窗口
template_match_result.jpg

實(shí)現(xiàn)代碼如下:

# coding: utf-8
import cv2
import numpy as np

'''
函數(shù)名:template_match
輸入:
template    模板
img   原圖
輸出:
(x,y)    匹配位置的左上角坐標(biāo)篱瞎,找不到返回None
'''
def template_match(template, img):
    tpl_h, tpl_w = template.shape[:2]
    img_h, img_w = img.shape[:2]
    for i in xrange(img_h - tpl_h):
        for j in xrange(img_w - tpl_w):
            roi = img[i:i+tpl_h, j:j+tpl_w]
            if (template == roi).all():
                return (j,i)
    return None

# 程序入口
def main():
    # 整圖
    cars = cv2.imread('car_test.jpg')
    # 車模板
    car_tpl = cars[117:199, 24:246].copy()

    pos = template_match(car_tpl, cars)
    tpl_h, tpl_w = car_tpl.shape[:2]

    if pos is not None:
        x,y = pos
        cv2.rectangle(cars, (x,y), (x+tpl_w,y+tpl_h), (0,255,0), 2)

    cv2.imshow('template', car_tpl)
    cv2.imshow('result', cars)
    cv2.imwrite('template_match_result.jpg', cars)
    cv2.waitKey(0)

if __name__ == '__main__':
    main()

這樣做的缺點(diǎn)很明顯苟呐,只要有一個(gè)像素點(diǎn)跟模板不相等就找不到了,如果只是要找些非常固定的東西那用這種方法是可以的俐筋,比如以前做游戲腳本的時(shí)候要實(shí)現(xiàn)鼠標(biāo)點(diǎn)到某個(gè)固定的技能或道具上牵素。

二、相關(guān)系數(shù)

這時(shí)候要用更靠譜的測(cè)度——例如相關(guān)系數(shù)(除此之外還有平方差等)澄者。
圖像的相關(guān)系數(shù)的計(jì)算方法參考這個(gè)公式两波,是從Matlab的文檔截下來的。

相關(guān)系數(shù)公式

分子是圖像與模板的協(xié)方差闷哆,分母是它們的標(biāo)準(zhǔn)差的乘積腰奋。
具體原理參考知乎的這個(gè)回答
它會(huì)返回一個(gè)數(shù)值表示圖像的相關(guān)程度抱怔,越相關(guān)劣坊,值越靠近1,實(shí)現(xiàn)代碼如下:

# 輸入灰度圖
def norm_corr(template, img):
    tpl_h, tpl_w = template.shape[:2]
    img_h, img_w = img.shape[:2]
    expand_img = np.zeros((tpl_h+img_h, tpl_w+img_w), dtype=np.uint8)
    expand_img[:img_h, :img_w] = img
    img_h, img_w = expand_img.shape[:2]

    # 圖像均值
    tpl_mean = np.mean(template)
    # 減均值
    tpl_sub_mean = template - tpl_mean
    # 標(biāo)準(zhǔn)差
    sigma_tpl = np.sum(tpl_sub_mean**2)
    # 相關(guān)系數(shù)圖
    corr = np.zeros(img.shape, dtype=np.float32)

    for i in xrange(img_h - tpl_h):
        for j in xrange(img_w - tpl_w):
            roi = expand_img[i:i+tpl_h, j:j+tpl_w]
            # 圖像均值
            roi_mean = np.mean(roi)
            # 減均值
            roi_sub_mean = roi - roi_mean
            # 標(biāo)準(zhǔn)差
            sigma_roi = np.sum(roi_sub_mean**2)
            # 協(xié)方差
            cov = np.sum(tpl_sub_mean * roi_sub_mean)
            # 相關(guān)系數(shù)
            corr[i,j] = cov / np.sqrt(sigma_tpl * sigma_roi)

    # 歸一化到0-255
    corr_max = corr.max()
    corr_min = corr.min()
    print 'max = ', corr_max
    print 'min = ', corr_min
    if corr_max != corr_min:
        corr = 255 * (corr - corr_min) / (corr_max - corr_min)
    return corr.astype(np.uint8)

要注意輸入是灰度圖屈留,最后輸出是一張表示每一個(gè)位置上的相關(guān)系數(shù)的圖局冰,歸一化到0-255就可以顯示出來了。再次使用上面的模板圖和大圖灌危,得到的相關(guān)系數(shù)圖如下:

相關(guān)系數(shù)圖

圖中越亮的地方表示把模板的左上角在大圖的對(duì)應(yīng)位置的可能性越大康二。
我們可以把相關(guān)圖上值超過127(最大255,可以自行設(shè)置這個(gè)閾值)的地方用矩形框標(biāo)出來勇蝙。
代碼如下:

idx = np.where(corr > 0.5 * 255)
rows = idx[0]
cols = idx[1]
rects = []
for r,c in zip(rows, cols):
    if c+tpl_w < img_w and r+tpl_h < img_h:
        rects.append((c,r,c+tpl_w,r+tpl_h))

for rect in rects:
    tx,ty,bx,by = rect
    cv2.rectangle(cars, (tx,ty), (bx,by), (0,255,0), 2)

效果如下:


所有框

可以看到雖然用的模板是左邊的車沫勿,但由于兩臺(tái)車很相似,所以右邊的車也被檢出來了,但是框非常的多产雹,我們可以想辦法做去重诫惭,把頂點(diǎn)靠近的矩形框當(dāng)作一個(gè)子集,最后分別給出各個(gè)矩形集的平均位置蔓挖,代碼如下夕土,可以根據(jù)需要子集改進(jìn):

def group_rects(rects, diff=20):
    groups = [[rects[0]]]
    for rect in rects[1:]:
        tx,ty,bx,by = rect
        found = False
        for gr in groups:
            for gre in gr:
                if abs(gre[0]-tx) < diff and abs(gre[1]-ty) < diff and abs(gre[2]-bx) < diff and abs(gre[3]-by) < diff:
                    gr.append(rect)
                    found = True
                    break
            if found:
                break
        if not found:
            groups.append([rect])
    result = []
    for group in groups:
        result.append(np.array(group).mean(axis=0).astype(np.int32).tolist())
    return result

這樣就得到了很好的兩個(gè)框。


框融合結(jié)果

總結(jié)

即使改變了使用的距離函數(shù)瘟判,我們也只使用了一個(gè)數(shù)據(jù)(圖像)就希望能檢測(cè)到其他的同類物體怨绣,的確是很以偏概全的想法。以檢測(cè)車子的例子來說拷获,我們是把一臺(tái)特定的車當(dāng)作模板梨熙,而沒有從更接近本質(zhì)的角度去解構(gòu)這個(gè)問題,假設(shè)我們能人為的定義車子該長什么樣也許就能很好的解決這個(gè)問題刀诬,比如說車有輪子、車窗邪财、車燈陕壹、整體是流線型的,等等树埠。這些性質(zhì)可以稱為車子的特征(feature)糠馆。計(jì)算機(jī)視覺有很大部分研究的問題都在圍繞著如何更好的描述物體,也就是如何得到物體更好的特征怎憋。特征可能是級(jí)聯(lián)的又碌,意思是說有輪子是車子的特征咬崔,輪子也有自己的特征(圓的领跛,黑的)芽世,特征總是從低層的只包含結(jié)構(gòu)艾恼、形狀等信息往高層的更不可描述的信息走曙旭。發(fā)展到現(xiàn)在荸镊,特征可以分為人為設(shè)計(jì)和通過機(jī)器學(xué)習(xí)的方法學(xué)習(xí)出來兩種拜马,人為設(shè)計(jì)的特征如HOG单芜、Haar等展姐,有著固定的計(jì)算過程躁垛,可以手工計(jì)算出來,在深度學(xué)習(xí)大熱的當(dāng)今已經(jīng)慢慢被新晉行業(yè)的人視為“傳統(tǒng)的技術(shù)”圾笨,但在我看來這兩者并沒有那么大的不同教馆,沒有必要放棄這些“old-school”的技術(shù),這樣只會(huì)造成“拿起錘子擂达,看什么都是釘子”的想法土铺。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子舒憾,更是在濱河造成了極大的恐慌镀钓,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件镀迂,死亡現(xiàn)場(chǎng)離奇詭異丁溅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)探遵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門窟赏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人箱季,你說我怎么就攤上這事涯穷。” “怎么了藏雏?”我有些...
    開封第一講書人閱讀 152,370評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵拷况,是天一觀的道長。 經(jīng)常有香客問我掘殴,道長赚瘦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評(píng)論 1 278
  • 正文 為了忘掉前任奏寨,我火速辦了婚禮起意,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘病瞳。我一直安慰自己揽咕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評(píng)論 5 371
  • 文/花漫 我一把揭開白布套菜。 她就那樣靜靜地躺著亲善,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逗柴。 梳的紋絲不亂的頭發(fā)上逗爹,一...
    開封第一講書人閱讀 48,954評(píng)論 1 283
  • 那天,我揣著相機(jī)與錄音嚎于,去河邊找鬼掘而。 笑死,一個(gè)胖子當(dāng)著我的面吹牛于购,可吹牛的內(nèi)容都是我干的袍睡。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼肋僧,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼斑胜!你這毒婦竟也來了控淡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,916評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤止潘,失蹤者是張志新(化名)和其女友劉穎掺炭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凭戴,經(jīng)...
    沈念sama閱讀 43,382評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涧狮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了么夫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片者冤。...
    茶點(diǎn)故事閱讀 37,989評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖档痪,靈堂內(nèi)的尸體忽然破棺而出涉枫,到底是詐尸還是另有隱情,我是刑警寧澤腐螟,帶...
    沈念sama閱讀 33,624評(píng)論 4 322
  • 正文 年R本政府宣布愿汰,位于F島的核電站,受9級(jí)特大地震影響乐纸,放射性物質(zhì)發(fā)生泄漏衬廷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評(píng)論 3 307
  • 文/蒙蒙 一锯仪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧趾盐,春花似錦庶喜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至本缠,卻和暖如春斥扛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背丹锹。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評(píng)論 1 260
  • 我被黑心中介騙來泰國打工稀颁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人楣黍。 一個(gè)月前我還...
    沈念sama閱讀 45,401評(píng)論 2 352
  • 正文 我出身青樓匾灶,卻偏偏與公主長得像,于是被迫代替她去往敵國和親租漂。 傳聞我的和親對(duì)象是個(gè)殘疾皇子阶女,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評(píng)論 2 345

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

  • 不同圖像灰度不同颊糜,邊界處一般會(huì)有明顯的邊緣,利用此特征可以分割圖像秃踩。需要說明的是:邊緣和物體間的邊界并不等同衬鱼,邊緣...
    大川無敵閱讀 13,822評(píng)論 0 29
  • 這些年計(jì)算機(jī)視覺識(shí)別和搜索這個(gè)領(lǐng)域非常熱鬧,后期出現(xiàn)了很多的創(chuàng)業(yè)公司憔杨,大公司也在這方面也花了很多力氣在做鸟赫。做視覺搜...
    方弟閱讀 6,444評(píng)論 6 24
  • 前天晚上被頭條上關(guān)于電影《無問西東》的評(píng)論吸引惯疙,也到電影院觀影,可以說妖啥,這個(gè)冬天最溫暖霉颠、最文藝的兩部電影,一部是《...
    傍晚的早晨閱讀 214評(píng)論 0 0
  • 一周的踐行又到了尾聲荆虱,每周寫踐行記錄似乎也變的麻木起來蒿偎,重復(fù)次數(shù)的增加都給我們帶來了哪方面的進(jìn)步呢? 英語 最近一...
    穆建園閱讀 224評(píng)論 0 0
  • 是一個(gè)月以前的一次旅行了,我在臺(tái)灣交換學(xué)習(xí)菜枷,周末有時(shí)間就出去走走苍糠。前一天已經(jīng)到了花蓮,不過沒玩什么地方啤誊,第二天與朋...
    雙木中堂閱讀 485評(píng)論 5 10