程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

【OpenCV-Python-課程學習(賈)】OpenCV3.3課程學習筆記:ROI和泛洪填充(切片索引、watershed),opencv中的魔法棒工具

編輯:Python

一、什麼是ROI?

ROI是Region Of Interest的簡寫,字面義是感興趣的區域,或者說是需要進行某種操作的「目標區域」。

二、如何獲取ROI?

如果想要對ROI區域進行操作,首先要選中並獲取到這個區域。

最簡單的方式就是利用Numpy的數組索引切片來獲取到一個矩形ROI(當然其他形狀的ROI或許更加適合具體情況下的某些Object,但是顯然無法通過如此簡單的方法就能獲取,必須經過有一定復雜度的算法才能得到)。

假設某張image寬高形狀是[400, 400],通道數為3,那麼如果想要選中中間的一個寬高[40, 40]的物體,可以用下面這個切片索引

img[180:220, 180:220, :] 

三、泛洪填充——floodfill()

參考:OpenCV: Miscellaneous Image Transformations-floodfill()

泛洪填充的典型應用:填充和目標像素的取值相近的鄰近區域;類似Adobe Photoshop中的魔法棒工具所實現的功能。

實現泛洪填充的API是floodfill(),語法如下

cv.floodFill(image, mask, seedPoint, newVal[, loDiff[, upDiff[, flags]]]) ->retval, image, mask, rect

  • image是原圖像,除非flags的高八位設置成cv.FLOODFILL_MASK_ONLY,否則函數會對image做出改變。image可以是單通道灰度圖,也可是多通道彩圖。
  • mask是掩模,必須是單通道無符號8位整型數組,並且寬和高分別比原圖像image的要大2;掩模中的零值區域用來限定圖像變化的區域,而非零值區域會屏蔽泛洪填充;mask既是輸入也是輸出,輸出的mask相比原先,泛洪區域全部填充1或者flags裡的中八位數值(後續在flags中講解)。
  • seedPoint是泛洪基點,也即“泛洪”從此開始向外擴展,直至碰到掩模邊界或者超過loDiff、upDiff邊界;當flags不指定為cv.FLOODFILL_FIXED_RANGE時,除了基點附近4或8個像素點是根據它判斷的,其他像素點都是根據已經處於泛洪區域上的邊界點鄰域范圍上的點來判斷;當flags指定為cv.FLOODFILL_FIXED_RANGE時,所有像素點都基於該點來判斷。
  • newVal是泛洪填充值,如果原圖像是一個單通道圖像,newVal是單個數值,而如果原圖像是一個三通道圖像,newVal應該是一個長度為3的元組。
  • loDiff和upDiff分別是下、上邊界差值,與newVal的長度一致,只有像素點大於判斷基點減去loDiff值、並且小於加上upDiff值時,才會劃入泛洪區域。
  • flags一共有3個字節,低八位表示鄰域范圍,默認是4,也可設置成8;中八位表示給mask填充的數值,比如(255 << 8)表示將255左移八位得到的結果;高八位如果不設定,表示會更改image圖像,並且是用float_range判斷泛洪區域的方式,如果設定為cv2.FLOODFILL_FIXED_RANGE,表示僅憑與泛洪基點的像素差值判斷是否屬於泛洪區域,如果設定為cv2.FLOODFILL_MASK_ONLY,表示不改變image圖像,僅僅改變mask;唯一我有疑惑的就是cv2.FLOODFILL_FIXED_RANGE能否和cv2.FLOODFILL_MASK_ONLY一齊存在呢??邏輯上完全沒問題的。
  • rect是最後得到的泛洪區域的最小矩形邊界的坐標、寬高。

講點宏參數方面的問題

我們通過floodfill()的官方API文檔也可以知道,flags是有低、中、高八位的;而高八位是由宏參數定義的。

在學習C語言的時候,我們講過用define命令可以定義宏對象,比如把常用到的3.1415926...這個常數π給定義為PI,這樣我們就不用時刻把這麼長的一串數字打出來了,或者對於記憶不好的同學,也不用記π的小數點後是哪些數字了。

為了讓各位人類更方便地進行編程,不用記住那些意義不直觀的數字組合,OpenCV的開發人員把高八位的幾種選項對應的數值,預定義了幾個宏參數,我們程序員只需將宏參數字符串傳入API。

最後講一個錯誤, 大家執行下面的代碼;會發現mask沒有什麼變化,而image也發生了改變。

import cv2 as cv
import numpy as np
def fill_binary():
image = np.zeros([400, 400, 3], np.uint8)
image[100:300, 100:300, :] = 255
cv.imshow("fill_binary", image)
mask = np.ones([402, 402, 1], np.uint8)
mask[101:301, 101:301] = 0
print(np.sum(mask))
cv.floodFill(image, mask, (200, 200), (0, 0, 255), 4 | (127 << 8) | cv.FLOODFILL_MASK_ONLY)
cv.imshow("filled binary", image)
print(np.sum(mask))
print(np.unique(mask))
cv.imshow("mask", mask)
fill_binary()
cv.waitKey(0)
cv.destroyAllWindows()

 

這是因為,在flags參數前面還有兩個loDiff和upDiff參數;如果不給這兩個參數傳值,又不以關鍵詞參數的形式給參數flags傳值,函數就會誤將flags的值傳入loDiff,顯然是錯誤的。

修改成下面正確的版本後。

import cv2 as cv
import numpy as np
def fill_binary():
image = np.zeros([400, 400, 3], np.uint8)
image[100:300, 100:300, :] = 255
cv.imshow("fill_binary", image)
mask = np.ones([402, 402, 1], np.uint8)
mask[101:301, 101:301] = 0
print(np.sum(mask))
cv.floodFill(image, mask, (200, 200), (0, 0, 255), flags=4 | (127 << 8) | cv.FLOODFILL_MASK_ONLY)
cv.imshow("filled binary", image)
print(np.sum(mask))
print(np.unique(mask))
cv.imshow("mask", mask)
fill_binary()
cv.waitKey(0)
cv.destroyAllWindows()

這才對了!


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved