基本となる画像処理を一から勉強していくシリーズ (3)。
OpenCV-Pythonチュートリアルを参考に、
画像認識本 https://www.amazon.co.jp/dp/4061529129/
でやっている処理の理解を進める方針です。
目次
- 環境
- Sobel、Laplacianフィルタ
- Cannyエッジ検出
- モルフォロジー変換
- 輪郭抽出トライ
1. 環境
Python 3.7.0
OpenCV 4.1.0
Jupyter Notebook
2. Sobel、Laplacianフィルタ
Sobelフィルタは1次微分によるエッジの検出で、注目画素を重要視したもの。
Laplacianフィルタは2次微分によるエッジの検出。
img = cv2.imread('brabra/1.jpg',0)
# Laplacianフィルタ
laplacian = cv2.Laplacian(img,cv2.CV_64F)
# Sobelフィルタx方向
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=15)
# Sobelフィルタy方向
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=15)
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()
Sobelフィルタではx,y方向のエッジに反応している。
3. Cannyエッジ検出
・ガウシアンフィルタにより平滑化後(5x5のカーネル)、
・Sobelフィルタによってx,y方向の1次微分(Gx,Gy)を取得して
√(Gx^2 + Gy^2)のgradientを得る。勾配方向も(Gx,Gy)から得ます。
・次に、その注目画素の勾配方向の両隣の画素と比較し、
注目画素が極大値でなければエッジとしない処理(細線化)を行う。
・次に、minVal,maxValを設定し、minValより小さければ除去、
maxValより大きければ残す、minVal~maxValでは隣がmaxValより大きければ
残す処理を行う。これにより輪郭を繋げることと、誤検出を取り除くそう。
img = cv2.imread('brabra/1.jpg',0)
minVal = 50
maxVal = 250
SobelSize = 10
edges = cv2.Canny(img,minVal,maxVal,SobelSize)
plt.subplot(251),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(252),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
輪郭はうまく繋がってはいないが、形状は認識できている感じ。
4. モルフォロジー変換
モルフォロジー=形態。全体的に太くしたり細くしたりする。
・Erosion(収縮)
・Dilation(膨張)
・Opening(収縮⇒膨張 小さい点のようなノイズ除去)
・Closing(膨張⇒収縮 小さい箇所の穴埋め)
・勾配(膨張-収縮で輪郭を得る)
・トップハット(入力-Opening)
・ブラックハット(入力-Closing)
演習には2値化されたパンダを使用。
img = cv2.imread('brabra/6.jpg',0)
# 大津の2値化されたパンダ
abc,two = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# 白黒反転(白に適用されるため)
two = cv2.bitwise_not(two)
# Erositon
kernel = np.ones((35,35),np.uint8)
erosion = cv2.erode(two,kernel,iterations = 1)
# Dilation
kernel = np.ones((35,35),np.uint8)
dilation = cv2.dilate(two,kernel,iterations = 1)
# Opening
kernel = np.ones((35,35),np.uint8)
opening = cv2.morphologyEx(two, cv2.MORPH_OPEN, kernel)
# Closing
kernel = np.ones((35,35),np.uint8)
closing = cv2.morphologyEx(two, cv2.MORPH_CLOSE, kernel)
# Gradient
kernel = np.ones((35,35),np.uint8)
gradient = cv2.morphologyEx(two, cv2.MORPH_GRADIENT, kernel)
# Tophat
kernel = np.ones((35,35),np.uint8)
tophat = cv2.morphologyEx(two, cv2.MORPH_TOPHAT, kernel)
# Blackhat
kernel = np.ones((35,35),np.uint8)
blackhat = cv2.morphologyEx(two, cv2.MORPH_BLACKHAT, kernel)
plt.subplot(251),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(252),plt.imshow(two,cmap = 'gray')
plt.title('2value Image'), plt.xticks([]), plt.yticks([])
plt.subplot(253),plt.imshow(erosion,cmap = 'gray')
plt.title('Erosion Image'), plt.xticks([]), plt.yticks([])
plt.subplot(254),plt.imshow(dilation,cmap = 'gray')
plt.title('Dilation Image'), plt.xticks([]), plt.yticks([])
plt.subplot(255),plt.imshow(opening,cmap = 'gray')
plt.title('Opening Image'), plt.xticks([]), plt.yticks([])
plt.subplot(256),plt.imshow(closing,cmap = 'gray')
plt.title('Closing Image'), plt.xticks([]), plt.yticks([])
plt.subplot(257),plt.imshow(gradient,cmap = 'gray')
plt.title('Gradient Image'), plt.xticks([]), plt.yticks([])
plt.subplot(258),plt.imshow(tophat,cmap = 'gray')
plt.title('Tophat Image'), plt.xticks([]), plt.yticks([])
plt.subplot(259),plt.imshow(blackhat,cmap = 'gray')
plt.title('Blackhat Image'), plt.xticks([]), plt.yticks([])
plt.show()
5. 輪郭抽出トライ
Cannyでエッジ検出した後、Closingで中空部をくっつけてガイコツの領域を抽出してみた。
img = cv2.imread('brabra/1.jpg',0)
edges = cv2.Canny(img,50,250,10)
# Closing
kernel = np.ones((5,5),np.uint8)
closing = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
kernel = np.ones((35,35),np.uint8)
closing2 = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
kernel = np.ones((135,135),np.uint8)
closing3 = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
plt.subplot(251),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(252),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.subplot(253),plt.imshow(closing,cmap = 'gray')
plt.title('Closing Image'), plt.xticks([]), plt.yticks([])
plt.subplot(254),plt.imshow(closing2,cmap = 'gray')
plt.title('Closing2 Image'), plt.xticks([]), plt.yticks([])
plt.subplot(255),plt.imshow(closing3,cmap = 'gray')
plt.title('Closing3 Image'), plt.xticks([]), plt.yticks([])
plt.show()
まとめ
エッジ検出とモルフォロジー変換について理解を深めた。
参考文献
-
OpenCVを使った画像処理(OpenCV-Pythonチュートリアル)
http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_imgproc/py_table_of_contents_imgproc/py_table_of_contents_imgproc.html#py-table-of-content-imgproc -
画像認識(機械学習プロフェッショナルシリーズ)
https://www.amazon.co.jp/dp/4061529129/ -
Cannyエッジ検出
https://algorithm.joho.info/image-processing/canny-edge-detecter/