電気回路技術者からITエンジニアを目指す!

子持ちのアラフォー回路屋さんがITエンジニアを目指します

画像処理と統計処理の勉強に、硬貨の選別プログラムを組んで見る その2 グレイスケール値で背景部分を排除してみる

日本の硬貨、コインを画像処理で識別するチャレンジを進めていこうと思います。

今回は、コイン部分を抜き出す方法について考えてみます。

 

前回記事は以下を参照。 

www.galleon.blue

 

環境は

  • python 3.6.1
  • opencv 3.4.1+contrib

です。

 

使用する画像

ぐちゃっとコインが置いてある状況だと、データがぐちゃぐちゃして分析しづらそうだったので、処理の検討用に、きれいに並んでいる写真を撮りました。

f:id:galleon_blue:20180506103019p:plain

最終的には、グチャッとした画像でも処理できることを目指します。

 

 

とりあえず、画像を読み込んで表示

必要なモジュールをインポートしてー

f:id:galleon_blue:20180506132535p:plain

 

画像ファイルを読み込んで表示

f:id:galleon_blue:20180506132630p:plain

In[2]で読みこんで、In[3]で表示してます。

 

In[3]の1行目では、OpenCVのcvtColor関数を使って、BGRからRGBへの色変換をしてます。

OpenCVが画像ファイルを読み込んだときは、BGRの順番で画像を読み込むのに対して、matplotlib.pyplotのimshowでは、データがRGBの順番であることを前提として表示をするみたい。

だから、この一行が無いと、変な色で表示されます。

 

グレイスケール値でコイン部分を抜き出せるか

色の分析

さて、次に、コイン部分を抜き出す、ということをやってみます。

まずは、背景の白色を検出して、それ以外の部分をコインとする、という方法で抜き出してみます。

f:id:galleon_blue:20180506133055p:plain

1行目で、BGR形式の画像データを、グレイスケールの画像に変換しています。

つまり、ピクセルごとの明るさを、0~255の値に変換しています。

 

2行目では変換した画像を表示、3行目でカラーバーを表示してます。

 

するとこんな感じの出力に。

元の画像で白かった部分(背景の紙)は、黄色っぽく、暗かった部分は青っぽくなっています。

この、黄色い部分を消せば、硬貨部分だけが取り出せることになります。

f:id:galleon_blue:20180506104015p:plain

右下部分、撮影時に手か何かの影になった部分が低めになっているのがちょっと気になりますが・・・。

 

 画像を見ても、どういう数値が入っているのかよくわからず、処理が組めません。

様子を見るために、グレイスケールの輝度の分布をヒストグラムにして表示してみます。

f:id:galleon_blue:20180506134105p:plain

img_gray.flatten() というのは、二次元のアレイになっている画像データ(img_gray)を、一次元の細長い数値のアレイに変換する(flatten())、ということです。

plt.hist()で、グレイスケールの画像データを、1つのデータとして扱うために、このようにしています。

得られたヒストグラムは以下です。

ちょっと粗くてよくわからない、ので、ヒストグラムの段階を細かくとってみます。

f:id:galleon_blue:20180506135745p:plain

つまり、以下のようにします。

bins以下を追加しています。

binsというのが、ヒストグラムの段階を指定する変数です。

今回は、0~255まで8刻みでヒストグラムの段階を指定する、という設定になっています。

普通にリストで値を与えてもいいです。

f:id:galleon_blue:20180506135904p:plain

すると、こんなヒストグラムが得られます。

f:id:galleon_blue:20180506140126p:plain

200前後より上が背景の白部分で、それより下が硬貨部分、なのかな。

 

グレイスケール値で二値化してみる

さて、背景を完全に排除したいので、200よりちょっと下の180を閾値として、二値化してみます。

以下のコードを使って・・

f:id:galleon_blue:20180506140507p:plain

cv2.thresholdというのが、二値化につかう関数です。

入力画像、閾値、二値化後の値、二値化の方法の順番で変数が入っています。

二値化の方法でcv2.THRESH_BINARY_INVとあるのは、今回、グレイスケール画像中で値が低い方の部分(硬貨部分)を255に、背景を0にする二値化を行うためです。

INVつまり、inverseで、逆の二値化を行う、くらいの意味になっています。

 

さて、二値化の結果は以下の通りになりました。

f:id:galleon_blue:20180506140827p:plain

やはり、右下の影の部分がちょっと入り込んでますねー。

それ以外はまあまあ良いのではないでしょうか。硬貨の形状はうまく取れています。

 

閾値を下げると、この影は消えそうですが・・・

消えるところまで(閾値150)下げると、こうなります。

f:id:galleon_blue:20180506141301p:plain

影は消えるけれども、硬貨部分も結構消えています。

輪郭は取れるから、使えなくはなさそうだけれども・・・。

 

まとめ

グレイスケールだと、影の映り込みとかでうまく硬貨部分を抽出できないみたいです。

もしかしたら、背景が白でなく、黒い紙だったら、うまくいくのかもですが・・・。

 

次回、グレイスケール以外の方法も試してみます。

 

 

詳解 OpenCV 3 ―コンピュータビジョンライブラリを使った画像処理・認識

詳解 OpenCV 3 ―コンピュータビジョンライブラリを使った画像処理・認識

  • 作者: Gary Bradski,Adrian Kaehler,松田晃一,小沼千絵,永田雅人,花形理
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2018/05/26
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る