IT/AI\ML

[python/OpenCV] 이미지 처리 예제 Q11~Q15

개발자 두더지 2020. 4. 20. 19:37
728x90

문제 링크

https://github.com/yoyoyo-yo/Gasyori100knock/tree/master/Question_11_20

 

yoyoyo-yo/Gasyori100knock

画像処理100本ノックして画像処理を画像処理して画像処理するためのもの For Japanese, English and Chinese - yoyoyo-yo/Gasyori100knock

github.com


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

 

Python3 & OpenCV で画像処理を学ぶ[6] 〜 numpy で畳み込み演算と平滑化フィルタの実装 - Optie研

1. はじめに 2. 基本概念 2.1. 空間フィルタリングとは 2.2. 畳み込み演算とは 3. 平滑化の実装 3.1. 平均化フィルタ 3.1.1 python/numpy による実装 3.1.2 opencvによる実装 3.2. ガウシアンフィルタ 3.3. 応用 : 特定方向の平滑化 4. おわりに 5. 参考文献 1. はじめに 今回は、空間フィルタリングの基礎概念に触れて、いくつかの平滑化フィルタを実装します。 理解を深めるため, まず畳み込み演算から自力でnumpyで実装し, 次にOpenCV

optie.hatenablog.com

https://teratail.com/questions/221425

 

画像の特定方向への平滑化|teratail

画像を特定方向(左斜め)に平滑化したいです。 画像全体の平滑化はできましたがこれを特定方向に平滑化することが出来ません。行列は7*7でやりたいのですがこの場合のフィルタ処理のしかたがわかりません。■■な機能を実装中に以下のエラーメッセージが発生しました。 該当のソースコードPythonソースコー

teratail.com

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

 

Python3 & OpenCV で画像処理を学ぶ[7] 〜 エッジを保存する平滑化フィルタ - Optie研

1. はじめに 2. エッジ保存平滑化 2.1. 下準備 2.2. メディアンフィルタ 2.3. バイラテラルフィルタ 2.4. 最大値・最小値フィルタ 3. まとめ 4. 参考文献 1. はじめに 前回 optie.hatenablog.com は線形フィルタによるたたみこみで平滑化を行いました。 しかし、平均を用いた平滑化は全体が一様にぼけるため, エッジが失われてしまいます。 そこで今回は, エッジを保存したまま平滑化を行う方法を見ていきます。 2. エッジ保存平滑化 2.1. 下準備 いつものように

optie.hatenablog.com


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/

 

【Python/OpenCV】微分フィルタの注意点(負の値の処理)

Python版OpenCVの微分フィルタ(Sobelなど)を利用する時の注意点についてソースコード付きで解説します。

algorithm.joho.info

<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/

 

【Python/OpenCV】Prewittフィルタで輪郭検出

Python+OpenCVでPrewittフィルタを「NumPy」「cv2.filter2D」で実装し、輪郭検出する方法をソースコード付きで解説します。

algorithm.joho.info

https://betashort-lab.com/opencv/pythonopencvprewitt%E3%83%95%E3%82%A3%E3%83%AB%E3%82%BF%E3%83%BC/#toc4

 

Python+OpenCV|Prewittフィルター

PrewittフィルターPrewittフィルターは、次のフィルターで表される。x方向$$F_x = \begin{bmatrix} -1 & 0 & 1 \\ -1 & 0 & 1 \\ -1 & 0

betashort-lab.com

위의 두 가지 링크를 참고하여 작성한 코드는 아래와 같다.

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()

엣지 검출과 관련된 내용을 잘 정리한 블로그가 있어서 공유

http://blog.daum.net/trts1004/12109067

728x90