Python(51)- CLAHE(평탄화), 색상추출, hist
*이 글을 읽기전에 작성자 개인의견이 있으니, 다른 블로그와 교차로 읽는것을 권장합니다.*
1_keyEvent
키보드 이벤트
cv2.waitKey()
delay: 밀리초 단위 대기(0보다 작거나 같으면 무한정 기다림. 기본값은 0)
반환값: 눌려진 키의 아스키 코드값(ESC: 27, ENTER: 13, TAB:9)
import cv2
img = cv2.imread('./dog.bmp')
cv2.imshow('img', img)
while True:
keyvalue = cv2.waitKey()
if keyvalue == ord('i') or keyvalue == ord('I'):
img = ~img
cv2.imshow('img', img)
elif keyvalue == 27:
break
2_mouseEvent
마우스 이벤트
cv2.setMouseCallback(윈도우이름, 콜백함수, 파라미터)
윈도우이름: 마우스 이벤트를 처리할 윈도우 장의 이름
콜백함수: 마우스 이벤트가 발생할 때 호출될 콜백 함수를 설정
파라미터: 콜백함수에 전달할 추가적인 정보
콜백함수를 만드는 방법
def 함수명(event, x, y, flage, param):
pass
event: 이벤트 객체
x, y: 마우스, x, y좌표
flags: 마우스 버튼이 눌리고 있는지, 떼졌는지 여부
param: 추가적인 정보가 전달되었다면 저장
import cv2
import numpy as np
oldx = oldy = 0
def on_mouse(event, x, y, flags, param):
global oldx, oldy
if event == cv2.EVENT_LBUTTONDOWN:
print('왼쪽버튼이 눌렸어요: %d, %d' % (x, y))
oldx, oldy = x, y
elif event == cv2.EVENT_LBUTTONUP:
print('왼쪽버튼이 떼졌어요: %d, %d' % (x, y))
elif event == cv2.EVENT_MOUSEMOVE:
if flags & cv2.EVENT_FLAG_LBUTTON:
# print('드래그 중이에요: %d, %d' % (x, y))
cv2.line(img, (oldx,oldy), (x,y), (255,51,255), 3)
cv2.imshow('img',img)
oldx, oldy = x, y
img = np.ones((500,500,3), dtype=np.uint8) * 255
cv2.namedWindow('img') # 창이름을 먼저 세팅
cv2.setMouseCallback('img', on_mouse)
cv2.imshow('img', img)
cv2.waitKey()
3_BGR
영상의 화소처리
영상의 특정 좌표 픽셀값을 변경하여 출력 영상의 좌표 픽셀을 설정하는 모든 연산
밝기 조절: 영상을 전체적으로 밝게하거나 어둡게 하는 연산
cv2.add(), cv2.subtract(), cv2.multiply(), cv2.divide()
cv2.addWeighted(): 두 영상의 같은 위치에 존재하는 픽셀값에 대하여 가중합을 계산해서 결과 영상의 픽셀값으로 설정(가중치의 합이 1이 됨)
cv2.absdiff(): 두 영상의 픽셀 값을 빼면 음수가 나올 수 있는데 해당 값에 절대값을 취한 값
import cv2
img1 = cv2.imread('./dog.bmp', cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread('./dog.bmp')
dst1 = cv2.add(img1, 100)
dst2 = cv2.add(img2, (100, 100, 100, 0)) # BGR순서, (255, 255, 255, 3)
dst3 = cv2.subtract(img1, 100)
dst4 = cv2.multiply(img1, 10)
dst5 = cv2.divide(img1, 10)
cv2.imshow('img1', img1)
cv2.imshow('img2', img2)
cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.imshow('dst3', dst3)
cv2.imshow('dst4', dst4)
cv2.imshow('dst5', dst5)
cv2.waitKey()
4_blending
import cv2
import matplotlib.pyplot as plt
img1 = cv2.imread('./man.jpg')
img2 = cv2.imread('./turkey.jpg')
# img1 + img2: 255을 넘어갈 경우 해당값의 256을 빼서 표현
dst1 = img1 + img2
# cv2.add(): 255를 넘어갈 경우 255로 고정
dst2 = cv2.add(img1, img2)
# cv2.imshow('dst1,', dst1)
# cv2.imshow('dst2,', dst2)
# cv2.waitKey()
img = {'img1': img1, 'img2': img2, 'dst1': dst1, 'dst2': dst2}
for i, (k, v) in enumerate(img.items()):
plt.subplot(2, 2, i+1)
plt.imshow(v[:, :, ::-1])
plt.title(k)
plt.show()
5_addWeighted
import cv2
import matplotlib.pyplot as plt
import numpy as np
img1 = cv2.imread('./man.jpg')
img2 = cv2.imread('./turkey.jpg')
alpha = 0.7
dst1 = cv2.addWeighted(img1, alpha, img2, (1-alpha), 0)
dst2 = img1 * alpha + img2 * (1-alpha)
dst2 = dst2.astype(np.uint8)
img = {'img1': img1, 'img2': img2, 'dst1': dst1, 'dst2': dst2}
for i, (k, v) in enumerate(img.items()):
plt.subplot(2, 2, i+1)
plt.imshow(v[:, :, ::-1])
plt.title(k)
plt.show()
6_arithmetic
# add, addWeighted, subtract, absdiff
# absdiff(img1, img2)
# cv2.absdiff(): 두 영상의 픽셀 값을 빼면 음수가 나올 수 있는데 해당 값에 절대값을 취한 값
# matplotlib의 subplot을 이용하여 4가지 연산을 비교
import cv2
import matplotlib.pyplot as plt
img1 = cv2.imread('./dog.jpg')
img2 = cv2.imread('./square.bmp')
dst1 = cv2.add(img1, img2)
dst2 = cv2.addWeighted(img1, 0.5, img2, 0.5, 0)
dst3 = cv2.subtract(img1, img2)
dst4 = cv2.absdiff(img1, img2)
img = {'dst1': dst1, 'dst2': dst2, 'dst3': dst3, 'dst4': dst4}
for i, (k, v) in enumerate(img.items()):
plt.subplot(2, 2, i+1)
plt.imshow(v[:, :, ::-1])
plt.title(k)
plt.show()
7_color
컬러 영상과 색
- 컬러 영상은 3차원 배열
- numpy.ndarray
- img.shape: (h, w, 3) -> opencv에서는 BGR, (높이, 너비, 채널)
- 색상 채널 분리: cv2.split(영상)
- 색상 채널 결합: cv2.merge(입력 영상 채널의 리스트 또는 튜플)
import cv2
img = cv2.imread('./candies.png')
print('shape: ', img.shape)
print('dtype: ', img.dtype)
'''
b = img[:, :, 0]
g = img[:, :, 1]
r = img[:, :, 2]
'''
b, g, r = cv2.split(img)
cv2.imshow('img', img)
cv2.imshow('b',b)
cv2.imshow('g',g)
cv2.imshow('r',r)
cv2.waitKey()
8_hist
히스토그램(histogram)
영상의 픽셀값 분포를 그래프 형태로 표현
예) 그레이스케일 영상에서 밝기 정보에 해당하는 픽셀의 개수를 구하고 막대 그래프로 표현
cv2.calcHist(영상, 채널, None, 빈의 개수를 나타내는 리스트, 각 차원의 최소값과 최대값으로 구성된 리스트) # None은 C언어의 pointer에 해당하는 값 = 조절못하기에 None처리
영상과 히스토그램의 관계
- 밝은 영상이면 히스토그램이 전체적으로 오른쪽으로 치우쳐져 있음
- 어두운 영상이면 히스토그램이 전체적으로 왼쪽으로 치우쳐져 있음
- 명암비가 확실한 영상이면 히스토그램이 양쪽으로 분포해 있음
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('./dog.bmp', cv2.IMREAD_GRAYSCALE)
hist = cv2.calcHist([img], [0], None, [256], [0, 255])
cv2.imshow('img', img)
plt.plot(hist)
plt.show()
cv2.waitKey()
# dog, bmp 영상을 컬러로 불러와 3채널을 계산하여 히스토그램 그리기
# 단, subplot을 사용하여 RGB 그래프 그리기(색상을 다르게 표현)
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('./dog.bmp')
colors = ['b', 'g', 'r']
bgr = cv2.split(img)
for (b,c) in zip(bgr, colors):
hist = cv2.calcHist([b], [0], None, [256], [0,255])
plt.plot(hist, color=c)
cv2.imshow('img',img)
plt.show()
cv2.waitKey()
10_equalize
균등화, 평탄화(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()
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('./field.bmp')
ycrcb = []
dst = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
ycrcb = cv2.split(dst)
ycrcb = list(ycrcb)
# print(ycrcb)
ycrcb[0] = cv2.equalizeHist(ycrcb[0])
dst = cv2.merge(ycrcb)
dst = cv2.cvtColor(dst, cv2.COLOR_YCrCb2BGR)
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()
색공간
YCbCr
- 색공간을 밝기 정보로 표현하는 방식
- Y: 밝기 정보
- YCbCr을 줄여서 YCC라고도 부름
HSV
- 색을 표현하는 방법이자 색을 배치하는 방식
- H(색상, 빨강녹색파랑), S(채도, 선명도), V(명도, 빛의 밝기)
11_CLAHE
CLAHE(Contrast Limited Adaptive Histogram Equalization)
- 평탄화를 하면 이미지의 밝은 부분이 날라가는 현상을 보정하기 위해 사용
- 이미지의 일정한 영역으로 나누어 평탄화를 적용
객체 = cv2.createCLAHE()
객체.apply(영상)
import cv2
img = cv2.imread('./field.bmp')
dst = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
img_eq = dst.copy()
img_clahe = dst.copy()
img_eq[:, :, 0] = cv2.equalizeHist(img_eq[:, :, 0])
img_eq = cv2.cvtColor(img_eq, cv2.COLOR_YCrCb2BGR)
clahe = cv2.createCLAHE(clipLimit = 4, tileGridSize=(4,4))
img_clahe[:, :, 0] = clahe.apply(img_clahe[:, :, 0])
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()
12_normalize
정규화(Normalization)
- 특정 영역에 값이 몰려 있는 경우, 화질을 개선하고 이미지간의 연산 시 서로 조건이 다른 경우, 같은 조건으로 변경
cv2.normalize()
cv2.NORM_MINMIAX: 최소값과 최대값 구간
cv2.NORM_L1: 전체 합으로 나눔
cv2.NORM_L2: 단위 벡터로 정규화
cv2.NROM_INF: 최대값으로 나눔
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('./Hawkes.jpg', cv2.IMREAD_GRAYSCALE)
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('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()
13_inRange
색상 추출
영상에서 지정된 범위안에 픽셀을 선택
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)
'''
HSV에서의 녹색계열
50 <= H <= 80
150 <= S <= 255
0 <= V <= 255
'''
dst = cv2.inRange(hsv, (50,150,0), (80,255,255)) # 색상추출
cv2.imshow('img', img)
cv2.imshow('dst', dst)
cv2.waitKey()
14_copyTo
마스크 연산
마스크 연산을 지원하는 픽셀 값 복사 함수
cv2.copyTo()
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('img', img)
cv2.imshow('mask', mask)
cv2.imshow('temp', temp)
cv2.imshow('dst',dst)
cv2.waitKey()