OpenCV与图像处理学习九——连通区域分析算法(含代码)
OpenCV與圖像處理學(xué)習(xí)九——連通區(qū)域分析算法(含代碼)
- 一、連通區(qū)域概要
- 二、Two-Pass算法
- 三、代碼實現(xiàn)
一、連通區(qū)域概要
連通區(qū)域(Connected Component)一般是指圖像中具有相同像素值且位置相鄰的前景像素點組成的圖像區(qū)域,連通區(qū)域分析是指將圖像中的各個連通區(qū)域找出并標(biāo)記。連通區(qū)域分析是一種在CV和圖像分析處理的眾多應(yīng)用領(lǐng)域中較為常用和基本的方法。
例如: OCR識別中字符分割提取(車牌識別、文本識別、字幕識別等)、視覺跟蹤中的運動前景
目標(biāo)分割與提取(行人入侵檢測、遺留物體檢測、基于視覺的車輛檢測與跟蹤等)、醫(yī)學(xué)圖像處
理(感興趣目標(biāo)區(qū)域提取)等。
在需要將前景目標(biāo)提取出來以便后續(xù)進行處理的應(yīng)用場景中都能夠用到連通區(qū)域分析
方法,通常連通區(qū)域分析處理的對象是一張二值化后的圖像。
在圖像中,最小的單位是像素,每個像素周圍有鄰接像素,常見的鄰接關(guān)系有2種: 4鄰接與8鄰接,如下圖所示:
如果A與B連通, B與C連通,則A與C連通,在視覺上看來,彼此連通的點形成了一個區(qū)域,而不連通的點形成了不同的區(qū)域。這樣的一個所有的點彼此連通點構(gòu)成的集合,我們稱為一個連通區(qū)域。
我們來看一下下面這個二值化的圖:
對于每一個前景像素,只要它的鄰域中有像素也是前景,那么它們就屬于一個連通區(qū)域,在這張圖中,如果使用四鄰域的規(guī)則,那么將可以分成三個連通區(qū)域,而使用八鄰域的規(guī)則,則可以分成兩個連通區(qū)域。
二、Two-Pass算法
基于上述概念,我們再來學(xué)習(xí)連通區(qū)域分析算法中常用的Two-Pass算法 (兩遍掃描法),正如其名,指的就是通過掃描兩遍圖像,將圖像中存在的所有連通域找出并標(biāo)記。
第一次掃描:
若一張二值圖如下所示(藍點為前景點):
則第一遍掃描之后記錄的label如下所示:
通過領(lǐng)域像素得到label或成為領(lǐng)域像素得到label依據(jù)的像素點都將記錄為一個集合,只有毫無聯(lián)系的才會記錄為不同的集合,如上圖所示,前景點被分為了兩個集合(橙色標(biāo)記)。
第二次掃描:
則就可以得到兩個連通區(qū)域:
三、代碼實現(xiàn)
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#四領(lǐng)域或八領(lǐng)域判斷 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__":#創(chuàng)建四行七列的矩陣binary_img = np.zeros((4, 7), dtype=np.int16)#指定點設(shè)置為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")#調(diào)用Two Pass算法,計算第一遍掃面的結(jié)果binary_img = Two_Pass(binary_img, NEIGHBOR_HOODS_4)#print(binary_img)#計算第一遍掃面的結(jié)果binary_img, points = reorganize(binary_img)print(binary_img)#print(points)結(jié)果如下所示:
原始二值圖像 [[ 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]]總結(jié)
以上是生活随笔為你收集整理的OpenCV与图像处理学习九——连通区域分析算法(含代码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统--内核级线程实现
- 下一篇: 模式识别:绪论