https://blog.csdn.net/weixin_42296411/article/details/80966724
函數原型
參數:
image 【輸入/輸出】 1或者3通道、 8bit或者浮點圖像。僅當參數flags的FLOODFILL_MASK_ONLY標誌位被設置時image不會被修改,否則會被修改。
mask 【輸入/輸出】 操作掩碼,必須爲單通道、8bit,且比image寬2個像素、高2個像素。使用前必須先初始化。Flood-filling無法跨越mask中的非0像素。例如,一個邊緣檢測的結果可以作爲mask來阻止邊緣填充。在輸出中,mask中與image中填充像素對應的像素點被設置爲1,或者flags標誌位中設置的值(詳見flags標誌位的解釋)。此外,該函數還用1填充了mask的邊緣來簡化內部處理。因此,可以在多個調用中使用同一mask,以確保填充區域不會重疊。
seedPoint 起始像素點
newVal 重繪像素區域的新的填充值(顏色)
rect 可選輸出參數,返回重繪區域的最小綁定矩形。
loDiff 當前選定像素與其連通區中相鄰像素中的一個像素,或者與加入該連通區的一個seedPoint像素,二者之間的最大下行差異值。
upDiff 當前選定像素與其連通區中相鄰像素中的一個像素,或者與加入該連通區的一個seedPoint像素,二者之間的最大上行差異值。
flags flags標誌位是一個32bit的int類型數據,其由3部分組成: 0-7bit表示鄰接性(4鄰接、8鄰接);8-15bit表示mask的填充顏色;16-31bit表示填充模式(詳見填充模式解釋)
flood fill填充模式:
//! floodfill algorithm flags
enum FloodFillFlags {
/** If set, the difference between the current pixel andseed pixel is considered. Otherwise,
the difference between neighbor pixels is considered (that is, the rangeis floating). */
FLOODFILL_FIXED_RANGE = 1 << 16,
/** If set, the function does not change the image ( newValis ignored), and only fills the
mask with the value specified in bits 8-16 of flags as described above.This option only make
sense in function variants that have the mask parameter. */
FLOODFILL_MASK_ONLY = 1 <<17
};
FLOODFILL_FIXED_RANGE:如果設置了該值,則考慮當前像素與seed像素之間的差異,否則考慮相鄰像素之間的差異(即浮動區間)。
FLOODFILL_MASK_ONLY:如果設置了該值,floodFill函數不會修改image的內容(newVal被忽略),只使用flags標誌中bit8-15的值填充mask。該選項僅在含mask參數的floodFill函數中有效。
函數作用:
用給定的顏色填充一個連通區域。
下面我們通過Code來演示floodFill函數的用法及效果:
先創建一個20*10像素的灰度圖像,爲了便於觀察,我們以60個灰度爲一個等級填充圖片。
Code-1:
- import cv2
- import numpy as np
-
- img = np.zeros((20,10), dtype=np.uint8)
- i = 0
- for v in img:
- v[:] = i//5 * 60
- i += 1
-
- cv2.imshow('img', img)
- cv2.waitKey(0)
- cv2.destroyAllWindows()
得到的圖片輸出(爲方便觀察,使用畫圖軟件打開,下同):
該圖片被分爲4個橫條塊,其灰度值自頂向下依次爲:0、60、120、180。
接下來,我們選定seed=(7,7), 該點落在這裏(下圖第二個橫條小白點處):
我們選定該點作爲seedPoint,對img圖片進行floodFill。
Code-2:
- #encoding=utf-8
- import cv2
- import numpy as np
-
- img = np.zeros((20,10), dtype=np.uint8)
- i = 0
- for v in img:
- v[:] = i//5 * 60
- i += 1
-
- cv2.imwrite('img_init.png', img)
-
- seed = (7, 7)
- #構建mask,根據mask參數的介紹,其size必須爲寬img+2,高img+2
- mask = np.zeros((img.shape[0]+2, img.shape[1] +2), dtype=np.uint8)
- newVal = (127) #img fill的填充值
- mask_fill = 252 #mask的填充值
- #floodFill充值標誌
- flags = 4|(mask_fill<<8)|cv2.FLOODFILL_FIXED_RANGE
- #連通區範圍設定
- loDiff, upDiff = 20,20
- #執行floodFill操作
- ret, image, mask, rect = cv2.floodFill(img, mask, seed, newVal,(loDiff), (upDiff), flags)
- cv2.imwrite('img.png', img)
- cv2.imwrite('img_mask.png', mask)
floodFill前、後的img圖像(左前右後):
對比發現,img圖像的第二行顏色變了,check一下第二行的顏色值,發現變爲了127,這與Code-2中
newVal =(127)#img fill的填充值
是一致的:
再check一下得到的mask圖像:
其像素值爲:
我們觀察mask的像素組成會發現,執行floodFill後得到的mask值,其被填充部分的值來自於:mask_fill =252 #mask的填充值
並且,最外圍邊緣一週的像素點,全部被填充爲1,這與mask參數的描述完全一致。
接下來,我們調整一下loDiff的值爲70,我們看看會有什麼不一樣:
loDiff, upDiff =70,20
得到的img圖像爲:與原始img圖片對比:
觀察floodFill後的img像素值:
我們發現img圖像第一、二行的值均被置爲127了,這是因爲當loDiff值爲70時,seed=(7,7)所在點的值爲60,而60-loDiff=-10,60+upDiff=80,而img圖片第一、二行的像素值分別爲0和60,均值[-10,80]這個區間內,故img圖片第一、二行均被填充。
以上都是基於FLOODFILL_FIXED_RANGE這種填充方式的,下面我們對比一下使用FLOODFILL_MASK_ONLY方式來填充會有什麼不一樣。其他code保存不變,我們只需將
flags =4|(mask_fill<<8)|cv2.FLOODFILL_FIXED_RANGE
改爲:
flags =4|(mask_fill<<8)|cv2.FLOODFILL_MASK_ONLY
運行程序後,發現img圖片第一、第二行的值均未發生變化:
但mask圖片第一、第二行的值與前面使用FLOODFILL_FIXED_RANGE時是一樣的:
故此,可以驗證前面對FLOODFILL_MASK_ONLY的解釋,隻影響mask的輸出,對image無影響。
最後,對flags的0-7bit鄰接性進行分析。
相鄰像素
1) 4領域
對位於座標(x,y)的像素p有4個水平和垂直的相鄰像素,它們的座標是:
(x+1,y), (x-1,y),(x,y+1),(x,y-1)
這組像素稱爲p的4鄰域,用N4(p)表示:
對角相鄰像素
p的四個對角像素的座標爲:
(x+1,y+1), (x+1,y-1),(x-1,y+1),(x-1,y-1)
用ND(p)表示:
8領域
N4(p)和ND(p)組成像素p的8個相鄰像素,稱爲p的8鄰域,用N8(p)表示:
鄰接性
4鄰接-如果q在集合N4(p)中,則p和q是4鄰接。
8鄰接-如果q在集合N8(p)中,則p和q是8鄰接。
最後,通過代碼來演示一下:
Code-3-1:
- #encoding=utf-8
- #創建一個8x8的圖片
- import cv2
- import numpy as np
-
- size = 8
- img = np.zeros((size,size), dtype=np.uint8)
- img[:] = 0
- img[4,4] = 1
- img[3,4] = 1
- img[4,3] = 1
- img[4,5] = 1
- img[5,4] = 1
- img[2,4] = 1
- img[1,5] = 1
- img[1,3] = 1
- img[2,2] = 1
- img[3,1] = 1
- img[4,0] = 1
- img[5,1] = 1
- img[6,2] = 1
- img[7,3] = 1
- print(img)
創建一個以p(4,4)爲中心像素的8x8圖像:
下面以p(4,4)作爲seed,對該圖像進行floodFill操作,對比4鄰接和8鄰接的差異。
Code-3-2:
- #encoding=utf-8
- #創建一個8x8的圖片
- import cv2
- import numpy as np
-
- size = 8
- img = np.zeros((size,size), dtype=np.uint8)
- img[:] = 0
- seed_x = 4
- seed_y = 4
- img[seed_x, seed_y] = 1
- img[4,4] = 1
- img[3,4] = 1
- img[4,3] = 1
- img[4,5] = 1
- img[5,4] = 1
- img[2,4] = 1
- img[1,5] = 1
- img[1,3] = 1
- img[2,2] = 1
- img[3,1] = 1
- img[4,0] = 1
- img[5,1] = 1
- img[6,2] = 1
- img[7,3] = 1
-
- seed = (seed_x, seed_y)
- mask= np.zeros((size+2,size+2), dtype=np.uint8)
-
- img1 = img.copy()
- img2 = img.copy()
- mask1 = mask.copy()
- mask2 = mask.copy()
-
- ret, img1,mask1, rect=cv2.floodFill(img1, mask1, seed,(8), (0),(0), flags=4|(3<<2)|cv2.FLOODFILL_FIXED_RANGE)
- ret, img2,mask2, rect=cv2.floodFill(img2, mask2, seed,(8), (0),(0), flags=8|(3<<2)|cv2.FLOODFILL_FIXED_RANGE)
- print(img)
- print(img1)
- print(img2)
img1爲4鄰接填充:img2爲8鄰接填充: