문제링크
https://github.com/yoyoyo-yo/Gasyori100knock/tree/master/Question_11_20
Q16. Sobel필터(Sobelフィルタ)
Sobel필터(3x3)를 적용해보자.
Sobel필터도 선 추출하는 필터이며, 아래와 같이 정의되어 있다.
1) 세로 방향
2) 가로 방향
이것은 prewitt 필터의 중심 부분에 가중치를 부여하는 필터이다.
A16. Sobel필터(Sobelフィルタ)의 답안
import cv2
import numpy as np
# Gray scale
def BGR2GRAY(img):
b = img[:, :, 0].copy()
g = img[:, :, 1].copy()
r = img[:, :, 2].copy()
# Gray scale
out = 0.2126 * r + 0.7152 * g + 0.0722 * b
out = out.astype(np.uint8)
return out
# sobel filter
def sobel_filter(img, K_size=3):
if len(img.shape) == 3:
H, W, C = img.shape
else:
img = np.expand_dims(img, axis=-1)
H, W, C = img.shape
# Zero padding
pad = K_size // 2
out = np.zeros((H + pad * 2, W + pad * 2), dtype=np.float)
out[pad: pad + H, pad: pad + W] = gray.copy().astype(np.float)
tmp = out.copy()
out_v = out.copy()
out_h = out.copy()
## Sobel vertical
Kv = [[1., 2., 1.],[0., 0., 0.], [-1., -2., -1.]]
## Sobel horizontal
Kh = [[1., 0., -1.],[2., 0., -2.],[1., 0., -1.]]
# filtering
for y in range(H):
for x in range(W):
out_v[pad + y, pad + x] = np.sum(Kv * (tmp[y: y + K_size, x: x + K_size]))
out_h[pad + y, pad + x] = np.sum(Kh * (tmp[y: y + K_size, x: x + K_size]))
out_v = np.clip(out_v, 0, 255)
out_h = np.clip(out_h, 0, 255)
out_v = out_v[pad: pad + H, pad: pad + W].astype(np.uint8)
out_h = out_h[pad: pad + H, pad: pad + W].astype(np.uint8)
return out_v, out_h
# Read image
img = cv2.imread("imori.jpg").astype(np.float)
# grayscale
gray = BGR2GRAY(img)
# sobel filtering
out_v, out_h = sobel_filter(gray, K_size=3)
# Save result
cv2.imwrite("out_v.jpg", out_v)
cv2.imshow("result", out_v)
cv2.waitKey(0)
cv2.imwrite("out_h.jpg", out_h)
cv2.imshow("result", out_h)
cv2.waitKey(0)
cv2.destroyAllWindows()
15번의 답안에서 커널의 숫자만 바꿨다.
import cv2
import numpy as np
img = cv2.imread("assets/imori.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
kernel_v = np.array([
[1, 0, -1],
[2, 0, -2],
[1, 0, -1]
])
kernel_h = np.array([
[1, 2, 1],
[0, 0, 0],
[-1,-2, -1]
])
out_v = cv2.filter2D(gray, -1, kernel_v)
out_h = cv2.filter2D(gray, -1, kernel_h)
cv2.imwrite("out_v.jpg", out_v)
cv2.imshow("result", out_v)
cv2.waitKey(0)
cv2.imwrite("out_h.jpg", out_h)
cv2.imshow("result", out_h)
cv2.waitKey(0)
cv2.destroyAllWindows()
Q17. Laplacian필터(Laplacianフィルタ、ラプラシアンフィルタ)
Laplacian필터를 적용해보자.
Laplacian필터는 휘도의 2차 미분을 취하는 것으로 선 검출을 하는 필터이다.
디지털 이미지는 분산데이터로 존재하기 때문에,
x방향・y방향의 1차미분은 다음의 식과 같이 정의 되어 있다. (미분 필터와 같다.)
계속해서 2차미분은 다음과 같이 정의되어 있다.
사실 위의 식보다 라플라시안은 x, y의 양쪽의 편미분의 합이 되어, 다음 식으로 정의된다.
이것을 커널로 표현하자면 결국 아래와 같은 행렬이 된다.
A17. Laplacian필터(Laplacianフィルタ、ラプラシアンフィルタ)의 답안
import cv2
import numpy as np
# Gray scale
def BGR2GRAY(img):
b = img[:, :, 0].copy()
g = img[:, :, 1].copy()
r = img[:, :, 2].copy()
# Gray scale
out = 0.2126 * r + 0.7152 * g + 0.0722 * b
out = out.astype(np.uint8)
return out
# laplacian filter
def laplacian_filter(img, K_size=3):
if len(img.shape) == 3:
H, W, C = img.shape
else:
H, W = img.shape
# zero padding
pad = K_size // 2
out = np.zeros((H + pad * 2, W + pad * 2), dtype=np.float)
out[pad: pad + H, pad: pad + W] = gray.copy().astype(np.float)
tmp = out.copy()
# laplacian kernle
K = [[0., 1., 0.],[1., -4., 1.], [0., 1., 0.]]
# filtering
for y in range(H):
for x in range(W):
out[pad + y, pad + x] = np.sum(K * (tmp[y: y + K_size, x: x + K_size]))
out = np.clip(out, 0, 255)
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
return out
# Read image
img = cv2.imread("assets/imori.jpg").astype(np.float)
# grayscale
gray = BGR2GRAY(img)
# prewitt filtering
out = laplacian_filter(gray, K_size=3)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
위의 경우 코드는 파이썬으로 하드 코딩한 것이고 아래는 15, 16번의 커널의 숫자만 변경한 내용이다.
import cv2
import numpy as np
img = cv2.imread("assets/imori.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
kernel= np.array([
[0, 1, 0],
[1, -4, 1],
[0, 1, 0]
])
out = cv2.filter2D(gray, -1, kernel)
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
그리고 마지막으로 OpenCV로 작성한 코드는 아래와 같다.
https://algorithm.joho.info/programming/python/opencv-laplacian-filter-py/
import cv2
import numpy as np
img = cv2.imread("assets/imori.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
out = cv2.Laplacian(img,cv2.CV_32F, ksize=3)
cv2.imwrite("out.jpg",out)
cv2.imshow("result",out)
cv2.waitKey(0)
cv2.destroyAllWindows()
Q18. Emboss필터(Embossフィルタ、エンボスフィルタ)
Emboss필터를 적용해보자.
Emboss필터란 윤곽을 뚜렷히 하는 필터로 다음과 같이 정의되어 있다.
A18. Emboss필터(Embossフィルタ、エンボスフィルタ)의 답안
import cv2
import numpy as np
# Gray scale
def BGR2GRAY(img):
b = img[:, :, 0].copy()
g = img[:, :, 1].copy()
r = img[:, :, 2].copy()
# Gray scale
out = 0.2126 * r + 0.7152 * g + 0.0722 * b
out = out.astype(np.uint8)
return out
# emboss filter
def emboss_filter(img, K_size=3):
H, W, C = img.shape
# zero padding
pad = K_size // 2
out = np.zeros((H + pad * 2, W + pad * 2), dtype=np.float)
out[pad: pad + H, pad: pad + W] = gray.copy().astype(np.float)
tmp = out.copy()
# emboss kernel
K = [[-2., -1., 0.],[-1., 1., 1.], [0., 1., 2.]]
# filtering
for y in range(H):
for x in range(W):
out[pad + y, pad + x] = np.sum(K * (tmp[y: y + K_size, x: x + K_size]))
out = np.clip(out, 0, 255)
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
return out
# Read image
img = cv2.imread("assets/imori.jpg").astype(np.float)
# grayscale
gray = BGR2GRAY(img)
# emboss filtering
out = emboss_filter(gray, K_size=3)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
여기서도 역시 커널의 값만 변경한 코드
참고자료
https://algorithm.joho.info/programming/python/opencv-emboss-filter-py/
import numpy as np
img = cv2.imread("assets/imori.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
kernel= np.array([
[-2, -1, 0],
[-1, 1, 1],
[0, 1, 2]
])
out = cv2.filter2D(gray, -1, kernel)
cv2.imwrite("out.jpg",out)
cv2.imshow("result",out)
cv2.waitKey(0)
cv2.destroyAllWindows()
Q19. LoG필터(LoGフィルタ)
LoG필터(sigma = 3, 커널 사이즈 = 5)를 적용해, imori_noise.jpg의 선을 검출해보자.
LoG필터란 Laplacian of Gaussian으로,
가우시간 필터로 이미지의 평활화한 후에 라플라시안 필터로 윤곽을 잡아내는 필터이다.
Laplacian필터는 2차 미분을 취하므로 노이즈가 강조되는 것을 막기 위해 우선 Gaussian필터로 노이즈를 정리를 한다.
LoG필터는 다음 식으로 정의된다.
라플라 시안을 ∇^2, 가우시안 필터를 G, 이미지를 I로 한다.
다음의 식에 의해 가우시안 필터링 후에 라플라시안 필터를 적용하는 조작을,
가우시안 필터를 라플라시안한 것으로 필터링하는 조작으로 치환하는 것이 가능하다.
2차 미분은 다음의 식
y에 관하여는 x의 부분을 교체하기만 하면 되므로 LoG필터는 다음과 같은 식이 된다.
A19. LoG필터(LoGフィルタ)의 답안
import cv2
import numpy as np
# Gray scale
def BGR2GRAY(img):
b = img[:, :, 0].copy()
g = img[:, :, 1].copy()
r = img[:, :, 2].copy()
# Gray scale
out = 0.2126 * r + 0.7152 * g + 0.0722 * b
out = out.astype(np.uint8)
return out
# LoG filter
def LoG_filter(img, K_size=5, sigma=3):
if len(img.shape) == 3:
H, W, C = img.shape
else:
H, W = img.shape
# zero padding
pad = K_size // 2
out = np.zeros((H + pad * 2, W + pad * 2), dtype=np.float)
out[pad: pad + H, pad: pad + W] = gray.copy().astype(np.float)
tmp = out.copy()
# LoG Kernel
K = np.zeros((K_size, K_size), dtype=np.float)
for x in range(-pad, -pad + K_size):
for y in range(-pad, -pad + K_size):
K[y + pad, x + pad] = (x ** 2 + y ** 2 - 2 * (sigma ** 2)) * np.exp( - (x ** 2 + y ** 2) / (2 * (sigma ** 2)))
K /= (2 * np.pi * (sigma ** 6))
K /= K.sum()
"""
K = np.array([[0, 0, 1, 0, 0],
[0, 1, 2, 1, 0],
[1, 2, -16, 2, 1],
[0, 1, 2, 1, 0],
[0, 0, 1, 0, 0]])
"""
print(K)
# filtering
for y in range(H):
for x in range(W):
out[pad + y, pad + x] = np.sum(K * tmp[y: y + K_size, x: x + K_size])
out = np.clip(out, 0, 255)
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
return out
# Read image
img = cv2.imread("assets/imori_noise.jpg")
# grayscale
gray = BGR2GRAY(img)
# LoG filtering
out = LoG_filter(gray, K_size=5, sigma=1)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
<cv2.converScaleAbs()함수>
cv2.convertScaleAbs(src[, dst[, alpha[, beta]]])
스케일링 한 후에 절대값을 계산하고, 결과를 8비트로 변환하는 함수
- src : 입력 배열
- dst : 출력 배열
- alpha : (옵션) scale 요소
- beta : (옵션) 스케일링된 값에 델타 추가
Q20. 히스토그램 표시(ヒストグラム表示)
matplotlib을 사용하여 imori_dark.jpg의 히스토그램을 표시해보자.
히스토그램이랑 화소의 출현 횟수를 그래프로 표시하는 것이다.
matplotlib에는 hist()라는 함수가 있으므로, 이것을 이용하여 답을 도출해보자.
A20. 히스토그램 표시(ヒストグラム表示)의 답안
import cv2
import numpy as np
import matplotlib.pyplot as plt
# Read image
img = cv2.imread("assets/imori_dark.jpg").astype(np.float)
# Display histogram
plt.hist(img.ravel(), bins=255, rwidth=0.8, range=(0, 255))
plt.savefig("out.png")
plt.show()
<matplotlib.pyplot.hist()의 인수>
matplotlib.pyplot.hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, hold=None, data=None, **kwargs)
인수 | 의미 | 비고 |
x, y | 데이터의 배열 |
- 입력 필수 - 복수 지정 가능 |
bins | 클래스의 막대 수 (계급의 수) | - 기본 값 10 |
range | bins의 범위(최대값, 최소값)을 지정할 수 있음 | - 기본 값 (x.min(), x.max()) |
normed | 정규화 설정 | - 기본 값 False |
histtype |
히스토그램의 종류를 선택 종류로는 bar, barstacked, step, stepfilled이 있음 |
- 기본 값 bar |
orientation | 그래프의 방향을 수직(vertical)으로 할지, 수평(horizontal)으로 할지에 대해 설정 | - 기본 값은vertical |
rwidth | 막대의 폭 지정 | - 기본값 None(지정하지 않음) |
log | 세로축을 로그의 눈금으로 표시할지 여부를 지정 | - 기본값 False |
color | 히스토그램의 색상 지정 | - 기본값 None(지정하지 않음) |
label | 차트에 범례 표시 여부 | - 기본값 None(지정하지 않음) |
'IT > AI\ML' 카테고리의 다른 글
[python/OpenCV] 이미지 처리 예제 Q26~Q30 (0) | 2020.04.20 |
---|---|
[python/OpenCV] 이미지 처리 예제 Q21~Q25 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리 예제 Q11~Q15 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리 예제 Q06~Q10 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리 예제 Q01~Q05 (0) | 2020.04.20 |