美文网首页
原神位置检测【OpenCV 特征匹配】

原神位置检测【OpenCV 特征匹配】

作者: skkily | 来源:发表于2020-10-10 16:21 被阅读0次

OpenCV版本是3.4.2
Python版本是3.6
pyautogui版本是0.9.51
显示器为1920x1080
(其他像素当然能用,需要自己改)

效果

本项目实现了原神游戏中实时位置检测,将会在控制台返回人物所在的位置的(x,y)坐标,对应大地图上的像素点坐标。


run.gif

思路

1.使用OpenCV里面的Flann图片特征匹配,实现用右上角的小地图去匹配保存在本地的大地图

截图这个小区域
本地保存的大地图
注:地图截屏于原神wiki里的地图,链接
https://wiki.biligame.com/ys/

2.大地图匹非常耗时[将近5秒],而且吃CPU,所以大地图匹配一次后下次只匹配当前位置的大地图的一个小区域,可以看到第一次很慢,之后就快的多了


传送后地图大改变,只能重新全图匹配

2.使用一个小地图模板来实现检测当前是否是在游戏中,避免没有检测到地图也硬要去匹配地图,造成计算资源浪费


避免切换画面都会全图匹配

改进

1.可以不用截屏,obs采集屏幕,启用虚拟摄像头,opencv捕捉这个虚拟摄像头,可以有很好的防检测能力,就是会有不小的延迟
2.截屏也可以全图截屏,然后模板匹配后进行剪裁再规定此后的截屏大小,其实也不错,实现起来不费劲,但就是懒啊.....

用处?

这个只是检测,是第一步,获得位置后就能做导航,安卓端或者web端,想想一下在手机上可以跟百度地图一样显示当前位置,显示资源位置,规划导航路线,自己录制锄地路线,还是很有意思的,也许有空会做?(lazy)

Github

有点事情,等下上传

网盘链接

https://darksuger.lanzous.com/i3omghbfhlg

代码贴出来

import pyautogui
import os
import sys
import numpy as np
import cv2 as cv
import time

#OpenCV版本是3.4.2
#Python版本是3.6
#pyautogui版本是0.9.51


#设置项:截图的长宽
grapW=330
grapH=250

refreshSP=1

mapPath=os.path.join(sys.path[0],'map.png')
maskPath=os.path.join(sys.path[0],'mask.png')

mapCache=cv.imread(mapPath,0) #读取地图
mask=cv.imread(maskPath,0)#读取识别模板

theGlob=200 #地图剪裁半径
theX=theGlob 
theY=theGlob

largeMapping=True #大地图匹配位,表示是否进行全图匹配
ready=False #主页匹配位,表示当前截取到的画面是否包含地图

while True:
    map=mapCache.copy()
    img = pyautogui.screenshot(region=[0,0,grapW,grapH]) # 截图的x y w h
    img = cv.cvtColor(np.asarray(img),cv.COLOR_RGB2GRAY) # 图片灰度化
    #这个是用来测试的,测试屏幕截图的效果,能出现完整的居中的小地图即可
    #没有双屏可以先截图游戏再用截图测试
    #test(img) 

    try:
        if ready:
            if largeMapping==False:
                #将大地图裁剪后识别,增加匹配速度,减少cpu压力
                map=map[theY-theGlob:theY+theGlob,theX-theGlob:theX+theGlob]
                retX,retY=mapper(map,img)
                if retX!=-1:
                    #区域地图匹配成功
                    theX+=(retX-theGlob)
                    theY+=(retY-theGlob)
                    print((theX,theY))
                    time.sleep(refreshSP)
                else:
                    #区域地图匹配失败
                    print('none')
                    retX,retY=mapper(img,mask)#模板匹配,判断是否截图的是小地图
                    if retX!=-1:
                        largeMapping=True#模板匹配成功,判断已经进行了传送,转大地图匹配
                    else:
                        print('check ready')
                        ready=False
                        time.sleep(1)                     
            else:
                #全图匹配
                retX,retY=mapper(map,img)
                if retX!=-1:
                    theX=retX
                    theY=retY
                    print((theX,theY))
                    largeMapping=False
                else:
                    print('mapper error!')#全图匹配失败?
                    time.sleep(4)
        else:
            #模板匹配,判断是否截图到的图像是小地图
            retX,retY=mapper(img,mask)
            if retX!=-1:
                ready=True
                print('is ready')
            else:
                print('no ready!')
                time.sleep(1)
    except:
        print('???')#匹配算法出错,纯色截图下会出错,捕捉一下不处理。
        time.sleep(1)

def mapper(map,mapping):
    MIN_MATCH_COUNT=10 #设置最低匹配数量为10

    sift=cv.xfeatures2d.SIFT_create() #创建sift检测器
    kp1,des1=sift.detectAndCompute(mapping,None) 
    kp2,des2=sift.detectAndCompute(map,None)
    #创建设置FLAAN匹配
    FLANN_INDEX_KDTREE=0
    index_params=dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
    search_params=dict(checks=50)
    flann=cv.FlannBasedMatcher(index_params,search_params)
    mathces=flann.knnMatch(des1,des2,k=2)
    good=[]
    #过滤不合格的匹配结果,大于0.7的都舍弃
    for m,n in mathces:
        if m.distance<0.7*n.distance:
            good.append(m)
        #如果匹配结果大于10,则获取关键点的坐标,用于计算变换矩阵
    if len(good)>MIN_MATCH_COUNT:
        src_pts=np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1,1,2)
        dst_pts =np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)

        #计算变换矩阵和掩膜
        M,mask=cv.findHomography(src_pts,dst_pts,cv.RANSAC,10.0)
        matchesMask=mask.ravel().tolist()
        #根据变换矩阵进行计算,找到小图像在大图像中的位置
        h,w=img.shape
        pts=np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)

        dst=cv.perspectiveTransform(pts,M)#从左上逆时针表示的矩阵顶点

        theX=int((dst[0][0][0]+dst[2][0][0])/2)
        theY=int((dst[0][0][1]+dst[2][0][1])/2)#计算坐标点
        
        return theX,theY     
    else:
        return -1,-1
def test(img):
    cv.imshow(img)
    cv.waitKey(0)

转载注明原帖,禁止商用

相关文章

网友评论

      本文标题:原神位置检测【OpenCV 特征匹配】

      本文链接:https://www.haomeiwen.com/subject/ycfjpktx.html