9 분 소요


해당 포스트는 나도코딩님의 파이썬 무료 강의 (활용편6) - 이미지 처리(OpenCV)를 들으며 정리한 내용과 코드 입니다.

환경설정

In [1]:
import cv2
cv2.__version__
Out [1]:
'4.7.0'

OpenCV(Computer Vision)

이미지/동영상 처리에 사용되는 오픈소스 라이브러리

1.이미지 출력

pixabay - 무료 이미지

In [2]:
import cv2
img = cv2.imread('img.jpg') # 해당경로 파일 읽어오기
cv2.imshow('img', img) # img이름 창에 img표시
key = cv2.waitKey(5000) # 지정된 시간(ms) 동안 사용자 키 입력 대기 # 0: 무한
# key = cv2.waitKey(5000)
# print(key) # 아스키 코드로 입력확인(a:87, q:113)
cv2.destroyAllWindows() # 모든 창 닫기

img

읽기 옵션

  1. cv2.IMREAD_COLOR: 컬러 이미지, 투명 영역은 무시(디폴트)
  2. cv2.IMREAD_GRAYSCALE: 흑백 이미지
  3. cv2.IMREAD_UNCHANGED: 투명 영역까지 포함
In [3]:
import cv2
img_color = cv2.imread('img.jpg', cv2.IMREAD_COLOR)
img_gray = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE)
img_unchanged = cv2.imread('img.jpg', cv2.IMREAD_UNCHANGED)


cv2.imshow('img_color', img_color)
cv2.imshow('img_gray', img_gray)
cv2.imshow('img_unchanged', img_unchanged)

key = cv2.waitKey(0)
cv2.destroyAllWindows() 

img

Shape

이미지의 height, width, channel 정보 출력

In [4]:
import cv2
im = cv2.imread('img.jpg')
img.shape # 높이, 넓이, channel # r,g,b, a(알파값)
Out [4]:
(640, 613, 3)

2.동영상 출력

pexels - 무료 영상, 이미지

동영상 파일 출력

In [6]:
import cv2
cap = cv2.VideoCapture('video.mp4')

while cap.isOpened(): # 영상파일이 올바르게 열렸는 확인
    ret, frame = cap.read() # ret: 성공여부, frame: 받아온 이미지(프레임)
    if not ret:
        print('더 이상 가져올 프레임이 없어요')
        break
    
    cv2.imshow('video', frame)
    
    if cv2.waitKey(25) == ord('q'): # ord: 아스키 코드로 변환 # key대기 숫자에 따라 재생속도 조절가능
        print('사용자 입력에 의해 종료합니다')
        break

cap.release() # 자원 해제(반환)
cv2.destroyAllWindows()
Out [6]:
더 이상 가져올 프레임이 없어요

img

카메라 출력

In [7]:
import cv2
cap = cv2.VideoCapture(0) # 0번째 카메라 장치(Device ID)

if not cap.isOpened(): # 카메라가 잘 열리지 않은 경우
    exit() # 프로그램 종료
    
while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    cv2.imshow('camera', frame)
    
    if cv2.waitKey(1) == ord('q'): # 사용자가 q 입력 시
        break

cap.release()
cv2.destroyAllWindows()

3.도형 그리기

빈 스케치북 만들기

In [1]:
import cv2
import numpy as np

# 세로 480, 가로 640, 3 channel(BGR)에 해당하는 스케치북 만들기
img = np.zeros((480, 640 ,3), dtype=np.uint8) # 0(검은색) 으로 채운
# img[:] = (255, 255, 255) # 전체 공간을 흰색으로 채우기

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

일부 영역 색칠

In [2]:
import cv2
import numpy as np

img = np.zeros((480, 640 ,3), dtype=np.uint8)
img[100:200, 200:300] = (255, 255, 255) # 세로영역, 가로영역을 흰색으로 채우기

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

직선

직선의 종류(line type)

  1. cv2.LINE_4: 상하좌우 4방향으로 연결된 선
  2. cv2.LINE_8: 대각선을 포함한 8방향으로 연결된 선(디폴트)
  3. cv2.LINE_AA: 부드러운 선(anti-aliasing)
In [3]:
import cv2
import numpy as np

img = np.zeros((480, 640 ,3), dtype=np.uint8)

COLOR = (0, 255, 255) # 색깔: BGR순서, Yellow
THICKNESS = 3 # 두께

cv2.line(img, (50, 100), (400, 50), COLOR, THICKNESS, cv2.LINE_8)
# 그릴 위치, 시작점, 끝점, 색깔, 두께, 선종류

cv2.line(img, (50, 200), (400, 150), COLOR, THICKNESS, cv2.LINE_4)
cv2.line(img, (50, 300), (400, 250), COLOR, THICKNESS, cv2.LINE_AA)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

In [4]:
import cv2
import numpy as np

img = np.zeros((480, 640 ,3), dtype=np.uint8)

COLOR = (255, 255, 0) # 색깔: BGR순서, Skyblue
RADIUS = 50 # 반지름
THICKNESS = 10 # 두께

cv2.circle(img, (200, 100), RADIUS, COLOR, THICKNESS, cv2.LINE_AA) # 속이 빈 원
# 그릴 위치, 원의 중심점, 반지름, 색깔, 두께, 선종류

cv2.circle(img, (400, 100), RADIUS, COLOR, cv2.FILLED, cv2.LINE_AA) # 꽉 찬 원
# cv2.circle(img, (400, 100), RADIUS, COLOR, -1, cv2.LINE_AA) # 속이 꽉찬 원

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

사각형

In [5]:
import cv2
import numpy as np

img = np.zeros((480, 640 ,3), dtype=np.uint8)

COLOR = (0, 255, 0) # 색깔: BGR순서, Green
THICKNESS = 3 # 두께

cv2.rectangle(img, (100, 100), (200, 200), COLOR, THICKNESS) # 속이 빈 사각형
# 그릴 위치, 왼쪽 위 좌표, 오른쪽 아래 좌표, 색깔, 두께

cv2.rectangle(img, (300, 100), (400, 300), COLOR, cv2.FILLED) # 꽉 찬 사각형

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

다각형

In [6]:
import cv2
import numpy as np

img = np.zeros((480, 640 ,3), dtype=np.uint8)

COLOR = (0, 0, 255) # 색깔: BGR순서, Red
THICKNESS = 3 # 두께

pts1 = np.array([[100, 100], [200, 100], [100, 200]]) # 3개 좌표를 잇는 다각형: 삼각형
pts2 = np.array([[200, 100], [300, 100], [300, 200]])
# cv2.polylines(img, [pts1], True, COLOR, THICKNESS, cv2.LINE_AA)
# cv2.polylines(img, [pts2], True, COLOR, THICKNESS, cv2.LINE_AA)
# 그릴 위치, [그릴 좌표들], 닫힘 여부, 색깔, 두께, 선종류
cv2.polylines(img, [pts1, pts2], True, COLOR, THICKNESS, cv2.LINE_AA)

pts3 = np.array([[[100, 300], [200, 300], [100, 400]], [[200, 300], [300, 300], [300, 400]]])
cv2.fillPoly(img, pts3, COLOR, cv2.LINE_AA) # 꽉 찬 다각형
# 그릴 윛, 그릴 좌표들, 색깔, 선종류

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

4.텍스트

OpenCV에서 사용하는 글꼴 종류

  1. cv2.FONT_HERSHEY_SIMPLEX : 보통 크기의 산 세리프(sans-serif) 글꼴
  2. cv2.FONT_HERSHEY_PLAIN : 작은 크기의 산 세리프 글꼴
  3. cv2.FONT_HERSHEY_SCRIPT_SIMPLEX : 필기체 스타일 글꼴
  4. cv2.FONT_HERSHEY_TRIPLEX : 보통 크기의 세리프 글꼴
  5. cv2.FONT_ITALIC : 기울임 (이텔릭)
In [7]:
import numpy as np
import cv2

img = np.zeros((480, 640, 3), dtype=np.uint8)

SCALE = 1 # 크기
COLOR = (255, 255, 255) # 흰색
THICKNESS = 1 # 두께

cv2.putText(img, "Text Simplex", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, SCALE, COLOR, THICKNESS)
# 그릴 위치, 텍스트 내용, 시작위치, 폰트종류, 크기, 색깔, 두께
cv2.putText(img, "Text Plain", (20, 150), cv2.FONT_HERSHEY_PLAIN, SCALE, COLOR, THICKNESS)
cv2.putText(img, "Text Script Simplex", (20, 250), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, SCALE, COLOR, THICKNESS)
cv2.putText(img, "Text Triplex", (20, 350), cv2.FONT_HERSHEY_TRIPLEX, SCALE, COLOR, THICKNESS)
cv2.putText(img, "Text Italic", (20, 450), cv2.FONT_HERSHEY_TRIPLEX | cv2.FONT_ITALIC, SCALE, COLOR, THICKNESS)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

한글 우회

In [8]:
import numpy as np
import cv2

img = np.zeros((480, 640, 3), dtype=np.uint8)

SCALE = 1 # 크기
COLOR = (255, 255, 255) # 흰색
THICKNESS = 1 # 두께

cv2.putText(img, "텍스트 출력", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, SCALE, COLOR, THICKNESS)
# 그릴 위치, 텍스트 내용, 시작위치, 폰트종류, 크기, 색깔, 두께


cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

한글 우회 방법

In [9]:
import numpy as np
import cv2
# PIL (Python Image Library)
from PIL import ImageFont, ImageDraw, Image

def myPutText(src, text, pos, font_size, font_color):
    img_pil = Image.fromarray(src)
    draw = ImageDraw.Draw(img_pil)
    font = ImageFont.truetype('fonts/gulim.ttc', font_size)
    draw.text(pos, text, font=font, fill=font_color)
    return np.array(img_pil)

img = np.zeros((480, 640, 3), dtype=np.uint8)

FONT_SIZE = 30
COLOR = (255, 255, 255) # 흰색


# cv2.putText(img, "텍스트 출력", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, SCALE, COLOR, THICKNESS)
# 그릴 위치, 텍스트 내용, 시작위치, 폰트종류, 크기, 색깔, 두께
img = myPutText(img, "텍스트 출력", (20, 50), FONT_SIZE, COLOR)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

5.파일 저장

이미지 저장

In [10]:
import cv2
img = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE) # 흑백으로 이미지 불러오기
cv2.imshow('img', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

result = cv2.imwrite('img_save.jpg', img)
print(result)
Out [10]:
True

저장 포맷(jpg, png)

In [11]:
import cv2
img = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE) # 흑백으로 이미지 불러오기

# 이미지 처리 과정 삽입 가능

cv2.imwrite('img_save.png', img) # png 형태로 저장
Out [11]:
True

동영상 저장

In [12]:
import cv2
cap = cv2.VideoCapture('video.mp4')

# 코덱 정의(four character code)
fourcc = cv2.VideoWriter_fourcc(*'DIVX') # *'DIVX' == 'D','I','V','X'

# 프레임 크기, FPS 정의
width = round(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = round(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)
# fps = cap.get(cv2.CAP_PROP_FPS)*2 # 영상 재생 속도 2배

out = cv2.VideoWriter('output_fast.avi', fourcc, fps, (width, height))
# 저장 파일명, 코덱, FPS, 크기(width, height)

while cap.isOpened():
    ret, frame = cap.read()
    
    if not ret:
        break
    
    out.write(frame) # 영상 데이터만 저장(소리x)
    cv2.imshow('viedo', frame)
    if cv2.waitKey(1) == ord('q'):
        break
        
out.release() # 자원 해제
cap.release()
cv2.destroyAllWindows()
In [8]:
# *'DIVX' == 'D','I','V','X'
codec = 'DIVX'
print(codec)
print(*codec)
print([codec])
print([*codec])
Out [8]:
DIVX
D I V X
['DIVX']
['D', 'I', 'V', 'X']

6. 크기조정

이미지

고정 크기로 설정

In [13]:
import cv2
img = cv2.imread('img.jpg')
dst = cv2.resize(img, (400, 500)) # width, height 고정크기

cv2.imshow('img', img)
cv2.imshow('resize', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

비율로 설정

In [14]:
import cv2
img = cv2.imread('img.jpg')
dst = cv2.resize(img, None, fx=0.5, fy=0.5) # x, y 비율 정의(0.5배로 축소)

cv2.imshow('img', img)
cv2.imshow('resize', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

보간법

이미지를 줄이거나 키울 때 자연스럽게 처리하는 방법

  1. cv2.INTER_AREA: 크기를 줄일 때 사용
  2. cv2.INTER_CUBIC: 크기를 늘릴 때 사용(속도 느림, 퀄리티 좋음)
  3. cv2.INTER_LINEAR: 크기를 늘릴 때 사용(default)

보간법 적용 축소

In [15]:
import cv2
img = cv2.imread('img.jpg')
dst = cv2.resize(img, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA) # x, y 비율 정의(0.5배로 축소)

cv2.imshow('img', img)
cv2.imshow('resize', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

보간법 적용 확대

In [16]:
import cv2
img = cv2.imread('img.jpg')
dst = cv2.resize(img, None, fx=1.5, fy=1.5, interpolation=cv2.INTER_CUBIC) # x, y 비율 정의(1.5배로 확대)

cv2.imshow('img', img)
cv2.imshow('resize', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

동영상

고정 크기로 설정

In [17]:
import cv2
cap = cv2.VideoCapture('video.mp4')

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    
    frame_resized = cv2.resize(frame, (400, 500)) # 프레임을 고정 크기로
    cv2.imshow('video', frame_resized)
    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

img

비율로 설정

In [18]:
import cv2
cap = cv2.VideoCapture('video.mp4')

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    
    frame_resized = cv2.resize(frame, None, fx=1.5, fy=1.5, interpolation=cv2.INTER_CUBIC) # 프레임을 비율로
    cv2.imshow('video', frame_resized)
    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

img

7.이미지 자르기

영역을 잘라서 새로운 윈도우에 표시

In [19]:
import cv2
img = cv2.imread('img.jpg')
# img.shape # (640, 613, 3)

crop = img[100:200, 200:400] # [세로범위, 가로범위]

cv2.imshow('img', img)
cv2.imshow('crop', crop)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

영역을 잘라서 기존 윈도우에 표시

In [20]:
import cv2
img = cv2.imread('img.jpg')

crop = img[100:200, 200:400] # [세로범위, 가로범위]
img[100:200, 400:600] = crop

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

8.이미지 대칭

좌우 대칭

In [21]:
import cv2
img = cv2.imread('img.jpg')
flip_horizontal = cv2.flip(img, 1) # flipCode > 0: 좌우 대칭 Horizontal

cv2.imshow('img', img)
cv2.imshow('flip_horizontal', flip_horizontal)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

상하 대칭

In [22]:
import cv2
img = cv2.imread('img.jpg')
flip_vertical = cv2.flip(img, 0) # flipCode == 0: 상하 대칭 Vertical

cv2.imshow('img', img)
cv2.imshow('flip_vertical', flip_vertical)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

상하좌우 대칭

In [23]:
import cv2
img = cv2.imread('img.jpg')
flip_both = cv2.flip(img, -1) # flipCode < 0: 상하좌우 대칭 Vertical

cv2.imshow('img', img)
cv2.imshow('flip_both', flip_both)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

9.이미지 회전

시계 방향 90도 회전

In [24]:
import cv2
img = cv2.imread('img.jpg')

rotate_90 = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE) # 시계 방향으로 90도 회전

cv2.imshow('img', img)
cv2.imshow('rotate_90', rotate_90)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

180도 회전

In [25]:
import cv2
img = cv2.imread('img.jpg')

rotate_180 = cv2.rotate(img, cv2.ROTATE_180) # 180도 회전

cv2.imshow('img', img)
cv2.imshow('rotate_180', rotate_180)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

반시계 방향으로 90도 회전(시계 방향으로 270도 회전)

In [26]:
import cv2
img = cv2.imread('img.jpg')

rotate_270 = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE) # 반시계 방향으로 90도 회전

cv2.imshow('img', img)
cv2.imshow('rotate_270', rotate_270)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

10.이미지 변형(흑백)

이미지에서 필요없는 부분을 없애는 전처리

이미지를 흑백으로 읽음

In [27]:
import cv2
img = cv2.imread('img.jpg', cv2.IMREAD_GRAYSCALE)

cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

불러온 이미지를 흑백으로 변형

In [28]:
import cv2
img = cv2.imread('img.jpg')

dst = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

cv2.imshow('img', img)
cv2.imshow('gray', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

11.이미지 변형(흐림)

외곽선 검출을 더 쉽게, 노이즈 제거

가우시안 블러

커널 사이즈 변화에 따른 흐림

In [29]:
import cv2
img = cv2.imread('img.jpg')

# 커널 사이즈는 일반적으로 양의 홀수가 우수한 성능
# (3, 3), (5, 5), (7, 7)
kernel_3 = cv2.GaussianBlur(img, (3, 3), 0) # 0:자동으로 시그마x(표준편차)
kernel_5 = cv2.GaussianBlur(img, (5, 5), 0)
kernel_7 = cv2.GaussianBlur(img, (7, 7), 0)

cv2.imshow('img', img)
cv2.imshow('kernel_3', kernel_3)
cv2.imshow('kernel_5', kernel_5)
cv2.imshow('kernel_7', kernel_7)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

표준 편차 변화에 따른 흐림

In [30]:
import cv2
img = cv2.imread('img.jpg')

sigma_1 = cv2.GaussianBlur(img, (0, 0), 1) # sigmaX: 가우시안 커널의 x 방향의 표준편차
sigma_2 = cv2.GaussianBlur(img, (0, 0), 2)
sigma_3 = cv2.GaussianBlur(img, (0, 0), 3)

cv2.imshow('img', img)
cv2.imshow('sigma_1', sigma_1)
cv2.imshow('sigma_2', sigma_2)
cv2.imshow('sigma_3', sigma_3) # 가우시안보다 블러가 많이 적용
cv2.waitKey(0)
cv2.destroyAllWindows()

img

12.이미지 변형(원근)

사다리꼴 이미지 펼치기

In [31]:
import cv2
import numpy as np

img = cv2.imread('newspaper.jpg')

width, height = 640, 240 # 출력 결과물

src = np.array([[511, 352], [1008, 345], [1122, 584], [455, 594]], dtype=np.float32) # 변형할 영역 4개의 지점(input)
dst = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32) # output
# 좌상, 우상, 우하, 좌하 (시계 방향으로 4지점 정의)

matrix = cv2.getPerspectiveTransform(src, dst) # matrix 얻어옴
result = cv2.warpPerspective(img, matrix, (width, height)) # matrix 대로 변환함

cv2.imshow('img', img)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

회전된 이미지 세우기

In [33]:
import cv2
import numpy as np

img = cv2.imread('poker.jpg')

width, height = 530, 710

src = np.array([[702, 143], [1133, 414], [726, 1007], [276, 700]], dtype=np.float32) # 변형할 영역 4개의 지점(input)
dst = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32) # output
# 좌상, 우상, 우하, 좌하 (시계 방향으로 4지점 정의)

matrix = cv2.getPerspectiveTransform(src, dst) # matrix 얻어옴
result = cv2.warpPerspective(img, matrix, (width, height)) # matrix 대로 변환함

cv2.imshow('img', img)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

미니 프로젝트: 반자동 문서 스캐너

마우스 이벤트 등록

In [7]:
import cv2

def mouse_handler(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONDOWN: # 좌측 버튼 DOWN 이벤트
        print('좌버튼 Down')
        print(x, y)
    elif event == cv2.EVENT_LBUTTONUP: # 좌측 버튼 UP 이벤트
        print('좌버튼 Up')
        print(x, y)
    elif event == cv2.EVENT_LBUTTONDBLCLK: # 좌측 버튼 더블 클릭
        print('더블클릭')
    # elif event == cv2.EVENT_MOUSEMOVE: # 마우스 이동
    #     print('마우스 이동')
    elif event == cv2.EVENT_RBUTTONDOWN: # 마우스 우측 버튼 DOWN
        print('우클릭')

img = cv2.imread('poker.jpg')
cv2.namedWindow('img') # img란 이름의 윈도우를 먼저 만들어둠, 여기에 마우스 이벤트를 처리하기 위한 핸들러 적용
cv2.setMouseCallback('img', mouse_handler)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Out [7]:
좌버튼 Down
368 329
좌버튼 Up
368 329
더블클릭
좌버튼 Up
368 329

미니 프로젝트

In [36]:
import cv2
import numpy as np

point_list = []
src_img = cv2.imread('poker.jpg')

COLOR = (255, 0, 255) # pink


def mouse_handler(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONDOWN:
        point_list.append((x, y))
    
    for point in point_list:
        cv2.circle(src_img, point, 15, COLOR, cv2.FILLED)
    
    if len(point_list) == 4:
        show_result() # 결과 출력
        
    cv2.imshow('img', src_img)

def show_result():
    width, height = 530, 710

    src = np.float32(point_list)
    dst = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32)

    matrix = cv2.getPerspectiveTransform(src, dst)
    result = cv2.warpPerspective(src_img, matrix, (width, height))
    cv2.imshow('result', result)
    
cv2.namedWindow('img')
cv2.setMouseCallback('img', mouse_handler)
cv2.imshow('img', src_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

선 긋기 추가

In [37]:
import cv2
import numpy as np

point_list = []
src_img = cv2.imread('poker.jpg')

COLOR = (255, 0, 255) # pink
THICKNESS = 3
drawing = False # 선을 그릴지 여부

def mouse_handler(event, x, y, flags, params):
    global drawing
    
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True # 선을 그리기 시작
        point_list.append((x, y))
        
    if drawing:
        prev_point = None # 직선의 시작점
        for point in point_list:
            cv2.circle(src_img, point, 15, COLOR, cv2.FILLED)
            if prev_point:
                cv2.line(src_img, prev_point, point, COLOR, THICKNESS, cv2.LINE_AA)
            prev_point = point
    
    if len(point_list) == 4:
        show_result() # 결과 출력
        
    cv2.imshow('img', src_img)

def show_result():
    width, height = 530, 710

    src = np.float32(point_list)
    dst = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32)

    matrix = cv2.getPerspectiveTransform(src, dst)
    result = cv2.warpPerspective(src_img, matrix, (width, height))
    cv2.imshow('result', result)
    
cv2.namedWindow('img')
cv2.setMouseCallback('img', mouse_handler)
cv2.imshow('img', src_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

실시간 선 긋기

In [38]:
import cv2
import numpy as np

point_list = []
src_img = cv2.imread('poker.jpg')

COLOR = (255, 0, 255) # pink
THICKNESS = 3
drawing = False # 선을 그릴지 여부

def mouse_handler(event, x, y, flags, params):
    global drawing
    dst_img = src_img.copy()
    
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True # 선을 그리기 시작
        point_list.append((x, y))
        
    if drawing:
        prev_point = None # 직선의 시작점
        for point in point_list:
            cv2.circle(dst_img, point, 15, COLOR, cv2.FILLED)
            if prev_point:
                cv2.line(dst_img, prev_point, point, COLOR, THICKNESS, cv2.LINE_AA)
            prev_point = point
            
        next_point = (x, y)
        if len(point_list) == 4:
            show_result() # 결과 출력
            next_point = point_list[0] # 첫 번째 클릭한 점

        cv2.line(dst_img, prev_point, next_point, COLOR, THICKNESS, cv2.LINE_AA)
        
    cv2.imshow('img', dst_img)

def show_result():
    width, height = 530, 710

    src = np.float32(point_list)
    dst = np.array([[0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32)

    matrix = cv2.getPerspectiveTransform(src, dst)
    result = cv2.warpPerspective(src_img, matrix, (width, height))
    cv2.imshow('result', result)
    
cv2.namedWindow('img')
cv2.setMouseCallback('img', mouse_handler)
cv2.imshow('img', src_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

img

Reference

댓글남기기