官术网_书友最值得收藏!

3.3 使用OpenCV“摳圖”——基于顏色通道以及形態特征

3.2節用簡單的矩陣操作方法對二維碼圖片進行了一系列操作,包括去Logo、降低像素等。本節談一談如何對圖片進行一些比較復雜的操作,比如我們3.1.1節中用數組切片來抓取足球,使用的命令是:

    ball = img[280:340, 330:390]

為什么是這個坐標?這個坐標是我們人眼看出來的,能否讓計算機自動識別這個足球的位置?這里提供一種基于OpenCV的“套路”。

首先,還是需要認真觀察數據,就是剛才抓下來的球(如圖3-11所示):

圖3-11 從原圖中截取足球區域

    plt.imshow(ball)

這個球具有以下特點:

  • 看起來是個圓形。
  • 顏色是黃色+藏藍色。
  • 由于在草地上,因此背景是綠色。

根據這三個特點,我們大致確定思路,幾個步驟依次對應下面幾個特點:

  • 看看有沒有圓形的識別算法——Hough變換。
  • 用黃色+藏藍色將球從背景提取出來。
  • 用綠色過濾背景色。

我們觀察這張球小型圖片中的60×60 =3600個像素,其中RGB的分布如何。這里仿照第2章用過的seaborn的pairplot函數來表達RGB三種顏色的兩兩組合,其結果如圖3-12所示:

圖3-12 圖3-11中各像素點RGB的分布情況

圖中的黃色與藍黑色均為足球的顏色,而綠色則是足球場的顏色。我們接下來要做的就是找一個規則來區分足球與足球場。這里簡單地寫一個規則組合,其結果如圖3-13所示:

    fig = plt.figure(figsize=(15, 5))
    ax1 = fig.add_subplot(131)
    ax2 = fig.add_subplot(132)
    ax3 = fig.add_subplot(133)
    ax1.imshow( (ball[:,:,0]>200) )
    ax2.imshow( (ball[:,:,0]>130)+(ball[:,:,0]<50) )
    ax3.imshow( (ball[:,:,0]>130)+(ball[:,:,0]<50)+(ball[:,:,1]<120) )

圖3-13 使用顏色規則對球的區域進行二值化(黑色代表球的區域)

好了,根據顏色規則,我們已經依稀得到了一個圓形物體。下一步,將這一規則推廣到整張圖片中,其結果如圖3-14所示。

    fig = plt.figure(figsize=(12, 5))
    ax1 = fig.add_subplot(121)
    ax2 = fig.add_subplot(122)
img1 = ((img[:,:,0]>130)+(img[:,:,0]<50)+(img[:,:,1]<120)).astype(np.uint8) ax1.imshow(img) ax2.imshow(img1)

圖3-14 使用顏色規則對整張圖片球的區域進行二值化(黑色代表球的區域)

由此可見,對整張圖片進行的顏色二值化處理還是比較有效的,至少球這里出現了圓形的形狀,我們經過簡單的處理后,將這里的圓形提取出來即可。但是這里任務并不輕松,因為圖中還是比較雜亂:首先,球中間的黑色部分含有白色,需要填充掉;其次,背景部分有很多觀眾、標語造成的白色環狀噪點,這些噪點不大,但會在圓形檢測環節干擾結果。

為了讓圖片結果減少噪點,我們這里利用OpenCV進行一組侵蝕(erode)稀釋(dilute)操作,如圖3-15(對圖3-14的結果先進行2像素侵蝕,再進行8像素的稀釋,最后進行3像素的侵蝕的整個過程)所示。形象地說,可以將圖中的黑色區域看成是海島,白色看成是海洋。進行侵蝕操作后,海水上漲,白色區域變多,將孤立的黑色區域“淹沒”;然后進行稀釋操作。此時海水退去,沒有被完全淹沒的、面積較大的海島基本恢復以前的樣子,而被完全淹沒的、面積小的海島則從此消失。

圖3-15 侵蝕、稀釋操作

經過侵蝕、稀釋操作后,圖中的黑色部分將會完全連在一起,面積較小的噪點則會被完全淹沒在背景中。此時,下面的兩個黑色圓形物體正是我們需要識別的球。現在先不著急,因為OpenCV的圓形識別算法識別的并非圓形物體,而是圓形的線條。因此還需要將這張圖片的邊緣提取出來,提取邊緣的方法就是對整張圖片計算梯度,此時如果一張像素周圍全是黑色或者全是白色,則梯度為0;而旁邊既有黑色又有白色,則會產生一個顏色梯度,即圖片邊緣。我們可以用Sobel算子分別對圖像的橫向、縱向計算顏色梯度,然后求平方根,得到總梯度。Sobel算子是一個3×3的卷積核,定義如下:

計算過程如下:

Opencv-python的對應代碼如下:

    sobelx = cv2.Sobel(img_ede*255, cv2.CV_64F, 1, 0)
    sobely = cv2.Sobel(img_ede*255, cv2.CV_64F, 0, 1)
    img_sob = np.sqrt(sobelx**2+sobely**2).astype(np.uint8)
    plt.imshow(img_sob)

其結果如圖3-16所示。

圖3-16 對圖3-15的結果使用Sobel算子找出其邊緣位置所在

此時已經得到了圓形的邊緣,接下來調用OpenCV的圓形檢測函數——cv2.HoughCircle,用Hough變換提取圖中的圓形物體即可,如圖3-17所示。

圖3-17 成功識別圖3-14中球所在的位置

最后多說幾句:

(1)Hough變換可以在圖中檢索線段以及圓形,具體原理與利用極坐標系來表示線段、圓上的點有關,大家可以另行學習。常見的應用場景包括自動駕駛系統檢測道路線(直線檢測),以及顯微鏡下觀察細胞(圓形檢測)。

(2)通常情況下,Hough變換可以直接用在灰度圖上,即上一個代碼框里的gray = img_sob可以是gray = img_gray。這里之所以沒有這么做,是因為背景部分同樣有很多類似圓形的物體,造成了很多干擾,可能需要調試很多參數才能得到想要的結果,讀者不妨試一試。如果通過顏色選擇將特征二值化,進而通過侵蝕、稀釋操作進一步去除背景噪聲之后,可以讓輸入的圖形更加簡單,更加方便參數的調試。

主站蜘蛛池模板: 孟州市| 大兴区| 长顺县| 常宁市| 白玉县| 金川县| 呼玛县| 新邵县| 淮安市| 九台市| 天长市| 本溪市| 屏东市| 加查县| 延津县| 长治县| 合阳县| 云梦县| 金山区| 天柱县| 嘉祥县| 桃园市| 钟祥市| 文化| 娄底市| 手游| 莆田市| 库尔勒市| 长沙市| 贵州省| 邛崃市| 中西区| 红桥区| 介休市| 义马市| 罗甸县| 义马市| 光山县| 中山市| 湘潭市| 安顺市|