본문 바로가기
Image Processing/OpenCV

[OpenCV] 사용자 인터페이스

by AteN 2022. 11. 9.

영상처리는 무엇이라 생각하는가? 영상처리를 한다미로 말하면 2차원 행렬에 대한 연산이라고 할 수 있다

OpenCV 에서는 원도우 (window, 창)가 활성화된 상태에서만 마우스나 키보드 이벤트를 감지 할 수 있다. 따라서 이런 이벤트를 감지 해서 처리하려면 원도우를 생성하고 제어할 수 있어야 한다

윈도우 제어

  • cv2.namedWindow() : 원도우 이름을 설정한 후, 해당 이름으로 원도우 생성
    • namedWindow(winname[,flags])
  • cv2.imshow() : 원도우 이름의 mat 행렬을 영상으로 표시함
    • imshow(winname, mat)
  • cv2.destroyAllWindows() : 인수로 지정된 타이들 원도우 파괴
  • cv2.moveWindow() : winname 이름의 원도우를 지정된 위치인 (x,y)로 이동, (기존위치는 좌측 상단 )
    • moveWindow(winname, x, y)
  • cv2.resizeWindow() : 윈도우 크기 재조정
    • resizeWindow(winname, width, height)
import numpy as np
import cv2
 
image = np.zeros((200, 400), np.uint8) # 행렬 생성
image[:] = 200 # 밝은 회색(200) 바탕 영상 생성
 
title1, title2 = 'Position1','Position2'
cv2.namedWindow(title1, cv2.WINDOW_AUTOSIZE) # 원도우 생성 및 크기 조정 옵션
cv2.namedWindow(title2)
cv2.moveWindow(title1, 150, 150) # 윈도우 이동 - 위치 지정
cv2.moveWindow(title2, 400, 50)

cv2.imshow(title1, image) # 행렬 원소를 영상으로 표시
cv2.imshow(title2, image)
cv2.waitKey(0) # 키 이벤트 대기
cv2.destroyAllWindows() # 열린 모든 윈도우 파괴 

 

윈도우의 크기 변경

import numpy as np
import cv2

image = np.zeros((200, 400), np.uint8) # ndarray 행렬 생성
image.fill(255) # 모든 원소에 255(흰색) 지정

title1, title2 = 'AUTOSIZE','NORMAL'
cv2.namedWindow(title1, cv2.WINDOW_AUTOSIZE) # 원도우 생성 - 크기 변경 불가
cv2.namedWindow(title2, cv2.WINDOW_NORMAL) # 크기 변경 가능
# 윈도우 생성은 두가지 옵션 가능
# cv2.WINDOW_AUTOSIZE -> 크기 변경 불가
# cv2.WINDOW_NORMAL -> 크기 변경 가능
cv2.imshow(title1, image)
cv2.imshow(title2, image)
# ------------------------------
cv2.moveWindow(title1, 400, 300) # 크기 변경 불가
cv2.moveWindow(title2, 400, 300) # 크기 변경 가능
# -------------------------------
cv2.waitKey(0)
cv2.destroyAllWindows()

 

이벤트 처리 함수

  • 일반적으로 이벤트를 처리하기 위해 콜백(Callback) 함수를 사용한다
  • openCV 에서 대표적으로 키보드 이벤트, 마우스 이벤트, 트랙바(trackbar) 이벤트를 처리하는 콜백 함수들이 있다

키보드 이벤트 제어

  • cv2.waitKey() : delay : ms(milisscond) 시간 만큼 키 입력을 대기 하고, 키 이벤트가 발생하면 해당 키 값 반환
    • waitKey([,delay])
    • delay <= 0 : 키이벤트 발생까지 무한대기, delay < 0 : 지연시간 동안 키 입력 대기, 지연시간 안에 키 이벤트 없으면 -1 반환
  • cv2.waitKeyEX() : waitKey() 와 동일하지만, 전체 키 코드(full key code)를 반환, 화살표 키 등을 입력 받을 때 사용
    • waitKeyEX([,delay])
import numpy as np
import cv2
switch_case = {
    ord('a'): "a키 입력", # ord() 함수 문자 -> 아스키 코드 변환
    ord('b'): "b키 입력",
    0x41 : "A키 입력",
    int('0x42', 16) : "B키 입력", # 0x42(16진수) -> 10진수 변환
    2424832 : "왼쪽 화살표 입력", # 0x250000
    2490368 : "윗쪽 화살표 입력", # 0x260000
    2555904 : "오른쪽 화살표 입력", # 0x270000
    2621440 : "아래쪽 화살표 입력", # 0x280000
}
 
image = np.ones((200, 300), np.float) # 원소값 1인 행렬 생성
cv2.namedWindow("Keyboard Event")
cv2.imshow("keyboard Event", image)

while True: # 무한 반복
    key = cv2.waitKeyEx(100) # 100ms 동안 키 이벤트 대기
    if key == 27: break # ESC 누르면 종료

    try:

        result = switch_case[key]
        print(result)
    except KeyError:
        result = -1

cv2.destroyAllWindows()

마우스 이벤트 제어

  • 마우스 이벤트는 openCV 가 제공하는 콜백 함수로 제어할 수 있다
  • setMouseCallback() 함수를 통해서 시스템에 등록하고 시스템이 마우스 이벤트를 감지했을대 사용자가 만든 콜백 함수를 호출한다
  • def setMouseCallback(windowName, onMouse, param=None) - 사용자가 정의한 마우스 콜백 함수에 등록
  • onMouse (event, x, y ,flags, param=None)
    • event : 발생한 이벤트 종류
    • x,y : 이벤트에 발생 시 마우스 포인트의 좌표
    • flags : 마우스버튼과 동시에 특수키([Shift], [Alt], [Ctrl])를 눌렀는지 여부
    • param : 콜백함수로 전달하는 추가적인 사용자 정의 인수
import numpy as np
import cv2
def onMouse(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        print("Left down")
    elif event == cv2.EVENT_RBUTTONDOWN:
        print("Right Down")
    elif event == cv2.EVENT_RBUTTONUP:
        print("Right up")
    elif event == cv2.EVENT_LBUTTONDBLCLK:
        print("Left Double Click")

image = np.full((200, 300), 255, np.uint8)
 
title1, title2 = 'Mouse Event1','Mouse Event1'
cv2.imshow(title1, image)
cv2.imshow(title2, image)


cv2.setMouseCallback(title1, onMouse) # mouse callback function
cv2.waitKey(0)
cv2.destroyAllWindows()

트랙바 이벤트 제어

  • 트랙바는 일정한 범위에서 특정한 값을 선택할 때 사용하는 일종의 스크롤 바 혹은 슬라이더바를 말한다
  • cv2.createTrackbar(trackbarname, winname, value count, onChange) : 트랙바를 생성한 후에 지정한 원도에 추가하는 함수
    • onChange(pos) : 트랙바 슬라이더의 위치가 변경될 때마다 호출되는 콜백함수
      • pos : 트랙바 슬라이더의 위치
  • cv2.getTrackbarPos(trackbarname, winname) : 지정한 트랙바의 슬라이더 위치를 반환
  • cv2.getTrackbarPos(trackbarname, winname, pos) : 지정한 트랙바의 슬라이더 위치를 설정
import numpy as np
import cv2
 
def onChange(value): # 트랙바 콜백 함수
    global image, title # 전역 변수

    add_value = value -int(image[0][0]) # 트랙바 값과 영상 화소값의 차
    image = image + add_value # 행렬과 스칼라 덧셈
    cv2.imshow(title, image)

image = np.zeros((300, 500), np.uint8) # 영상 생성
 
title = "trackbar event"
cv2.imshow(title, image)

cv2.createTrackbar("Brightness", title, image[0][0], 255, onChange) # 트랙바 콜백
cv2.waitKey(0)
cv2.destroyAllWindows()

마우스 및 트랙바 이벤트 사용

import numpy as np
import cv2
 
def onChange(value):
    global image, title

    add_value = value -int(image[0][0])
    image = image + add_value
    cv2.imshow(title, image)
 
def onMouse(event, x, y, flags, param):
    global image, bar_name

    if event == cv2.EVENT_RBUTTONDOWN:
        if (image[0][0] < 246):
            image = image + 10
            cv2.setTrackbarPos(bar_name, title, image[0][0])
            cv2.imshow(title, image)

    elif event == cv2.EVENT_LBUTTONDOWN:
        if (image[0][0] >=10):
            image = image - 10
            cv2.setTrackbarPos(bar_name, title, image[0][0])
            cv2.imshow(title, image)
 
image = np.zeros((300, 500), np.uint8) # 영상 생성
title = "Mouse & Trackbar  event"
bar_name = "Brightness"
cv2.imshow(title, image)

cv2.createTrackbar(bar_name, title, image[0][0], 255, onChange) # 트랙바 콜백
cv2.setMouseCallback(title, onMouse)
cv2.waitKey(0)
cv2.destroyAllWindows()

직선과 사각형 그리기

  • cv2.line(image, pt1, pt2, color[, thickness[, lineType[, shift]]]) : pt1, pt2를 잇는 직선을 그린다
    • cv2.LINE_4 : 4-방향 연결선
    • cv2.LINE_8 : 8-방향 연결선
    • cv2.LINE_AA : 계단 현상을 감소시킨 선
  • cv2.rectangle(image, pt1, pt2, color[, thickness[, lineType[, shift]]]) : 2가지 방식 (두 좌표, 사각형 영역)으로 사각형을 그린다
  • cv2.rectangle(image, rec, color[, thickness[, lineType[, shift]]])
    • pt1, pt2 : 시작 좌표와 종료 좌표(정수형)
    • rec : 사각형 영역 (x,y,w,h)을 나타내는 4원소 튜플(정수형)
 
import numpy as np
import cv2
from matplotlib import pyplot as plt
 
blue, green, red = (255, 0, 0), (0, 255, 0), (0,0,255)
image = np.zeros((400, 600,3), np.uint8)
image[:] = (255, 255, 255) # 3채널 흰색
 
pt1, pt2 = (50, 50), (250, 150)
pt3, pt4 = (400, 150), (500, 50)
roi = (50, 200, 200, 100) # 시갹형 영역 = 4원소 튜플

직선 그리기

cv2.line(image, pt1, pt2, red)
cv2.line(image, pt3, pt4, green, 3, cv2.LINE_AA) # 계산 현상 감소선

b, g, r = cv2.split(image)
image2 = cv2.merge([r, g, b])
plt.imshow(image2)
plt.xticks([])  # x축 눈금
plt.yticks([])  # y축 눈금
plt.show()

사각형 그리기

# cv2.imshow("Line & Rectangle", image)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
 
cv2.rectangle(image, pt1, pt2, blue, 3, cv2.LINE_4) # 4방향 연결선
cv2.rectangle(image, roi, red, 3, cv2.LINE_8) # 8방향 연결선
cv2.rectangle(image, (400, 200, 100, 100), green, cv2.FILLED) # 내부채움

b, g, r = cv2.split(image)
image2 = cv2.merge([r, g, b])
plt.imshow(image2)
plt.xticks([])  # x축 눈금
plt.yticks([])  # y축 눈금
plt.show()

글자 쓰기

  • cv2.putText(iamge, text, org, fontFace, fontScale, color[, thickness[, lineType[, shift[, bottomLeftOrigin]]]])
    • text 문자열을 org 좌표에 color 색상으로 그린다
    • image : 문자열을 작성할 대상 행렬(영상)
    • text : 작성할 문자열
    • fontface : 문자열의 시작 좌표, 문자열에서 가장 왼쪽 하단을 의미
    • fontScale : 글자 크기 확대 비율
    • color : 글자의 색상
    • thickness : 글자의 굵기
    • lineType : 글자 선의 형태
    • bottomLeftOrigin : 영상의 원점 좌표 설정 (True - 좌하단 왼쪽, False - 좌상단)

문자열의 폰트 (fontFace)에 대한 옵션과 의미

  • cv2.FONT_HERSHEY_SIMPLEX (값 : 0) : 중간 크기 산세리프 폰트
  • cv2.FONT_HERSHEY_PLAIN (값 : 1) : 작은 크기 산세리프 폰트
  • cv2.FONT_HERSHEY_DUPLEX (값 : 2) : 2줄 산세리프 폰트
  • cv2.FONT_HERSHEY_COMPLEX (값 : 3) : 중간 크기 세리프 폰트
  • cv2.FONT_HERSHEY_TRIPLEX (값 : 4) : 3줄 세리프 폰트
  • cv2.FONT_HERSHEY_COMPLEX_SMALL (값 : 5) : complex 보다 작은 폰트
  • cv2.FONT_HERSHEY_SCRIPT_SIMPLEX (값 : 6) : 필기체 스타일 폰트
  • cv2.FONT_HERSHEY_SCRIPT_COMPLEX (값 : 7) : 복잡하 필기체 스타일
  • cv2.FONT_ITALIC (값 : 16) : 이탤릭체를 위한 플래그
import numpy as np
import cv2
from matplotlib import pyplot as plt
 
olive, violet, brown = (128, 128, 0), (221, 160, 221), (42 , 42, 165) 
pt1, pt2 = (50, 230), (50, 310) # 문자열 위치 좌표
 
image = np.zeros((350, 500,3), np.uint8)
image.fill(255)
 
cv2.putText(image, "SIMPLEX", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 2, brown)
cv2.putText(image, "DUPLEX", (50, 120), cv2.FONT_HERSHEY_DUPLEX, 2, olive)
cv2.putText(image, "TRIPLEX", pt1, cv2.FONT_HERSHEY_TRIPLEX, 2, violet)
fontFace = cv2.FONT_HERSHEY_PLAIN | cv2.FONT_ITALIC 
cv2.putText(image, "ITALIC ", pt2, fontFace, 2, violet)

b, g, r = cv2.split(image)
image2 = cv2.merge([r, g, b])
plt.imshow(image2)
plt.xticks([])  
plt.yticks([]) 
plt.show()
 
 

원 그리기

  • cv2.circle(image, center, redius, color[, thickness[, lineType[, shift]]])
    • image : 원을 그릴 대상 행렬 (영상)
    • center : 원의 중심 좌표
    • redius : 원의 반지름
    • color : 선의 색상
    • thickness : 선의 두께
    • lineType : 선의 형태 cv2.line() 함수의 인수와 동일
    • shift : 좌표에 대한 비트 시프트 연산
import numpy as np
import cv2
from matplotlib import pyplot as plt
 
blue, green, red = (255, 0, 0), (0, 255, 0), (0,0,255)
white, black = (255, 255, 255), (0,0,0)
image = np.full((300, 500,3),white, np.uint8)
 
center = (image.shape[1]//2, image.shape[0]//2) # 중심 좌표 - 역순 구성
pt1, pt2 = (300, 50), (100, 220) # 문자열 위치 좌표
shade = (pt2[0] + 2, pt2[1] + 2) # 그림자 좌표
 
cv2.circle(image, center, 100, blue)
cv2.circle(image, pt1, 50, green, 2)
cv2.circle(image, pt2, 70, red, -1)

font = cv2.FONT_HERSHEY_COMPLEX;
cv2.putText(image, "center_blue", center, font, 1.0, blue)
cv2.putText(image, "pt1_green", pt1, font, 0.8, green)
cv2.putText(image, "pt2_red", shade,font, 1.2, black, 2)
cv2.putText(image, "pt2_red", pt2, font, 1.2, red, 1)

b, g, r = cv2.split(image)
image2 = cv2.merge([r, g, b])
plt.imshow(image2)
plt.xticks([])  
plt.yticks([]) 
plt.show()
 

타원 그리기

  • cv2.ellipse(image, center, axes, angle, startAngle, endAngle, color[, thickness[, lineType[, shift]]])
    • center를 중심으로 axes 크기의 타원을 그린다
    • image : 그릴 대상 행렬
    • center : 원의 중심 좌표
    • axes : 타원의 절반 크기 (x축 반지름, y축 반지름)
    • startAngle : 호의 시작 각도
    • endAngle : 호의 종룔 각도
    • color 선의 색상
    • thickness : 선의 두께
    • lineType : 선의 형태
    • shift : 좌표에 대한 비트 시프트 연산

 

import numpy as np
import cv2
from matplotlib import pyplot as plt
 
orange, blue, white = (0, 165, 255), (255, 0, 0), (255,255,255) # 색상 지정
image = np.full((300, 700, 3), white, np.uint8)
 
pt1, pt2 = (180, 150), (550, 150)                       # 타원 중심점
size = (120, 60)                                        # 타원 크기 - 반지름 값임
 
cv2.circle(image, pt1, 1, 0, 2)                         # 타원의 중심점(2화소 원) 표시
cv2.circle(image, pt2, 1, 0, 2)

cv2.ellipse(image, pt1, size,  0, 0, 360, blue, 1)      # 타원 그리기
cv2.ellipse(image, pt2, size, 90, 0, 360, blue, 1)
cv2.ellipse(image, pt1, size,  0, 30, 270, orange, 4)   # 호 그리기
cv2.ellipse(image, pt2, size, 90,-45,  90, orange, 4)

b, g, r = cv2.split(image)
image2 = cv2.merge([r, g, b])
plt.imshow(image2)
plt.xticks([])  
plt.yticks([]) 
plt.show()

'Image Processing > OpenCV' 카테고리의 다른 글

[OpenCV] 01. 화소 처리  (0) 2022.11.22
[OpenCV] 산출 연산 함수  (0) 2022.11.21
[OpenCV] 기본 배열 연산 (Operations On Arrays)  (0) 2022.11.19
[OpenCV] VideoCapture  (0) 2022.11.15
[OpenCV] I/O 처리  (0) 2022.11.10

댓글