OpenCV學習 基礎圖像操作(十七):泛洪與分水嶺算法

原理

泛洪填充算法和分水嶺算法是圖像處理中的兩種重要算法,主要用于區域分割,但它們的原理和應用場景有所不同,但是他們的基礎思想都是基于區域迭代實現的區域之間的劃分

泛洪算法

泛洪填充算法(Flood Fill)是一種經典的圖像處理算法,用于確定和標記與給定點連接的區域,通常在圖像填充、分割、邊界檢測等方面應用廣泛。為了更直觀地理解泛洪填充算法,我們可以通過一系列生動的圖像和步驟來介紹其工作原理。

假設我們有一個二維圖像,每個像素可以有不同的顏色或灰度值。泛洪填充算法的目標是從某個起始像素開始,填充所有與其相連且具有相同顏色的像素。常見的應用包括圖像編輯中的填充工具(如油漆桶工具)和迷宮求解等。

算法流程

以下是泛洪填充算法的基本步驟,配合圖像說明:

  1. 選擇起始點和目標顏色

    1. 選擇圖像中的一個起始像素點(如鼠標點擊的位置),記作 (x, y)。
    2. 確定要填充的目標顏色。
  2. 初始化隊列

    • 將起始點 (x, y) 加入隊列。
  3. 處理隊列

    當隊列不為空時,重復以下步驟:
    • 從隊列中取出一個像素點 (cx, cy)。
    • 如果 (cx, cy) 的顏色等于目標顏色,則進行填充。
    • 將 (cx, cy) 的四個鄰居(上、下、左、右)加入隊列(如果這些鄰居還沒有被處理過且顏色等于目標顏色)。

分水嶺算法

分水嶺算法是一種基于形態學和拓撲學的圖像分割技術。它將圖像視為一個拓撲地形,通過標記圖像的不同區域(例如山脈和盆地)進行分割。分水嶺算法的基本思想是通過模擬雨水從山頂流向盆地的過程,確定圖像中不同區域的邊界。

分水嶺迭代過程:

  1. 把梯度圖像中的所有像素按照灰度值進行分類,并設定一個測地距離閾值。
  2. 找到灰度值最小的像素點(默認標記為灰度值最低點),讓threshold從最小值開始增長,這些點為起始點。
  3. 水平面在增長的過程中,會碰到周圍的鄰域像素,測量這些像素到起始點(灰度值最低點)的測地距離,如果小于設定閾值,則將這些像素淹沒,否則在這些像素上設置大壩,這樣就對這些鄰域像素進行了分類。
  4. 隨著水平面越來越高,會設置更多更高的大壩,直到灰度值的最大值,所有區域都在分水嶺線上相遇,這些大壩就對整個圖像像素的進行了分區。

實際應用時常結合其他預處理,來實現前后景的分割:

算法流程

  1. 梯度計算: 首先計算圖像的梯度,梯度可以使用 Sobel 算子或其他方法計算。梯度圖像反映了圖像中像素值變化的幅度。

    G(x,y)=\sqrt{(\frac{\partial I}{\partial x})^2+(\frac{\partial I}{\partial y})^2}

    其中,𝐼?是原始圖像,𝐺是梯度圖像。

  2. 標記區域: 對圖像進行標記,將前景對象和背景標記出來。可以使用形態學操作來獲取這些標記。

    • 確定前景:使用距離變換和閾值化來確定前景區域。

      D(x,y)=distance\_tranform(I)
      foreground(x,y)=\begin{cases} 1 & \text{ if } D(x,y) > 1 \\ 0 & \text{ if } othersize \end{cases}

    • 確定背景:通過膨脹操作擴展前景區域,從而確定背景區域。

      background(x,y)=dilate(foreground,kernel)

  3. 確定未知區域: 未知區域是背景和前景的差集。

    unknown=background-foreground

  4. 連接組件標記: 對前景區域進行連通組件標記,每個連通組件代表一個獨立的前景對象。

    markers=connected\_components(foreground)

  5. 分水嶺變換: 使用分水嶺變換對梯度圖像進行處理,分割圖像中的不同區域。

    markers=watershed(G,markers)

    分水嶺變換后,標記圖像的邊界區域將被標記為 -1。

API介紹

floodfill

int cv::floodFill	(	InputOutputArray 	image,   //輸入圖像InputOutputArray 	mask,                        //輸入輸出的maksPoint 	seedPoint,                               //種子點Scalar 	newVal,                                  //信的Rect * 	r    ect = , 0                           // 存儲填充區域的邊界Scalar 	loDiff = , Scalar()                      // 允許填充的像素值差的下屆Scalar 	upDiff = , Scalar()                      // 允許填充的像素值差的上屆int 	flags = 4                                // 4聯通或8聯通
)	
import cv2
import numpy as np
import matplotlib.pyplot as plt
def main():# 加載圖像image_path = 'D:\code\src\code\lena.jpg'  # 替換為你的圖像路徑image = cv2.imread(image_path)if image is None:print("Error: Unable to load image.")return# 定義種子點和新顏色seed_point = (30, 30)  # 替換為你希望的種子點 (x, y)new_color = (0, 0, 255)  # 新顏色為綠色 (B, G, R)# 創建掩碼,比原圖多出兩行兩列mask = np.zeros((image.shape[0] + 2, image.shape[1] + 2), np.uint8)# 設置差值范圍lo_diff = (10, 10, 10)up_diff = (10, 10, 10)image_src = image.copy()# 執行泛洪填充flags = 4  # 4-連通num, im, mask, rect = cv2.floodFill(image, mask, seed_point, new_color, lo_diff, up_diff, flags)# 顯示填充后的圖像plt.subplot(131),plt.imshow(image_src[...,::-1]),plt.title('Source Image'), plt.xticks([]), plt.yticks([])plt.subplot(132),plt.imshow(mask[...,::-1]),plt.title('Mask Image'), plt.xticks([]), plt.yticks([])plt.subplot(133),plt.imshow(image[...,::-1]),plt.title('Filled Image'), plt.xticks([]), plt.yticks([])plt.show()if __name__ == '__main__':main()

watermeshed

cv::watershed	(	InputArray 	image,  //輸入圖像
InputOutputArray 	markers             //輸入出的標記
)	
//即根據傳入的確信區域以及原圖,經過分水嶺迭代后,得到的確信區域
import cv2
import numpy as np
import matplotlib.pyplot as plt
import imageiodef plot_image(image, title, save_path):plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))plt.title(title)plt.axis('off')plt.savefig(save_path)plt.close()def save_gif(frames, filename, duration=0.5):imageio.mimsave(filename, frames, duration=duration)def watershed_segmentation(image_path):# Read the imageimage = cv2.imread(image_path)gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# Apply thresholdingret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# Noise removal with morphological operationskernel = np.ones((3, 3), np.uint8)opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)# Sure background areasure_bg = cv2.dilate(opening, kernel, iterations=3)# Finding sure foreground areadist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)# Finding unknown regionsure_fg = np.uint8(sure_fg)unknown = cv2.subtract(sure_bg, sure_fg)# Marker labellingret, markers = cv2.connectedComponents(sure_fg)# Add one to all labels so that sure background is not 0, but 1markers = markers + 1# Now, mark the region of unknown with zeromarkers[unknown == 255] = 0# Apply watershedmarkers = cv2.watershed(image, markers)image[markers == -1] = [255, 0, 0]  # Mark boundaries with red color# Collect frames for GIFframes = []for step in ['Original', 'Threshold', 'Morph Open', 'Sure BG', 'Sure FG', 'Unknown', 'Markers', 'Watershed']:if step == 'Original':frame = image.copy()elif step == 'Threshold':frame = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)elif step == 'Morph Open':frame = cv2.cvtColor(opening, cv2.COLOR_GRAY2BGR)elif step == 'Sure BG':frame = cv2.cvtColor(sure_bg, cv2.COLOR_GRAY2BGR)elif step == 'Sure FG':frame = cv2.cvtColor(sure_fg, cv2.COLOR_GRAY2BGR)elif step == 'Unknown':frame = cv2.cvtColor(unknown, cv2.COLOR_GRAY2BGR)elif step == 'Markers':frame = np.zeros_like(image)for i in range(1, ret + 1):frame[markers == i] = np.random.randint(0, 255, size=3)elif step == 'Watershed':frame = image.copy()frame_path = f"{step.lower().replace(' ', '_')}.png"plot_image(frame, step, frame_path)frames.append(imageio.imread(frame_path))return frames# Main execution
image_path = 'D:\code\src\code\R-C.png'  # Replace with your image path
frames = watershed_segmentation(image_path)
save_gif(frames, 'watershed.gif', duration=1000)

參考鏈接

OpenCV(26)圖像分割 -- 距離變換與分水嶺算法(硬幣檢測、撲克牌檢測、車道檢測)_分水嶺算法分割咖啡豆-CSDN博客

圖像處理之漫水填充算法(flood fill algorithm)-騰訊云開發者社區-騰訊云 (tencent.com)

【OpenCV(C++)】分水嶺算法_opencv分水嶺c++-CSDN博客

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20527.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20527.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20527.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

修改element-ui el-radio顏色

修改element-ui el-radio顏色 需求效果圖代碼實現 小結 需求 撤銷扣分是綠色&#xff0c;駁回是紅色 效果圖 代碼實現 dom <el-table-columnlabel"操作"width"200px"><template v-slot"scope"><el-radio-group v-model"s…

Vue插槽與作用域插槽

title: Vue插槽與作用域插槽 date: 2024/6/1 下午9:07:52 updated: 2024/6/1 下午9:07:52 categories: 前端開發 tags:VueSlotScopeSlot組件通信Vue2/3插槽作用域API動態插槽插槽優化 第1章&#xff1a;插槽的概念與原理 插槽的定義 在Vue.js中&#xff0c;插槽&#xff08;…

如何用FPGA實現SINC濾波

目錄 簡介: 技術說明: 代碼如下: 簡介: sinc(音同“sink”)濾波器是由sinc函數構造的濾波器。sinc函數的定義可以參考抽樣信號Sa的定義,這里只需知道矩形脈沖和sinc函數是一個變換對。當矩形脈沖的頻譜沒有混疊時,它就是sin(x)/x,一個sinc函數,對于連續信號,矩形脈…

【記錄43】el-table @selection-change 數據回顯、條件約束、歷史回顯清除

場景 在其他地方設置好人員&#xff0c;到對應的頁面直接在表格中復選設置好的人員。解決方案用到selection-change方法 <el-button click"EchoClick()">回顯設置好的人</el-button> <el-table ref"choeck" :data"TableData" s…

c++(七)

c&#xff08;七&#xff09; 內聯函數內聯函數的特點為什么要有內聯函數內聯函數是如何工作的呢 類型轉換異常處理智能指針單例模式懶漢模式餓漢模式 VS中數據庫的相關配置 內聯函數 修飾類的成員函數&#xff0c;關鍵字&#xff1a;inline inline 返回值類型 函數名(參數列…

vue-el-steps 使用2[代碼示例]

效果圖 代碼 element代碼 <template> <div class"app-container"> <el-form :model"queryForm" size"small" :inline"true"> <el-form-item label"內容狀態"> <el-button-group> <el-bu…

Docker 容器中運行Certbot獲取和管理 SSL 證書

如果你在 Docker 容器中運行 Nginx 并希望使用 Certbot 獲取和管理 SSL 證書&#xff0c;可以使用 Certbot 的官方 Docker 鏡像來完成這項工作。以下是使用 Docker 和 Certbot 獲取 SSL 證書并配置 Nginx 的詳細步驟&#xff1a; 1. 拉取 Certbot Docker 鏡像 首先&#xff0…

window下C語言程序報錯

Thread 1 received signal SIGSEGV, Segmentation fault. ___chkstk_ms () at ../../../../../src/gcc-8.1.0/libgcc/config/i386/cygwin.S:126 126 ../../../../../src/gcc-8.1.0/libgcc/config/i386/cygwin.S: No such file or directory. 參考&#xff1a;不同平臺下對…

代碼隨想錄訓練營Day 46|力扣完全背包、518. 零錢兌換 II、377. 組合總和 Ⅳ

1.完全背包 視頻講解&#xff1a;帶你學透完全背包問題&#xff01; 和 01背包有什么差別&#xff1f;遍歷順序上有什么講究&#xff1f;_嗶哩嗶哩_bilibili https://programmercarl.com/%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80%E5%AE%8C%E…

as keyof GlobalStore

解釋 as keyof GlobalStore 在 TypeScript 中&#xff0c;as keyof GlobalStore 是一種類型斷言語法。它告訴 TypeScript&#xff0c;返回的值是一個特定類型的值&#xff0c;這里是 GlobalStore 類型的鍵。這在編譯時有助于確保類型安全。 關鍵點&#xff1a; 類型斷言&…

【三國戰紀game】

編寫一個完整的《三國戰紀》游戲是一個龐大的項目&#xff0c;需要一個專業的游戲開發團隊和大量的時間。但是&#xff0c;我可以給你一個簡化的概念&#xff0c;幫助你開始這個過程。 游戲概念&#xff1a;三國戰紀 《三國戰紀》是一個以中國三國時期為背景的策略游戲&#…

構建智慧銀行保險系統的先進技術架構

隨著科技的不斷發展&#xff0c;智慧銀行保險系統正日益受到關注。在這個數字化時代&#xff0c;構建一個先進的技術架構對于智慧銀行保險系統至關重要。本文將探討如何構建智慧銀行保險系統的先進技術架構&#xff0c;以提升服務效率、降低風險并滿足客戶需求。 ### 1. 智慧銀…

qwen-moe

一、定義 qwen-moe 代碼講解&#xff0c; 代碼qwen-moe與Mixtral-moe 一樣&#xff0c; 專家模塊qwen-moe 開源教程Mixture of Experts (MoE) 模型在Transformer結構中如何實現&#xff0c;Gate的實現一般采用什么函數&#xff1f; Sparse MoE的優勢有哪些&#xff1f;MoE是如…

C++學習 const 上

&#x1f308; C Primer 的學習筆記 前言 這篇blog 主要是想具體講講新學到的const 當然不止是const 而是基于這個const引申出來的指針和引用。還是需要捋一捋的&#xff0c;這還是有點困難的。 我會把每一節的重點都摘出來&#xff0c;放在前面~ 1??首先講講const 2??…

Linux C/C++動態庫制作

概念&#xff1a;程序在編譯時不會把庫文件的二進制代碼鏈接到目標程序中&#xff0c;而是在運行時候才被載入。 如果多個進程中用到了同一動態庫中的函數或類&#xff0c;那么在內存中只有一份&#xff0c;避免了空間浪費問題。 特點&#xff1a; 程序運行在運行的過程中&…

統計信號處理基礎 習題解答10-6

題目 在例10.1中&#xff0c;把數據模型修正為&#xff1a; 其中是WGN&#xff0c;如果&#xff0c;那么方差&#xff0c;如果&#xff0c;那么方差。求PDF 。把它與經典情況PDF 進行比較&#xff0c;在經典的情況下A是確定性的&#xff0c;是WGN&#xff0c;它的方差為&#…

5.算法講解之-二分查找(簡單易懂)

1.簡介 1.二分查找的思路簡單易懂&#xff0c;較難的是如何處理查找過程中的邊界條件&#xff0c;當較長時間沒寫二分查找的時候就容易忘記如何處理邊界條件。 2.只有多寫代碼&#xff0c;多做筆記就不易忘記邊界條件 2.算法思路 正常查找都是從頭到尾查找一個數字是否在數組中…

使用pycharm+opencv進行視頻抽幀(可以用來擴充數據集)+ labelimg的使用(數據標準)

一.視頻抽幀 1.新創建一個空Pycharm項目文件&#xff0c;命名為streach zhen 注&#xff1a;然后要做一個前期工作 創建opencv環境 &#xff08;1&#xff09;我們在這個pycharm項目的終端里面輸入下面的命令&#xff1a; pip install opencv-python --user -i https://pypi.t…

SettingWithCopyWarning: A value is trying to be set on a copy of a slice fro

SettingWithCopyWarning: A value is trying to be set on a copy of a slice fro 錯誤代碼&#xff1a; while i < len(data_csv_data):if data_csv_data[flowmember][i] j:data_csv_data[label][i] data_csv_label[label][j-1]data_csv_data[classes][i]data_csv_label[…

[數據集][目標檢測]獼猴桃檢測數據集VOC+YOLO格式1838張1類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;1838 標注數量(xml文件個數)&#xff1a;1838 標注數量(txt文件個數)&#xff1a;1838 標注…