見出し画像

初心者向け:データ分析⑤



1. はじめに


こんにちは、大学院生のYukiです。

前回の記事からの続きの記事になります。

https://note.com/littlesnowman/n/ncfcb780404ba

本日から複数回にかけて画像データ分析を行なっていきます。

  1. 画像合成

  2. 物体検出

  3. CNN モデル作成

データ分析として画像を取り扱うにあたり、RGBチャネル調整等のColor CorrectionやNoise処理の話からするか、それらを飛び越えて画像分析界隈で有名な畳み込み(CNN)での手書き数字処理の話から始めるか悩んだのですが、
前半ばかりだとデータ分析の解説範囲からズレてしまうし、初心者に対してモデル作りの話から始めるのはいささか基礎をすっ飛ばしすぎている気がするので、順序立てて話を進めていきます。

本日は画像検出の理解を深めるために、画像合成を学んでいきましょう。


2. 色空間調整


まずは画像の色空間について簡単に確認だけします。元祖画像分析にあたり、色彩やシャープネス、コントラスト、色温度等の画像処理は欠かせません。

ただこの講座の目標はあくまでデータ分析ですので、簡単に色空間について手を動かしながら概要だけ学んでいきましょう。

まずはじめに下準備を行います。


適当な背景画像
適当なグリーンバック画像
import cv2
import numpy as np
import sys

# 'XYZ', 'Lab', 'YCrCb', 'HSB'
COLOR_SPACES = 'XYZ'

scenic_image = cv2.imread("風景画像までのPath")
green_image = cv2.imread("グリーンバック画像までのPath")

本日使用予定の画像と読み込み用のコードです。画像を保存して各自調整を行なってください

if color_space == 'XYZ':
    converted = cv2.cvtColor(image, cv2.COLOR_BGR2XYZ)
elif color_space == 'Lab':
    converted = cv2.cvtColor(image, cv2.COLOR_BGR2Lab)
elif color_space == 'YCrCb':
    converted = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb)
elif color_space == 'HSB':
    converted = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
else:
    print(f"Error: Invalid color space")
    sys.exit(1)
c1, c2, c3 = cv2.split(converted)
c1 = cv2.normalize(c1, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
c2 = cv2.normalize(c2, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)
c3 = cv2.normalize(c3, None, 0, 255, cv2.NORM_MINMAX).astype(np.uint8)

top_row = np.hstack((image, cv2.cvtColor(c1, cv2.COLOR_GRAY2BGR)))
bottom_row = np.hstack((cv2.cvtColor(c2, cv2.COLOR_GRAY2BGR), cv2.cvtColor(c3, cv2.COLOR_GRAY2BGR)))
result_image = np.vstack((top_row, bottom_row))

cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow('image', result_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

色空間は4種類ほど指定できるようにしてありますが、ひとまずはXYZで確認してみることにします。

こちらを実行すると、オリジナル画像とCIE XYZ色空間を確認することができます。
右上がX空間、左下がY空間、右下がZ空間を表します。

人間はかつてより、視覚で確認できる空間を数値で表すためにさまざまな方法を編み出してきました。CIE XYZはデバイスに依存しない色空間として長く愛用されてきた方法です。

他にも「COLOR_SPACES = 'XYZ'」の値を変えることで、CIE Lab色空間、YCrCb色空間、HSV(HSB)色空間を確認することができます。

CIE XYZ色空間
人間の視覚特性に基づく基本的な色空間。デバイスに依存しない絶対的な数値での色表現が可能で、異なる色空間間の変換の基準として有名。ディスプレイやプリンタなど、異なるデバイス間での色の一貫性を保つために使われてます。
X: 仮想的な赤色の応答値(人間の目の赤錐体の応答に近似)
Y: 輝度成分(人間が知覚する明るさを表現)
Z: 仮想的な青色の応答値(人間の目の青錐体の応答に近似)

CIE Lab色空間
人間の視覚に近い知覚的な均一性がある空間です。画像の色調補正や色の比較が容易にできて、画像加工アプリで一般的に使用されてます。
L: 明度(Lightness、0=黒〜100=白)
a: 赤-緑の軸(+値=赤、-値=緑)
b: 青-黄の軸(+値=黄、-値=青)

YCrCb色空間
デジタル画像・映像の圧縮に適した色空間です。輝度と色差を分離して表現するため、人間の目が色差よりも輝度に敏感という特性を活かした効率的なデータ圧縮が可能です。JPEGやMPEG等の画像・動画圧縮で広く使用されています。
Y: 輝度成分(明るさ情報)
Cr: 赤の色差成分(赤から輝度を引いた値)
Cb: 青の色差成分(青から輝度を引いた値)

HSV(HSB)色空間
人間が色を認識する方法に近い直感的な色空間です。色相、彩度、明度の3要素で色を表現するため、特定の色の検出や選択が容易です。画像処理やコンピュータビジョンでの物体検出、色選択インターフェースなどで広く使用されています。
H: 色相(Hue、0-360度)色合いを表す
S: 彩度(Saturation、0-100%)色の鮮やかさを表す
V/B: 明度(Value/Brightness、0-255)明るさを表す


3. 画像合成


それでは前述の色空間の調整知識を活かしながら、画像合成を行なってみましょう。画像処理にあたっては、HSV(HSB)色空間を使用していきます。

hsv = cv2.cvtColor(green_image, cv2.COLOR_BGR2HSV)
lower_green = np.array([40, 40, 40])
upper_green = np.array([80, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green)
mask_inv = cv2.bitwise_not(mask)

こちらでは色検出を安定させるため、画像をBGR色空間からHSV色空間に変換しています。さらにグリーンバックの箇所を正しくマスク箇所(削除する部分)として特定するために、緑色の細かな定義を行なっています。

ここで出来上がった'mask'は人物の部分が透過された黒色の画像になっています。これに対してcv2.bitwise_not()を適用すると、緑色だった部分が黒(0)に、人物部分が白(255)に反転します。この反転したマスクmask_invを、人物(前景)の領域を示すマスクとして使用します。

green = cv2.bitwise_and(green_image, green_image, mask=mask_inv)

white_image = np.ones_like(green_image) * 255
green_white_image = cv2.bitwise_or(green, cv2.bitwise_and(white_image, white_image, mask=mask))

bitwise_andでは、先ほど作成したmask_invを使用して、元画像から緑色の背景を綺麗に除去しています。この作業により、人物だけの情報を含んだ画像が抽出されます。

(下2行ですが、目視でマスク処理結果を確認したいので白画像とgreen(人物抽出画像)を合体しています)

scenic = cv2.resize(scenic_image, (green_image.shape[1], green_image.shape[0]))
background = cv2.bitwise_and(scenic, scenic, mask=mask)
scenic = cv2.add(background, green)

こちらでは、風景と人物の画像合成を行なっています。風景画像をグリーンバック画像と同じサイズにリサイズし、スケールの統一を行ったのちに、先ほど作ったmaskを使って風景画像から人物部分を切り取り背景画像を作成。最後に人物だけの画像と背景画像を組み合わせることで合成画像を作成してます。

それでは以下のコードを使って完成品を確認してみましょう。

top_row = np.hstack((green_image, green_white_image))
bottom_row = np.hstack((cv2.resize(scenic_image, (green_image.shape[1], green_image.shape[0])), scenic))
result_image = np.vstack((top_row, bottom_row))

cv2.namedWindow('image2', cv2.WINDOW_NORMAL)
cv2.imshow('image2', result_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

左側にはオリジナルの画像を表示し、右上には抽出した人物(プラス白背景)と、右下には合成後の写真を表示しています。

もし布などで緑背景を作っていて、撮影時の影などからうまくマスクが作れない場合はlower_greenとupper_greenの値を変えてみましょう。



4. 最後に


非常に簡単な色区間調整と画像合成について解説を行いました。

画像合成のマスクがうまくできない場合は、本来緑色検知範囲を広げるだけでなく、モルフォロジー演算で穴埋めやノイズ除去を行ったり、色空間を変えてみたり、エッジ検出をする必要があります。

現状、影の処理に対する対応をほとんど行っておりません。ネットに転がっている適当なグリーン布を使った画像を使用すると、人物の周りに暗い緑のブレアがかかってしまう可能性が非常に高いです。

こういう細かい調整方針を思いつくためにも、本来、画像処理を行う人々には座学としてカメラ構造等基礎的なコンピュータービジョンの理解が欠かせません。そしてこのような細かい画像処理の果てに、画像分析として適当なデータを作成することができます。

次回は物体検出についてもう少し切り込んでお話をしていきたいと思います。

最後まで読んでいただき、ありがとうございました。

Yuki


いいなと思ったら応援しよう!