WHAT'S UP?

New post every sometimes. Here's OKKAH NET.

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: 二値画像の入力配列


実際にラベリングしてみる
入力画像
f:id:okkah:20180802161057j:plain


・簡易版

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)


二値化画像
f:id:okkah:20180802161131j:plain

ラベリング画像(簡易版)
f:id:okkah:20180802161312j:plain


・詳細版

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)


ラベリング画像(詳細版)
f:id:okkah:20180802161435j:plain