【アイデミー学習録】データクレンジング (3) 画像データ前処理やOpenCV

NO IMAGE

画像データの基本

RGBデータについて

発色はどのようになされているのでしょうか。通常、デジタル機器(ディスプレイ、デジタルカメラ等)においては、赤(R)、緑(G)、青(B)の三色の強さを調整し、あらゆる色を表現しています。

この強さを0~255の256階層(=2の8乗)で表される。

また、RGBのまとまりを1ピクセルという。OpenCVでは、1ピクセルで表すことができる色素数をチャンネル数という。RGBカラーはチャンネル数が3、モノクロ画像はチャンネル数が1となる。

画像フォーマット

画像フォーマットには色々と種類があるので、下記にまとめます。

タイトルPNGJPG(JPEG)GIFBMP
特徴・多色で表現
・可逆圧縮
・多色で表現
・非可逆&高圧縮
・色は少ない
・アニメーション可
・無圧縮で重い
・Windows標準
400×400
写真サイズ
178KB23.6KB55.8KB(劣化)468KB
透過処理
サポート
一部可

OpenCVの基本

OpenCVとは、画像を扱うためのライブラリとなります。

cv2.imread()関数で画像を読み込み、cv2.imshow()関数で出力する

OpenCVライブラリのcv2.imread()関数は以下の構造です。

cv2.imread("画像のファイルパス/ファイル名"(, 0))

第2引数はカラー画像の場合は省略グレースケール(白黒)は0となる。

出力のcv2.imshow()は以下の構造です。

cv2.imshow("ウィンドウ名", 読み込んだ画像データ)

np.array()関数で画像を作成・保存

cv2で画像処理する際は、RGBの順ではなくBGRの順であることに注意(要は、短波長〜長波長、の順に並ぶ)。

画像生成のレシピとしては、

  • NumPyの行列を作成するnp.array関数を利用
  • for文とrange()関数を組み合わせた多重ループで色情報を並べる
  • 1つ目のfor文で横に512ピクセル、2つ目のfor文で縦に512ピクセルの色を指定
  • ループには「for _ in range」を使用。_は変数名を明示しない場合に使用
  • B, G, Rはリスト型 → [B, G, R]として作成
  • データ型は符号なし8bit整数型(uint8)

まとめると、以下のようなプログラム構造となる。

np.array([[[B, G, R] for _ in range(横の画像ピクセル数)] for _ in range(縦の画像ピクセル数)], dtype = "uint8")

ここまでの内容について、プログラム例を作成してみます。

img[y始点: y終点, x始点: x終点]でトリミング/cv2.resize()関数でリサイズ

画像の左上が原点(0, 0)としたときの、画像のトリミングは以下となります。

img[y始点: y終点, x始点: x終点]

また、画像のサイズ変更はcv2.resize()関数を用いて以下の構造となります。

cv2.resize(画像データ, (幅, 高さ))

トリミング取りサイズの使い方は以下の通り。

cv2.warpAffine()関数で、画像を回転・反転させる

アフィン変換と呼ばれる幾何学変換を実施する関数として、cv2.warpAffine()関数が用意されている。

アフィン変換とは、平行移動、線形変換(拡大・縮小、剪断(Skew)、回転)を行う処理のこと。

関数の構造は以下となります。

cv2.warpAffine(第一引数, 第二引数, 第三引数)
とりぞー
とりぞー

その”引数”とはなんぞよ

第一引数 〜 第三引数 は以下のとおりです。

  • 第一引数:回転する元画像のデータ(NumPy配列のndarrayデータ型)
  • 第二引数:変換行列(NumPy配列のndarrayデータ型)
  • 第三引数:出力画像サイズ(タプル =つまりデータの組)

第二引数の変換行列はcv2.getRotationMatrix2D()関数で取得。構造は以下のとおり。

cv2.getRotationMatrix2D(画像の中心座標, 回転させる角度, 拡大倍率)
  • 画像の中心座標:座標(タプル)
  • 回転させる角度:数値(°)
  • 拡大倍率:数値

プログラムの例は以下。

cv2.flip()関数で楽に画像反転

cv2.warpAffine()関数を用いたアフィン変換では、変換行列を作成するなど、手間ひまがかかる操作をしなければならなかった。しかし反転であれば、cv2.flip()関数で楽に操作が可能。

cv2.flip()関数の構造は以下となります。

cv.flip(画像, flipCode)

flipCodeは聞き慣れないが、以下の要領である。

  • X軸を中心とした反転(つまり上下が反転):flipCode = 0
  • y軸を中心とした左右が反転::flipCode > 0
  • y軸を中心とした上下左右が反転:flipCode < 0

cv2.cvtColor()関数で色調変換・反転

cv2.cvtColor()関数を使うことで、画像を別の色空間を変換が可能、らしい。

とりぞー
とりぞー

い、異空間に飛ばされるの?

まぁ、線形代数の世界では別空間への変換、というのは存じております・・・。

発色の規定はRGB(BGR)以外にも色々な色度座標があるようです。

詳しくは以下のwikipediaを読まれるといいでしょう。

参考>>色空間_wikipedia – 3. 一般的な色空間

関数の構造は以下。

cv2.cvtColor(画像データ, 別の色空間への変換コード) 

変換コードは覚える必要なさそう。全ては、OpenCVの公式サイトに掲載されているので、ググりながら入力しましょう。

反転はcv2.bitwise_not()関数で楽に操作

cv2.flip()関数同様、色についても反転操作は楽に可能。関数の構造は以下のとおり。

cv2.bitwise_not(画像データ)

特に別の色空間への変換が不要かつ反転させるのであれば、cv2.bitwise_not()関数で楽に操作できる。

OpenCVを使ってみる

cv2.threshold()関数で2値化処理

画像処理ではよく2値化が多用される。特定のマークや物体を抜き出すために、しきい値以上に明るい色で白・黒に分離する処理のことを2値化という。

Pythonでの二値化はcv2.threshold()関数を利用します。関数の構造は以下。

cv2.threshold(元画像データ, 閾値とする階調, 階調の最大値, 閾値処理の種類)
とりぞー
とりぞー

ちょっと、ややこしいぞ・・・

まとめると、

  • 元画像データ:2値化処理前の画像
  • 閾値とする階調:2値化する閾値(0~255)
  • 階調の最大値:利用しうる階調の最大値(0~255)
  • 閾値処理の種類:OpenCVの公式ページ参照 (後述します)
閾値処理の種類
cv2.THRESH_BINARY :閾値以下を0、閾値以上を階調最大値に
cv2.THRESH_BINARY_INV:閾値以下を最大値、閾値以上を0に
cv2.THRESH_TRUNC:閾値以下をそのまま、閾値以上を閾値に
cv2.THRESH_TOZERO:閾値以下を0、閾値以上をそのままに
cv2.THRESH_TOZERO_INV:閾値以下はそのまま、閾値以上を0に
cv2.THRESH_OTSU:大津の手法で閾値を自動的に決定

etc…

なお、cv2.threshold()関数の出力は、(閾値, 2値化後の画像データ)となる。プログラミングの一例は以下。

cv2.bitwise_and()関数でマスキングする

元画像に白黒画像でマスクし、白の部分(あるいは黒の部分)と被る部分だけ元画像を表示することをマスキングといいます。関数は以下を利用。

cv2.bitwise_and(元画像1, 元画像2, mask= マスク画像)

元画像1と元画像2は同じ画像でも問題有りません。プログラミング例は以下です。

cv2.GaussianBlur()関数でぼかし処理(平滑化)

カーネルサイズ( n x n )を指定し、カーネルサイズの範囲に含まれるピクセルを平均化させることで、ぼかす処理を平滑化というらしい。関数は以下の構造。

cv2.GaussianBlur(画像データ, カーネルサイズ(n, n), 0)

プログラミンの例を書いてみた。

cv2.fastNlMeansDenoising()関数でノイズ除去

2値化などを行う場合、画像にノイズが乗っていると正確に処理されない場合があります。

そのため、事前のデータクレンジングとして、ノイズ除去を行うことがあるらしい。

ノイズ除去に使われるのは以下の二種類。

カラー画像の場合

cv2.fastNlMeansDenoisingColored(画像データ)

グレースケールの場合

cv2.fastNlMeansDenoising(画像データ)

プログラミングとしては、以下のように扱います。

cv2.dilate()関数による膨張

膨張(や後に出てくる収縮)もノイズ除去に使われる。膨張は、フィルタ内の最大値(白)を中心に重畳処理(要は掛け算)するもの。

cv2.dilate(画像データ, フィルタ)

フィルタは主に二種類あるようだ。以下の4近傍/8近傍のフィルタ。

cv2.erode()関数による収縮

同様にフィルタ内の最小値(黒)を中心に重畳処理したものを収縮というらしい。

cv2.erode(画像データ, フィルタ)

フィルタは先程の4近傍/8近傍フィルタを使用する事が多いようだ。