토이 프로젝트

OpenCV를 활용한 화면 감지 프로그램

길용쓰 2023. 12. 10. 17:33

 

메이플엔 물약 봉인 몬스터, 일명 물봉몹이 존재한다

체력이 일정 수치 이하로 떨어지면 자동으로 포션을 먹는데,

해당 몬스터는 포션 사용 금지 + 체비뎀 10%를 넣기때문에 사냥터에서의 잠수를 막는다.

 

그렇기에 물봉몹이 등장하면 이를 감지하여 알람을 울려주는 프로그램을 만들어봤다.

어떤 언어를 사용할까 고민하다가... 학부시절 배운 OpenCV가 생각나 이를 활용해보기로 결정

 

def capture_screen():
    screenshot = pyautogui.screenshot()
    screen = np.array(screenshot)
    screen = cv2.cvtColor(screen, cv2.COLOR_RGB2BGR)
    return screen

 

화면 캡쳐 함수.

pyautogui가 제공하는 screenshot() 함수로 스크린샷을 찍고

이를 numpy 배열로 변환

게임 이미지는 RGB이지만 Opencv는 BGR을 사용하므로 변환해서 리턴해준다.

 

def is_image_on_screen(template, screen, threshold):
    result = cv2.matchTemplate(screen, template, cv2.TM_CCOEFF_NORMED)
    _, max_val, _, _ = cv2.minMaxLoc(result)
    return max_val > threshold

특정 이미지가 화면에 존재하는지 확인하는 함수

threshold는 임계값으로, 높을수록 더 정확한 이미지를 요구한다.

cv2.TM_CCOEFF_NORMED는 이미지 매칭 메서드로, 정규화된 상관 계수를 사용한다.

스킬 아이콘으로 사용 여부를 판단하기로 했기에, 

밝기 변화에 민감한 해당 메서드를 사용했다.

 

https://deep-learning-study.tistory.com/242

 

[파이썬 OpenCV] 탬플릿 매칭으로 원하는 영상 찾기 - cv2.matchTemplate

탬플릿 매칭 - Template matching 템플릿 매칭은 입력 영상에서 (작은 크기의) 템플릿 영상과 일치하는 부분을 찾는 기법입니다. 템플릿은 찻을 대상이 되는 작은 영상을 의미합니다. 커널이라는 용어

deep-learning-study.tistory.com

더 자세한 설명은 여기

 

 

min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
_, max_val, _, _ = cv2.minMaxLoc(result)

return max_val > threshold

minMaxLoc는 최소값과 최대값, 그 위치를 리턴하는 함수로,

가장 높은 값만 필요하니 나머진 언더바로 처리했다.

해당 최대값이 임계값보다 높은지 아닌지로 특정 이미지가 존재하는지를 판단한다.

 

 

 

다음은 물봉몹 이미지.

처음엔 실제 gif를 프레임별로 나눈 뒤 배경을 제거하였는데

생각보다 적중률이 떨어져서 그냥 실제 인게임 사진을 찍었다.

 

 

이런 느낌으로 10장정도 찍었다

 

 

def load_images(image_paths):
    images = {}
    for i, path in enumerate(image_paths, start=1):
        image = load_image(path)
        images[f"img{i}"] = image
    return images

monster_image_paths = ["image/img1.png", "image/img2.png", "image/img3.png",
               "image/img4.png", "image/img5.png", "image/img6.png",
               "image/img7.png", "image/img8.png", "image/img9.png",
               "image/img10.png"]
monster_images = load_images(monster_image_paths)

이미지 로드해주고

 

def detect_monster(images, screen):
    for img_name, template in images.items():
        try:
            image_found = is_image_on_screen(template, screen, 0.5)
            if image_found:
                print(f"{img_name}이(가) 존재합니다.")
                play_music("music/monster_appear.mp3")
                return True
    else:
        print("모든 이미지가 화면에 존재하지 않습니다.")
        pygame.mixer.music.stop()
    return False

10장의 사진에 대해 위에서 만든 이미지 대조 함수를 호출한다.

만약 true값이 나오면 바로 break하게 하였음

 

def play_music(sound_path):
    pygame.mixer.music.stop()
    pygame.mixer.music.load(sound_path)
    pygame.mixer.music.play()

경고음은 pygame으로 mp3 파일 재생하면 간단히 해결

 

 

 

그리고 스킬 사용시 3분 쿨타임이 지나면 알람이 울리는 기능을 추가하였다. 

처음엔 스킬 키 입력을 트리거로 사용하려했는데

마우스가 게임에 포커스된 채론 키보드 입력을 인식 못하더라.

찾으면 방법이 있겠다만 그냥 화면 인식으로 뽕 뽑기로 했다.

 

처음엔 스킬 이펙트를 감지하려 했는데

감지 능력이 묘하게 불안불안해서...

그냥 스킬 아이콘을 감지하게 하고 임계값을 올리니 훨씬 안정적이었다.

def detect_attack_skill(screen):
    global is_attack_trigger, wtime
    if is_attack_trigger:
        is_attack = is_image_on_screen(w_icon_template, screen, 0.9)
        if is_attack:
            # 이후 3분동안 감지하지 않음
            is_attack_trigger = False
            wtime = time.time()
            play_music("music/skill_use.mp3")
            print("W 감지")
    else:
        if time.time() - wtime > 180:
            is_attack_trigger = True
            play_music("music/skill_cool_done.mp3")
            print("w 쿨타임 완료")

몬스터는 동적으로 움지이기에 임계값을 0.5로 하였는데,

스킬 아이콘은 정확히 구분해야하므로 0.9로 하였다.

 

그리고 스킬을 사용을 감지하고 이후 3분동안은

스킬 감지를 진행하지 않도록 하였다.

 

while True:
    # 화면 캡처후 특정 이미지 존재 여부 검사
    screen = capture_screen()

    # 몬스터 감지 및 소리 재생
    if detect_monster(monster_images, screen):
        continue  # Skip the rest of the loop if a monster is found

    # 공격 스킬 사용 감지
    detect_attack_skill(screen)
        
    time.sleep(0.5)

 

이제 반복문으로 매 초마다 화면을 감지하게 해주면 끝!

 

 

시범 영상

정상적으로 잘 작동한다!

 

 

 

https://github.com/gillyongs/Game-screen-detection/tree/main

 

GitHub - gillyongs/Game-screen-detection

Contribute to gillyongs/Game-screen-detection development by creating an account on GitHub.

github.com

깃허브.