Schoolwork/컴퓨터그래픽스 및 비젼

[Python] 06주차 과제 - Perspective transform

FATKITTY 2020. 9. 5. 14:37
반응형

 목적:

- 이 과제에서는 자동차 번호판을 정상의 형태로 변형하여 보여준다.

 

기타:

- 주요한 과정에 대하여 opencv, numpy 등 package 함수를 사용해도 무방합니다.

- 필요한 경우 각 단계에서 *적절한* 최적화 가 필요합니다. 여러분의 최적화 노력을 PPT에 간략하게 설명하기 바랍니다.

- 기타 세부적인 사항은 합리적으로 가정하시기 바랍니다.

- 영상에 대하여 적절한 해상도를 선택하세요. 고해상도일수록 처리 속도가 느려집니다.

- 이 프로그램은 여러분이 최적화한 파라미터값으로 진행되는 것을 원칙으로 합니다.

 

 과제의 내용

1. 아래 그림과 같이 첨부된 자동차 번호판 이미지(영상 A)를 정상의 상태(영상 B)로 변환하여 디스플레이하는 프로그램을 작성하라.

A. 프로그램에서 주요 단계를 차례대로 보여 줄 것.

2. 아래 단계에 대한 결과를 PPT에 포함할 것. 

A. 실제 자동차 번호판의 비율을 측정하고 이 비율을 이용하여 적절한 크기의 Template 를 만든다. Template 의 적절한 크기(가로 세로 픽셀 수)를 정한다. Template 는 실제 영상일 필요는 없고 가상적인 직사각형이다.

B. 자동차 번호판영상과 template 에서 네 개의 매칭 포인트 쌍을 구하라.

C. 자동차 번호판 → template 로 변환하는 투영행렬은 무엇인가?

D. 이 투영행렬은 전방향, 역방향 중 어떤 매핑인가?

과제내용

 

Code

# mouse_handler.py

import cv2
import numpy as np

img_path = 'car_number.jpg'
ori_img = cv2.imread(img_path)

src = []  # 왼쪽위, 오른쪽위, 오른쪽아래, 왼쪽아래 순으로 각 점의 좌표

# mouse callback handler
def mouse_handler(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONUP:  # 마우스가 좌클릭을 했을때 (4번의 클릭으로 좌표 얻기)
        img = ori_img.copy()

        src.append([x, y])

        for xx, yy in src:  # 클릭한 곳에 점 그리기
            cv2.circle(img, center=(xx, yy), radius=5, color=(0, 255, 0), thickness=-1)

        cv2.imshow('Original Image - Car', img)

        # perspective transform
        if len(src) == 4:
            src_np = np.array(src, dtype=np.float32)
            print("original points : \n", src_np)

cv2.namedWindow('Original Image - Car')
cv2.setMouseCallback('Original Image - Car', mouse_handler)  # 마우스 이벤트 전달

cv2.imshow('Original Image - Car', ori_img)
if cv2.waitKey(0) == 32:
    cv2.destroyAllWindows()
# car.py

import cv2
import numpy as np
import keyboard

img_path = 'car_number.jpg'
ori_img = cv2.imread(img_path)

src = []  # 왼쪽위, 오른쪽위, 오른쪽아래, 왼쪽아래 순으로 각 점의 좌표
src.append([126, 218])
src.append([343, 266])
src.append([340, 345])
src.append([121, 283])

# 32비트로 바꿔줌
src_np = np.array(src, dtype=np.float32)

# width ,height 길이 계산
width = max(np.linalg.norm(src_np[0] - src_np[1]), np.linalg.norm(src_np[2] - src_np[3]))
height = max(np.linalg.norm(src_np[0] - src_np[3]), np.linalg.norm(src_np[1] - src_np[2]))

# width, height 비율
width_ratio = (width / height)
height_ratio = 1

# 비율 * 300 으로 픽셀 크기 맞춤
dst_np = np.array([[0, 0],
                    [int(width_ratio * 300), 0],
                    [int(width_ratio * 300), int(height_ratio * 300)],
                    [0, int(height_ratio * 300)]
                    ], dtype=np.float32)

M = cv2.getPerspectiveTransform(src=src_np, dst=dst_np)
result = cv2.warpPerspective(ori_img, M=M, dsize=(int(width_ratio * 300), height_ratio * 300))
#print("Perspective Transformation :\n", M)

cv2.imshow('img', ori_img)

print("스페이스바를 누르면 번호판의 4개 매칭점이 구해집니다.")

if cv2.waitKey(0) == ord(' '):
    for xx, yy in src:
        cv2.circle(ori_img, center=(xx, yy), radius=5, color=(0, 255, 0), thickness=-1, lineType=cv2.LINE_AA)
cv2.imshow('img', ori_img)
print("original points : \n", src_np)

if cv2.waitKey(0) == ord(' '):
    cv2.imshow('result', result)
    print("\ndestination points : \n", dst_np)

if cv2.waitKey(0) == ord(' '):
    cv2.destroyAllWindows()

 

점수 10/10

 

 

  ❤와 댓글은 큰 힘이 됩니다. 감사합니다 :-)  

반응형