-
안면인식 프로그램에 이어 이미지 스캐너입니다.
https://pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/
How to Build a Kick-Ass Mobile Document Scanner in Just 5 Minutes - PyImageSearch
Building a document scanner with OpenCV can be accomplished in just three simple steps: Step 1: Detect edges. Step 2: Use the edges in the image to find the contour (outline) representing the piece of paper being scanned. Step 3:…
pyimagesearch.com
이미지 스캐너란?
하나의 이미지 속에서 따로 원하는 영역을 자르고 싶을 때,
그 원하는 요소의 모서리를 클릭 함으로써 이미지가 쉽게 잘리도록 돕는 프로그램입니다.
1. 라이브러리 호출과 이미지 띄우기
import cv2 import numpy as np img = cv2.imread('img.jpg') cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows()이 곳은 딱히 어려운 점이 없습니다.
기본적인 OpenCV 이미지 호출 방법을 사용하기 때문입니다2. 마우스 클릭이 감지되면 그 감지된 위치 저장하기
import cv2 import numpy as np point_list = [] # 감지된 위치를 저장할 곳 img = cv2.imread('img.jpg') # 마우스 이벤트 함수 def mouse_handler(event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: # 마우스 왼쪽 버튼 누름을 감지하는 이벤트 point_list.append((x, y)) # 튜플형으로 삽입 cv2.namedWindow('img') # img란 이름의 윈도우를 먼저 만들어두는 것, 여기에 마우스 이벤트를 처리하기 위한 핸들러 적용 cv2.setMouseCallback('img', mouse_handler cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows()먼저 위치를 저장할 공간이 필요하기 때문에 point_list 라는 List를 생성해줍니다.
그리고 마우스 클릭 기능을 구현해야하기 때문에 mouse_handler라는 함수(def) 를 만들어줍니다.
이 함수의 소스코드가 굉장히 복잡해보이지만 코드를 말로 쉽게 풀어서, 만약 마우스 왼쪽 버튼 클릭이 감지 된다면, 아까 만들어주었던 point_list 안에 그 감지된 위치를 넣어준다. 라고 이해하면 될 것 같습니다.한마디로 mouse_handler 함수 == 클릭한 위치를 찾도록 돕는 역할,
point_list == mouse_handler 함수를 통해 찾은 클릭한 위치를 담고있는 공간3. 클릭한 지점을 이미지 위에 표시
import cv2 import numpy as np point_list = [] # 감지된 위치를 저장할 곳 img = cv2.imread('img.jpg') COLOR = (255, 0, 255) # 핑크색 # 마우스 이벤트 함수 def mouse_handler(event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: # 마우스 왼쪽 버튼 누름을 감지하는 이벤트 point_list.append((x, y)) # 튜플형으로 삽입 for point in point_list: cv2.circle(img, point, 15, COLOR, cv2.FILLED) # 어떤 이미지에? 중심점? 원의 크기, 원의 색, 원의 모양 (꽉차게) cv2.imshow('img', img) cv2.namedWindow('img') # img란 이름의 윈도우를 먼저 만들어두는 것, 여기에 마우스 이벤트를 처리하기 위한 핸들러 적용 cv2.setMouseCallback('img', mouse_handler cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows()마우스 이벤트 함수안에 for문 하나가 추가 됬는데, 이 for문의 역할을 살펴보겠습니다.
아까 마우스를 클릭한 위치에 작은 원을 그려 어떤 곳에 클릭을 했는지 표시해주겠다 라는 뜻으로 해석하면 쉽습니다. 그렇다면 원의 색상도 지정해줘야겠죠? 코드 윗 부분에 COLOR 라는 변수를 두고 RGB 값으로 색상을 지정 해주었습니다.
그럼 이제 여기까지의 결괏값을 한번 확인해볼까요?

지금까지의 결괏 값 이렇게 이미지 위에 마우스 클릭을 하면, 핑크색의 원으로 클릭을 했던 곳 위에 표시가 됩니다.
그럼 이제 모서리를 클릭한 요소를 잘라내는 기능을 구현을 할 차례입니다.
4. 클릭한 요소 잘라내기 (참고)
import cv2 import numpy as np img = cv2.imread('newspaper.jpg') # 여기서 부터 기능구현 시작 width, height = 640, 240 # 가로 크기 640, 세로 크기 240 으로 결과물 출력 # input 데이터 만들기 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(img, matrix, (width, height)) # 결괏값의 창의 크기 설정 cv2.imshow('img', img) cv2.imshow('result', result) cv2.waitKey(0) cv2.destroyAllWindows()클릭한 요소를 잘라내기 전에 알아야 할 몇가지 개념이 있어서 준비해봤습니다!
윗줄 코드에 width와 height의 크기를 지정해놨는데, 이건 그냥 결과값의 크기(잘린이미지)를 지정해놓은 코드입니다.
point_list안에 있는 클릭한 위치의 값들을 나중에 변환행렬하여 결괏값을 도출하기 위해
src라는 변수에 float32라는 함수를 활용해 point_list를 넣어줍니다.그리고, dst라는 변수의 속성 값들은 우리가 모서리를 클릭해서 자르면 또 하나의 결괏 값 창이 나오는데, 그 창의 크기를 지정하기 위한 속성이라고 생각하면 됩니다. ( 윗 코드에서 width, height를 지정해놓은 코드와 동일한 기능 )
(밑 내용은 대충 이해한다는 느낌으로만 읽어주세요.)
warpPerspective 함수를 사용하여 퍼스펙티브 변환(PerspectiveTransformation)을 구현합니다.
퍼스펙티브 변환에서 원본 이미지의 모든 직선은 출력 이미지에서 직선으로 유지됩니다.
(이미지가 아무리 삐뚤어져있어도 모서리를 클릭해서 잘라내면 쭉 펴서 볼 수 있음)
퍼스펙티브 변환 행렬을 찾으려면 입력 이미지의 4점과 대응하는 출력 이미지의 4점(point_list)이 필요합니다.
getPerspectiveTransform 함수를 사용하면 대응하는 4점 쌍에 대한 변환 행렬을 구할 수 있습니다.
warpPerspective 함수를 사용하여 변환을 실행합니다.
위 내용이 무슨 말인지 이해를 못하실 분들을 위해 아주 간단하게 정리해드리겠습니다.
getPerspectiveTransform 함수로 인해 행렬변환이 이루어져 4개의 모서리대로 이미지가 잘리고,
warpPerspective를 활용해 잘린 이미지(결괏 값)를 도출 해 냅니다.4. 클릭한 요소 잘라내기 (final)
import cv2 import numpy as np img = cv2.imread('images/poker.jpg') width, height = 530, 710 point_list = [] COLOR = (255, 0, 255) def mouse_handler(event, x, y, flags, param): if event == cv2.EVENT_LBUTTONDOWN: # 마우스 왼쪽 버튼 누름을 감지하는 이벤트 point_list.append((x, y)) for point in point_list: cv2.circle(img, point, 15, COLOR, cv2.FILLED) if len(point_list) == 4: show_result() # 결과 출력함수 cv2.imshow('img', img) def show_result(): width, height = 530, 710 # input 데이터 만들기 src = np.float32(point_list) dst = np.array([ [0, 0], [width, 0], [width, height], [0, height]], dtype=np.float32) # Output 4개 지점 # 좌상, 우상, 우하, 좌하 (시계 방향으로 4 지점을 정의) matrix = cv2.getPerspectiveTransform(src, dst) # Matrix 얻어옴 result = cv2.warpPerspective(img, matrix, (width, height)) # matrix 대로 변환을 함 cv2.imshow('result', result) cv2.namedWindow('img') # img란 이름의 윈도우를 먼저 만들어 둠 -> 여기에 마우스 이벤트를 처리하기 위한 핸들러 적용 cv2.setMouseCallback('img', mouse_handler) cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows()그럼 이제 마지막입니다.
위에서 행렬변환을 위해 사용했던 코드를 그대로 가져와 show_result 라는 함수안에 복사 붙여넣기 하면 끝입니다!그럼 최종적으로 우리는 한 프로젝트 안에서 두개의 기능을 구현했습니다.
1. 마우스를 클릭하면 핑크색 원으로 클릭한 위치 표시.2. 마우스로 모서리를 클릭해 그 모서리 안에 담긴 요소를 잘라내 새로운 창에 표시.
결괏 값

참고문서
https://deep-learning-study.tistory.com/200
https://www.youtube.com/watch?v=XK3eU9egll8&t=8724s
https://pyimagesearch.com/2014/09/01/build-kick-ass-mobile-document-scanner-just-5-minutes/
'프로젝트' 카테고리의 다른 글
Python - 안면인식(OpenCV) (0) 2021.10.15