骰子定位識別

引言

一年前我還在上海從事過機器視覺軟件的開發,時光荏苒。這是在公司期間做了一個有趣的項目,現講一下其主要思想及如何實現。
先來看一下效果圖,Look
這裏寫圖片描述
嗯,看的出來,雖然背景光線不均勻,雖然骰子挨的那麼近,還是很好的識別出來,程序的健壯性很強嘛。PS.爲避免不必要的麻煩,我將自己的姓名和聯繫方式馬賽克掉,嘿嘿。
這裏程序的主要功能是識別出場景中存在多少粒骰子,以及每個骰子的位置,點子數,還有一些其他統計信息。當然,這只是一個機器視覺裏的一個小Demo,可以繼續完善。

思路

這是怎麼做到的呢?這屬於模式識別問題了。思路如下:

  1. 首先需要將目標(這裏是整個骰子區域)從背景中正確分離出來;
  2. 將目標正確分離開來,即骰子之間要分離正確;
  3. 對單個骰子進行閾值分割,統計其中心座標。

問題的關鍵點在於,第一步中如何正確將目標從背景中分離以及第二步沾黏的物體如何分離開來。

方法

頂帽變換

非均勻光照的最終結果導致了區域的分割錯誤(一些區域錯誤地分類了),且骰子的某些部分沒有提取出來。頂帽變換的一個重要用途就是校正不均勻光照的影響。
頂帽(Top-hat)變換
原圖像與開運算結果圖之差。

dst=tophat(src,element)=srcopen(src,element)

與頂帽變換相反的是底帽(bottom-hat)變換:
閉運算結果圖與原圖像之差。
dst=blackhat(src,element)=close(src,element)src

這裏寫圖片描述
下面分割花生爲例。用手機在室內環境下將花生放在黑色鼠標墊上拍攝的。沒有額外打光,只是打開相機的閃燈光,拍攝效果還行。但是,這樣的結果很容易受到光照影響,可以看出,圖像中間最爲明亮,邊緣都有些黑暗,對比度不是太明顯。用一個半徑爲40的圓盤形結構元進行開運算,可以看出圖像背景已經均勻了,有點類似於執行了一次濾波操作。圖3-4依次展示了頂帽變換之後的圖像(圖像減去其開操作),底帽變換之後的圖像(閉操作減去原圖像),頂帽變換聯合底帽變換(原圖像加上頂帽變換減去底帽變換)。經過處理之後的圖像對比度明顯變大,這樣經過閾值分割之後,就可以得到正確的分割結果了。

距離變換與分水嶺算法

距離變換

距離變換圖算法是一種針對柵格圖像的特殊變換,是把二值圖像變換爲灰度圖像,其中每個像素的灰度值等於它到柵格地圖上相鄰物體的最近距離。目前被廣泛應用於計算機圖形學、GIS空間分析和模式識別等領域。
按距離類型劃分,距離變換可分爲:非歐氏距離變換和歐氏距離變換(EDT)。其中EDT精度高,與實際距離相符,應用更廣泛。
基本思想是把離散分佈在空間中的目標根據一定的距離定義方式生成距離圖, 其中每一點的距離值是到所有空間目標距離中最小的一個。
基於“歐幾里德距離”公式的距離變換圖算法 :
在二維平面上定義兩點,那麼他們之間的歐氏距離表示爲 :

D=(x1x2)2+(y1y2)2

在二值圖像中,1 代表目標點,0 代表背景;在灰度圖像中,柵格的灰度值表示該柵格點到最近目標點的距離值。這樣一張M×N 的圖像可以表示爲一個二維數組A[M][N] ,其中A[i][j]=1 對應的柵格表示目標點,A[i][j]=0 對應的柵格表示背景點。設B=(x,y)|A[i][j]=1 爲目標點集合,則歐氏距離變換就是對A 中所有的柵格點求:
D[i][j]=min{Distance[(i,j),(x,y)]}

其中 ,從而得到二值圖像A的歐氏距離變換圖。

分水嶺算法

分水嶺分割方法,是一種基於拓撲理論的數學形態學的分割方法,其基本思想是把圖像看作是測地學上的拓撲地貌,圖像中每一點像素的灰度值表示該點的海拔高度,每一個局部極小值及其影響區域稱爲集水盆,而集水盆的邊界則形成分水嶺。分水嶺的概念和形成可以通過模擬浸入過程來說明。在每一個局部極小值表面,刺穿一個小孔,然後把整個模型慢慢浸入水中,隨着浸入的加深,每一個局部極小值的影響域慢慢向外擴展,在兩個集水盆匯合處構築大壩,即形成分水嶺。
直接應用分水嶺分割算法的效果往往並不好,通常會由於噪聲和梯度的其他局部不規則形造成過度分割。所以在圖像中先用距離變換、梯度或者控制標記符對前景對象和背景對象進行標註區別,再應用分水嶺算法會取得較好的分割效果。
使用距離變換的分水嶺分割如圖所示。經過從圖中可以看出,區域被很好的分割開了,結果是令人滿意的。
這裏寫圖片描述

統計信息

將分水嶺分割後的區域與二值圖像做交集,就可以得到分割後的目標區域。對每一個目標區域去求它的面積,周長等感興趣信息。很多圖像處理函數庫都有計算面積、周長等圖像處理基礎的算子。

代碼

這裏,我使用的了Halcon說明,但所幸代碼很短,而且Halcon支持生成其他語言,代碼也容易理解,可以改成其他語言的。注意,我這裏沒有添加消除不均勻光影響的代碼。

dev_close_window()
dev_open_window (0, 0, 744, 480, 'black', WindowHandle)

for Num := 1 to 10 by 1
    read_image (Image, Num+'.bmp')
    get_image_size (Image, Width, Height)

    dev_set_colored (12) 
    decompose3 (Image, ImageR, ImageG, ImageB)
    threshold (ImageR, Region, 100, 255)
    fill_up (Region, RegionFillUp)

    connection (RegionFillUp, ConnectedRegions)

    ********************距離變換算法*************************
    distance_transform (ConnectedRegions, DistanceImage, 'octagonal', 'true', 744, 480)
    convert_image_type (DistanceImage, DistanceImageByte, 'byte')
    invert_image (DistanceImageByte, DistanceImageInv)
    scale_image_max (DistanceImageInv, DistanceImageInvScaled)
    *******************提取分水嶺和盆地***********************
    watersheds_threshold (DistanceImageInv, Basins, 5)

    *******************取交集*******************************
    intersection (Basins, ConnectedRegions, SegmentedDices)
    dev_display (Image)
    dev_display (SegmentedDices)

    count_obj (SegmentedDices, Number)

    Sum:=0
    Min:=6
    Max:=0
    for Index := 1 to Number by 1
        select_obj (SegmentedDices, Obj, Index)
        reduce_domain (ImageB, Obj, ImageReduced)
        mean_image (ImageReduced, ThresholdImage, 31, 31)
        dev_display (ImageReduced)
        dyn_threshold (ImageReduced, ThresholdImage, RegionDynThresh, 20, 'dark')
        erosion_circle (RegionDynThresh, RegionErosion, 1.5)
        connection (RegionErosion, ConnectedDotRegions)
        select_shape (ConnectedDotRegions, ConnectedDotRegions, ['area','roundness'], 'and', [150,0.5808], [950,1])
        count_obj (ConnectedDotRegions, DotNumber)

        if(Max<DotNumber)
            Max:=DotNumber
        endif

        if(Min>DotNumber)
            Min:=DotNumber
        endif

        Sum:=Sum+DotNumber
        area_center (Obj, Area, CenterY, CenterX)
        disp_message (WindowHandle, '點數:'+DotNumber+'('+CenterX$'.1f'+','+CenterY$'.1f'+')', 'image', CenterY, CenterX, 'red', 'false') 
    endfor

    disp_message (WindowHandle, '區域內共有:'+Number+'個骰子', 'image', 20, 20, 'red', 'false')
    disp_message (WindowHandle, '點數之和:'+Sum, 'image', 40, 20, 'red', 'false')
    disp_message (WindowHandle, '最小點數:'+Min+' 最大點數:'+Max, 'image', 60, 20, 'red', 'false')

    disp_continue_message (WindowHandle, 'black', 'true')
    stop ( )
endfor

更多閱讀

數字圖像處理(第三版) 岡薩雷斯著 chapter 9.6, 灰度級形態學
數字圖像處理(第三版) 岡薩雷斯著 chapter 10.5, 使用形態學分水嶺的分割

轉載請保留以下信息

作者 日期 聯繫方式
風吹夏天 2015年8月5日 wincoder[at]qq.com
發佈了50 篇原創文章 · 獲贊 76 · 訪問量 37萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章