OpenCVのmorphologyEx関数を使った画像のモーフォロジー変換

概要

この記事ではOpenCVのモーフォロジー変換(morphologyEx)関数について紹介していきます。OpenCVのmorphologyEx関数は、画像のモーフォロジー変換(形状に基づく画像処理)を行うためのツールで、画像のノイズ除去、小さな穴の埋め込み、線の連結、細かい部分の除去など、画像の前処理や後処理に広く使用され、収縮、膨張、オープニング(収縮後の膨張)、クロージング(膨張後の収縮)といった処理を実行できます。これらの処理は、特にバイナリ画像(白と黒の二値で表現された画像)の処理に有用で、物体の形状分析やテキスト認識などの前処理として活用されています。

出力結果

noise.jpg 出力画像

プログラム全体

#解説1 # 必要なライブラリをインポート import cv2 import numpy as np from matplotlib import pyplot as plt #解説2 # ローカルの画像ファイルを読み込む img = cv2.imread('noise.jpg', 0) img=255-img # 二値化を適用 ret, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) #解説3 # 構造要素は、モーフォロジー変換に使用されるカーネルで、ここでは5x5の正方形を使用します。 kernel = np.ones((5,5),np.uint8) # 収縮、膨張、オープニング(収縮後の膨張)、クロージング(膨張後の収縮)を適用します。 erosion = cv2.erode(thresh,kernel,iterations = 1) dilation = cv2.dilate(thresh,kernel,iterations = 1) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel) closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) #解説4 # 結果を表示 titles = ['2値画像','収縮','膨張','オープニング','クロージング'] images = [thresh, erosion, dilation, opening, closing] for i in range(5): plt.subplot(2,3,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()

解説

解説1: ライブラリのインポート

# 必要なライブラリをインポート import cv2 import numpy as np from matplotlib import pyplot as plt

この部分では、プログラムで必要となるライブラリをインポートしています。ライブラリは、特定の機能を提供するコードの集合で、これにより画像処理や数値計算、グラフ描画などの複雑な操作を簡単に行うことができます。今回使用しているライブラリはOpenCVとnumpyというライブラリを使用しており、この2つは同時に使われることが非常に多いです。また、データの視覚化のためにmatplotlibというライブラリも使用しています。

cv2 OpenCV(Open Source Computer Vision Library)のPythonバージョンで、画像処理やコンピュータビジョンのタスクを行うための関数を提供します。
numpy 数値計算を効率的に行うためのライブラリで、特に大量のデータを扱う際に有用です。
matplotlib.pyplot データの視覚化(グラフ描画)を行うためのライブラリです。

解説2: 画像の読み込みと二値化

# ローカルの画像ファイルを読み込む img = cv2.imread('noise.jpg', 0) img=255-img # 二値化を適用 ret, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

この部分では、画像ファイルを読み込み、threshold関数を使用して二値化(画像のすべてのピクセルを2種の色に分類)を適用しています。

cv2.imread('noise.jpg', 0) ここで、cv2.imread関数を使用して画像ファイルを読み込んでいます。第二引数の0は、画像をグレースケール(白黒)で読み込むことを指定しています。
cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) ここで、cv2.threshold関数を使用して画像を二値化しています。二値化とは、画像のピクセル値を特定の閾値で分けて、白と黒の二つの値に変換する処理です。この処理により、画像の解析が容易になります。

解説3: モーフォロジー変換の適用

# 構造要素は、モーフォロジー変換に使用されるカーネルで、ここでは5x5の正方形を使用します。 kernel = np.ones((5,5),np.uint8) # 収縮、膨張、オープニング(収縮後の膨張)、クロージング(膨張後の収縮)を適用します。 erosion = cv2.erode(thresh,kernel,iterations = 1) dilation = cv2.dilate(thresh,kernel,iterations = 1) opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel) closing = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

この部分では、モーフォロジー変換(形状に基づく画像処理)を適用しています。

kernel = np.ones((5,5),np.uint8) モーフォロジー変換に使用するカーネル(構造要素)を定義しています。ここでは5x5の正方形を使用しています。
cv2.erode
cv2.dilate
cv2.morphologyEx
これらの関数を使用して、収縮、膨張、オープニング(収縮後の膨張)、クロージング(膨張後の収縮)というモーフォロジー変換を適用しています。これらの変換は、画像のノイズ除去や形状の強調などに使用されます。

補足:モーフォロジー演算の種類について

収縮 cv2.erodeで適用される演算です。出力ピクセル値は、近傍の中ですべてのピクセルの "最小" 値となります。バイナリイメージの場合、近傍のピクセルの中に値 0 のものが存在すると、ピクセルは 0 になります。モーフォロジー収縮により、浮遊しているようなピクセルや細いラインがなくなり、実質的なオブジェクトだけが残ります。残っているラインは細く見えるようになり、形状は小さく見えるようになります。
膨張 cv2.dilateで適用される演算です。出力ピクセル値は、近傍の中ですべてのピクセルの "最大" 値となります。バイナリイメージの場合、近傍のピクセルの中に値 1 のものが存在すると、ピクセルは 1 になります。膨張処理によりオブジェクトの可視性が増し、オブジェクト内の小さな穴が埋まります。ラインは太く見えるようになり、塗りつぶされた形状は大きく見えるようになります。
オープニング cv2.morphologyEx(,cv2.MORPH_OPEN,)で適用される演算です。オープニングは、画像の各ピクセルに対してその周囲のピクセルとの関係を考慮して処理を行います。その際、どの程度の範囲を周囲と見なすか、またその形状は何かをkernelで定義しています。kernel = np.ones((5,5),np.uint8)と定義しているので、画像の各ピクセルに対してその周囲5x5ピクセルの範囲を考慮した処理が行われます。kernelの大きさを大きくすると大きなノイズを除去できますが、細かい情報が失われる可能性があります。逆にkernelの大きさを小さくすると細かい情報は保持できますが、大きなノイズを除去できなくなります。
クロージング cv2.morphologyEx(,cv2.MORPH_CLOSE,)で適用される演算です。クロージングは、まず画像の白い部分を大きくし(膨張)、その後に白い部分を元の大きさに戻す(収縮)ことをしています。クロージングによって、白い部分の小さな黒い穴を白くすることができます。オープニングと同様にkernelによってクロージングの適用範囲を指定することができます。

解説4: 結果の表示

# 結果を表示 titles = ['元の画像','収縮','膨張','オープニング','クロージング'] images = [thresh, erosion, dilation, opening, closing] for i in range(5): plt.subplot(2,3,i+1),plt.imshow(images[i],'gray') plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()

この部分では、元の画像と各モーフォロジー変換の結果を表示しています。

plt.subplot(2,3,i+1),plt.imshow(images[i],'gray') ここで、plt.subplot関数を使用して複数の画像を同時に表示するレイアウトを定義し、plt.imshow関数を使用して画像を表示しています。
plt.title(titles[i]) ここで、plt.title関数を使用して各画像のタイトルを設定しています。
plt.xticks([]),plt.yticks([]) これらの関数を使用して、x軸とy軸の目盛りを非表示にしています。これにより、画像だけに焦点を当てることができます。
plt.show() これにより、定義したすべてのプロットを表示します。

おまけ

テキスト認識では、まずテキストが含まれる領域を正確に検出することが重要です。しかし、画像にはノイズが含まれていることが多く、これがテキストの領域検出を難しくしてしまいます。モーフォロジー変換のは、これらの小さなノイズを効果的に除去することができます。TheImagingSource社のカメラは、照明やカメラのパラメータ調整をすることで、画像を取得する際にノイズ成分をできるだけ抑えて綺麗な画像を取得できます。これは、モーフォロジー変換を行う前の前処理として非常に有用です。ノイズが少ない画像を用いることで、モーフォロジー変換の効果を最大限に引き出すことができ、結果としてテキスト認識の精度をさらに向上させることができます。
https://www.argocorp.com/cam/usb3/tis/DFK_DMK.html