본문 바로가기

딥러닝

[딥러닝] 키이벤트, 마우스이벤트, 화소처리, 히스토그램

728x90

1. 키보드 이벤트

  • cv2.waitKey(delay)
  • delay:  밀리초 단위 대기(0보다 작거나 같으면 무한정 기다림. 기본값은 0)
  • 반환값: 눌려진 키의 아스키 코드값(ESC: 27, ENTER:13, TAB: 9 ..)

 

✔️ 'i' 또는 'I' 키를 누를 때마다 이미지의 색상 반전시키기

import cv2

img = cv2.imread('./dog.bmp')
cv2.imshow('img', img)

while True:
	keyvalue = cv2.waitKey()   # 키 입력을 대기
    if keyvalue == ord('i') or keyvalue == ord('I'):    # 소문자 i와 대문자 I의 ASCII 값
    	img = ~img    # 이미지 색상을 반전
        cv2.imshow('img', img)
    elif keyvalue == 27:
    	break

'i'키 누르면 색 반전됨

2. 마우스 이벤트

  • cv2.setMouseCallback(윈도우이름, 콜백함수)
  • 윈도우이름: 마우스 이벤트를 처리할 창의 이름
  • 콜백함수: 마우스 이벤트가 발생할 때 자동으로 호출될 함수를 설정

콜백함수를 만드는 방법

def 함수명(event, x, y, flags, 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:  # 왼쪽 버튼 눌린 상태라면, 이전 좌표에서 현재 좌표까지 선 그리기
        	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  # 이미지 초기화: 흰색 배경의 500x500 이미지 생성
cv2.imshow('img', img)
cv2.setMouseCallback('img', on_mouse)   # 마우스 이벤트 등록
cv2.waitKey()

 

 

3. 영상의 화소처리

-> 영상의 특정 좌표 픽셀값을 변경하여 출력 영상의 좌표 픽셀을 설정하는 모든 연산

 

밝기 조절: 영상을 전체적으로 밝게 하거나 어둡게 하는 연산

  • 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)     # img1의 각 픽셀 값에 100을 더함 -> 전체적으로 밝아짐
dst2 = cv2.add(img2, (100, 100, 100, 0))    # (R,G,B)값이 100씩 증가 -> 전체적으로 밝아짐
dst3 = cv2.subtract(img1, 10)   # 100을 뺌 -> 전체적으로 어두워짐
dst4 = cv2.multiply(img1, 10)   # 픽셀 값을 10배 증가 -> 밝은 부분이 더 강조, 어두운 부분은 하얗게
dst5 = cv2.divide(img1, 10)   # 전체적으로 어두워짐

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

 

 

✔️ '+' 와 'add()' 연산 비교하기

import cv2
import matplotlib.pyplot as plt

img1 = cv2.imread('./man.jpg')
img2 = cv2.imread('./turkey.jpg')

dst1 = img1 + img2  # RGB 값들을 단순하게 더하는 방식 -> 값이 255를 초과하면 넘치는 값 그대로 사용됨
dst2 = cv2.add(img1, img2)  # 각 픽셀 값이 255를 넘지 않도록 클리핑함

cv2.imshow('dst1', dst1)
cv2.imshow('dst2', dst2)
cv2.waitKey()

'dst1'에서 이상한 결과가 보임

# matplotlib으로 비교하기
img = {'img': 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])  # BGR -> RGB로 변환
    plt.title(k)
    
plt.show()

 

 

✔️ cv2.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    # img1의 가중치는 0.7, img2의 가중치는 (1-alpha)
dst1 = cv2.addWeighted(img1, alpha, img2, (1-alpha), 0)    # 가중치에 따라 혼합, gamma는 0
dst2 = img1 * alpha + img2 * (1-alpha)   # numpy를 사용하여 두 이미지를 가중치에 따라 혼합
dst2 = dst2.astype(np.uint8)  # uing8형식으로 변환하여 OpenCV와 호환되도록 함

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()

 

 

✔️ 두 이미지를 다양한 방식으로 합성하기

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)   # 가중치가 각각 0.5이므로, 평균을 낸 것과 같음 -> 부드럽게 섞임
dst3 = cv2.subtract(img1, img2)   # 이미지의 차이점이 강조됨
dst4 = cv2.absdiff(img1, img2)  # 절대 차이 계산 -> dst3보다 차이를 더 명확하게 표현함

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()

 

 

 

4. 컬러 영상과 색

  • 컬러영상은 3차원 배열
  • numpy.ndarray
  • img.shape: (h, 2, 3) -> OpenCV에서는 BGR, (높이, 너비, 채널)
  • 색상 채널 분리: cv2.split(영상)
  • 색상 채널 결합: cv2.merge(입력 영상 채널의 리스트 또는 튜플)

 

✔️ 색상 채널 분리하기

import cv2

img = cv2.imread('./candies.png')
print('shape: ', img.shape)   # (높이, 너비, 채널 수)
print('dtype: ', img.dtype)

# b, g, r = cv2.split(img)
# 위와 같이 함수 쓰지 않고 더 간편하게 분리하기
b = img[:, :, 0]    # blue 채널
g = img[:, :, 1]    # green 채널
r = img[:, :, 2]    # red 채널

cv2.imshoW('img', img)
cv2.imshow('b', b)    # blue 부분이 밝게
cv2.imshow('g', g)    # green 부분이 밝게
cv2.imshow('r', r)    # red 부분이 밝게
cv2.waitKey()

 

 

 

5. 히스토그램(histogram)

  • 영상의 픽셀값 분포를 그래프 형태로 표현
  • 예) 그레이스케일 영상에서 밝기 정보에 해당하는 픽셀의 개수를 구하고 막대 그래프로 표현
  • cv2.calcHist(영상, 채널, None, 빈의 개수를 나타내는 리스트, 각 차원의 최솟값과 최댓값으로 구성된 리스트)
    • 채널: 히스토그램을 계산할 채널
    • None: 특정 영역만 히스토그램을 계산할 때 사용할 마스크. None을 설정하면 전체 이미지에 대해 계산
    • 빈의 개수를 나타내는 리스트: 빈의 수를 지정. 보통 256를 사용. 0~255까지
    • 각 차원의 최솟값과 최댓값으로 구성된 리스트: 범위를 지정. 보통 [0, 255] 사용

 

✔️ 그레이스케일 이미지의 히스토그램 계산하기

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.show()
cv2.waitKey()
  • cv2.calcHist()
    • [img]: 입력 이미지 리스트이다. 여러 이미지를 처리할 수 있도록 리스트로 입력된다.
    • [0]: 계산할 채널을 지정한다. '0'은 그레이스케일 이미지를 의미한다.
    • None: 마스크를 사용하지 않음을 의미한다.
    • [256]: 히스토그램의 빈 개수를 지정한다. 그레이스케일 이미지는 256개의 톤(0~255)을 가지므로, 256으로 설정한다.
    • [0, 255]: 픽셀 값의 범위를 지정한다.

 

 

 

✔️ 컬러 이미지의 히스토그램 계산하기

# dog.bmp 영상을 컬러로 불러와 3채널을 계산하여 히스토그램 그리기
# 단, 하나의 plot에서 BGR 그래프를 그리기(색상을 다르게 표현)

import cv2
import matplotlib.pyplot as plt

img = cv2.imread('./dog.bmp')

colors = ['b', 'g', 'r']
bgr = cv2.split(img)   # 이미지의 채널을 분리하여 bgr리스트에 저장

for (b, c) in zip(bgr, colors):
	hist = cv2.calcHist([b], [0], None, [256], [0, 255])
    plt.plot(hist, color = c)  # Blue, Green, Red 각각의 채널에 해당하는 히스토그램이 그려짐
    
cv2.imshow('img', img)
plt.show()
cv2.waitKey()

각 색상 채널의 픽셀 값 분포를 확인할 수 있다

 

728x90