๐ ๊ณต๋ถํ๋ ์ง์ง์ํ์นด๋ ์ฒ์์ด์ง?
[v0.21]์์์ฒ๋ฆฌ_๋ชจํด๋ก์ง(Morphology) ์ฐ์ฐ ๋ณธ๋ฌธ
[v0.21]์์์ฒ๋ฆฌ_๋ชจํด๋ก์ง(Morphology) ์ฐ์ฐ
์ง์ง์ํ์นด 2022. 1. 11. 01:35220110 ์์ฑ
<๋ณธ ๋ธ๋ก๊ทธ๋ ๊ทํ์ด ์์ฌ๋์ ๋ธ๋ก๊ทธ๋ฅผ ์ฐธ๊ณ ํด์ ๊ณต๋ถํ๋ฉฐ ์์ฑํ์์ต๋๋ค>
OpenCV - 19. ๋ชจํด๋ก์ง(Morphology) ์ฐ์ฐ (์นจ์, ํฝ์ฐฝ, ์ด๋ฆผ, ๋ซํ, ๊ทธ๋ ๋์ธํธ, ํํ, ๋ธ๋ํ)
์ด๋ฒ ํฌ์คํ ์์๋ ๋ชจํด๋ก์ง๋ผ๋ ๊ฐ๋ ์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฒ ํฌ์คํ ์ญ์ 'ํ์ด์ฌ์ผ๋ก ๋ง๋๋ OpenCV ํ๋ก์ ํธ(์ด์ธ์ฐ ์ )'๋ฅผ ์ ๋ฆฌํ ๊ฒ์์ ๋ฐํ๋๋ค. ์ฝ๋: github.com/BaekKyunShin/OpenCV_Projec
bkshin.tistory.com
๋ชจํด๋ก์ง(morphology)
: 'ํํํ'
: ์์ ๋ถ์ผ์์ ๋ ธ์ด์ฆ ์ ๊ฑฐ, ๊ตฌ๋ฉ ์ฑ์ฐ๊ธฐ, ๋์ด์ง ์ ์ด์ด ๋ถ์ด๊ธฐ ๋ฑ ํํํ์ ์ฐ์ฐ
: ๋ชจํด๋ก์ง ์ฐ์ฐ์ ๊ฒ์์๊ณผ ํฐ์์ผ๋ก๋ง ๊ตฌ์ฑ๋์ด ์๋ ๋ฐ์ด๋๋ฆฌ(binary) ์ด๋ฏธ์ง์ ์ ์ฉ
: ์นจ์, ํฝ์ฐฝ, ์ด๋ฆผ, ๋ซํ
1. ์นจ์ ์ฐ์ฐ (Erode)
: ์ด๋ฏธ์ง๋ฅผ ๊น์ ๋ด๋ ์ฐ์ฐ
: ์์ ๋ฌผ์ฒด๋ ์์ ์์ ๋ฒ๋ฆฌ๋ฏ๋ก ๋ ธ์ด์ฆ ์ ๊ฑฐ ํจ๊ณผ
์๋๋ ๋จ์ด์ ธ ์๋ ๋ฌผ์ฒด์ธ๋ฐ ๊ฒน์ณ ์๋ ๊ฒ์ ์๋ก ๋ผ์ด๋ด๋ ๋ฐ๋ ํจ๊ณผ
: ๊ตฌ์กฐํ ์์ ์ปค๋(structuring element kernel)์ด๋ผ๋ 0๊ณผ 1๋ก ๊ตฌ์ฑ๋ ์ปค๋์ด ํ์
: ๊ตฌ์กฐํ ์์ ์ปค๋์ 1์ด ์ฑ์์ง ๋ชจ์์ ๋ฐ๋ผ ์ฌ๊ฐํ, ํ์ํ, ์ญ์ํ ๋ฑ์ผ๋ก ์ฌ์ฉ
: ์ ๋ ฅ ์ด๋ฏธ์ง์ ์ ์ฉํด์ 1๋ก ์ฑ์์ง ์์ญ์ ์จ์ ํ ์ฌ๋ ค ๋์ ์ ์์ผ๋ฉด
ํด๋น ํฝ์ ์ 0์ผ๋ก ๋ณ๊ฒฝ
- ์ญ์ํ ๊ตฌ์กฐํ ์์ ์ปค๋๋ก ์นจ์ ์ฐ์ฐ์ ํ๋ ๊ณผ์
: A ์ด๋ฏธ์ง์์ ํฐ์ ๋ฐฐ๊ฒฝ์ 0์ด๊ณ , ํ๋์ ์ ๊ฒฝ์ 1
: B๋ ์ญ์ํ ๊ตฌ์กฐํ ์์ ์ปค๋
: ์ญ์ํ ๊ตฌ์กฐํ ์์ ์ปค๋์ ์ค์ฌ๋ถ(๋นจ๊ฐ ์ ๋ถ๋ถ)๋ A ์ด๋ฏธ์ง์ ํ๋์ ๋ถ๋ถ์ ์ญ ํ๋๋ค
: ํ ์นธ ํ ์นธ ํ์ผ๋ฉด์ ๊ตฌ์กฐํ ์์ ์ปค๋์ด A ์ด๋ฏธ์ง์ ํ๋์ ๋ถ๋ถ๊ณผ ์์ ํ ๊ฒน์น์ง ์์ ๋๋ 0์ผ๋ก ๋ณ๊ฒฝ
: ์์ ํ ๊ฒน์น๋ฉด 1๋ก ๊ทธ๋๋ก
cv2.getStructuringElement(shape, ksize, anchor)
: ๊ตฌ์กฐํ ์์ ์ปค๋ ์์ฑ์ ์ํ ํจ์
- shape : ๊ตฌ์กฐํ ์์ ์ปค๋ ๋ชจ์
- cv2.MORPH_RECT : ์ฌ๊ฐํ
- cv2.MORPH_EPLIPSE: ํ์ํ
- cv2.MORPH_CROSS : ์ญ์ํ
- ksize : ์ปค๋ ํฌ๊ธฐ
- anchor(optional) : ๊ตฌ์กฐํ ์์์ ๊ธฐ์ค์ , cv2.MORPH_CROSS์๋ง ์๋ฏธ ์์ผ๋ฉฐ ๊ธฐ๋ณธ ๊ฐ์ ์ค์ฌ์ (-1, -1)
dst = cv2.erode(src, kernel, anchor, iterations, borderType, borderValue)
: ์นจ์ ์ฐ์ฐ์ ์ํํ๋ ํจ์
- src : ์ ๋ ฅ ์์, ๋ฐ์ด๋๋ฆฌ
- kernel : ๊ตฌ์กฐํ ์์ ์ปค๋
- anchor(optional) : cv2.getStructuringElement()์ ๋์ผ
- iterations(optional) : ์นจ์ ์ฐ์ฐ ์ ์ฉ ๋ฐ๋ณต ํ์
- boderType(optional) : ์ธ๊ณฝ ์์ญ ๋ณด์ ๋ฐฉ๋ฒ
- boderValue(optional) : ์ธ๊ณฝ ์์ญ ๋ณด์ ๊ฐ
# ์นจ์ ์ฐ์ฐ (morph_erode.py)
import cv2
import numpy as np
img = cv2.imread('img/morphology.JPG')
# ๊ตฌ์กฐํ ์์ ์ปค๋, ์ฌ๊ฐํ (3x3) ์์ฑ ---โ
k = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
# ์นจ์ ์ฐ์ฐ ์ ์ฉ ---โก
erosion = cv2.erode(img, k)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
merged = np.hstack((img, erosion))
cv2.imshow('Erode', merged)
cv2.waitKey(0)
cv2.destroyAllWindows()
- ๊ฐ๋์ด์ง๋น
=> ์นจ์์ ์ด๋์ด ๋ถ๋ถ์ ๋ ธ์ด์ฆ๋ฅผ ์ ๊ฑฐํ๋ ํจ๊ณผ
2. ํฝ์ฐฝ ์ฐ์ฐ (Dilatation)
: ์นจ์๊ณผ ๋ฐ๋๋ก ๋ฌผ์ฒด์ ์ฃผ๋ณ์ ํ์ฅํ๋ ์ฐ์ฐ
: ์์ ํ ๊ฒน์น์ง ์์ผ๋ฉด 1๋ก ๋ณ๊ฒฝ
dst = cv2.dilate(src, kernel, dst, anchor, iterations, bordeType, borderValue)
: ๋ชจ๋ ํ๋ผ๋ฏธํฐ๋ cv2.erode()์ ๋์ผ
# ํฝ์ฐฝ ์ฐ์ฐ
import cv2
import numpy as np
img = cv2.imread('img/dilate.JPG')
# ๊ตฌ์กฐํ ์์ ์ปค๋, ์ฌ๊ฐํ (3x3) ์์ฑ ---โ
k = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
# ํฝ์ฐฝ ์ฐ์ฐ ์ ์ฉ ---โก
dst = cv2.dilate(img, k)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
merged = np.hstack((img, dst))
cv2.imshow('Dilation', merged)
cv2.waitKey(0)
cv2.destroyAllWindows()
- ๊ฒ์ ๋ ธ์ด์ฆ ์์ด์ง
- ์๋๋ฉด ํฐ์์ด ๋ฐ๊นฅ, ์์ผ๋ก ํฝ์ฐฝ๋์ด ๋ฑ๋ก์ด๊ฐ ๋จ
=> ํฝ์ฐฝ์ ๋ฐ์ ๋ถ๋ถ์ ๋ ธ์ด์ฆ๋ฅผ ์ ๊ฑฐํ๋ ํจ๊ณผ
3. ์ด๋ฆผ, ๋ซํ, ๊ทธ๋ ๋์ธํธ, ํํ, ๋ธ๋ํ ์ฐ์ฐ
1) ์ด๋ฆผ(opening) ์ฐ์ฐ
: ์นจ์ ์ฐ์ฐ ํ ํฝ์ฐฝ ์ฐ์ฐ์ ์ ์ฉํ๋ ๊ฒ
: ์ฃผ๋ณ๋ณด๋ค ๋ฐ์ ๋ ธ์ด์ฆ๋ฅผ ์ ๊ฑฐ
: ๋ ๋ฆฝ๋ ๊ฐ์ฒด๋ฅผ ๋ถ๋ฆฌํ๊ฑฐ๋ ๋์ถ๋ ๋ชจ์์ ์ ๊ฑฐํ๋ ๋ฐ ํจ๊ณผ์
2) ๋ซํ(closing) ์ฐ์ฐ
: ํฝ์ฐฝ ์ฐ์ฐ ํ ์นจ์ ์ฐ์ฐ์ ์ ์ฉํ๋ ๊ฒ
: ์ฃผ๋ณ๋ณด๋ค ์ด๋์ด ๋ ธ์ด์ฆ๋ฅผ ์ ๊ฑฐ
: ํจ๊ณผ์ ์ด๋ฉด์ ๋์ด์ ธ ๋ณด์ด๋ ๊ฐ์ฒด๋ฅผ ์ฐ๊ฒฐํ๊ฑฐ๋ ๊ตฌ๋ฉ์ ๋ฉ์ฐ๋ ๋ฐ ํจ๊ณผ์
3) ๊ทธ๋ ๋์ธํธ(gradient) ์ฐ์ฐ
: ํฝ์ฐฝ ์ฐ์ฐ์ ์ ์ฉํ ์ด๋ฏธ์ง์์ ์นจ์ ์ฐ์ฐ์ ์ ์ฉํ ์ด๋ฏธ์ง๋ฅผ ๋นผ๋ฉด ๊ฒฝ๊ณ ํฝ์ ๋ง ์ป๊ฒ ๋จ
: ๊ทธ๋ ๋์ธํธ = ํฝ์ฐฝ - ์นจ์
4) ํํ(top hat)
: ์๋ณธ์์ ์ด๋ฆผ ์ฐ์ฐ ์ ์ฉ ๊ฒฐ๊ณผ๋ฅผ ๋นผ๋ฉด ๊ฐ์ด ํฌ๊ฒ ํ๋ ๋ฐ์ ์์ญ์ ๊ฐ์กฐ
: ํํ = ์๋ณธ - ์ด๋ฆผ
5) ๋ธ๋ํ(black hat) ์ฐ์ฐ
: ๋ซํ ์ฐ์ฐ ์ ์ฉ ๊ฒฐ๊ณผ์์ ์๋ณธ์ ๋นผ๋ฉด ์ด๋์ด ๋ถ๋ถ์ ๊ฐ์กฐ
: ๋ธ๋ํ = ๋ซํ - ์๋ณธ
dst = cv2.morphologyEx(src, op, kernel, dst, anchor, iteration, borderType, borderValue)
- src : ์
๋ ฅ ์์
- op : ๋ชจํด๋ก์ง ์ฐ์ฐ ์ข
๋ฅ
- cv2.MORPH_OPEN : ์ด๋ฆผ ์ฐ์ฐ
- cv2.MORPH_COLSE : ๋ซํ ์ฐ์ฐ
- cv2.MORPH_GRADIENT : ๊ทธ๋ ๋์ธํธ ์ฐ์ฐ
- cv2.MORPH_TOPHAT : ํํ ์ฐ์ฐ
- cv2.MORPH_BLACKHAT : ๋ธ๋ํ ์ฐ์ฐ
- kernel : ๊ตฌ์กฐํ ์์ ์ปค๋
- dst(optional) : ๊ฒฐ๊ณผ ์์
- anchor(optional) : ์ปค๋์ ๊ธฐ์ค์
- iteration(optional) : ์ฐ์ฐ ๋ฐ๋ณต ํ์
- borderType(optional) : ์ธ๊ณฝ ์์ญ ๋ณด์ ๋ฐฉ๋ฒ
- borderValue(optional) : ์ธ๊ณฝ ์์ญ ๋ณด์ ๊ฐ
# ์ด๋ฆผ๊ณผ ๋ซํ ์ฐ์ฐ์ผ๋ก ๋
ธ์ด์ฆ ์ ๊ฑฐ
import cv2
import numpy as np
img1 = cv2.imread('img/morphology.JPG', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('img/dilate.JPG', cv2.IMREAD_GRAYSCALE)
# ----------img resize---------------------
img1 = cv2.resize(img1, dsize = (288, 234))
# ๊ตฌ์กฐํ ์์ ์ปค๋, ์ฌ๊ฐํ (5x5) ์์ฑ ---โ
k = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
# ์ด๋ฆผ ์ฐ์ฐ ์ ์ฉ ---โก
opening = cv2.morphologyEx(img1, cv2.MORPH_OPEN, k)
# ๋ซํ ์ฐ์ฐ ์ ์ฉ ---โข
closing = cv2.morphologyEx(img2, cv2.MORPH_CLOSE, k)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
merged1 = np.hstack((img1, opening))
merged2 = np.hstack((img2, closing))
merged3 = np.vstack((merged1, merged2))
cv2.imshow('opening, closing', merged3)
cv2.waitKey(0)
cv2.destroyAllWindows()
- ์์ ๊น๋!
+) ํฝ์ฐฝ ์ฐ์ฐ์์ ์นจ์ ์ฐ์ฐ์ ๋บ ๊ทธ๋ ๋์ธํธ ์ฐ์ฐ
# ๋ชจํด๋ก์ง ๊ทธ๋ ์ด์ธํธ
import cv2
import numpy as np
img = cv2.imread('img/heart.JPG')
# ๊ตฌ์กฐํ ์์ ์ปค๋, ์ฌ๊ฐํ (3x3) ์์ฑ ---โ
k = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
# ์ด๋ฆผ ์ฐ์ฐ ์ ์ฉ ---โก
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, k)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
merged = np.hstack((img, gradient))
cv2.imshow('gradient', merged)
cv2.waitKey(0)
cv2.destroyAllWindows()
+) ํํ, ๋ธ๋ํ ์ฐ์ฐ ์ ์ฉ
# ๋ชจํด๋ก์ง ํํ, ๋ธ๋ํ ์ฐ์ฐ
import cv2
import numpy as np
img = cv2.imread('img/moon_gray.jpeg')
# ๊ตฌ์กฐํ ์์ ์ปค๋, ์ฌ๊ฐํ (5x5) ์์ฑ ---โ
k = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
# ํํ ์ฐ์ฐ ์ ์ฉ ---โก
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, k)
# ๋ธ๋ซํ ์ฐ์ฐ ์ ์ฉ ---โข
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, k)
# ๊ฒฐ๊ณผ ์ถ๋ ฅ
merged = np.hstack((img, tophat, blackhat))
cv2.imshow('tophat blackhat', merged)
cv2.waitKey(0)
cv2.destroyAllWindows()
- ํํ์ ๋ญ์ ๋ฐ์ ๋ถ๋ถ ๊ฐ์กฐ
- ๋ธ๋ํ์ ๋ฌ์ ์ด๋์ด ๋ถ๋ถ ๊ฐ์กฐ
์ถ์ต..
๊ทธ๋ฆผ๊ทธ๋ฆฌ๋๋ผ ํผ๋ฌ๋น