딥러닝 -OpenCV_007_HSV_모폴로지
[7차시] 학습목표 |
○ HSV 색상공간을 이해하고 원하는 색상을 추출하는 방법을 학습한다. ○ 크로마 키(Chroma key) 합성으로 이미지를 합성하는 방법을 학습한다. ○ 이미지 필터링 방법에 대해 학습한다. ○ 모폴로지 연산 방법에 대해 학습한다. |
1 색상공간 (Color Space) 이해하기
- RGB : Red, Green, Blue로 구성된 색상공간 - PC의 모니터에 주로 사용
- 가산혼합 : 색을 섞을수록 명도가 높아지는 혼합
CMYK : Cyan, Magenta, Yellow, Black으로 구성된 색상공간 - 인쇄용으로 주로 사용
- 감산혼합 : 색을 섞을수록 명도가 낮아지는 혼합
- HSV : Hue(색상), Saturation(채도), Value(명도)로 변환한 색상공간
- 직관적으로 색상 파악이 용이
- YUV : Y (밝기, 휘도), U, V (색상)을 이용해서 색상을 표현하는 색상공간
- U축 : 파란색에서 밝기 성분을 뺀 값 (U = B - Y)
- V축 : 빨간색에서 밝기 성분을 뺀 값 (V = R - Y)
- 아날로그 컬러신호 변환에 주로 사용
- TV나 비디오카메라에 주로 사용
- YCbCr : Y (밝기, 휘도), Cb (청색 크로마 성분), Cr (적색 크로마 성분)을 이용해서 색상을 표현하는 색상공간
- YUV와 유사한 형태로 RGB 색공간과는 다르게 별도의 명암을 구분하는 U(Cb), V(Cr) 사용
- 디지털 텔레비전, 비디오, 디지털 사진에서 사용하는 색공간
- CIE : 인간의 색채 인지에 대한 연구와 측정을 바탕으로 수학적으로 정의된 색상 공간
- XYZ : 적색(X), 녹색(Y), 청색(Z) 계열의 반응정도값을 적용
- Lab : 색오차와 근소한 색차이를 표현하기 위해 변환된 색상 공간
- Luv : 지각적 분균등성을 해소한 균등 색상 공간 (3차원 직교좌표를 이용하는 색상 공간)
HSV 색상공간의 구성
- 색상 값
- Hue 값은 0-179 범위로 설정
- 만약 Hue 값을 -로 설정하면 뒤쪽부터 인덱싱됨
1.1 색상추적
#실습
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("./images/balloon.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.axis("off")
이미지를 불러와서 matplotlib을 이용해 출력하는 코드입니다. cv2.imread()로 이미지를 읽어온 후,
색상 순서를 RGB로 변경해준 뒤 plt.imshow()를 통해 이미지를 출력하며,
plt.axis("off")를 이용해 이미지 위 아래의 빈 공간을 없애주었습니다.
#실습
hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
# 찾고자 하는 색상을 HSV 색상공간에 정의(마스킹)
# 색상, 채도 , 명도 최소값 ,색상, 채도 , 명도 최대값
mask = cv2.inRange(hsv,(40,40,40),(70,255,255))
# hsv에서 정의한 색상이 이미지도 있으면 잘라냄
img2 = cv2.bitwise_and(img,img, mask = mask)
plt.imshow(img2)
plt.axis("off")
실습문제
○ 다음과 같이 이미지에서 원하는 색상을 추출해보자.
1.2 크로마 키(Chroma key) 합성
- 녹색 또는 파란색 배경에서 촬영한 영상에 다른 배경 영상을 합성하는 기술
#실습
import cv2
import matplotlib.pyplot as plt
img = cv2.imread("./images/chromakey2.jpg")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
back = cv2.imread("./images/back2.png")
back = cv2.cvtColor(back, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.axis("off")
plt.show()
plt.imshow(back)
plt.axis("off")
plt.show()
해당 코드는 chromakey2.jpg와 back2.png 이미지를 읽어들여 RGB 형식으로 변경하고, 이를 각각 이미지로 출력하는 코드입니다.
matplotlib의 imshow() 함수를 이용하여 이미지를 출력하는데, axis() 함수를 이용하여 축을 제거하였습니다.
#실습
hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
#녹색범위 설정
mask = cv2.inRange(hsv, (50, 150, 50), (70, 255, 255))
plt.imshow(mask, cmap="gray")
plt.axis("off")
해당 코드는 입력 이미지를 RGB에서 HSV로 변환하여, 특정 범위 내의 색상을 가진 픽셀을 검출하는 코드입니다.
cv2.cvtColor() 함수를 이용하여 RGB 이미지를 HSV 형식으로 변환하고,
cv2.inRange() 함수를 이용하여 HSV 색공간에서 녹색의 범위를 설정하여,
해당 범위 내의 색상을 가진 픽셀을 검출합니다.
imshow() 함수를 이용하여 검출된 마스크 이미지를 출력하고, axis() 함수를 이용하여 축을 제거하였습니다.
#실습
# mask와 img을 and 연산한 후에 back에 복사 -> img 에 할당
# back, mask,img는 동일한 크기여야 함
# opencv3에서는 지원하지않음
cv2.copyTo(back, mask, img)
plt.imshow(img)
plt.axis("off")
위 코드에서는, 먼저 mask를 RGB 색공간으로 변환하여
cv2.bitwise_and() 함수를 이용하여 입력 이미지 img와 AND 연산을 수행한 뒤,
이 결과를 img_masked에 할당합니다. 마찬가지로,
back과 mask의 NOT 연산 결과를 cv2.bitwise_and() 함수를 이용하여 계산한 뒤
, 이 결과를 back_masked에 할당합니다.
마지막으로, img_masked와 back_masked를 cv2.add() 함수를 이용하여 더한 뒤
, 이 결과를 img에 할당하여 최종적으로 출력합니다.해당 코드는 cv2.copyTo() 함수를 이용하여, back과 mask를 AND 연산하여 얻은 마스크 이미지를, 입력 이미지 img에 적용하고 이를 img에 할당하는 코드입니다.
하지만 코드에는 문제가 있습니다. cv2.copyTo() 함수의 인자 순서는 다음과 같습니다.
따라서, 코드에서 back, mask, img의 인자 순서가 잘못되어 있습니다. 또한, img는 dst의 역할을 하므로, cv2.copyTo() 함수의 결과를 img에 할당하는 것은 올바르지 않습니다.
따라서, 아래와 같이 코드를 수정해주어야 합니다.
위 코드에서는, 먼저 mask를 RGB 색공간으로 변환하여 cv2.bitwise_and() 함수를 이용하여 입력 이미지 img와 AND 연산을 수행한 뒤, 이 결과를 img_masked에 할당합니다. 마찬가지로, back과 mask의 NOT 연산 결과를 cv2.bitwise_and() 함수를 이용하여 계산한 뒤, 이 결과를 back_masked에 할당합니다.
마지막으로, img_masked와 back_masked를 cv2.add() 함수를 이용하여 더한 뒤, 이 결과를 img에 할당하여 최종적으로 출력합니다.
2 이미지 연산
2.1 이미지 필터링 - blur
- cv2.filter2D(img, -1, kernel)
- 이미지와 필터를 컨볼루션 연산 수행
- 2번째 파라미터는 색의 깊이 (몇 비트)로 -1이면 원본 이미지와 동일
- kernel : 적용할 2차원 필터
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("./images/dip.jfif")
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 필터 설정
kernel = np.ones((5, 5), np.float32) / 25 # 모든값이 0.04로 변환
print(kernel)
result = cv2.filter2D(img, -1, kernel)
plt.imshow(img)
plt.axis("off")
plt.show()
plt.imshow(result)
plt.axis("off")
plt.show()
# 선명도
img_gray1 = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
img_gray2 = cv2.cvtColor(result, cv2.COLOR_RGB2GRAY)
edge1 = cv2.Canny(img_gray1, 100, 200)
edge2 = cv2.Canny(img_gray2, 100, 200)
print(f"img1의 선명도 : {np.average(edge1)}")
print(f"img2의 선명도 : {np.average(edge2)}")
- 이미지와 필터를 이용한 필터링 결과를 imshow() 함수를 이용하여 출력하는 부분에서 img 대신에 result를 출력하는 것이 맞습니다.
- 마지막으로 선명도 계산 부분에서 img_gray1 변수명이 오타가 났습니다. img_gray1 대신에 img_gray2를 출력해야 합니다.
2.2 모폴로지 - 침식과 팽창
- Morphology : 영상의 형태학적 측면을 다루는 기법으로 전처리 등에 사용
- Erosion (침식) : 이미지의 경계부분을 배경 픽셀로 변경하는 작업 (1이 0으로 변경)
- Dilation (팽창) : 이미지의 배경부분을 전경 픽셀로 변경하는 작업 (0이 1로 변경)
- iterations = 1 : 반복 적용 회수 (회수가 많아지면 침식과 팽창의 효과가 커짐)
#실습
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("./images/number.png", cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap="gray")
plt.axis("off")
plt.show()
#침식 및 팽창의 크기 설정(필터,커널)
#np.uint8: u(unsigned: 양수), int(정수), 8(8비트, 0~255 사이값)
kernel = np.ones((3,3), np.uint8)
#침식
ret_e = cv2.erode(img, kernel, iterations=1)
plt.title("erosion")
plt.imshow(ret_e, cmap="gray")
plt.axis("off")
plt.show()
#팽창
ret_d = cv2.dilate(img, kernel, iterations=1)
plt.title("dilation")
plt.imshow(ret_d, cmap="gray")
plt.axis("off")
plt.show()
이 코드는 이미지에서 침식(Erosion)과 팽창(Dilation) 연산을 수행하는 코드입니다.
먼저 cv2.imread() 함수로 이미지를 불러온 후, plt.imshow() 함수를 사용해 이미지를 시각화합니다.
이후 필터(커널) 크기를 설정하고 cv2.erode() 함수를 사용해 침식 연산을 수행합니다.
수행 결과를 plt.imshow() 함수를 사용해 시각화합니다.
마찬가지로, 필터(커널) 크기를 설정하고 cv2.dilate() 함수를 사용해 팽창 연산을 수행합니다.
수행 결과를 plt.imshow() 함수를 사용해 시각화합니다.
kernel = np.ones((3,3), np.uint8) 코드에서 np.uint8은 numpy 라이브러리에서 8비트 부호 없는 정수형을 의미합니다.
즉, 0~255 사이의 값만 표현할 수 있습니다. iterations 인자는 연산을 반복할 횟수를 의미합니다.
그러나 이미지 처리에서 연산 결과가 의도한 대로 나오지 않을 때가 있습니다.
이 때는 연산 결과를 시각화하고, 필요하면 연산에 사용되는 파라미터를 조정해야 합니다.
실습문제 ○ 다음과 같이 열림과 팽창 연산을 수행해보자. |
2.3 Opening과 Closing
- Opening : erosion 수행 후에 바로 dilate을 수행하여 원래 이미지 크기로 돌려 놓는 것
- Closing : dilate 수행 후에 바로 erosion을 수행하여 원래 이미지 크기로 돌려 놓는 것
#실습
# openning
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("./images/noise_A.png", cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap="gray")
plt.axis("off")
plt.show()
kernel = np.ones((3,3), np.uint8)
#침식
ret_e = cv2.erode(img, kernel, iterations=2)
plt.title("erosion")
plt.imshow(ret_e, cmap="gray")
plt.axis("off")
plt.show()
#팽창
ret_d = cv2.dilate(ret_e, kernel, iterations=2)
plt.title("dilation")
plt.imshow(ret_d, cmap="gray")
plt.axis("off")
plt.show()
이 코드는 노이즈 제거 기술 중 하나인 Opening을 구현한 코드입니다.
먼저, OpenCV를 이용해 grayscale 이미지를 읽어와서 imshow 함수로 시각화합니다.
그 후, 필터(kernel)의 크기를 3x3으로 설정하고, 이미지에 대해 침식(erode)을 2회 수행합니다.
그 결과를 시각화합니다. 이어서, 다시 그 결과에 대해 팽창(dilate)을 2회 수행하고, 이 결과를 다시 시각화합니다.
Opening은 먼저 침식 연산을 수행하여 이미지의 주변 노이즈를 제거한 후, 팽창 연산을 수행하여
이미지를 확장하는 기술입니다.
이를 통해 노이즈가 제거된 이미지를 얻을 수 있습니다.
이 기술은 머신러닝 등에서 전처리 단계에서 자주 사용됩니다.
주석에 "openning"이라고 적혀있는 부분이 오타인 것 같습니다. "opening"이 맞는 표현입니다.
#실습
#Closing
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("./images/noise_B.png", cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap="gray")
plt.axis("off")
plt.show()
kernel = np.ones((3,3), np.uint8)
#팽창
ret_d = cv2.dilate(img, kernel, iterations=2)
plt.title("dilation")
plt.imshow(ret_d, cmap="gray")
plt.axis("off")
plt.show()
#침식
ret_e = cv2.erode(ret_d, kernel, iterations=2)
plt.title("erosion")
plt.imshow(ret_e, cmap="gray")
plt.axis("off")
plt.show()
이 코드는 이미지에서 노이즈를 제거하기 위해 Closing 연산을 수행하는 코드입니다.
먼저, cv2.imread() 함수를 사용하여 이미지를 불러온 후,
plt.imshow() 함수를 사용하여 그레이스케일 이미지를 화면에 출력합니다.
다음으로, np.ones() 함수를 사용하여 3x3 크기의 커널을 생성합니다.
이어서, cv2.dilate() 함수를 사용하여 이미지를 팽창시킵니다.
이때, iterations 매개변수를 2로 설정하여 2번 팽창시킵니다.
그 다음, cv2.erode() 함수를 사용하여 이미지를 침식시킵니다.
이때도 iterations 매개변수를 2로 설정합니다.
마지막으로, plt.imshow() 함수를 사용하여 처리 결과를 화면에 출력합니다.
이 코드는 노이즈 제거를 위한 Closing 연산을 간단하게 구현한 것이므로, 이해하기 쉽고 구현하기 쉬운 코드입니다.
#실습
#opening
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("./images/noise_A.png", cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap="gray")
plt.axis("off")
plt.show()
#Closing 연산
#cv.MORPH_CLOSE(닫힘), cv.MORPH_OPEN(열림)
kernel = np.ones((5,5), np.uint8)
result = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel, iterations=2)
plt.imshow(result, cmap="gray")
plt.title("dilation")
plt.axis("off")
plt.show()
코드는 opening 연산이 아니라 closing 연산입니다.
또한 마지막 plt.title에서 "dilation"이 아닌 "closing"으로 수정해야 합니다.
실습문제 ○ 다음과 같이 모폴로지 연산을 이용하여 이미지를 필터링 해보자. |
[7차시] 정리하기 |
○ 색상공간의 종류 : RGB, CYMK, HSV, YUV, YCbCr, CIE 등 ○ HSV 색공간 : H(색상), S(채도), V(명도) ○ 크로마 키 합성 : 녹색 또는 파란색 배경에서 찰영한 영상에 다른 배경 영상을 합성하는 기술 ○ copyTo() : 녹색 영역에 다른 영역 배경을 합성하기 ○ cv2.filter2D(img, -1, kernel) : 이미지와 필터를 컨볼루션 연산 수행 ○ 모폴로지 연산 : 영상의 형태학적 측면을 다루는 기법으로 전처리 등에 사용
|