からあげ博士の日常と研究と

博士課程を満期退学した人が好きなことを好きなままに書くところ。

pythonとOpenCVで画像解析――画像を読み込もう

 こんにちは。からあげ博士です。「日常と研究と」と謳っているブログなのだから多少は研究に関わることも書いたほうがいいでしょう。とはいえがっつり研究のことを書く訳にもいかない、ということで今回は研究で使っている技術的な部分について書いていこうかと思います。

 なんとなく流行りに合わせてとりあえずはpythonとOpenCVというテーマで書いていこうかなと思います。本記事シリーズはpython 3.7.6とOpenCV 4.2.0を使って書かれています。

 この画像解析でどんなことを扱っていくかといえば、画像を使った定量化、みたいなものを扱えればいいのかなと思っています。と言っても結構単純なことしかしていないのですが。あとこのコードの書き方はあくまで自己流です。一冊ちゃんとした本を学ぶべきなんでしょうが、独学で身に着けてしまった癖みたいなものがどうしても抜けません。困ったものですね。なので「汚い」「もっとこんな書き方しろ」ということがあればどうぞコメントへ。勉強させていただきます。

 python環境が用意されていて、OpenCVがインストールされていることを前提にお話しします。自分の環境はAnaconda 3を用いていますが、Anaconda 3にOpenCVが入っていないんですよね。しかも conda installではインストールできないという罠まで。パッケージ管理が面倒だ!とAnaconda否定派が存在するのも分かる気がします。確かに自分もpip installで導入した。

まずは画像を読み込むところまで

import os
import cv2

base = "D://test_image/"
img_list = os.listdir(base)

file_name = base + img_list[0]

img = cv2.imread(file_name)

 ここではosとcv2をインポートしています。osはosモジュール。cv2は今回使うOpenCVライブラリですね。なんでosをインポートしているかと言われると、癖と言われればそれまでなのですが、画像解析において1枚の画像のみを解析するという例は少ないと思われます。今回のように解析対象が入ったフォルダについて、ファイル名のリストを取得しておくことでforループに対応できるかなあと。あと単純にファイル名を直打ちするのがめんどくさいということも。

 今回画像はDドライブの "test_image"というフォルダに格納してあります。os.listdirで格納フォルダ内のファイルネームをすべて取得できます。

 今回はまずはお試しの1枚ということでimg_listに格納されたファイル名のうち1つを読み込むことにします。pythonはキーが0始まりということで、Rとの違いでR信者から嫌われているポイントでもありますね。cv2.imread()は画像をフルパスで指定してあげる必要があるので、file_name = base + img_list[0]としてfile_nameに格納してあげることにします。なんとなくそのほうが見やすいから。

 ちなみにcv2.imread()の引数はいくつかあります。

img = cv2.imread(file_name, cv2.IMREAD_UNCHANGED)

img = cv2.imread(file_name, cv2.IMREAD_GRAYSCALE)

img = cv2.imread(file_name, cv2.IMREAD_COLOR) ##デフォルト

 それぞれが何を指定しているのか、ですが一番上のcv2.IMREAD_UNCHANGEDは分かりやすいのではないかと。端的になにもせずに画像を読み込むということです。アルファチャンネルを持つ画像であれば、それを含めて読み込むということになります。基本的に画像はRGBの画素値が記録されていてそれが読み込まれる訳ですが、アルファチャンネルはそれ以外の画素値がRGB以外にも記録されているということになります。画像は3次元配列ですが、アルファチャンネルが含まれることで4次元配列として読み込まれます。アルファチャンネルを持つ画像を読み込んだ場合imgには4次元配列が、そうでない場合は通常のBGR画像として3次元配列が代入されることになります。

 cv2.IMREAD_GRAYSCALEもまた分かりやすいですね。画像をグレースケールに変換して読み込みます。すなわちimgに代入される配列は2次元になります。

 cv2.IMREAD_COLORこれがデフォルトですが、なにをしてくれるのかというと、アルファチャンネルを持つ画像であってもそれを無視してBGRで読み込みますよ、ということになります。読み込まれた画像が、何次元のnumpy.arrayとして入力されたかは、img.shapeで確認することができますね。

 ここでさりげなくBGRで読み込まれるよと記載していますが、OpenCVを使う上での注意になります。画像は通常RGBの画素値で保存されると説明しましたが、OpenCVではBGRの順に読み込まれます。これに気を付けなければRの画素について操作しているつもりがBの画素を操作している、といったことになるので忘れずにということです。もちろん後から変換することができます。

BGR配列をRGB配列に変える

 もし読み込んだ画像の画素を操作する上でBGR配列のまま操作するということがミスを誘発したり、ちょっと直感的ではないな、ということであればもちろん変換することができます。これにはcv2.cvtColorという関数を使うことになります。

img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) ## 入力はBGRとする

img_HSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) ## 入力はBGRとする

img_gray = cv2.cvt.Color(img, cv2.COLOR_BGR2GRAY) ## 入力はBGRとする

img_R = img_RGB[:, ;, 0] ## Rの画素値のみ取得

 このように、BGR→RGBの変換だけではなく、HSVやグレースケールへの変換も可能です。cv2.cvtColorの使い方としては、cv2.cvtColor(入力画像, 引数)となります。引数部分は、cv2.COLOR_BGR2RGBのように、元の配列からどの配列に変換したいか、ということを入力してあげればよいことになっています。

 個人的には、BGR→RGBでこの機能を使うことはほとんどなく、HSVへの変換や、Labへの変換によく使う機能になっています。

まとめ

 今回は画像を読み込むところ、その画像のRGBやグレースケールへの変換方法について書きました。主にcv2.imreadの使い方と、cv2.cvtColorの使い方になります。こんなんで画像解析かと言われるとかなり微妙ですね。この画像をどのように扱っていくかを知りたいんじゃ、ということになっていくかと思います。  

 次に扱うこととしては、画像の二値化といったことを扱っていければと思っているので、期待せずに待っていただければと思います。