opencv-python 将图像迷宫转为迷宫数组

起因是我想做个自动走迷宫的外挂(其实是想做点实践),所以我需要在游戏中捕捉画面并自动寻路,然后再控制自动移动,此为第一部分:捕捉画面。

一.思路

1.取得图像迷宫

2.处理图像

3.图像分割

4.生成数组

二.代码

首先我们得捕捉屏幕画面,即获得迷宫图像,这里我是在steam上面找了一个迷宫小游戏作为捕捉对象

在这里插入图片描述

然后写个捕捉屏幕画面的函数

def VideoCapture():
    imm = ImageGrab.grab()  # 获得当前屏幕
    imm = cv2.cvtColor(np.array(imm), cv2.COLOR_RGB2GRAY)  # 转为opencv的灰度图
    imm = imm[35:1040, 450:1470]  # 1080*1100 裁剪图像,这是根据游戏画面调整的数值 
    imm = cv2.resize(imm, (250, 250))  # 19 * 19 缩小图像
    return imm

然后如果显示图像就能看到:

opencv-python 将图像迷宫转为迷宫数组_第1张图片

接着我们需要对图像进行处理,我们可以看到这个迷宫有三个对象:从上到下依次是巢,心,球。而我们是要操控球吃完所有的心再返回巢。所以 巢和心的是需要搜索路径的终点,球是起点,但是在此之前,我们需要一个完整的迷宫地图,所以我们要先找到这三个对象并涂白:

所以我们要进行模板匹配:

def match(target, template, color):
    global object
    # 获得模板图片的高宽尺寸
    theight, twidth = template.shape[:2]
    # 执行模板匹配,采用的匹配方式cv2.TM_SQDIFF_NORMED
    result = cv2.matchTemplate(target, template, cv2.TM_SQDIFF_NORMED)
    # 归一化处理
    cv2.normalize(result, result, 0, 1, cv2.NORM_MINMAX, -1)
    # 寻找矩阵(一维数组当做向量,用Mat定义)中的最大值和最小值的匹配结果及其位置
    min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result)
    # 匹配值转换为字符串
    # 对于cv2.TM_SQDIFF及cv2.TM_SQDIFF_NORMED方法min_val越趋近与0匹配度越好,匹配位置取min_loc
    # 对于其他方法max_val越趋近于1匹配度越好,匹配位置取max_loc
    strmin_val = str(min_val)
    # 绘制矩形边框,将匹配区域涂成白色
    # min_loc:矩形定点
    # (min_loc[0]+twidth,min_loc[1]+theight):矩形的宽高
    # color:矩形的边框颜色;2:矩形边框宽度
    cv2.rectangle(target, min_loc, (min_loc[0] + twidth, min_loc[1] + theight), color, -1)
    # 返回操作后图像,以及对象的四点坐标
    return [target, (int(min_loc[0]), int(min_loc[1]), int(min_loc[0] + twidth), int(min_loc[1] + theight))]

执行后效果如图所示:

opencv-python 将图像迷宫转为迷宫数组_第2张图片

然后我们要把图像转化为标准的迷宫图像,黑白块的大小要相等,这样才方便转化成数组形式,所以我们对图像进行二值化后白色为可走趋于,黑色为障碍,接着通过腐蚀操作增大黑色趋于使之与白色块大小接近。

def pic(imm):
    ret, binary = cv2.threshold(imm, 200, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)# 二值化
    k = np.ones((7, 7), np.uint8)#定义核
    binary = cv2.erode(binary, k)# 腐蚀
    return binary

opencv-python 将图像迷宫转为迷宫数组_第3张图片

然后大致数出可以划分为19*19的色块,计算出单个色块的长度,然后定义每个色块的近中心点(因为坐标只能整数而计算中心点会有小数,一般略微靠近左上角比较准确),取其近中心点的颜色为整个色块的颜色转化为数组中:

def getBoard(imm):
    board = [[0 for w in range(19)] for h in range(19)]#创建数组
    for h in range(19):
        for w in range(19):
            if imm[13 * h + 5, 13 * w + 5] == np.uint8(255):#坐标转换
                board[h][w] = 255
    return board

然后我们把得到的数组以图像的形式打印出来看看:

在这里插入图片描述

对比一下原图像,已经实现了我们的目的。

最后我们再把其他信息获取一下,比如对象位置转化为数组坐标:

def getBoardIndex(cor):
    index = (int((cor[1] - 5) / 13), int((cor[0] - 5) / 13))
    return index

然后我们也方便日后的寻路算法应用(这么小,很快!)

最后的最后给个运行代码:

startFlag = False
while True:
    imm = VideoCapture()
    if startFlag:
        imm, ball = match(imm, cv2.imread("ball.png", 0), (255, 255, 255))
        imm, home = match(imm, cv2.imread("home.png", 0), (255, 255, 255))
        imm, heart = match(imm, cv2.imread("heart.png", 0), (255, 255, 255))
        imm = pic(imm)
        board = getBoard(imm)
        cv2.imwrite("board.png", np.array(board, dtype=np.uint8))
        ball = getBoardIndex(getPointCor(ball))
        heart = getBoardIndex(getPointCor(heart))
        home = getBoardIndex(getPointCor(home))
        print(ball, heart, home)
    key = cv2.waitKey(1)
    if key == ord('q'):
        break
    elif key == ord('g'):
        startFlag = True
    cv2.imshow("im", imm)
 key = cv2.waitKey(1)
    if key == ord('q'):
        break
    elif key == ord('g'):
        startFlag = True
    cv2.imshow("im", imm)

你可能感兴趣的:(opencv,python,计算机视觉)