[python OpenCV] 이미지 프로세싱 및 서칭

이진중·2023년 7월 3일

Python

목록 보기
1/2

📌프로젝트 설명

메이플스토리에는 "수상한큐브"라는 아이템이 존재한다. 해당 아이템을 통해서 아이템의 잠재능력을 재설정 할 수 있다. 각각의 옵션에 대한 확률을 구하기 위해 큐브매크로 및 이미지 서칭을 진행했다.
이 글은 그중 "이미지서치"를 하는 방법에 초점두고 있습니다.

본 테스트는 테스트서버에서 진행했음을 전합니다.


📌사용한 라이브러리

OpenCV, numpy, ImageGrab


📌Why OpenCV (vs pyautogui)

파이썬에 이미지 서치 라이브러리 'pyautogui'와 OpenCV 라이브러리가 이미지 서치를 지원한다.
먼저 pyautogui의 사용법은 다음과 같다.

# input : 이미지에 해당하는 url
# doing : 이미지가 화면에 등장할때까지 while 대기
import pyautogui as pag
pos = pag.locateCenterOnScreen(url)

pag.locateCenterOnScreen(url)은 현재 화면을 캡쳐한 캡쳐본에 URL에 해당하는 이미지가 존재하는지 확인하는 함수이다.

해당 라이브러리는 이미지들을 섬세하게 컨트롤하기 힘들었다.
따라서 하나의 픽셀의 하나의 명암이 달라도 매칭이 발생하지 않는 상황이 발생했다.
예시 : 아래 이미지처럼 반투명 이미지의 경우 매칭이 발생하지 않는다.

메이플 옵션

다음은 OpenCV 라이브러리 사용방법이다.

# 이미지를 로드
img = cv2.imread(url, cv2.IMREAD_GRAYSCALE)
# 전처리 : v값를 임계값으로 v보다 작은 명암을 가진 픽셀은 0으로 큰 픽셀은 255로 만든다.
trash, processingImg = cv2.threshold(cap, v, 255, cv2.THRESH_BINARY)
# 이미지 매칭 결과를 res에 저장
res = cv2.matchTemplate(img, templete,  cv2.TM_CCOEFF_NORMED)
# 매칭카운트 계산하는 방법
loc = np.where(res >= 0.998)
matchingCount = len(loc[::-1][0])

📌최종적으로 다음과 같은 함수 2개를 만들어서 사용했다.

  1. 이미지를 로드하여 조건에 맞게 전처리하는 imgPreprocessing 함수
def imgPreprocessing(url, v = 127):
    cap = cv2.imread(url, cv2.IMREAD_GRAYSCALE)
    return cv2.threshold(cap, v, 255, cv2.THRESH_BINARY)
  1. 이미지 두개를 입력으로 받은 후 templete 에 해당하는 이미지가 img에 존재하는지 확인하는 함수
def imgMatching(img, templete):
    res = cv2.matchTemplate(img, templete, cv2.TM_CCOEFF_NORMED)
    loc = np.where(res >= 0.998)

    return len(loc[::-1][0])

📌핵심 코드

trash, cap = imgPreprocessing('./cap.png')
optionList = [
        'S6', 'S3', 'plus',
        'D6', 'D3',
        'I6', 'I3',
        'L6', 'L3']
        
for i in optionList:
        stetUrl = IMG_URL + "/stet_inven/" + i + ".png"
        trash, templete = imgPreprocessing(stetUrl)
        cnt = imgMatching(cap,templete)

        if cnt > 0:
            if i[0] == 'S':
                if i[1] == '6' or i[1] == '4':
                    STET[0] += 6 * cnt
                else:
                    STET[0] += 3 * cnt
            if i[0] == 'D':
                if i[1] == '6' or i[1] == '4':
                    STET[1] += 6 * cnt
                else:
                    STET[1] += 3 * cnt
            if i[0] == 'I':
                if i[1] == '6' or i[1] == '4':
                    STET[2] += 6 * cnt
                else:
                    STET[2] += 3 * cnt
            if i[0] == 'L':
                if i[1] == '6' or i[1] == '4':
                    STET[3] += 6 * cnt
                else:
                    STET[3] += 3 * cnt
            if i[0] == 'p':
                STET[0] += 1
    # print(STET)

📌 이미지 서치 원리

실제로 필자가 처음 시도한 방법은 for문 2개로 픽셀 하나하나 비교하는 방법이었다. 그렇게 알고리즘을 작성한 후 실행했을땐 하나의 이미지를 서치하는 시간이 몇초단위로 걸렸다. 반면 라이브러리의 경우 ms 단위로 서치가 가능했다.

pyautogui, OpenCV의 경우 어떻게 그렇게 빠른 연산이 가능했을까?? cv2 홈페이지에서 matching 함수에 대한 내부동작 연산을 찾을 수 있었다.

사이트

수학적 배경지식 없이 이해하기 힘들었지만, Docs 예시에서도 매칭 결과인 res를 numpy로 다루는 것을 미루어 보아 numpy와 수학적 알고리즘을 사용하여 단순히 하나의 픽셀들을 비교하는 게 아니라, 여러 픽셀들을 합연산 및 곱연산을 진행하여 정보를 탐색하는 것을 알 수 있었다.

📌 느낀점

여러 라이브러리들을 사용해보면서 나의 프로젝트에 어떤 라이브러리가 적합한지 고민해보았다.

'개발편의성' (pyautogui처럼 단순 url만 입력해도 이미지서치가 가능)
'커스텀가능성' (OpenCV처럼 기능들을 얼마나 분리하여 마음대로 수정할 수 있는지)
들을 고민하여 라이브러리를 선택해야겠다.

0개의 댓글