前回の続きをやっていきます。
チュートリアルのタイトルは「画像の平滑化」で、内容としては画像にフィルタをかけて平滑化する、というものになります。
画像の平滑化 — OpenCV-Python Tutorials 1 documentation
ターゲット画像
前回と同じ画像を使います。
>>> img1 = cv2.imread('harupan_200317_1.jpg') >>> v, h = img1.shape[:2] >>> size = (int(h/10), int(v/10)) >>> img1 = cv2.resize(img1, size, interpolation=cv2.INTER_AREA)
これに色々処理をかけてみたいと思います。
filter2D()
を使う
まずはfilter2D()
関数を使っての平均化フィルタ処理。
filter2D()
関数自体は任意のカーネルと画像の畳み込みを計算してくれるので、汎用性が高そうです。
ここでは、5x5の領域での平均化フィルタをかけています。
チュートリアルを見ると、matplotlibのsubplotを使って複数画像の表示をしていたので、これを使ってみます。
ただし、OpenCVではカラー画像をBGRフォーマット(チャネル0が青、チャネル1が緑、チャネル2が赤)で扱いますが、matplotlibではRGB(青と赤が逆)になっているので、あらかじめ変換しておきます。cvtColor()
を使います。
>>> img1_rgb = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB) >>> import numpy as np >>> kernel = np.ones((5,5), np.float32)/25 >>> img1_filterD = cv2.filter2D(img1_rgb, -1, kernel) >>> >>> from matplotlib import pyplot as plt >>> plt.subplot(121), plt.imshow(img1_rgb), plt.title('original'), plt.xticks([]), plt.yticks([]) (<AxesSubplot:title={'center':'original'}>, <matplotlib.image.AxesImage object at 0x000001762E327AC8>, Text(0.5, 1.0, 'original'), ([], []), ([], [])) >>> plt.subplot(122), plt.imshow(img1_filter2D), plt.title('filter2D'), plt.xticks([]), plt.yticks([]) (<AxesSubplot:title={'center':'filter2D'}>, <matplotlib.image.AxesImage object at 0x000001762BD7EDC8>, Text(0.5, 1.0, 'filter2D'), ([], []), ([], [])) >>> plt.show()
しっかりぼけました。
subplot()
の詳細は以下を参考にさせてもらいました。
subplot | Python で一枚のプロットに複数グラフを描く方法
subplot()
の引数は、左の桁から順に分割行数、分割列数、アクティベートするサブ領域番号となるようです。
カンマで区切っても、3桁の数値として入れてもいいよう。
あとは軸目盛は表示したくないので、xticks()
, yticks()
で消しておきます。
blur()
で平均処理
filter2D()
でやったのと同じことを、blur()
を使ってやります。
>>> img1_blur = cv2.blur(img1_rgb, (5,5))
同じような画像になっています。
ガウシアンフィルタ
上記と同じカーネルサイズのガウシアンフィルタをかけてみます。
>>> img1_GaussianBlur = cv2.GaussianBlur(img1_rgb, (5,5), 0)
ガウシアンフィルタだとカーネルの中央により重みがあるので、ぼけ具合が少し小さくなっています。
バイラテラルフィルタ
エッジを保存しつつノイズを除去するのに適したフィルタとのこと。
python+OpenCVでエッジを保存した平滑化(BilateralFilter, NLMeansFilter) - Qiita
>>> img1_bilateral = cv2.bilateralFilter(img1_rgb, 9, 75, 75)
フローリングの細かい模様はなめらかになっていますが、シールの境界、台紙の境界等ははっきりしたままです。
すごいですね。
bilateralFilter()
の引数がいくつかありますが、また必要になったら調べようかな。
ここまで
ほぼチュートリアル通りの内容を、自分の画像でやってみただけになりました。
シール点数集計には直接役に立たないかもしれません。
filter2D()
は汎用性がありそうなので使えるかな?