제공된 데이터셋을 분석하여 도전 주제에 맞춘 비전 기술을 개발하라!
images.zip
: 다양한 조건에서 촬영된 명함 이미지 36장
데이터로는 명함이미지 36장이 주어졌는데, 이미지들의 특성이 각각 제각각이었다. 어떤 이미지는 거꾸로 찍힌 이미지도 있었고 어떤 이미지는 명함이 잘려서 찍힌 이미지도 있었고, 또 어떤 이미지는 여러 명함이 동시에 찍힌 이미지도 있었다.
이러한 상황에서 명함의 네 모서리를 정확히 탐지해서 투시변환하는 작업이 어렵다고 생각했고, 직접 수동으로 OCR
을 진행할 부분을 지정하는게 좋겠다고 생각했다.
따라서 마우스 이벤트를 이용해 명함 이미지를 띄운 후 OCR
을 진행할 꼭짓점 네 군데를 지정하는 방식으로 진행했다.
# 마우스 클릭 이벤트 콜백 함수
def mouse_callback(event, x, y, flags, param):
# 마우스 왼쪽 버튼을 클릭할 때
if event == cv.EVENT_LBUTTONDOWN:
if len(coords) == 0:
print(f"좌상단: ({x}, {y})")
coords.append((x, y))
elif len(coords) == 1:
print(f"우상단: ({x}, {y})")
coords.append((x, y))
elif len(coords) == 2:
print(f"좌하단: ({x}, {y})")
coords.append((x, y))
elif len(coords) == 3:
print(f"우하단: ({x}, {y})")
coords.append((x, y))
# 좌표가 4개가 되면
if len(coords) == 4:
# 종료
cv.destroyAllWindows()
이런식으로 클릭할 때마다 해당 좌표가 출력되는 방식으로 구성했다.
프로그램을 실행할 때 OCR
을 진행할 이미지 파일을 두번째 인자로 주는 방법을 선택했고, 좌표를 지정한 후 해당 좌표로 명함 비율에 맞춰 투시변환을 진행했다.
투시변환 이후 그레이 스케일 변환, 가우시안 블러링, 가우시안 쓰레쉬홀딩 및 침슥과정을 진행해 글자를 더욱 선명하게 만들고 테서랙트 OCR
을 이용해서 변환 진행하였다.
# 이미지 투시 변환
pts1 = np.float32([coords[0], coords[1], coords[2], coords[3]])
# 해당 좌표로 투시변환 가로 세로 90:50 비율로
pts2 = np.float32([[0, 0], [900, 0], [0, 500], [900, 500]])
m = cv.getPerspectiveTransform(pts1, pts2)
card_image = cv.warpPerspective(img_resized, m, (900, 500))
# to gray scale
gray = cv.cvtColor(card_image, cv.COLOR_BGR2GRAY)
# apply gaussian blur
blurred = cv.GaussianBlur(gray, (3, 3), 0)
# adaptive thresholding
thresh = cv.adaptiveThreshold(blurred, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY, 9, 5)
# erode
kernel = np.ones((1, 3), np.uint8)
erode = cv.erode(thresh, kernel, iterations=1)
# OCR 수행
options = "-l kor+eng --oem 3 --psm 6"
text = pyt.image_to_string(erode, config=options)
# output
print(text)
다음과 같이 OCR
이 잘 진행되었음을 볼 수 있다.
하지만 이러한 방식의 파이프라인의 한계점은 명확한데, 명함의 비율로 고정 변환을 하기 때문에 한장에 명함 여러징이 있는 경우 해당 명함들의 배치가 리사이즈 비율과 맞지 않다면 한번에 여러장을 처리할 수 없고 해당 이미지 한장을 처리하기 위해 이미지 내의 명함 개수만큼 프로그램을 실행해야 한다는 단점이 있다.