OpenCV与图像处理学习九——连通区域分析算法(含代码)
OpenCV與圖像處理學習九——連通區域分析算法(含代碼)
- 一、連通區域概要
- 二、Two-Pass算法
- 三、代碼實現
一、連通區域概要
連通區域(Connected Component)一般是指圖像中具有相同像素值且位置相鄰的前景像素點組成的圖像區域,連通區域分析是指將圖像中的各個連通區域找出并標記。連通區域分析是一種在CV和圖像分析處理的眾多應用領域中較為常用和基本的方法。
例如: OCR識別中字符分割提取(車牌識別、文本識別、字幕識別等)、視覺跟蹤中的運動前景
目標分割與提取(行人入侵檢測、遺留物體檢測、基于視覺的車輛檢測與跟蹤等)、醫學圖像處
理(感興趣目標區域提取)等。
在需要將前景目標提取出來以便后續進行處理的應用場景中都能夠用到連通區域分析
方法,通常連通區域分析處理的對象是一張二值化后的圖像。
在圖像中,最小的單位是像素,每個像素周圍有鄰接像素,常見的鄰接關系有2種: 4鄰接與8鄰接,如下圖所示:
如果A與B連通, B與C連通,則A與C連通,在視覺上看來,彼此連通的點形成了一個區域,而不連通的點形成了不同的區域。這樣的一個所有的點彼此連通點構成的集合,我們稱為一個連通區域。
我們來看一下下面這個二值化的圖:
對于每一個前景像素,只要它的鄰域中有像素也是前景,那么它們就屬于一個連通區域,在這張圖中,如果使用四鄰域的規則,那么將可以分成三個連通區域,而使用八鄰域的規則,則可以分成兩個連通區域。
二、Two-Pass算法
基于上述概念,我們再來學習連通區域分析算法中常用的Two-Pass算法 (兩遍掃描法),正如其名,指的就是通過掃描兩遍圖像,將圖像中存在的所有連通域找出并標記。
第一次掃描:
若一張二值圖如下所示(藍點為前景點):
則第一遍掃描之后記錄的label如下所示:
通過領域像素得到label或成為領域像素得到label依據的像素點都將記錄為一個集合,只有毫無聯系的才會記錄為不同的集合,如上圖所示,前景點被分為了兩個集合(橙色標記)。
第二次掃描:
則就可以得到兩個連通區域:
三、代碼實現
import cv2 import numpy as np# 4鄰域的連通域和 8鄰域的連通域 # [row, col] NEIGHBOR_HOODS_4 = True OFFSETS_4 = [[0, -1], [-1, 0], [0, 0], [1, 0], [0, 1]]NEIGHBOR_HOODS_8 = False OFFSETS_8 = [[-1, -1], [0, -1], [1, -1],[-1, 0], [0, 0], [1, 0],[-1, 1], [0, 1], [1, 1]] #第二遍掃描 def reorganize(binary_img: np.array):index_map = []points = []index = -1rows, cols = binary_img.shapefor row in range(rows):for col in range(cols):var = binary_img[row][col]if var < 0.5:continueif var in index_map:index = index_map.index(var)num = index + 1else:index = len(index_map)num = index + 1index_map.append(var)points.append([])binary_img[row][col] = numpoints[index].append([row, col])#print(binary_img)#print(points)return binary_img, points#四領域或八領域判斷 def neighbor_value(binary_img: np.array, offsets, reverse=False):rows, cols = binary_img.shapelabel_idx = 0rows_ = [0, rows, 1] if reverse == False else [rows-1, -1, -1]cols_ = [0, cols, 1] if reverse == False else [cols-1, -1, -1]for row in range(rows_[0], rows_[1], rows_[2]):for col in range(cols_[0], cols_[1], cols_[2]):label = 256if binary_img[row][col] < 0.5:continuefor offset in offsets:neighbor_row = min(max(0, row+offset[0]), rows-1)neighbor_col = min(max(0, col+offset[1]), cols-1)neighbor_val = binary_img[neighbor_row, neighbor_col]if neighbor_val < 0.5:continuelabel = neighbor_val if neighbor_val < label else labelif label == 255:label_idx += 1label = label_idxbinary_img[row][col] = labelprint('第一遍掃描:',binary_img)print('開始第二遍...')return binary_img# binary_img: bg-0, object-255; int #第一遍掃描 def Two_Pass(binary_img: np.array, neighbor_hoods):if neighbor_hoods == NEIGHBOR_HOODS_4:offsets = OFFSETS_4elif neighbor_hoods == NEIGHBOR_HOODS_8:offsets = OFFSETS_8else:raise ValueErrorbinary_img = neighbor_value(binary_img, offsets, False)return binary_imgif __name__ == "__main__":#創建四行七列的矩陣binary_img = np.zeros((4, 7), dtype=np.int16)#指定點設置為255index = [[0, 2], [0, 5],[1, 0], [1, 1], [1, 2], [1, 4], [1, 5], [1, 6],[2, 2], [2, 5],[3, 1], [3, 2], [3, 4],[3,5], [3, 6]]for i in index:binary_img[i[0], i[1]] = np.int16(255)print("原始二值圖像")print(binary_img)#print("Two_Pass")#調用Two Pass算法,計算第一遍掃面的結果binary_img = Two_Pass(binary_img, NEIGHBOR_HOODS_4)#print(binary_img)#計算第一遍掃面的結果binary_img, points = reorganize(binary_img)print(binary_img)#print(points)結果如下所示:
原始二值圖像 [[ 0 0 255 0 0 255 0][255 255 255 0 255 255 255][ 0 0 255 0 0 255 0][ 0 255 255 0 255 255 255]] 第一遍掃描: [[0 0 1 0 0 2 0][3 3 1 0 4 2 2][0 0 1 0 0 2 0][0 5 1 0 6 2 2]] 開始第二遍... [[0 0 1 0 0 2 0][3 3 1 0 4 2 2][0 0 1 0 0 2 0][0 5 1 0 6 2 2]]總結
以上是生活随笔為你收集整理的OpenCV与图像处理学习九——连通区域分析算法(含代码)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统--内核级线程实现
- 下一篇: 模式识别:绪论