#はじめに
OpenCVのスーパーピクセル(領域分割)画像処理について、前回記事を書きましたが
分割してどうする?のどうするかについての部分を書いていませんでしたので
書きたいと思います。
#スーパーピクセルについて
スーパーピクセルは領域分割とかセグメンテーションアルゴリズムのことで
領域を分割した上で画像処理をします。
今回は、スーパーピクセルで分割した領域のラベル情報(マスク)を取得し
それを表示します。
また、そのラベル情報(マスク)で、分割領域のBGR平均値を取得し、画像に
反映することをやってみようと思います。
##1)スーパーピクセルインスタンスの生成
まず、スーパーピクセルインスタンス生成し、画像データをインスタンスに入力します。
seeds = cv2.ximgproc.createSuperpixelSEEDS(width, height, channels, num_superpixels,
num_levels, prior, num_histogram_bins, double_step)
# 画像のスーパーピクセルセグメンテーションを計算
# 入力画像は,HSVまたはL*a*b*
converted = cv2.cvtColor(input_image, cv2.COLOR_BGR2HSV)
seeds.iterate(converted, num_iterations)
入力画像はHSV色空間かまたはLab*色空間を使います。
上記サンプルconverted画像はHSV色空間です。
##2)スーパーピクセルセグメンテーションの境界を取得
各分割された領域を分ける線を黄色で線引きします。
これは、人にわかりやすくするための処理で、必ずしも必須ではありません。
# スーパーピクセルセグメンテーションの境界を取得
contour_mask = seeds.getLabelContourMask(False)
result = input_image.copy()
result[0 < contour_mask] = ( 0, 255, 255)
領域を分ける線情報へのアクセス方法を掲載しています。
##3)セグメンテーション情報取得
セグメンテーション(領域分割)の分割数と、ラベル情報を取得します。
ラベル情報は、np.int32型の2次元配列です。
ここに分割猟奇事に数字が入っています。
ちょうど、粒子解析ラベリングとかブロブ処理と言われる場合にも
同様なイメージが使われているかと思います。
# セグメンテーション数の取得
nseg = seeds.getNumberOfSuperpixels()
# セグメンテーション分割情報の取得
labels = seeds.getLabels()
##4)セグメンテーション状況(ラベル情報)を表示
セグメント分けがどのようになっているかを見る為に
ラベル情報をランダムBGR表示しています。
これは確認用の処理です。
randcolor = np.random.randint(255, size=[nseg,3])
lbsegimg = np.zeros((height, width, channels), dtype=np.uint8)
for m in range(0, nseg):
lbsegimg[labels == m] = randcolor[m]
lbsegimgがラベル情報をランダムBGRタイリング画像
##5)セグメンテーション平均化処理
セグメンテーション(領域分割)のセグメント毎にBGR平均値をマスク処理で取得します。
返却値は浮動小数点型のタプルなので、これをint型配列に変換し、画像に設定します。
# セグメンテーション毎のBGR平均値を取得
segavgimg = np.zeros((height, width, channels), dtype=np.uint8)
lb = np.zeros((height, width), dtype=np.uint8)
for m in range(0, nseg):
lb.fill(0)
lb[labels == m] = 255
bgrm = cv2.mean(input_image, lb) # BGR平均値を取得
# tuple float形式の平均値情報をint形式に変換
bgr = [int(bgrm[0]), int(bgrm[1]), int(bgrm[2])]
segavgimg[lb == 255] = bgr
segavgimg画像が、セグメンテーションの平均化処理イメージです。
cv2.mean()は、マスク画像をしていすることで、マスク領域の平均値を取得することができます。
#サンプルプログラム
import cv2
import math
import numpy as np
def main():
input_image = cv2.imread('Vegetables.jpg')
if input_image is None:
print("ファイルオープンエラー")
return -1
# スーパーピクセルセグメンテーションの生成
height, width, channels= input_image.shape[:3]
num_iterations = 4
prior = 2
double_step = False
num_superpixels = 500
num_levels = 4
num_histogram_bins = 5
seeds = cv2.ximgproc.createSuperpixelSEEDS(width, height, channels, num_superpixels,
num_levels, prior, num_histogram_bins, double_step)
# 画像のスーパーピクセルセグメンテーションを計算
# 入力画像は,HSVまたはL*a*b*
converted = cv2.cvtColor(input_image, cv2.COLOR_BGR2HSV)
seeds.iterate(converted, num_iterations)
# スーパーピクセルセグメンテーションの境界を取得
contour_mask = seeds.getLabelContourMask(False)
result = input_image.copy()
result[0 < contour_mask] = ( 0, 255, 255)
# セグメンテーション数の取得
nseg = seeds.getNumberOfSuperpixels()
# セグメンテーション分割情報の取得
labels = seeds.getLabels()
# セグメンテーション状況(ラベル情報)をランダムBGRでタイリング
randcolor = np.random.randint(255, size=[nseg,3])
lbsegimg = np.zeros((height, width, channels), dtype=np.uint8)
for m in range(0, nseg):
lbsegimg[labels == m] = randcolor[m]
# セグメンテーション毎のBGR平均値を取得
segavgimg = np.zeros((height, width, channels), dtype=np.uint8)
lb = np.zeros((height, width), dtype=np.uint8)
for m in range(0, nseg):
lb.fill(0)
lb[labels == m] = 255
bgrm = cv2.mean(input_image, lb) # BGR平均値を取得
# tuple float形式の平均値情報をint形式に変換
bgr = [int(bgrm[0]), int(bgrm[1]), int(bgrm[2])]
segavgimg[lb == 255] = bgr
# 画像表示
cv2.imshow('Vegetableslbsegimg', lbsegimg)
cv2.imshow('Vegetablesresult', result)
cv2.imshow('Vegetables means image', segavgimg)
cv2.waitKey(0)
return 0
if __name__ == '__main__':
main()
#結果
##入力画像
入力画像は、野菜の盛り合わせ写真。
「野菜生活」 photoAC掲載 koma-komaさんの写真です。記事掲載用に少し縮小しました。
この画像に対してスーパーピクセル処理を行います。
黄色い線の黄色い線の内側をランダムカラーで塗ったイメージです。
各セグメント毎に平均色で色分けしています。
#最後に
前回記事を書いた後、すぐにこれのような記事を書こうとしていたのですが、いろいろ忙しく、
また興味が他に移っていたこともあり保留となっていました。
残件を仕上げた感じで少しさわやかないいかんじです。
#実行環境
Windows10 Anaconda (Miniforge3)
Python 3.9.2 packaged by conda-forge
OpenCV 4.5.1
#参考
Qiita - OpenCVのスーパーピクセル
Emotion Explorer - OpenCVのスーパーピクセル(3) - SuperpixelLSCクラスを試す。
Emotion Explorer - OpenCVのスーパーピクセル(2) - SuperpixelSLICクラスを試す。
Emotion Explorer - OpenCVのスーパーピクセル(1) - SuperpixelSEEDSクラスを試す。
Emotion Explorer - Watershedアルゴリズムの領域分割
Emotion Explorer - 画素の平均を計算
docs.opencv.org - Superpixels Extended Image Processing
docs.opencv.org - cv::ximgproc::SuperpixelSEEDS Class Reference
docs.opencv.org - cv::ximgproc::SuperpixelSLIC Class Reference
docs.opencv.org - cv::ximgproc::SuperpixelLSC Class Reference