画像データの基本
RGBデータについて
発色はどのようになされているのでしょうか。通常、デジタル機器(ディスプレイ、デジタルカメラ等)においては、赤(R)、緑(G)、青(B)の三色の強さを調整し、あらゆる色を表現しています。
この強さを0~255の256階層(=2の8乗)で表される。
また、RGBのまとまりを1ピクセルという。OpenCVでは、1ピクセルで表すことができる色素数をチャンネル数という。RGBカラーはチャンネル数が3、モノクロ画像はチャンネル数が1となる。
画像フォーマット
画像フォーマットには色々と種類があるので、下記にまとめます。
タイトル | PNG | JPG(JPEG) | GIF | BMP |
特徴 | ・多色で表現 ・可逆圧縮 | ・多色で表現 ・非可逆&高圧縮 | ・色は少ない ・アニメーション可 | ・無圧縮で重い ・Windows標準 |
400×400 写真サイズ | 178KB | 23.6KB | 55.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近傍フィルタを使用する事が多いようだ。