1. 그레이 스케일(gray-scale) 이미지가 의미하는 것이 무엇인지 설명하시오.
디지털 영상처리에서 보통 단일채널의 영상을 그레이 스케일(gray-scale) 영상이라고 부른다. 하나의 화소값은 0~255의 값을 가지는데 0은 검은색을, 255는 흰색을 의미한다. 이렇게 화소값이 회색의 비율 정도로 표현되고, 0~255값을 가지는 화소들이 모여서 구성된 것이 영상이 때문에 그레이 스케일 영상이라 한다.
(교재 226p)
2. 화소의 밝기와 화소값에 대해서 설명하시오.
하나의 화소값은 0~255의 값을 가지는데 0은 검은색을, 255는 흰색을 의미한다.
(교재 226p)
3. 두 개의 영상을 합성하는 방법을 두 가지 이상 기술하시오.
두 개의 영상을 합하면 영상 합성을 할 수 있다.
OpenCV를 이용하여 영상 합성을 할 수 있는 방법은 아래와 같다.
add_img1 = cv2.add(image1 , image2) # 두 영상 단순 더하기
alpha, beta = 0.6, 0.7
#####
add_img2 = cv2.add(image1 * alpha , image2 * beta) # 두영상 비율에 따른 더하기
add_img2 = np.clip(add_img2, 0, 255).astype("uint8") # saturation 처리
#####
alpha, beta = 0.6, 0.7
add_img3 = cv2.addWeighted(image1, alpha, image2, beta, 0) # 두영상 비율에 따른 더하기
4. 영상에서 밝기 변경과 명암 대비 변경의 차이를 설명하시오.
밝기 변경 | 화소값은 영상의 밝기를 나타내기 때문에 단순히 특정 상숫값을 더하면 영상이 밝아지고, 빼면 영상이 어두워진다. |
명암 대비 변경 | 명암 대비(contrast)는 상이한 두 가지 색(밝기)이 경계에서 서로 영향을 미쳐 그 차이가 강조되어 나타나는 현상이다. 낮은 명암 대비의 영상은 어두운 값과 밝은 값의 차이가 크지 않아 전체적으로 어둡거나 밝은 영상이며, 높은 명암 대비 영상은 그와 반대이다. 명암 대비 변경을 하기 위해서는 어두운 부분은 더 어둡게, 밝은 부분을 더 밝게 해야 하며, 단순 상숫값을 더하는 밝기 변경과는 차이가 있다. 명암 대비 변경을 하는 가장 단순한 방법으로 곱셈 연산이 있다. 명암 대비를 늘리기 위해서는 1.0 이상의 값을 곱해주고, 명암 대비를 줄이기 위해서는 1.0 이하의 값을 곱해주면 된다. |
5. 영상처리에서 히스토그램이란 무엇인가?
특정 밝기 부분만 있는 영상은 전체적으로 선명하지 않으며 또렷하지 않다. 이런 영상을 히스토그램으로 나타내면 한쪽으로 치우쳐서 히스토그램 분포가 좁은 그래프들로 나타난다. 히스토그램 분포가 좁아 영상 대비가 좋지 않은 영상들의 화질을 개선할 수 있는 알고리즘이 히스토그램 스트레칭(histogram stretching)이다.
스트레칭이라는 용어에서 알 수 있듯이 명암 분포가 좁은 히스토그램을 좌우로 잡아당겨 고른 명암 분포를 가진 히스토그램이 되게 하는 것이다.
(교재 246p)
히스토그램의 x축 위에서 빈도값이 존재하는 가장 낮은 화소값(low value)과 가장 높은 화소값(high value)을 찾아 가장 낮은 화소값을 0으로 당기고 가장 높은 화소값을 255로 당긴다. 중간의 화소값들은 각각의 비율에 따라서 화소값의 위치를 조정하면 된다.
실제 화소값에 대한 수식으로 표현하면 다음과 같다. 영상의 모든 화소에 대해서 다음 수식을 적용하면 히스토그램 스트레칭이 완료된다.
$$ 새 화소값 = \frac{(화소값) - low}{high - low} * 255 $$
(교재 247p)
7. 히스토그램 평활화 과정을 기술하시오.
히스토그램 평활화를 통해 영상의 인지도를 높이며, 영상의 화질을 개선할 수 있다. 평활화 알고리즘은 히스토그램 평활화의 사전적 의미인 “분포의 균등”이라는 방법을 이용해 명암 대비를 증가시킨다. 히스토그램의 분포가 좁지는 않지만, 특정 부분에서 한쪽으로 치우친 명암 분포를 가진 영상들의 히스토그램 재분배 과정을 거쳐 균등한 히스토그램 분포를 가지게 하는 알고리즘이 “히스토그램 평활화” 알고리즘이다.
히스토그램 평활화를 수행하는 전체 과정은 다음과 같다.
- 영상의 히스토그램을 계산한다.
- 히스토그램 빈도값에서 누적 빈도수(누적합)을 계산한다.
- 누적 빈도수를 정규화(정규화 누적합) 한다.
- 결과 화소값 = 정규화 누적합 * 최대 화소값
(교재 252p)
8. OpenCV함수 중에서 cv2.addWeighted() 함수를 사용해서 두 영상을 합성하는 프로그램을 작성하시오.
import numpy as np, cv2
image1 = cv2.imread("images/add1.jpg", cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread("images/add2.jpg", cv2.IMREAD_GRAYSCALE)
if image1 is None or image2 is None: raise Exception("영상 파일 읽기 오류 발생")
dst = cv2.addWeighted(image1, 0.5, image2, 0.5, None)
dst = np.hstack((image1,dst, image2))
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
9. 8번 문제에 두 개의 트렉바를 추가해서 각 영상의 반영 비율을 조절할 수 있도록 수정하시오.
import numpy as np, cv2
image1 = cv2.imread("images/add1.jpg", cv2.IMREAD_GRAYSCALE)
image2 = cv2.imread("images/add2.jpg", cv2.IMREAD_GRAYSCALE)
if image1 is None or image2 is None: raise Exception("영상 파일 읽기 오류 발생")
alpha, beta = 50, 50
def showWeightedImg():
global alpha, beta
dst = cv2.addWeighted(image1, alpha/100, image2, beta/100, None)
dst = np.hstack((image1, dst, image2))
cv2.imshow("dst", dst)
def onAlphaChange(a):
global alpha
alpha = a
showWeightedImg()
def onBetaChange(b):
global beta
beta = b
showWeightedImg()
cv2.namedWindow("dst")
cv2.createTrackbar("image1", "dst", alpha, 100, onAlphaChange)
cv2.createTrackbar("image2", "dst", beta, 100, onBetaChange)
showWeightedImg()
cv2.waitKey(0)
cv2.destroyAllWindows()
10. 예제_6.2.1를 수정해서 np.float32(CV_32F)형으로 행렬을 선언하며, 회색이 점진적으로 짙어지는 영상을 만드시오.
import numpy as np, cv2
image1 = np.ones((50, 512), np.float32) # 50 x 512 영상 생성
image2 = np.ones((50, 512), np.float32)
rows, cols = image1.shape[:2]
for i in range(rows): # 행렬 전체 조회
for j in range(cols):
image1[i, j]= -1 - j // 2 # 화소값 점진적 증가
image2[i, j]= -1 - j // 20 * 10 # 계단 현상 증가
cv2.imshow("image1", image1.astype('uint8'))
cv2.imshow("image2", image2.astype('uint8'))
cv2.waitKey(0)
cv2.destroyAllWindows()
11. cv2.calcHist() 함수는 1~3채널 영상에 대해서 히스토그램을 계산할 수 있다. 예제_6.3.5에서 calc_histo() 함수는 단일채널 영상에서 히스토그램을 계산하는데 cv2.calcHist() 함수와 같이 2채널 혹은 3채널 영상에서 2차원 혹은 3차원 히스토그램을 계산하도록 빈칸을 채우시오.
import numpy as np, cv2
### calc_histo 정의
def calc_histo(image, channels, bsize, ranges):
shape = bsize if len(channels) > 1 else(bsize[0], 1)
hist = np.zeros(shape, dtype=np.float32)
gap = np.divide(ranges[1::2], bsize[0])
for row in image:
for val in row:
idx = np.divide(val[channels], gap).astype('uint')
hist[tuple(idx)] += 1
return hist
### cv2.calcHist()와 calc_histo()가 같은 결과를 내는지 테스트
image = cv2.imread("images/hue_hist.jpg", cv2.IMREAD_COLOR) # 영상읽기
if image is None: raise Exception("영상 파일 읽기 오류")
bsize, ranges = [64, 64, 64], [0,256,0,256,0,256]
my_hist = calc_histo(image, [0,1,2], bsize, ranges).astype('uint8')
cv_hist = cv2.calcHist([image], [0,1,2], None, bsize, ranges).astype('uint8')
diff = (my_hist - cv_hist).all()
print("cv2.calcHist()와 calc_histo()의 모든 원소의 차이는 %d으로" %diff, "같은" if diff == 0 else "다른", "결과를 가짐")
### 시각화로 비교
import matplotlib.pyplot as plt
fig, ax = plt.subplots(2,figsize=(15, 8))
my_b_hist = np.sum(my_hist, axis=(1, 2)) # B만 남기기
my_g_hist = np.sum(my_hist, axis=(0, 2)) # G만 남기기
my_r_hist = np.sum(my_hist, axis=(0, 1)) # R만 남기기
index = np.arange(64)
bar_width = 0.25
ax[0].bar(index, my_b_hist, bar_width,alpha=0.4, color='blue', label='B')
ax[0].bar(index + bar_width, my_g_hist, bar_width, alpha=0.4, color='green', label='G')
ax[0].bar(index + 2 * bar_width, my_r_hist, bar_width, alpha=0.4, color='red', label='R')
ax[0].legend(title='calc_histo()')
cv_b_hist = np.sum(cv_hist, axis=(1, 2)) # B만 남기기
cv_g_hist = np.sum(cv_hist, axis=(0, 2)) # G만 남기기
cv_r_hist = np.sum(cv_hist, axis=(0, 1)) # R만 남기기
ax[1].bar(index, cv_b_hist, bar_width,alpha=0.4, color='blue', label='B')
ax[1].bar(index + bar_width, cv_g_hist, bar_width, alpha=0.4, color='green', label='G')
ax[1].bar(index + 2 * bar_width, cv_r_hist, bar_width, alpha=0.4, color='red', label='R')
ax[1].legend(title='cv2.calcHist()')
plt.show()
13. 컬러 영상을 입력받아서 YCbCr 컬러 공간으로 변환하고 다시 환원하는 프로그램을 작성하시오. 단, cv2.cvtColor() 함수를 사용하지 않고, YCbCr 변환 수식에 따라서 직접 구현하시오.
import numpy as np, cv2
BGR_img = cv2.imread("images/color_space.jpg", cv2.IMREAD_COLOR) # 컬러 영상 읽기
if BGR_img is None: raise Exception("영상 파일 읽기 오류")
def BGR2YCrCb(img):
B,G,R = cv2.split(img.astype(np.float32))
Y = 0.299 * R + 0.587 * G + 0.114 * B
Cr = (R - Y) * 0.713 + 128
Cb = (B - Y) * 0.564 + 128
YCrCb = cv2.merge([Y, Cr, Cb])
YCrCb = np.clip(YCrCb, 0, 255).astype("uint8")
return YCrCb
def YCrCb2BGR(img):
Y, Cr, Cb = cv2.split(img.astype(np.float32))
R = Y + 1.403*(Cr-128)
G = Y - 0.714*(Cr-128) - 0.344 * (Cb-128)
B = Y + 1.773*(Cb-128)
BGR = cv2.merge([B,G,R])
BGR = np.clip(BGR, 0, 255).astype("uint8")
return BGR
YCC_img = BGR2YCrCb(BGR_img) # YCbCr 컬러 공간 변환
Y, Cr, Cb = cv2.split(YCC_img)
YCC_merged = np.hstack((Y, Cr, Cb))
restore_BGR_img = YCrCb2BGR(YCC_img)
cv2.imshow("Original BGR_img", BGR_img)
cv2.imshow("restored BGR_img", restore_BGR_img)
cv2.imshow("YCC_img: Y, Cr, Cb ", YCC_merged)
cv2.waitKey(0)
cv2.destroyAllWindows()
14. 컬러 영상 파일을 읽어 들여서 HSV 컬러 공간으로 변환하고, Hue와 Saturation 채널로 2차원 히스토그램을 그림과 같이 만드시오. 즉, 2차원 히스토그램의 Hue(세로)와 Saturation(가로)을 2개 축으로 구성하고, 빈도값을 밝기로 표현해서 오른쪽 그림과 같이 2차원 그래프로 그리시오.
import numpy as np, cv2
def draw_histo2(hist):
if hist.ndim != 2: print('2차원 히스토그램 아님')
h, w = hist.shape[:2]
graph = [[(i, j, hist[i,j]) for j in range(w)] for i in range(h)]
ratios = (180/h, 256/w, 256 )
graph= np.multiply(graph, ratios).astype('uint8')
bgr = cv2.cvtColor(graph, cv2.COLOR_HSV2BGR)
bgr = cv2.resize(bgr, None, fx=10, fy=10, interpolation=cv2.INTER_AREA)
return bgr
image = cv2.imread("images/Pink_flower.jpg", cv2.IMREAD_COLOR) # 영상읽기
if image is None: raise Exception("영상 파일 읽기 오류")
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
ch, bsize, ranges = [0, 1], [30, 48], [0, 180, 0, 256] # 히스토그램 간격수, 값 범위
hist = cv2.calcHist([hsv], ch, None, bsize, ranges) # OpenCV 함수
cv2.normalize(hist, hist, 0, 1, cv2.NORM_MINMAX)
dst = draw_histo2(hist)
cv2.imshow("dst", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
'Programming > Python' 카테고리의 다른 글
[OpenCV] OpenCV-Python으로 배우는 영상 처리 및 응용 - 5장 연습문제 풀이 (0) | 2025.06.30 |
---|---|
[OpenCV] OpenCV-Python으로 배우는 영상 처리 및 응용 - 4장 연습문제 풀이 (6) | 2025.06.30 |
[Jupyter extension] Jupyter 확장프로그램 개발 환경 구축 (1) | 2024.09.02 |
[OpenCV] 채널 별 배열 구조 + 이미지 투명화 (1) | 2023.10.17 |