こんにちは、のっくん(@yamagablog)です。
今日は画像処理の1つであるセグメンテーションについて学習していきたいと思います。
皆さんは、セグメンテーションをご存知でしょうか。これは映った物体や文字と背景を分離させる処理です。
背景の暗さや明るさによって物体や文字を切り出すのが難しいですが、Pythonのライブラリであるskimageでは色んなライブラリが用意されているので数行のコードで試せます。
それではみていきましょう。
目次
セグメンテーションの種類
コードを書く前に、セグメンテーションの種類を整理しておきたいと思います。
- supervised segmentation(教師ありセグメンテーション)
これは事前知識、つまりユーザによるデータ入力が必要です。
人のデータ入力が必要なスレッショルド法やアクティブカウンター法などがあります。
例えば、スレッショルド法だと閾値をユーザが指定して処理を行います。
- unsupervised segmentation(教師なしセグメンテーション)
こちらは事前知識が必要、つまりユーザによるデータ入力が必要ないです。
何かデータを与えれば勝手に分離してくれるので便利ですね。
人のデータ入力が必要ないスレッショルド法やSlic法があります。
使用するデータ
skimageに付属しているデータを使います。
def image_show(image, nrows=1, ncols=1, cmap='gray'): fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(14, 14)) ax.imshow(image, cmap='gray') ax.axis('off') return fig, ax text = data.page() image_show(text)

左の方が影になっていて、右のほうが明るくなっています。
ヒストグラムをみてみます。
fig, ax = plt.subplots(1, 1) ax.hist(text.ravel(), bins=32, range=[0, 256]) ax.set_xlim(0, 256);

グレースケール画像は8bitなので、横幅であるx軸が0-255の範囲になっています。0が黒、255が白です。
右側の明るい(白っぽい)背景のエリアが多いので、その部分だけ数が多くなっています。
教師ありセグメンテーション
スレッショルド値を決めて、分離する教師ありセグメンテーションをやってみます。
スレッショルド値は50に設定してみます。
text_segmented = text > (50) image_show(text_segmented);

ちょっと文字が薄くて読めませんね。
次に値を120にしてみます。
text_segmented = text > (120) image_show(text_segmented);

文字は読めるようになりましたが、左のほうに影が映ってしまいました。
値が小さいと文字がかすれてしまい、逆に値が大きいと影が入ってしまいます。
さじ加減が難しいですね。
値の調整が面倒なのも教師ありセグメンテーションの特徴です。
教師なしセグメンテーション
教師ありセグメンテーションの種類はたくさんあって、li、otsu、local、isodataなどがあります。
試しに、liのセグメンテーションを使ってみます。
text_threshold = filters.threshold_li(text) image_show(text > text_threshold);

左側の影が映ってしまっていて、うまく分離できていないですね。
次にlocalを使ってみます。localを使った教師ありセグメンテーションでは、ブロックサイズとoffsetを指定します。
(パラメータについて詳しく知りたい方はこちらを参照ください。)
text_threshold = filters.threshold_local(text,block_size=51, offset=10) image_show(text > text_threshold);

良い感じに文字を分離することができました!
おわり。
参考
Medium:
https://towardsdatascience.com/image-segmentation-using-pythons-scikit-image-module-533a61ecc980
scikit-image:
https://scikit-image.org/docs/dev/api/skimage.filters.html#skimage.filters.threshold_li