Ch2. OpenCV로 시작하는 컴퓨터 비전

wonnie1224·2023년 4월 5일
0

ML / DL

목록 보기
6/11

2.1 OpenCV 소개

OpenCV : 인텔 사에서 만든 컴퓨터 비전 라이브러리, C와 C++로 개발됨

  • 사용가능한 인터페이스 언어 : C, C++, 자바, 자바스크립트, 파이썬

2.3 객체지향 잘 활용하기

  • type(객체) : 해당 객체가 어떤 클래스인지 확인
  • dir(객체) : 해당 객체가 사용 가능한 멤버 함수 목록 확인

2.4 영상을 읽고 표시하기

🌿 ex.2-2 영상 파일 읽고 윈도우에 디스플레이

# ex.2-2
import cv2 as cv # cv2 모듈 불러와 cv 이름 부여
import sys # exit 함수 쓰기 위해 불러옴

img=cv.imread('soccer.jpg') # 영상 읽기

if img is None: # 파일이 없거나 읽는 도중 오류 발생하면
    sys.exit('파일을 찾을 수 없습니다.') # 오류 메시지 출력

cv.imshow('Image Display',img)  # 윈도우에 영상 표시

cv.waitKey()
cv.destroyAllWindows()
  • imread 함수 : 지정된 영상 파일을 폴더에서 읽어와 결과 반환
    • 사진 파일은 소스 파일과 동일한 폴더 상에 있어야 함
  • cv.imshow(윈도우 이름, 영상 이름) : 윈도우에 영상 표시
  • waitKey 함수 : 키보드의 키가 눌릴 때까지 기다리다가, 키가 눌리면 해당 키의 유니코드 값 반환

📌 OpenCV에서 영상은 numpy.ndarray 클래스 형의 객체

  • img 객체 : numpy.ndarray 클래스 타입
  • OpenCV에선 3개 채널 기본이 BGR 순
  • 화소(pixel) : 영상 구성하는 한 점
  • 화소의 위치 : (r,c)
  • 수학 좌표계와 달리 CV에선 원점 = 왼쪽 위, 좌표 (y,x)순으로 표기
  • 컬러 영상 한 픽셀 - B, G, R 3개 값 가짐
    • img[x좌표, y좌표, 0~2] 로 확인 가능

2.5 영상 형태 변환 & 크기 축소

🌿 ex 2-3. 영상 → 명암 영상으로 변환 후 반으로 축소하기

import cv2 as cv
import sys

img=cv.imread('soccer.jpg')

if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY) # BGR 컬러 영상을 명암 영상으로 변환
gray_small=cv.resize(gray,dsize=(0,0),fx=0.5,fy=0.5)    # 크기 반으로 축소

cv.imwrite('soccer_gray.jpg',gray)  # 영상을 파일에 저장
cv.imwrite('soccer_gray_small.jpg',gray)

cv.imshow('Color image',img)
cv.imshow('Gray image',gray)
cv.imshow('Gray image small',gray_small)

cv.waitKey()
cv.destroyAllWindows()

output image

  • cvtColor(컬러 영상 객체, cv.COLOR_BGR2GRAY) : 컬러 영상 → 명암 영상으로 변환, 리턴 타입 : 영상 객체
  • resize(입력 영상 객체, dsize=(변환할 크기), fx=x축 변환비율, fy=y축 변환비율)
  • imwrite(파일명, 영상 객체) : 지정한 영상을 지정한 파일에 저장

📌 cvtColor 함수의 원리

  • 아래와 같은 컬러 이론에 기반한 BGR 영상 → 명암 영상 변환 공식 이용
  • 모든 픽셀에 연산 적용함

2.6 웹 캠에서 비디오 읽기

📌 웹 캠에서 비디오 읽기

🌿 ex 2-4 웹 캠을 통해 입력되는 동영상을 윈도우에 디스플레이

import cv2 as cv
import sys

cap = cv.VideoCapture(0,cv.CAP_DSHOW)   # 카메라와 연결 시도

if not cap.isOpened():
    sys.exit('카메라 연결 실패')

while True:
    ret, frame = cap.read() # 비디오를 구성하는 프레임 획득

    if not ret:
        print('프레임 획득에 실패하여 루프를 나갑니다.')
        break

    cv.imshow('Video display', frame)

    key = cv.waitKey(1) # 1밀리초 동안 키보드 입력 기다림
    if key==ord('q'):   # 'q' 키가 들어오면 루프를 빠져나감
        break

cap.release()   # 카메라와 연결을 끊음
cv.destroyAllWindows()

💡 실행 로직

1) VideoCapture 함수 : 웹 캠과 연결 시도함

  • 연결 실패 시 cap.isOpened 함수 - False

2) while문으로 동영상 입력

  • cap.read 함수 : 호출한 순간의 영상 1장(=프레임) 획득 → 성공 여부 & 프레임 return
  • ret 객체 : 성공 여부. frame 객체 : 프레임 저장

3) 윈도우에 획득한 영상을 지정한 시간 간격마다 디스플레이

📌 비디오에서 영상 수집하기

import cv2 as cv
import numpy as np
import sys

cap = cv.VideoCapture(0,cv.CAP_DSHOW)   # 카메라와 연결 시도

if not cap.isOpened():
    sys.exit('카메라 연결 실패')

frames=[]
while True:
    ret, frame = cap.read() # 비디오를 구성하는 프레임 획득

    if not ret:
        print('프레임 획득에 실패하여 루프를 나갑니다.')
        break

    cv.imshow('Video display', frame)

    key = cv.waitKey(1) # 1밀리초 동안 키보드 입력 기다림
    if key==ord('c'):   # 'c' 키가 들어오면 프레임을 리스트에 추가
        frames.append(frame)
    elif key==ord('q'):   # 'q' 키가 들어오면 루프를 빠져나감
        break

cap.release()   # 카메라와 연결을 끊음
cv.destroyAllWindows()

if len(frames)>0:   # 수집된 영상이 있으면
    imgs=frames[0]
    for i in range(1,min(3,len(frames))):   # 최대 3개까지 이어 붙임
        imgs=np.hstack((imgs, len(frames[i])))
    
    cv.imshow('collected images', imgs)

    cv.waitKey()
    cv.destroyAllWindows()

  • frames 리스트의 요소 : 컬러 영상
  • imgs : 3장의 컬러 영상을 이어 붙여 만듦, numpy.ndarray 타입

2.7 그래픽 기능 & 사용자 인터페이스 만들기

📌 영상에 도형 & 글씨

import cv2 as cv
import sys

img=cv.imread('soccer.jpg')

if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

cv.rectangle(img,(830,30),(1000,200),(0,0,255),2)   # 빨간색, 선의 두께 2인 직사각형 그리기
cv.putText(img,'LeeGangIn',(830,24),cv.FONT_HERSHEY_SIMPLEX,1,(255,0,0),2)  # 글씨 쓰기

cv.imshow('Draw',img)

cv.waitKey()
cv.destroyAllWindows()

📌 마우스를 통한 상호작용

  • 마우스를 다루는 프로그램에선 클릭 / 커서 이동 등의 이벤트가 언제 발생할지 알 수 X ⇒ 콜백 함수 필요!
import cv2 as cv
import sys

img=cv.imread('soccer.jpg')

if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

# 콜백 함수
def draw(event,x,y,flags,param):
    if event==cv.EVENT_FLAG_LBUTTONDOWN:    # 마우스 왼쪽 버튼 클릭 시
        cv.rectangle(img,(x,y),(x+200,y+200),(0,0,255),2)
    elif event==cv.EVENT_FLAG_RBUTTONDOWN:  # 마우스 오른쪽 버튼 클릭 시
        cv.rectangle(img,(x,y),(x+100,y+100),(255,0,0),2)

    cv.imshow('Drawing',img)

cv.namedWindow('Drawing')
cv.imshow('Drawing',img)

cv.setMouseCallback('Drawing',draw) # Drawing 윈도우에 draw 콜백 함수 지정

while(True):    # 마우스 이벤트가 언제 발생할지 모르므로 무한 반복
    if cv.waitKey(1)==ord('q'):
        cv.destroyAllWindows()
        break

💡 실행 로직

  1. ‘Drawing’ 윈도우 생성 후 img 영상 디스플레이
  2. 윈도우에서 마우스 이벤트 발생하면 draw라는 콜백 함수 호출하라고 등록
  3. 무한 루프 : 실행 도중 마우스 이벤트 발생하면, 콜백 함수 호출됨 → img 영상에 직사각형 그림

📌 마우스 드래그로 도형 크기 조절

콜백 함수 - 버튼 클랙했을 때 & 놓았을 때의 좌표 읽어서 직사각형 그리면 됨

  • 버튼 클릭 순간의 좌표 저장할 ix, iy; 전역변수로 선언 ⇒ global 안 붙이면, 콜백 함수 #번 호출에서 변수 계속 생성&소멸되므로 좌푯값 유지 X
import cv2 as cv
import sys

img=cv.imread('soccer.jpg')

if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

# 콜백 함수
def draw(event,x,y,flags,param):
    global ix,iy

    if event==cv.EVENT_LBUTTONDOWN:    # 마우스 왼쪽 버튼 클릭 시
        ix,iy = x,y
    elif event==cv.EVENT_LBUTTONUP:  # 마우스 오른쪽 버튼 클릭 시
        cv.rectangle(img,(ix,iy),(x,y),(0,0,255),2)

    cv.imshow('Drawing',img)

cv.namedWindow('Drawing')
cv.imshow('Drawing',img)

cv.setMouseCallback('Drawing',draw) # Drawing 윈도우에 draw 콜백 함수 지정

while(True):    # 마우스 이벤트가 언제 발생할지 모르므로 무한 반복
    if cv.waitKey(1)==ord('q'):
        cv.destroyAllWindows()
        break

2.8 페인팅 기능 만들기

import cv2 as cv
import sys

img=cv.imread('soccer.jpg')

if img is None:
    sys.exit('파일을 찾을 수 없습니다.')

BrushSiz=5  # 붓의 크기
LColor,RColor=(255,0,0),(0,0,255)   # 파란색과 빨간색

def painting(event,x,y,flags,param):
    if event==cv.EVENT_LBUTTONDOWN:
        cv.circle(img,(x,y),BrushSiz,LColor,-1) # 마우스 왼쪽 버튼 클릭하면 파란색
    elif event==cv.EVENT_RBUTTONDOWN:
        cv.circle(img,(x,y),BrushSiz,RColor,-1) # 마우스 오른쪽 버튼 클릭하면 빨간색
    elif event==cv.EVENT_MOUSEMOVE and flags==cv.EVENT_FLAG_LBUTTON:
        cv.circle(img,(x,y),BrushSiz,LColor,-1) # 왼쪽 버튼 클릭하고 이동하면 파란색
    elif event==cv.EVENT_MOUSEMOVE and flags==cv.EVENT_FLAG_RBUTTON:
        cv.circle(img,(x,y),BrushSiz,RColor,-1) # 오른쪽 버튼 클릭하고 이동하면 빨간색
    
    cv.imshow('Painting',img)   # 수정된 영상 다시 그림

cv.namedWindow('Painting')
cv.imshow('Painting',img)

cv.setMouseCallback('Painting',painting)

while(True):    # 마우스 이벤트가 언제 발생할지 모르므로 무한 반복
    if cv.waitKey(1)==ord('q'):
        cv.destroyAllWindows()
        break

profile
안녕하세요😊 인공지능을 공부하고 있는 대학생입니다 🙌

0개의 댓글