문제 링크
https://github.com/yoyoyo-yo/Gasyori100knock/tree/master/Question_11_20
Q11. 평활화 필터(平滑化フィルタ)
평활화필터(3x3)를 적용해보자.
평활화필터는 필터 내의 화소의 평균치를 출력하는 필터이다.
A11. 평활화 필터(平滑化フィルタ)의 답안
import cv2
import numpy as np
# mean filter
def mean_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, C), dtype=np.float)
out[pad: pad + H, pad: pad + W] = img.copy().astype(np.float)
tmp = out.copy()
# filtering
for y in range(H):
for x in range(W):
for c in range(C):
out[pad + y, pad + x, c] = np.mean(tmp[y: y + K_size, x: x + K_size, c])
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
return out
# Read image
img = cv2.imread("imori.jpg")
# Mean Filter
out = mean_filter(img, K_size=3)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
아래는 OpenCV를 사용한 코드이다.
import cv2
import numpy as np
img = cv2.imread("assets/imori.jpg")
out = cv2.blur(img,(3,3))
cv2.imwrite("out.jpg",out)
cv2.imshow("result",out)
cv2.waitKey(0)
cv2.destroyAllWindows()
< cv2.blur()함수 >
out=cv2.blur(img,(ax,ay))
- img : 입력 이미지
- ax: 커널의 가로 폭
- ay: 커널의 세로 폭
(cf) cv2.blur()대신 cv2.boxFilter()도 사용가능하다.
참고로 정규화된 상자형 필터를 사용하고 싶지 않다면, cv2.boxFilter()의 함수 인수로 normalize=False를 지정하여라.
<Numpy의 ones 와 zeros 함수>
(1) ones함수
np.ones(shape, dtype=float, order='C')
- shape : int형, int형의 튜플새로운 배열의 shape이다. 예 (2,3) 또는 2
- dtype: 데이터형, 이 인자는 옵션이므로 지정 안 해도 괜찮다.
새로운 배열의 데이터형을 지정한다.
예 numpy.int8등으로 지정가능하다.디폴트는 np.float64
- oder : {`C`,F``}, 이 인자는 옵션이므로 반드시 지정할 필요는 없다.
다차원배열을 행우선(C-style) 영우선(Fortran-style)으로 메모리에 저장할지를 지정한다.디폴트는 `C`
> 리턴값은 ndarray
(2) zeros함수
np.zeros(shape, dtype=float, order='C')
- shape : int형, int형의 튜플새로운 배열의 shape이다. 예 (2,3) 또는 2
- dtype: 데이터형, 이 인자는 옵션이므로 지정 안 해도 괜찮다.새
로운 배열의 데이터형을 지정한다.
예 numpy.int8등으로 지정가능하다
.디폴트는 np.float64
- oder : {`C`,F``}, 이 인자는 옵션이므로 반드시 지정할 필요는 없다.
다차원배열을 행우선(C-style) 열 우선(Fortran-style)으로 메모리에 저장할지를 지정한다.
디폴트는 `C`
> 리턴값은 ndarray
Q12. 모션 필터(モーションフィルタ)
모션 필터(3x3)를 적용해보자.
모션 필터는 대각방향의 평균치를 구하는 필터로, 수식은 다음과 같이 정의되어 있다.
A12. 모션 필터(モーションフィルタ)의 답안
import cv2
import numpy as np
# motion filter
def motion_filter(img, K_size=3):
H, W, C = img.shape
# Kernel
K = np.diag( [1] * K_size ).astype(np.float)
K /= K_size
# zero padding
pad = K_size // 2
out = np.zeros((H + pad * 2, W + pad * 2, C), dtype=np.float)
out[pad: pad + H, pad: pad + W] = img.copy().astype(np.float)
tmp = out.copy()
# filtering
for y in range(H):
for x in range(W):
for c in range(C):
out[pad + y, pad + x, c] = np.sum(K * tmp[y: y + K_size, x: x + K_size, c])
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
return out
# Read image
img = cv2.imread("imori.jpg")
# motion filtering
out = motion_filter(img, K_size=3)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
아래는 더 짧게 엇비슷하게 만들어봤는데 확실히 답안과 깉은 동작을 하는 코드인지는 확신이 없다.
조금 더 조사해볼 필요가 있을 것 같다.
우선은 참고한 블로그는 아래에 남겨둔다.
http://optie.hatenablog.com/entry/2018/03/21/185647
https://teratail.com/questions/221425
import cv2
import numpy as np
img = cv2.imread("assets/imori.jpg")
kernel = np.array([
[1/3, 0, 0],
[0, 1/3, 0],
[0, 0, 1/3]
])
out = cv2.filter2D(img, -1, kernel)
cv2.imwrite("motion.jpg",out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
이 외에 가로, 세로 모션 블러를 적용한 예는 아래의 링크를 참조.
https://www.geeksforgeeks.org/opencv-motion-blur-in-python/
<cv2.filter2D 함수>
dst = cv2.filter2D(src, -1, kernel)
- src : 입력 이미지- kernel : 필터의 커넬(numpy배열)
- dst : 출력 이미지
Q13. MAX-MIN필터 (最大値・最小値フィルタ)
MAX-MIN필터를 적용해보자.
MAX-MIN필터는 필터내의 화소의 최대치와 최소치의 차이를 출력하는 필터로,
엣지 검출의 필터의 하나이다.
엣지 검출이란 이미지내의 선을 검출하는 것이며, 이러한 이미지 내의 정보를 뽑아내는 것을 "특징 추출"이라고 부른다.
엣지 검출에서는 대부분 그렝 스케일을 한 이미지를 필터링한다.
따라서 처음에는 그레일 스케일화를 설정해야 한다.
A13. MAX-MIN필터 (最大値・最小値フィルタ)의 답안
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
# max-min filter
def max_min_filter(img, K_size=3):
if len(img.shape) == 3:
H, W, C = img.shape
## Zero padding
pad = K_size // 2
out = np.zeros((H + pad * 2, W + pad * 2, 3), dtype=np.float)
out[pad: pad + H, pad: pad + W] = img.copy().astype(np.float)
tmp = out.copy()
# filtering
for y in range(H):
for x in range(W):
for c in range(3):
out[pad + y, pad + x, c] = np.max(tmp[y: y + K_size, x: x + K_size, c]) - np.min(tmp[y: y + K_size, x: x + K_size, c])
out = out[pad: pad + H, pad: pad + W].astype(np.uint8)
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] = img.copy().astype(np.float)
tmp = out.copy()
# filtering
for y in range(H):
for x in range(W):
out[pad + y, pad + x] = np.max(tmp[y: y + K_size, x: x + K_size]) - np.min(tmp[y: y + K_size, x: x + K_size])
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)
# Max-Min filtering
out = max_min_filter(gray, K_size=3)
# Save result
cv2.imwrite("out.jpg", out)
cv2.imshow("result", out)
cv2.waitKey(0)
cv2.destroyAllWindows()
참고 자료
http://optie.hatenablog.com/entry/2018/04/07/232822
Q14. 미분 필터(微分フィルタ, differential filter)
미분 필터(3x3)을 적용시켜보자.
미분필터란 휘도의 변환이 급격한 곳의 선을 출력하는 필터로, 인접하는 화소의 차이를 구한다.
이미지에서 선이 되는 것은 휘도의 변화가 심한 부분으로, 빨간색으로 테두리 표시한 곳은 대부분 색의 변환이 없지만, 파란색 테두리는 색의 변화가 심하다.
이렇게 색의 변화가 급격하게 이루어지는 부분에 대해 선으로 표시하여 엣지를 검출해낸다.
이러한 색의 변화량은 미분으로 나타난다.
I(x, y)는 이미지의 (x, y) 위치의 휘도에 해당한다.
즉 이웃하는 픽셀의 차이가 픽셀의 미분값이 된다.
이것을 세로 방향, 가로 방향으로 나타내면 다음 필터를 적용하는 것과 같이 된다.
1) 세로 방향
2) 가로 방향
A14. 미분 필터(微分フィルタ, differential filter)의 답안
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
# different filter
def different_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()
# vertical kernel
Kv = [[0., -1., 0.],[0., 1., 0.],[0., 0., 0.]]
# horizontal kernel
Kh = [[0., 0., 0.],[-1., 1., 0.], [0., 0., 0.]]
# 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("assets/imori.jpg").astype(np.float)
# grayscale
gray = BGR2GRAY(img)
# different filtering
out_v, out_h = different_filter(gray, K_size=3)
# Save result
cv2.imwrite("out_v.jpg", out_v)
cv2.imshow("result_v", out_v)
while cv2.waitKey(100) != 27:# loop if not get ESC
if cv2.getWindowProperty('result_v',cv2.WND_PROP_VISIBLE) <= 0:
break
cv2.destroyWindow('result_v')
cv2.imwrite("out_h.jpg", out_h)
cv2.imshow("result_h", out_h)
# loop if not get ESC or click x
while cv2.waitKey(100) != 27:
if cv2.getWindowProperty('result_h',cv2.WND_PROP_VISIBLE) <= 0:
break
cv2.destroyWindow('result_h')
cv2.destroyAllWindows()
https://algorithm.joho.info/programming/python/opencv-differential-filter-point-py/
<np.expand_dims()함수>
배열의 모양을 확장한다.
기존의 축 위치에서 삽입할 새로운 축의 배열 형태
numpy.expand_dims(a, axis)
- a : array_like삽입 배열
- axis : int축을 확장할 위치 즉 새로운 축이 위치할 곳
> 리턴값 : ndarray
<np.clip()함수>
numpy.clip(a, a_min, a_max, out=None, **kwargs)
배열에서 값을 제한한다.구간이 주어지면 구간 외부의 값은 잘린다.
예를 들어, 만약 구간이 [0,1]로 정의되어지면, 0보다 작은 값은 0이 되고 1보다 큰 값은 1이 된다. np.maximum(a_min, np.minimum(a, a_max))과 동일하지만 속도는 더 빠르다.
a_min < a_max를 확인하기 위해 어떠한 점검도 수행되지 않는다.
- a : array_like 값을 제한할 요소가 들어 있는 배열
- a _min : scalar or array_like or None 최소값.
지정하지 않는 경우 제한은 아래 간격의 엣지에 실행되지 않는다.
a_min과 a_max 중 하나 이상의 값이 지정되지 않을 수 있다.
- a_max : scalar or array_like or None 최대값.
지정하지 않는 경우 위의 간격의 엣지에 실행되지 않는다.
a_min과 a_max 중 하나 이상의 값이 지정되지 않을 수 있다.
array_like이면 세 개의 배열의 모양이 일치되도록 변경된다.
- out : ndarray,optional
- **kwargs
> 리턴값 clipped_array : ndarray
< cv2.getWindowProperty() 함수 >
윈도우의 파라미터를 취득하는 함수로, 제 2의 인수에 cv2.WND_PROP_ASPECT_RATIO를 지정함으로써
창의 aspect비를 리턴값으로 취득하는 것이 가능하다.
닫기 버튼을 누르면 -1.0이 반환된다.
Q15. Prewiitt필터 (Prewittフィルタ)
Prewitt필터(3x3)를 적용해보자.
Prewitt필터란 선 추출 필터의 한 종류로, 아래와 같이 정의 되어 있다.
이는 미분 필터를 (3x3)으로 확장한 것이다.
1) 세로 방향
2) 가로 방향
A15. Prewiitt필터 (Prewittフィルタ)의 답안
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
# prewitt filter
def prewitt_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()
out_v = out.copy()
out_h = out.copy()
## prewitt vertical kernel
Kv = [[-1., -1., -1.],[0., 0., 0.], [1., 1., 1.]]
## prewitt horizontal kernel
Kh = [[-1., 0., 1.],[-1., 0., 1.],[-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("assets/imori.jpg").astype(np.float)
# grayscale
gray = BGR2GRAY(img)
# prewitt filtering
out_v, out_h = prewitt_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()
https://algorithm.joho.info/programming/python/opencv-prewitt-filter-py/
위의 두 가지 링크를 참고하여 작성한 코드는 아래와 같다.
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],
[-1, 0, 1],
[-1, 0, 1]
])
kernel_h = np.array([
[-1, -1, -1],
[0, 0, 0],
[1, 1, 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()
엣지 검출과 관련된 내용을 잘 정리한 블로그가 있어서 공유
'IT > AI\ML' 카테고리의 다른 글
[python/OpenCV] 이미지 처리 예제 Q21~Q25 (0) | 2020.04.20 |
---|---|
[python/OpenCV] 이미지 처리 예제 Q16~Q20 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리 예제 Q06~Q10 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리 예제 Q01~Q05 (0) | 2020.04.20 |
[python/OpenCV] 이미지 처리의 기본 (1) | 2020.04.20 |