[스터디노트] OpenCV - 명함 검출과 인식 3

Hwan·2024년 2월 12일

OpenCV

목록 보기
13/15

OpenCV 응용 - 명함 검출과 인식

(5) 명함 똑바로 펴기 - 1

영상의 기하학적 변환

  • 영상의 기하학적 변환(geometric transformation)이란?
    • 영상을 구성하는 픽셀의 배치 구조를 변경함으로써 전체 영상의 모양을 바꾸는 작업
    • 영상의 크기 변환, 대칭 변환, 회전 변환 등

  • 투시 변환 행렬 구하기

  • 영상의 투시 변환

  • 사각형 꼭지점 좌표쌍을 이용한 투시 변환 예제

import cv2
import sys
import numpy as np

# 영상 불러오기
src = cv2.imread('./data/namecard1.jpg')

if src is None:
    print('Image load failed')
    sys.exit()

w, h = 720, 400
# 입력 영상의 좌표(좌상단부터 시계방향)
srcQuad = np.array([[324, 308], [760, 369], [718, 611], [231, 517]], np.float32)
# 출력 영샹의 좌표(좌상단부터 시계방향)
dstQuad = np.array([[0, 0], [w-1, 0], [w-1, h-1], [0, h-1]], np.float32)
dst = np.zeros((h, w), np.uint8)


pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
dst = cv2.warpPerspective(src, pers, (w, h))

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

(6) 명함 똑바로 펴기 - 2

꼭지점 좌표 재조정

  • cv2.apporxPolyDP()가 반환한 approx 좌표의 문제점
    • approx.shape - (4,1,2)
    • approx.dtype = int32
    • 저장된 점들의 순서가 임의의 순서이기 때문에 순서를 재조정해야 함
  • shape, dtype 변경하기
    • cv2.getPerspectiveTransform()에 전달하기 위해 shape = (4,2), dtype = float32로 변경해야 함
  • 꼭지점 순서 변경하기

  • 명함 영역 사각형 똑바로 펴기 예제
import cv2
import sys
import numpy as np

# 점들의 순서를 좌상단부터 반시계 방향 순서로 변경하는 함수
def reorderPts(pts):
    idx = np.lexsort((pts[:, 1], pts[:, 0])) # 칼럼 0 -> 칼럼1 순으로 정렬한 인덱스를 반환
    pts = pts[idx] # x좌표로 정렬

    if pts[0, 1] > pts[1, 1]:
        pts[[0, 1]] = pts[[1, 0]]
    
    if pts[2, 1] < pts[3, 1]:
        pts[[2, 3]] = pts[[3, 2]]

    return pts



# 영상 불러오기
src = cv2.imread('./data/namecard1.jpg')

if src is None:
    print('Image load failed')
    sys.exit()

# 출력 영상 설정
# 점들의 순서를 좌상단부터 반시계 방향 순서로 저장
w, h = 720, 400
srcQuad = np.array([[0, 0], [0, h], [w, h], [w, 0]], np.float32)
dstQuad = np.array([[0, 0], [0, h], [w, h], [w, 0]], np.float32)
dst = np.zeros((h, w), np.uint8)

# 입력 영상을 그레이스케일 영상으로 변환
src_gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)

# 자동 이진화
th, src_bin = cv2.threshold(src_gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)
#외곽선 검출 및 명함 검출
contours, th = cv2.findContours(src_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

for pts in  contours:
    # 너무 작은 객체는 무시
    if cv2.contourArea(pts) < 1000:
        continue
    
    # 외곽선 근사화
    approx = cv2.approxPolyDP(pts, cv2.arcLength(pts, True)*0.02, True)

    # 사각형으로 근사화되면 외곽선 표시
    if len(approx) == 4:
        # cv2.polylines(src, [approx], True, (0, 255, 0), 2, cv2.LINE_AA)
        corners = approx.reshape(4, 2).astype(np.float32)
        srcQuad = reorderPts(corners)



pers = cv2.getPerspectiveTransform(srcQuad, dstQuad)
dst = cv2.warpPerspective(src, pers, (w, h))

cv2.imshow('src', src)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

profile
Hi.

0개의 댓글