Python+OpenCVでラベリング
Python+OpenCVを利用したラベリングについてです。
Pythonのバージョンは3.6.4、OpenCVのバージョンは3.4.1です。
ラベリングとは
二値化画像の白(または黒)の部分において、連続した画素に同じ番号を割り振る処理をラベリングと言います。
通常、同じ番号ごとの幅、高さ、面積(画素数)、重心などの特徴量を求め、オブジェクトの分類や欠陥検査などに利用します。
ラベリングの詳しい説明はこちら。
ラベリング処理アルゴリズム 画像処理ソリューション
OpenCVのラベリング関数
OpenCVのラベリング関数は2種類あります。
・簡易版
ラべリング画像のみを出力する簡易版です。
# ラベリング(簡易版)
nLabels, labelImages = cv2.connectedComponents(image_src)
・nLabels: ラベル数(ただし背景のラベル0もカウントされているため、オブジェクトの数はnLabels - 1)
・labelImages: ラベル番号が入った配列データ(座標 (x, y) のラベル番号は、labelImages[x, y] で参照できる)
・image_src: 二値画像の入力配列
・詳細版
簡易版に加えて、オブジェクトの外接矩形の情報(x, y, width, height)、面積、重心座標も出力する詳細版です。
# ラベリング(詳細版)
nLabels, labelImages, data, center = cv2.connectedComponentsWithStats(image_src)
・nLabels: ラベル数(ただし背景のラベル0もカウントされているため、オブジェクトの数はnLabels - 1)
・labelImages: ラベル番号が入った配列データ(座標 (x, y) のラベル番号は、labelImages[x, y] で参照できる)
・data: オブジェクトの詳細の配列データ(x, y, w, h, size = data[ラベル番号] で参照できる。w: width, h: height, size: 面積)
・center: オブジェクトの重心座標 (x, y) (浮動小数点数)
・image_src: 二値画像の入力配列
実際にラベリングしてみる
入力画像
・簡易版
import cv2 import numpy as np import random import sys # 画像の読み込み img = cv2.imread('sample.jpg') # グレースケール化 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 大津の二値化 gray = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 白黒反転 gray = cv2.bitwise_not(gray) # ラベリング処理(簡易版) n, label = cv2.connectedComponents(gray) # ラベリング結果書き出し準備 color_src = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) height, width = gray.shape[:2] colors = [] for i in range(1, n + 1): colors.append(np.array([random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)])) # ラベリング結果を表示 # 各オブジェクトをランダム色でペイント for y in range(0, height): for x in range(0, width): if label[y, x] > 0: color_src[y, x] = colors[label[y, x]] else: color_src[y, x] = [0, 0, 0] # オブジェクトの総数を黄文字で表示 cv2.putText(color_src, str(n - 1), (70, 70), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255)) # 画像の保存 cv2.imwrite('sample_label1.jpg', color_src)
二値化画像
ラベリング画像(簡易版)
・詳細版
import cv2 import numpy as np import sys # 画像の読み込み img = cv2.imread('sample.jpg') # グレースケール化 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 大津の二値化 gray = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # 白黒反転 gray = cv2.bitwise_not(gray) # ラベリング処理(詳細版) label = cv2.connectedComponentsWithStats(gray) # オブジェクト情報を項目別に抽出 n = label[0] - 1 data = np.delete(label[2], 0, 0) center = np.delete(label[3], 0, 0) # ラベリング結果書き出し用に二値画像をカラー変換 color_src = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR) # オブジェクト情報を利用してラベリング結果を表示 for i in range(n): # 各オブジェクトの外接矩形を赤枠で表示 x0 = data[i][0] y0 = data[i][1] x1 = data[i][0] + data[i][2] y1 = data[i][1] + data[i][3] cv2.rectangle(color_src, (x0, y0), (x1, y1), (0, 0, 255)) # 各オブジェクトのラベル番号と面積に黄文字で表示 cv2.putText(color_src, "ID: " +str(i + 1), (x0, y1 + 15), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255)) cv2.putText(color_src, "S: " +str(data[i][4]), (x0, y1 + 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255)) # 各オブジェクトの重心座標をに黄文字で表示 cv2.putText(color_src, "X: " + str(int(center[i][0])), (x1 - 10, y1 + 15), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255)) cv2.putText(color_src, "Y: " + str(int(center[i][1])), (x1 - 10, y1 + 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 255)) # 画像の保存 cv2.imwrite('sample_label2.jpg', color_src)
ラベリング画像(詳細版)