找不到“妹”字在哪?一款游戏看把你愁的,用我这个代码逻辑,不再被游戏困扰!

92 阅读3分钟

z.gif

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第30天,点击查看活动详情

项目需求

  翻遍了4399小游戏网站,发现一款考察“眼力”的游戏:“找妹子”。这款游戏的游戏目标是用最短的时间找到所有妹字,游戏的具体内容为在众多字中找到唯一的字。

  现在需要一套程序,该程序需要完成自动寻找一堆袜字中的妹字并点击该字的坐标。

需求分析

  实验着玩“找妹字”游戏,我顺手随便截取了几张游戏时候的画面(如下罗列所示:),对游戏画面分析可得如下信息:

  1. 游戏界面size基本保持一致(看起来不是这样的因为我截图时候手残);
  2. 每次的字体的底色都是白色,外界颜色却不一样;
  3. 妹和袜字的字体是一样的;
  4. 妹和袜字的字体大小也是一样的;
  5. 每一关出现的字的总数也都不一样;
  6. 每次的妹字出现方式为随机出现。
sendpix2.jpg sendpix3.jpg sendpix4.jpg sendpix5.jpg sendpix7.jpg

  总结上述的游戏逻辑与游戏画面的分析就很清楚了我们需要怎样去实现如何找到“妹”字了。
逻辑步骤:

  1. 截取当前屏幕图像(获取源数据);
  2. 直接对截屏图像进行裁剪,裁剪出边界银色的方框(因为游戏界面size不变);
  3. 提取出白底的妹与袜字;
  4. 对提取出来的字进行归一化到相同大小的size;
  5. 对提取出来的字进行对比,得到与“妹”字相同的字并记录位置;
  6. 鼠标点击一次输出的位置

  需要注意的是这里我们需要添加一个触发机制:只有当指定按键被按下时才执行“找妹字”辅助,因为这游戏不是打地鼠,可以在同一个位置重复点击。

实验调试

  构建从上述中的逻辑步骤的第3步获取汉字:从这个里面能够获取到核心的几个汉字,但是多了一个图像,这里可以暂时先不用理会,我们可以在后续归一化计算相似度剔除(明显和妹字不一样,这样只是增加了计算量)

image.png

import cv2
import numpy as np


# 输入灰度图,返回hash
def getHash(image):
    avreage = np.mean(image)  # 计算像素平均值
    hash = []
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            if image[i, j] > avreage:
                hash.append(1)
            else:
                hash.append(0)
    return hash


# 计算汉明距离  计算相似度越大越不相似
def Hamming_distance(hash1, hash2):
    num = 0
    for index in range(len(hash1)):
        if hash1[index] != hash2[index]:
            num += 1
    return num


img = cv2.imread("3.png")
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

h, w = gray.shape[:2]
m = np.reshape(gray, [1, w * h])  # 降维
mean = m.sum() / (w * h)  # 求均值

_, thresh1 = cv2.threshold(gray, mean, 255, cv2.THRESH_BINARY)  # 利用均值进行图像二值化

# 查找轮廓
_, contours, hierarchy = cv2.findContours(thresh1, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
img2 = img.copy()
cv2.drawContours(img2, contours, -1, (0, 0, 255), 0)

# 记录裁剪的坐标 ,裁剪图像的时候使用
list_coor = []

# 计算轮廓面积
for i in range(len(contours)):
    if i == 0:
        continue
    area = cv2.contourArea(contours[i])
    if area > 3000 and area < 5000:
        rect = cv2.minAreaRect(contours[i])
        box = cv2.boxPoints(rect)
        box = np.int0(box)
        list_coor.append(box)

# 要进行对比的图像
Image = cv2.imread('mei.jpg')
# 灰度化
Image = cv2.cvtColor(Image, cv2.COLOR_BGR2GRAY)
hash_1 = getHash(Image)

# 随便设置一个大值
error = 100000.0
error_coor = []
# 计算分割好的图像hash
for i in range(len(list_coor)):
    x, y = list_coor[i][1]
    x1, y1 = list_coor[i][3]
    img_temp = gray[min(x, x1):max(x, x1), min(y, y1):max((y, y1))]
    img_temp = cv2.resize(img_temp, (80, 80))
    cv2.imwrite("./img/%s.jpg" % i, img_temp)
    hash_2 = getHash(img_temp)

    ret = Hamming_distance(hash_1, hash_2)
    # print(ret)
    if ret < error:
        error = ret
        error_coor.clear()
        error_coor.append([min(x, x1), max(x, x1)])
        error_coor.append([min(y, y1), max(y, y1)])
        print(ret)

print(error_coor)  # [array([146, 144]), array([215,  74])]
x, y = error_coor[0]
x1, y1 = error_coor[1]
cv2.rectangle(img, (x, y), (x1, y1), (0, 0, 255), 3)
cv2.imshow('paper', img)

cv2.waitKey(0)