본문 바로가기

졸업프로젝트/OpenCV

[OpenCV] 이미지에서 특정 이미지 찾아내기

728x90

답지에서 해당 답의 영역만을 추출하기 위해서는

다음과 같은 "답"이라는 이미지를 답지 페이지내에서 찾아낸 후 해당 이미지를 기준으로 그 아래를 자르면 된다 

 

그래서 일단 이번 게시글에서는 

수능완성2021년 수학 가형 2page

이런 답지의 페이지 내에서 

다음과 같이 "답"이라는 이미지를 전부 찾아내는 것을 목적으로 한다 

 

 

1. 찾아내길 원하는 이미지 크롭하기

먼저 이 이미지를 따로 만들어내야 한다

주의할 점은 위와 같은 찾아내려는 목적이미지를 절대로 캡쳐 해서는 안되고 

원본이미지(답지이미지)에서 그 부분("답")을 잘라내야 한다는 점이다. 

 

잘라내는 방법으론 여러가지 방법이 있지만 그냥 자르는 사이트를 이용해서 잘라냈다

www.iloveimg.com/ko/crop-image

 

이미지를 신속하게, 무료로 잘라내세요!

JPG, PNG, GIF 파일을 신속하게, 무료로 잘라내세요!

www.iloveimg.com

 

2. 이미지 불러오기

답지 이미지찾아내길 원하는 이미지 (지금부터 탬플릿이라고 부른다) 를 불러온다

# 답지 이미지 
img_rgb = cv2.imread('/ans_2021_suwan_ga_002.png')

#탬플릿
template = cv2.imread('/answer_temp.png')

 

 

3. 템플릿 매칭 

 

더보기

matchTemplate

res = cv2.matchTemplate(image : 원본이미지 , template : 찾아낼 이미지 , method)

 

원본이미지와, 찾아낼 이미지(template)을 input으로 넣고, method를 정하면 

원본 픽셀이 템플릿의 이미지와 유사한 정도를 gray이미지로 표현한 것을 array형태로 return한다.

-> 이미지가 array형태로 변환되어 각 픽셀당 계산 값을 담아 출력된다.

(약간 이런형태)

 

이때 강도는 매칭 방법에 따라서 다르다. 

 

method 

  • TM_SQDIFF : 픽셀값의 제곱차를 이용 ,가장 어두운 곳을 기준으로 매칭 
  • TM_SQDIFF_NORMED : 제곱차 매칭 방법에서 정규화, 가장 어두운 곳을 기준으로 매칭 
  • TM_CCORR : 상관관계계 방법 입력 값의 곱을 모두 제곱하여 더함, 가장 밝은 곳을 기준으로 매칭
  • TM_CCORR_NORMED : 위의 방법을 정규화한 것, 가장 밝은 곳을 기준으로 매칭
  • TM_CCOEFF : 보통 가장 정확한 결과를 내나 연산량이 많음, 가장 밝은 곳을 기준으로 매칭
  • TM_CCOEFF_NORMED : 위의 방법을 정규화한 것, 가장 밝은 곳을 기준으로 매칭 

더 자세한 내용

docs.opencv.org/master/df/dfb/group__imgproc__object.html#ga3a7850640f1fe1f58fe91a2d7583695d

 

 

# 탬플릿 매칭 해내기 
res = cv2.matchTemplate(img_rgb, template, cv2.TM_CCOEFF_NORMED)

# 임계치 정하기 
threshold = .65

#임계치 이상만 배열에 저장
loc = np.where(res >= threshold)

템플릿을 매칭 한 후 임계치를 정한다 

특정 임계치 값을 넘어서는 값일 때만 "답"이미지 라고 판단한다 

*임계치는 실험적인 값으로 정해야한다

너무 작으면 이상한 이미지를 해당 이미지라고 할 수 있고,

너무 크면 "답"이미지를 정확하게 전부 추출할 수 없다.

np.where(조건문)

res라는 array에서 괄호 안에 들어있는 조건을 만족할 경우만 return한다.

 

 

4. 이미지에 박스 그리기

#템플릿의 가로(w),세로(h)길이 저장
h, w = template.shape[:-1]


for pt in zip(*loc[::-1]):  # Switch collumns and rows
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)
    #빨간색 굵기2의 박스를 그림 

cv2_imshow(img_rgb)

 

내장함수 zip

동일한 개수로 이루어진 자료형을 묶어 주는 효과를 준다.

 

loc를 출력해보면 다음과 같다 

print(loc)

>>(array([ 279,  279,  625,  626,  754,  754, 1026, 1027, 1235, 1235, 1716]), 
array([1544, 1545,  777,  777, 1544, 1545,  777,  777, 1544, 1545,  777]))

array 2개로 이루어져 있는데 

첫번째 array는 원본 이미지 내 "답"이라는 템플릿의 y좌표

두번째 array는 원본 이미지 내 "답"이라는 템플릿의  x좌표

이다. *여기서 보통 x가 먼저 오는게 순서에 맞기 때문에 [::-1]을 사용해서 column과 row를 바꾸어준 것 

 

이에 zip을 쓰면 첫번째와 두번째 array의 갯수가 동일 하기 때문에, 

이들을 각각 하나로 묶어서 pt라는 배열로 만들어준다 

#for를 이용하여 
print(pt)

>> (1544, 279)
(1545, 279)
(777, 625)
(777, 626)
(1544, 754)
(1545, 754)
(777, 1026)
(777, 1027)
(1544, 1235)
(1545, 1235)
(777, 1716)

pt[0] : x 좌표

pt[1] : y좌표 

 

*args

해당 파라미터에 몇개를 입력받을지 모를 때 사용한다.

함수 내부에서는 tuple로 받은 것 처럼 인식한다. 

-> 여기에서는 zip이라는 내장함수를 이용하는데 몇개의 파라미터를 받을지 모르기 때문에 사용한 것으로 추측 

 

 [:-1] : 맨 오른쪽 값을 제외한 전체
h, w = template.shape[:-1]

shape는 height,width, channel을 반환하기 때문에 맨 오른쪽 channel 값을 제외한

h = 템플릿의 height값

w = 템플릿의 width값 을 저장함

 

[::-1] : 역순으로 배열 

arr[a:b:c] , index a부터 index b까지 c의 간격으로 배열을 만들기

arr[::-1] : 전체 배열을 -1간격으로 (역순으로)

 

rectangle: 사각형 그리는 함수 
cv2.rectangle(image : 사각형을 그리려는 원본이미지, point1 : 왼쪽top point, point2 : 오른쪽 bottom point, color : rgb , thickness : 선 굵기)

 

 

5. 끝

전체코드)

import cv2
import numpy as np
from google.colab.patches import cv2_imshow

#구글 드라이브와 연동 
from google.colab import drive
drive.mount('/gdrive')
 


img_rgb = cv2.imread('/gdrive/MyDrive/ProjectStudy/answers/raw_data/Suwan_ga/2021/example/ans_2021_suwan_ga_002.png')
template = cv2.imread('/gdrive/MyDrive/cropStudy/answer_temp.png')
h, w = template.shape[:-1]

res = cv2.matchTemplate(img_rgb, template, cv2.TM_CCOEFF_NORMED)
threshold = .65
loc = np.where(res >= threshold)


for pt in zip(*loc[::-1]):  # Switch collumns and rows
    print(pt)
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0, 0, 255), 2)

cv2_imshow(img_rgb)

 

결과)

 

 

 

 

 

참고사이트 

stackoverflow.com/questions/7853628/how-do-i-find-an-image-contained-within-an-image

 

How do I find an image contained within an image?

I'm currently building what basically amounts to a cross between a search engine and a gallery for web comics that's focused on citing sources and giving authors credit. I'm trying to figure out a...

stackoverflow.com

m.blog.naver.com/windowsub0406/220540208296

 

템플릿 매칭(Template matching)

※ Visual Studio 2012 , Opencv 2.4.9 템플릿 매칭이란템플릿 매칭(template matching)은 참조 영상(re...

blog.naver.com

blog.wonkyunglee.io/3

 

[Tip] Python Array[::] 사용법

Python array[::] 용법 간단한 파이썬 팁입니다. arr[::], arr[1:2:3], arr[::-1] 등으로 배열의 index에 접근하는 방법을 Extended Slices 라고 부릅니다. 설명 arr[A:B:C]의 의미는, index A 부터 index B 까지..

blog.wonkyunglee.io

medium.com/@hckcksrl/python-zip-내장함수-95ad2997990

 

Python zip 내장함수

“Python zip 내장함수” is published by 홍찬기.

medium.com

brunch.co.kr/@princox/180

 

[나름 중급 파이썬1] *args와 **kwargs

항상 헷갈리는 두 가지 다시 한번 살펴보자 | 이 글은 파이썬의 문법을 모르면 이해하기 어렵습니다. python의 함수 작성 요령, 인자(argument)와 파라미터를 이해한다면 도움이 되는 내용입니다. 아

brunch.co.kr

 

728x90