딥러닝

[딥러닝] 평활화, 정규화, YCrCb, HSV, CLAHE, inRange(), copyTo()

Uno_says 2024. 8. 20. 15:00
728x90

1. 균등화, 평탄화(Equalization)

  • 히스토그램을 활용하여 이미지의 품질을 개선하기 위한 방법
  • 이미지의 대비를 증가시키는 데 유용하다. 특히 명암비가 낮아 어두운 부분이 많은 이미지에서 효과적이다.
  • 화소값을 0~255 사이에 고르게 분포하도록 개선
  • cv2.equalizeHist()

 

✔️ 히스토그램 평탄화를 적용하여 명암비 개선하기

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('img', img)
cv2.imshow('dst', dst)

hists = {'hist1': hist1, 'hist2': 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()

img, dst
밝기가 몰려있다가 퍼지면서 이미지가 명확해졌다.

 

 

 

2. 색공간

  • YCbCr
    • 색공간을 밝기 정보로 표현하는 방식
    • Y: 밝기 정보
  • HSV
    • 색을 표현하는 방법이자 색을 배치하는 방식
    • H(색상, 빨강녹색파랑), S(채도, 선명도), V(명도, 빛의 밝기)의 좌표를 색으로 지정

 

✔️ YCrCb 색 공간을 이용하여 평탄화하기

import cv2
 
img = cv2.imread('./field.bmp')

ycrcb = []
dst = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)  # BGR -> YCrCb로 변환, Y: 밝기, CrCb: 색차
ycrcb = cv2.split(dst)    # Y, Cr, Cb로 분리
ycrcb = list(ycrcb)       # 리스트로 변환
ycrcb[0] = cv2.equalizeHist(ycrcb[0])   # Y채널에 평탄화 적용
dst = cv2.merge(ycrcb)   # 다시 하나의 YCrCb 이미지로 병합
dst = cv2.cvtColor(dst, cv2.COLOR_YCrCb2BGR)   # YCrCb -> BGR로 변환

cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()

# split()와 merge()를 사용하지 않고 위 예제와 동일한 결과 영상 만들기
dst = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
dst[:, :, 0] = cv2.equalizeHist(dst[:, :, 0])
dst = cv2.cvtColor(dst, cv2.COLOR_YCrCb2BGR)

cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()




3. CLAHE(Contrast Limited Adaptive Histogram Equalization)

  • 평탄화를 하면 이미지의 밝은 부분이 날라가는 현상이 생길 수 있음
  • 이미지의 일정한 영역을 나누어 평탄화를 적용
  • CLAHE는 일반적인 히스토그램 평탄화와 달리, 이미지의 작은 영역에서 명암비를 조정하여 더 자연스러운 보정을 제공
  • 객체 = cv2.createCLAHE() -> 객체.apply(영상)

 

✔️ 평탄화와 CLAHE 비교하기

import cv2

img = cv2.imread('./field.bmp')
img = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)   # BGR -> YCrCb

img_eq = img.copy()
img_clahe = img.copy()
img = cv2.cvtColor(img, cv2.COLOR_YCrCb2BGR)   # 원래 이미지는 다시 BGR로 변환하여 저장

# 히스토그램 평탄화 적용
img_eq[:, :, 0] = cv2.equalizeHist(img_eq[:, :, 0])
img_eq = cv2.cvtColor(img_eq, cv2.COLOR_YCrCb2BGR)

# CLAHE 적용
# clipLimit: 명암비 제한 설정, tileGridSize: 이미지를 타일로 나누는 그리드 크기 설정
clahe = cv2.createCLAHE(clipLimit=2, tileGridSize=(4, 4))
img_clahe[:, :, 0] = clahe.apply(img_clahe[:, :, o])  # CLAHE를 img_clahe의 Y채널에 적용
img_clahe = cv2.cvtColor(img_clahe, cv2.COLOR_YCrCb2BGR)

cv2.imshow('img', img)
cv2.imshow('img_eq', img_eq)
cv2.imshow('img_clahe', img_clahe)
cv2.waitKey()

 

 

 

4. 정규화(Normalization)

  • 특정 영역에 값이 몰려 있는 경우 화질을 개선하고, 이미지 간의 연산 시 서로 조건이 다른 경우 같은 조건으로 변경
  • cv2.normalize()
    • cv2.NORM_MINMAX: 최솟값과 최댓값 계산
    • cv2.NORM_L1: 전체 합으로 나눔
    • cv2.NORM_L2: 단위 벡터로 정규화
    • cv2.NORM_INF: 최댓값으로 나눔

 

✔️ 이미지를 정규화하고 히스토그램 비교하기

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('./Hawkes.jpg', cv2.IMREAD_GRAYSCALE)

# 밝기 값을 0에서 255사이의 범위로 정규화
# 이미지의 최소값을 0으로, 최대값을 255로 스케일링
img_norm = cv2.normalize(img, None, 0, 255, cv2.NORM_MINMAX)  

# 히스토그램 계산
hist = cv2.calHist([img], [0], None, [256], [0, 255])
hist_norm = cv2.calcHist([img_norm], [0], None, [256], [0 255])

cv2.imshow('img', img)
cv2.imshow('img_norm', img_norm)

hists = {'hist': hist, 'hist_norm': 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()

img, img_norm

 

 

 

5. 색상 추출

  • 영상에서 지정된 범위 안에 픽셀을 선택
  • cv2.inRange()
  • BGR에서 녹색계열
    • 0 <= B <= 100
    • 128 <= G <= 255
    • 0 <= R <= 100
  • HSV에서 녹색계열
    • 50 <= H <= 80
    • 150 <= S <= 255
    • 0 <= V <= 255

 

 ✔️ 녹색계열을 필터링하고, 그 결과를 바이너리 이미지로 표시하기

import cv2

img = cv2.imread('./candies.png')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)    # BGR -> HSV(색조, 채도, 명도)

# 특정 색상 범위 필터링
# (50, 150, 0)은 하한 값, (80, 255, 255)은 상한 값으로, 이 범위 내의 색상만 선택됨
# 결과로 dst는 바이너리 이미지로, 지정된 색상 범위에 해당하는 픽셀은 흰색(255), 그렇지 않은 픽셀은 검은색(0)으로 표시됨
dst = cv2.inRange(hsv, (50, 150, 0), (80, 255, 255))

cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()

 

 

 

6. 마스크 연산

  • 마스크 연산을 지원하는 픽셀 값 복사 함수
  • cv2.copyTo()

 

✔️ 마스크 이미지를 활용하여 복사, 합성하기

import cv2

img = cv2.imread('./airplane.bmp')   # 복사할 소스 이미지
mask = cv2.imread('./mask_plane.bmp')  # img의 복사될 영역을 지정
dst = cv2.imread('./field.bmp')   # img가 복사될 대상 이미지

temp = cv2.copyTo(img, mask)   # img 이미지를 mask의 흰색 부분에 해당하는 영역에만 복사함
cv2.copyTo(img, mask, dst)   # img 이미지를 dst 이미지에 mask에 해당하는 부분만 복사하여 덮어씀

cv2.imshow('img', img)
cv2.imshow('mask', mask)
cv2.imshow('temp', temp)
cv2.imshow('dst', dst)
cv2.waitKey()

 

 

✔️ 크로마키 영상 다루기

import cv2

cap1 = cv2.VideoCapture('./woman.mp4')
cap2 = cv2.VideoCapture('./sea.mp4')

w = round(cap1.get(cv2.CAP_PROP_FRAME_WIDTH))   # 'woman.mp4'의 너비
h = round(cap1.get(cv2.CAP_PROP_FRAME_HEIGHT))   # 'woman.mp4'의 높이

frame_cnt1 = round(cap1.get(cv2.CAP_PROP_FRAME_COUNT)   # 'woman.mp4'의 총 프레임 수
frame_cnt2 = round(cap2.get(cv2.CAP_PROP_FRAME_COUNT)   # 'sea.mp4'의 총 프레임 수
fps = round(cap1.get(cv2.CAP_PROP_FPS))    # 'woman.mp4'의 초당 프레임 수

print(w)
print(h)
print(frame_cnt1)
print(frame_cnt2)
print(fps)

while True:
	ret1, frame1 = cap1.read()    # 'woman.mp4' 프레임 읽어오기
    if not ret1:       # 프레임 읽지 못하면 종료
    	break
    ret2, frame2 = cap2.read()     # 'sea.mp4' 프레임 읽어오기
    if not ret2:
    	break
        
    hsv = cv2.cvtColor(frame1, cv2.COLOR_BGR2HSV)   # BGR -> HSV 색공간 변환
    mask = cv2.inRange(hsv, (50, 150, 0), (70, 255, 255))  # 특정 색상 범위 선택을 위한 마스크 생성
    cv2.copyTo(frame2, mask, frame1)  # frame2에서 마스크가 적용된 영역만큼 frame1에 복사함
    cv2.imshow('frame1', frame1)
    key = cv2.waitKey(10)   # 10ms 동안 키 입력 대기
    if key == ord(' '):   # 스페이스바가 눌리면, 프로그램이 멈추가 추가 키 입력 대기
    	cv2.waitKey()
    elif key == 27:
    	break
        
cap1.release()
cap2.release()

728x90