OpenCV, PyAutoGui 를 이용한 느낌표 검출 (로아낚시매크로2)

이번 포스트에서는 PyAutoGui 라이브러리를 이용해 찌낚시의 완료를 알리는 느낌표를 검출해 보도록 하겠습니다. 

제목에 OpenCV 를 넣어놨지만 우리가 직접 OpenCV 를 사용하지는 않을 겁니다. 

다만 PyAutoGui 가 제공하는 함수중에 locateOnScreen 이라는 함수가 있습니다. 이 함수가 받는 optional 아규먼트 중에  confidence 라는 항목이 있는데 

이 항목을 지정하기 위해서는 OpenCV를 설치해야 합니다. 

(참고로 PyAutoGui 는 더블 모니터가 있을 경우 주 모니터만을 처리하게 됩니다. )

 

아래 명령어로 라이브러리를 설치해 줍니다. 

pip install pyautogui==0.9.38
pip install opencv_python

 

pyautogui 의 경우에 최신버전은 한글 윈도우에서 인코딩 문제로 설치되지 않습니다. 그래서 구버전을 지정해서 설치 했는데요. 구 버전도 쓰는데 문제는 없습니다. 

 

 1. 느낌표 스크린샷

코딩을 하기 전에 우선 느낌표 사진을 구해 봅시다.

로스트아크를 켜고 낚시를 수행하면서 뜨는 느낌표를 스크린샷 뜬 뒤 이쁘게 잘라줍니다. 저의 경우에는 아래와 같이 나왔네요 

다음으로 작업디렉토리에 img 폴더를 만들고 위 이미지 파일을 새로 만든 폴더 안에 저장해 줍니다. 그리고 이미지 파일 이름은 LA_exclamation_mark.png 로 설정하시기 바랍니다. 

작업 디렉토리는 아래와 같은 구조가 되겠습니다. 

/lostark

/ – /img

     / – LA_exclamation_mark.png

/ – fishing_place.py

/ – init.txt

 

그리고 init.txt 끝에 아래 내용을 추가 합니다. 

[lostark_fishing]
width = 200
heght = 200

 

 2. 느낌표 검출 코드

그럼 준비운동은 끝났고 이제 느낌표를 검출하는 코드를 만들어 보겠습니다. 

lostark 폴더 밑에 fishing_image.py 라는 파일을 만들고 아래 코드를 입력 합니다. 

import os
import time
import sys
import pyautogui as pa
import configparser

# - 주모니터의 화면의 Center 를 Return -
def getCenterOfScreen():
    tup = pa.size()
    tup = (int(tup[0]/2), int(tup[1]/2))
    return tup

# - 느낌표를 검출할 영역을 지정 -
def makeRegion(center, width, height):
    x = center[0]
    y = center[1]

    startPos = (x - width, y - height)
    region = (startPos[0], startPos[1], 2*width, 2*height)
    return region

# - 이미지 File이름, 검출 대상이 될 영역을 입력받아 이미지를 검출하는 함수
def findLcationWithImage(fileName, startPos, confidence=.7):
    file_path = os.path.dirname(os.path.realpath(__file__)) + '\\' + 'img' + '\\' + fileName
    result = pa.locateOnScreen(file_path, confidence=confidence, region=startPos)

    #print('.', end=' ')
    sys.stdout.write('. ')
    sys.stdout.flush()
    if result != None:
        print('Find Image ' +  str(result))
    return result


def findImageUntil(fileName, startPos, cnt = 60, confidence=0.8, wait=0.1):
    for i in range(cnt):
        imgpos = findLcationWithImage(fileName, startPos, confidence= confidence)
        if imgpos != None:
            break
        else:
            time.sleep(wait)
    if imgpos == None:
        return None
    else:
        return imgpos


if __name__ == "__main__":
    # - init.txt 의 width와 height 값을 읽어옴 
    configFile = os.path.dirname(os.path.realpath(__file__)) + '\\' + 'init.txt'
    config = configparser.ConfigParser()
    config.read(configFile)

    width = int(config['lostark_fishing']['width'])
    height = int(config['lostark_fishing']['heght'])

    region = makeRegion(getCenterOfScreen(), width, height)
    findImageUntil("LA_exclamation_mark.png", region, cnt=60, confidence=0.8)

 

위 코드에서 findImageUntil 이라는 함수에서 알 수 있듯이 지정한 영역에서 LA_exclamation_mark.png 의 그림과 비슷한 그림이 나올 때 까지 60번 동안 0.1초씩 쉬고 검출 작업을 수행하겠다는 내용입니다. 

이 60번이라는 숫자는 실험적으로 정한 숫자 입니다. 모니터 해상도에 따라 작업이 빨리 수행될 수도 있고 느리게 수행 될 수 도 있습니다. 

저는 4K 모니터를 쓰는데 cnt=60 이 가장 적당하더군요 ! 만약 4K 보다 낮은 해상도를 쓰신다면 그리고 Region 영역을 작게 잡으신 경우라면 60 보단 큰게 안정적일 수 있습니다. 

 

자 그럼 테스트를 해보겠습니다. 

로스트아크에 접속 하여 아래처럼 찌를 던진 뒤 코드를 실행해 보세요 

찌를 던진 뒤 코드를 실행

그러면 느낌표가 나오기 전까지는  . . . . 화면이 반복되다가 느낌표가 출력 되면 아래와 같이 Image 가 검출된 위치를 표시하는 내용이 나올 것입니다. 

만약 느낌표가 나오기 전에 프로그램이 종료 되어 버린다면 findImageUntil을 호출하는 부분에서 cnt 값을 늘려주세요 그리고 느낌표가 나왔는데도 프로그램이 검출을 못하는 경우엔 confidence를 0 ~ 1 사이의 값으로 조절해 보세요! (Full HD, 4K 에서는 confidence = 0.8 로 잘 검출 되는 것을 확인 했습니다.)

 

이것으로 이번 포스트는 마치도록 하겠습니다. 

다음 포스트에서는 낚시 매크로를 완성해 보도록 하겠습니다. 

You may also like...

15 Responses

  1. 댓글:

    심심해서 테스트 해보려다가 안되길래 왜 안되나 보니까,
    저는 느낌표 이미지 파일의 크기가 화면과 다르더군요 ^^
    혹시나 안되시는 분들은 참고하시길 (1/2사이즈 작게 하니 됬습니다. 본인 캡처파일도 해도될듯)
    재밌는 매크로 감사합니다

    • 호그 댓글:

      넵 맞습니다 ㅋㅋㅋ 사용자 별로 모니터 해상도가 다르다 보니 느낌표는 자기 모니터에서 캡쳐 해야 잘 동작 할 것 같습니다. ^^

  2. 우하하 댓글:

    정학한 실행법을 모르겠네요 ㅠ 대충 따라한것 같긴한데 뭘 어떻게 실행을 하는건지..ㅠㅠ

    • 호그 댓글:

      CMD에서 python fishing_image.py 하면 코드가 실행 됩니다. ㅎㅎ 그리고 해당 코드는 느낌표만 검출하는 코드입니다.

  3. 임윤 댓글:

    반갑습니다 코딩 잘 봤습니다
    전체적으로 어려운 부분이 많이 있는데 어디부분을 좀 기초적으로 배우면 될까요

    • 호그 댓글:

      일단 Python 기초 전체를 이해하시고 본문에서 소개한 도큐먼트들에 예제를 따라해 보면 될것 같습니다. ㅎㅎ 일단 https://wikidocs.net/43 요 사이트 참조 하셔도 좋을 것 같아요

  4. PUVI 댓글:

    코드를 실행하면 작동이 되지 않네요.. 오류가 났다고 하는데
    위에 코드중에서 제 상황에 맞게 바꿔야 하는 사항들이 있는건가요?

    • 호그 댓글:

      느낌표 스크린샷은 본인 환경에서 해야하고 파일 이름은 LA_exclamation_mark.png 이여야 하며 img 폴더 밑에 있어야합니다.
      혹시 어떤 에러 코드가 나왔나요 ?

  5. iiooii 댓글:

    질문이 있습니다. 느낌표 찾는 매크로를 돌리면 아래 부분부터 오류가 납니다.
    findImageUntil(“LA_exclamation_mark.png”, region, cnt=60, confidence=0.8)
    이유를 알 수 있을까요?

  6. T^T 댓글:

    아얘 작동을 안하는데 뭐가 문제일까요..?

  7. cons 댓글:

    정말 설명대로 차근차근 진행하니 정상작동되어 너무 기쁩니다.
    한가지 아쉬운점은 컴파일해서 onefile로 만들어서 실행하니 뭔가 문제가 있는지 작동을 안하네요.

    궁금한점은 confidence 값에 대해서 입니다. 1로 하면 어떤 현상이 일어나구 0으로 하면 어떤 현상이 일어나는지 설명가능하실까요? 1에 가까워질수록.. 값이 높을수록 이미지 파일과 동일해야만 반응하는지 .. 어떤지.. 알고싶습니다.

    • 호그 댓글:

      예상하신대로 입니다. confidence 가 1에 가까울수록 비교 사진과 같아야지만 검출됩니다. 반대로 0으로 갈수록 덜 비슷한 사진도 검출하게 됩니다.

  8. 황혼 댓글:

    안녕하세요? 파이썬이 흥미가 있어서 여러가지 매크로를 공부해보고 있습니다.
    최근에 유튜브를 보면서 기차자동예매라던가 공연티켓팅자동예매 등 같은걸로 공부해봤었는데
    이걸 보면서 궁금한게 생겼습니다.

    예를 들어서
    A바둑판과 B바둑판에 들어있는 여러가지 파일들이 있다고 상상해보고,
    바둑판안에 수많은 칸들이 들어있으며, 비어있는 칸들도 있고 파일이 들어간 칸들도 있습니다.
    (비어있는 칸은 하얀색칸, 파일이 들어가는 칸은 검정색)
    B바둑판에 있는 파일을 가지고 A바둑판에 있는 비어있는 칸으로 옮기고 싶다! 라고 한다면
    어떤 코드를 사용해야하는지 잘모르겠네요..

    (예시)
    #A바둑판 (파일을 넣을 A바둑판)
    f1_start = (1000,600) #영역내에서 시작한 위치부터 끝나는 위치까지 비어있는 칸을 찾아 넣기
    f1_end = (1200,800)
    #B바둑판 (넣을 파일을 꺼내야하는 B바둑판)
    f2_start = (250, 50) #영역내에서 시작한 위치부터 끝나는 위치까지 원하는 파일을 찾아 꺼내기
    f2_end = (400, 150)
    c_y = (255,255,255) #(칸에 파일보유중인 상태 / 하얀색칸)
    c_n = (0,0,0) #(칸이 완전히 비어있는 상태 / 검은색칸)

    이럴 경우에는, 어떻게 코드를 짜야되는지 알려주실 수 있으신가요?

댓글 남기기

이메일은 공개되지 않습니다.