OpenCV图像识别初探-50行代码教机器玩2D游戏

举报
菊花茶 发表于 2019/06/13 17:26:56 2019/06/13
【摘要】 最近在研究OpenCV,希望能通过机器视觉解决一些网络安全领域的问题。本文简要介绍如何通过OpenCV实现简单的图像识别,并让计算机通过“视觉”自动玩一个简单的2D小游戏,文末有视频演示及完整代码。0x01 OpenCV介绍Open Source Computer Vision Library.OpenCV于1999年由Intel建立,如今由Willow Garage提供支持。OpenCV是...

最近在研究OpenCV,希望能通过机器视觉解决一些网络安全领域的问题。本文简要介绍如何通过OpenCV实现简单的图像识别,并让计算机通过“视觉”自动玩一个简单的2D小游戏,文末有视频演示及完整代码。

0x01 OpenCV介绍

Open Source Computer Vision Library.OpenCV于1999年由Intel建立,如今由Willow Garage提供支持。OpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、MacOS操作系统上。它轻量级而且高效——由一系列 C 函数和少量C++类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。最新版本是3.1 ,2016年1月29日发布。(引自百度百科openCV)   

简言之,通过openCV可实现计算机图像、视频的编辑。广泛应用于图像识别、运动跟踪、机器视觉等领域。

0x02 环境

  • Win7 或Win10操作系统

  • Python 3.5 以上

0x03 安装

  • pip install --upgrade setuptools

  • pip install numpy Matplotlib

  • pip install opencv-python

  • pip install pyautogui

  • pip install mss

  • pip install pynput

0x04 代码说明

这个网站提供一个简单的2D小游戏,越过障碍获得分数,我们希望让计算机模拟人的行为控制小恐龙跳过地面上不断出现的树木,整个程序可以被分成三个阶段,即屏幕监控(看) > 障碍物识别(识别) > 键盘控制(控制)。

屏幕监控

我们使用python mss对屏幕的指定区域进行监控,其实就是不断截图并对一帧一帧的图片进行分析。 这里monitor变量保存的是屏幕监控的区域

with mss.mss() as sct:
    # Part of the screen to capture
   ** = {'top': 280, 'left': 100, 'width': 660, 'height': 300}
    while 'Screen capturing':
        # Get raw pixels from the screen, save it to a Numpy array
        img = numpy.array(sct.grab(monitor))

图像识别

上一步我们通过监控屏幕上的指定区域可以获取到一帧一帧的图片,我们的目的是识别屏幕上出现的障碍物,以及障碍物的相对位置,这里主要是用OpenCV的matchTemplate方法在目标截图中查找已知的图像元素,所以我们要先截取一些障碍物的图片,如下图所示:

然后在目标图像中查找,这里我们设定图片比对的相似度阈值为65%,这样相当于是做模糊匹配,虽然可能会降低识别精准度,但可以少准备几个截图

res2 = cv2.matchTemplate(img_gray, tree1, cv2.TM_CCOEFF_NORMED)
threshold = 0.65
loc2 = numpy.where(res2 >= threshold)

识别到相应的障碍物以后我们希望在物体周围画一个矩形框,这样方便调试和查看效果

for pt in zip(*loc2[::-1]):
cv2.rectangle(img, pt, (pt[0] + tw, pt[1] + th), (0, 0, 255), 2)

鼠标及键盘控制

识别到屏幕上的障碍物以后,我们要控制鼠标和键盘做出相应的操作,这里我们使用pyautoguipynput实现鼠标键盘的模拟

def startgame():
    pyautogui.click(web)
    time.sleep(0.03)
    pyautogui.keyDown('space')
    time.sleep(0.03)
    pyautogui.keyUp('space')
    print('game start')

def jump():
    key.release(Key.down)
    key.press(Key.space)
    print('jump')
    time.sleep(0.3)
    key.release(Key.space)
    key.press(Key.down)


效果演示

meetingrec_0.gif

import time
import pyautogui
from pynput.keyboard import Key, Controller
import cv2
import mss
import numpy

# use browser to visit http://www.trex-game.skipser.com/
# put the browser to the left side and run the programme

key = Controller()

web = (200, 400)

tree1 = cv2.imread('tree1.png', 0)
tw, th = tree1.shape[::-1]

tree4 = cv2.imread('tree4.png', 0)
tw4, th4 = tree4.shape[::-1]

birdie = cv2.imread('birdie1.png', 0)
nw, nh = birdie.shape[::-1]


def startgame():
    pyautogui.click(web)
    time.sleep(0.03)
    pyautogui.keyDown('space')
    time.sleep(0.03)
    pyautogui.keyUp('space')
    print('game start')


def jump():
    key.release(Key.down)
    key.press(Key.space)
    print('jump')
    time.sleep(0.3)
    key.release(Key.space)
    key.press(Key.down)


startgame()

with mss.mss() as sct:
    # Part of the screen to capture

    monitor = {'top': 280, 'left': 100, 'width': 660, 'height': 300}

    while 'Screen capturing':
        key.press(Key.down)
        # Get raw pixels from the screen, save it to a Numpy array
        img = numpy.array(sct.grab(monitor))

        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        res2 = cv2.matchTemplate(img_gray, tree1, cv2.TM_CCOEFF_NORMED)
        res5 = cv2.matchTemplate(img_gray, tree4, cv2.TM_CCOEFF_NORMED)
        res3 = cv2.matchTemplate(img_gray, birdie, cv2.TM_CCOEFF_NORMED)

        threshold = 0.65

        loc2 = numpy.where(res2 >= threshold)
        for pt in zip(*loc2[::-1]):
            cv2.rectangle(img, pt, (pt[0] + tw, pt[1] + th), (0, 0, 255), 2)
            if pt[0] + tw < 280:
                jump()
                break

        loc2 = numpy.where(res3 >= threshold)
        for pt in zip(*loc2[::-1]):
            cv2.rectangle(img, pt, (pt[0] + nw, pt[1] + nh), (0, 0, 255), 2)
            print("{0},{1}".format(pt[0], pt[1]))
            if pt[1] + nh > 280 and pt[0] + nw < 420:
                jump()
                break

        loc5 = numpy.where(res5 >= threshold)
        for pt in zip(*loc5[::-1]):
            cv2.rectangle(img, pt, (pt[0] + tw4, pt[1] + th4), (0, 0, 255), 2)
            if pt[0] + tw4 < 280:
                jump()
                break

        # Display the picture
        cv2.imshow('OpenCV/Numpy normal', img)

        # Press "q" to quit
        if cv2.waitKey(25) & 0xFF == ord('q'):
            cv2.destroyAllWindows()
            break


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。