floodFill詳解

https://blog.csdn.net/weixin_42296411/article/details/80966724

函數原型


參數:

       image 【輸入/輸出】 1或者3通道、 8bit或者浮點圖像。僅當參數flagsFLOODFILL_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:
  1. import cv2
  2. import numpy as np
  3. img = np.zeros((20,10), dtype=np.uint8)
  4. i = 0
  5. for v in img:
  6. v[:] = i//5 * 60
  7. i += 1
  8. cv2.imshow('img', img)
  9. cv2.waitKey(0)
  10. cv2.destroyAllWindows()

得到的圖片輸出(爲方便觀察,使用畫圖軟件打開,下同):

該圖片被分爲4個橫條塊,其灰度值自頂向下依次爲:0、60、120、180。

       接下來,我們選定seed=(7,7), 該點落在這裏(下圖第二個橫條小白點處):

       我們選定該點作爲seedPoint,對img圖片進行floodFill。

Code-2:
  1. #encoding=utf-8
  2. import cv2
  3. import numpy as np
  4. img = np.zeros((20,10), dtype=np.uint8)
  5. i = 0
  6. for v in img:
  7. v[:] = i//5 * 60
  8. i += 1
  9. cv2.imwrite('img_init.png', img)
  10. seed = (7, 7)
  11. #構建mask,根據mask參數的介紹,其size必須爲寬img+2,高img+2
  12. mask = np.zeros((img.shape[0]+2, img.shape[1] +2), dtype=np.uint8)
  13. newVal = (127) #img fill的填充值
  14. mask_fill = 252 #mask的填充值
  15. #floodFill充值標誌
  16. flags = 4|(mask_fill<<8)|cv2.FLOODFILL_FIXED_RANGE
  17. #連通區範圍設定
  18. loDiff, upDiff = 20,20
  19. #執行floodFill操作
  20. ret, image, mask, rect = cv2.floodFill(img, mask, seed, newVal,(loDiff), (upDiff), flags)
  21. cv2.imwrite('img.png', img)
  22. 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)中,則pq是4鄰接。

8鄰接-如果q在集合N8(p)中,則pq是8鄰接。

最後,通過代碼來演示一下:

Code-3-1:

  1. #encoding=utf-8
  2. #創建一個8x8的圖片
  3. import cv2
  4. import numpy as np
  5. size = 8
  6. img = np.zeros((size,size), dtype=np.uint8)
  7. img[:] = 0
  8. img[4,4] = 1
  9. img[3,4] = 1
  10. img[4,3] = 1
  11. img[4,5] = 1
  12. img[5,4] = 1
  13. img[2,4] = 1
  14. img[1,5] = 1
  15. img[1,3] = 1
  16. img[2,2] = 1
  17. img[3,1] = 1
  18. img[4,0] = 1
  19. img[5,1] = 1
  20. img[6,2] = 1
  21. img[7,3] = 1
  22. print(img)

創建一個以p(4,4)爲中心像素的8x8圖像:


下面以p(4,4)作爲seed,對該圖像進行floodFill操作,對比4鄰接和8鄰接的差異。

Code-3-2:

  1. #encoding=utf-8
  2. #創建一個8x8的圖片
  3. import cv2
  4. import numpy as np
  5. size = 8
  6. img = np.zeros((size,size), dtype=np.uint8)
  7. img[:] = 0
  8. seed_x = 4
  9. seed_y = 4
  10. img[seed_x, seed_y] = 1
  11. img[4,4] = 1
  12. img[3,4] = 1
  13. img[4,3] = 1
  14. img[4,5] = 1
  15. img[5,4] = 1
  16. img[2,4] = 1
  17. img[1,5] = 1
  18. img[1,3] = 1
  19. img[2,2] = 1
  20. img[3,1] = 1
  21. img[4,0] = 1
  22. img[5,1] = 1
  23. img[6,2] = 1
  24. img[7,3] = 1
  25. seed = (seed_x, seed_y)
  26. mask= np.zeros((size+2,size+2), dtype=np.uint8)
  27. img1 = img.copy()
  28. img2 = img.copy()
  29. mask1 = mask.copy()
  30. mask2 = mask.copy()
  31. ret, img1,mask1, rect=cv2.floodFill(img1, mask1, seed,(8), (0),(0), flags=4|(3<<2)|cv2.FLOODFILL_FIXED_RANGE)
  32. ret, img2,mask2, rect=cv2.floodFill(img2, mask2, seed,(8), (0),(0), flags=8|(3<<2)|cv2.FLOODFILL_FIXED_RANGE)
  33. print(img)
  34. print(img1)
  35. print(img2)
img1爲4鄰接填充:


img2爲8鄰接填充:





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章