이미지 처리 기법 및 OpenCV 활용 예제
이번 포스팅에서는 이미지 처리 기법 중 히스토그램 평탄화(Equalization), 색공간 변환, CLAHE, 정규화, 색상 추출, 마스크 연산 등 다양한 기술을 OpenCV를 이용해 다뤄보겠습니다.
히스토그램을 활용해 이미지의 품질을 개선하는 기법입니다. 이미지의 화소 값을 0~255 사이에 고르게 분포시키는 방식으로, 명암 대비를 향상시킬 수 있습니다.
import cv2 import matplotlib.pyplot as plt #그레이스케일 이미지 불러오기 img = cv2.imread('./Hawkes.jpg', cv2.IMREAD_GRAYSCALE) #히스토그램 평탄화 dst = cv2.equalizeHist(img) #원본 이미지와 평탄화된 이미지의 히스토그램 계산 hist1 = cv2.calcHist([img], [0], None, [256], [0, 255]) hist2 = cv2.calcHist([dst], [0], None, [256], [0, 255]) #결과 이미지와 히스토그램 표시 cv2.imshow('Original Image', img) cv2.imshow('Equalized Image', dst) #히스토그램 시각화 hists = {'Original Histogram': hist1, 'Equalized Histogram': hist2} plt.figure(figsize=(12, 8)) for i, (k, v) in enumerate(hists.items()): plt.subplot(1, 2, i + 1) plt.title(k) plt.plot(v) plt.show() cv2.waitKey(0) cv2.destroyAllWindows()결과
![]()
![]()
색상 정보를 밝기와 색 성분으로 나누어 표현하는 방법입니다. 주로 YCrCb와 HSV 색공간을 자주 사용합니다.
YCrCb: 밝기 정보(Y)와 색차 정보(Cr, Cb)로 구성.
HSV: 색상(Hue), 채도(Saturation), 명도(Value)로 구성.
import cv2 img = cv2.imread('./field.bmp') # BGR을 YCrCb로 변환 dst = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb) # 밝기 채널(Y)에만 평탄화 적용 dst[:, :, 0] = cv2.equalizeHist(dst[:, :, 0]) # YCrCb를 다시 BGR로 변환 dst = cv2.cvtColor(dst, cv2.COLOR_YCrCb2BGR) # 결과 이미지 출력 cv2.imshow('Original Image', img) cv2.imshow('Equalized YCrCb Image', dst) cv2.waitKey(0) cv2.destroyAllWindows()결과
평탄화를 적용할 때 이미지의 밝은 부분이 손실될 수 있습니다. CLAHE는 이미지를 일정한 영역으로 나눠서 각각에 대해 평탄화를 적용해 이런 문제를 해결합니다.
import cv2 img = cv2.imread('./field.bmp') img = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb) #기본 평탄화 img_eq = img.copy() img_eq[:, :, 0] = cv2.equalizeHist(img_eq[:, :, 0]) img_eq = cv2.cvtColor(img_eq, cv2.COLOR_YCrCb2BGR) #CLAHE 적용 clahe = cv2.createCLAHE(clipLimit=1, tileGridSize=(4, 4)) img_clahe = img.copy() img_clahe[:, :, 0] = clahe.apply(img_clahe[:, :, 0]) img_clahe = cv2.cvtColor(img_clahe, cv2.COLOR_YCrCb2BGR) #결과 이미지 출력 cv2.imshow('Original Image', img) cv2.imshow('Equalized Image', img_eq) cv2.imshow('CLAHE Image', img_clahe) cv2.waitKey(0) cv2.destroyAllWindows()결과
특정 영역에 값이 몰려 있는 경우 화질을 개선하거나, 이미지 간의 연산 시 조건을 맞추기 위해 정규화를 사용합니다.
import cv2 import matplotlib.pyplot as plt img = cv2.imread('./Hawkes.jpg', cv2.IMREAD_GRAYSCALE) #정규화 적용 (NORM_MINMAX) img_norm = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX) #히스토그램 계산 hist = cv2.calcHist([img], [0], None, [256], [0, 255]) hist_norm = cv2.calcHist([img_norm], [0], None, [256], [0, 255]) #결과 이미지 출력 cv2.imshow('Original Image', img) cv2.imshow('Normalized Image', img_norm) #히스토그램 시각화 hists = {'Original Histogram': hist, 'Normalized Histogram': hist_norm} for i, (k, v) in enumerate(hists.items()): plt.subplot(1, 2, i + 1) plt.title(k) plt.plot(v) plt.show() cv2.waitKey(0) cv2.destroyAllWindows()
특정 색상 범위에 해당하는 픽셀을 선택하여 마스크를 생성합니다. 예를 들어, 녹색 계열을 추출할 때 사용합니다.
import cv2 img = cv2.imread('./MNM.png') hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) #HSV 색상 범위에서 녹색 계열 추출 lower_green = (50, 150, 0) upper_green = (80, 255, 255) mask = cv2.inRange(hsv, lower_green, upper_green) #결과 이미지 출력 cv2.imshow('Original Image', img) cv2.imshow('Green Mask', mask) cv2.waitKey(0) cv2.destroyAllWindows()결과
특정 마스크를 사용하여 픽셀 값을 복사하거나 변경할 때 사용됩니다.
import cv2 img = cv2.imread('./airplane.bmp') mask = cv2.imread('./mask_plane.bmp') dst = cv2.imread('./field.bmp') #마스크 연산을 이용해 이미지 복사 temp = cv2.copyTo(img, mask) cv2.copyTo(img, mask, dst) #결과 이미지 출력 cv2.imshow('Original Image', img) cv2.imshow('Mask', mask) cv2.imshow('Temp Result', temp) cv2.imshow('Final Result', dst) cv2.waitKey(0) cv2.destroyAllWindows()결과
두 개의 동영상을 불러와서 하나의 영상에서 특정 색상 마스크를 적용해 다른 영상에 합성하는 예제입니다.
import cv2 cap1 = cv2.VideoCapture('./woman.mp4') cap2 = cv2.VideoCapture('./sea.mp4') #영상 크기 및 프레임 정보 가져오기 w = round(cap1.get(cv2.CAP_PROP_FRAME_WIDTH)) h = round(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT)) fps = round(cap1.get(cv2.CAP_PROP_FPS)) while True: ret1, frame1 = cap1.read() if not ret1: break ret2, frame2 = cap2.read() if not ret2: break #HSV 색공간으로 변환 후 녹색 계열 마스크 생성 hsv = cv2.cvtColor(frame1, cv2.COLOR_BGR2HSV) mask = cv2.inRange(hsv, (50, 150, 0), (70, 255, 255)) # 마스크를 적용해 두 영상을 합성 cv2.copyTo(frame2, mask, frame1) cv2.imshow('Merged Video', frame1) key = cv2.waitKey(10) if key == ord(' '): cv2.waitKey() elif key == 27: break cap1.release() cap2.release() cv2.destroyAllWindows()결과