作者:Yiutto,编程浪子
GitHub:
github.com/Yiutto
之前有看到有人用python实现自动运行
微信小程序《跳一跳》
,后来看到别人用hash码实现《加减大师》的自动答题领取娃娃,最近一直在研究深度学习,为啥不用机器学习实现呢?不就是一个分类问题吗!
如何实现自动答题微信小游戏《加减大师》?
思考:
一、图像特征工程
如何获取手机游戏上的图片?
实验结果:
三种截屏方式花费的时间差异很大,第一种每次截屏需要0.7s左右,第二种0.3s左右,第三种0.04s左右。
当然选择第3种咯,下载地址
[https://www.apowersoft.cn/phone-mirror]
,一个好的软件是成功的关键(够清晰)。
获取训练样本
相关步骤:
1.
util.py
中的
shotByWinAPI
函数:首先利用window自带api获取全屏图片,然后自定义
config.py
的相关参数。
# 从PC端截屏时,截取区域左上角相对桌面的x坐标
'projection_x': 32,
# 从PC端截屏时,截取区域左上角相对桌面的y坐标
'projection_y': 278,
# 从PC端截屏时,截取区域的宽度
'projection_width': 482,
# 从PC端截屏时,截取区域的高度
'projection_height': 854,
可以用window命令键
PrtScSysRq
(F12的右边),然后复制到画图中(1920x1080)。
用画图的放大镜放大,图中红色框的小方块位置(32x278)
projection_x
即32,
projection_y
即278。
在画图中计算出截图的宽度和高度,即
projection_width
和
projection_height
(482x854)
2.
img_tool.py
函数介绍:主要是通过
all(img,filename)
函数进行图片分割
srcImg = cv2.imread(os.path.join("ScreenShotForTrain", f), 0)
上述代码是为了将彩色图片灰度模式加载
def all(img, filename):
"""封装对图片的所有操作"""
img = cropImg(img)
img = binaryImg(img)
img1, img2 = cropAgain(img)
imgs = cutImg(img1, filename + '_1') + cutImg(img2, filename + '_2')
return imgs
def cropImg(img):
"""裁剪原始截图"""
height = img.shape[0]
img2 = img[
int(config.config['exp_area_top_rate'] * height):int(config.config['exp_area_bottom_rate'] * height),:]
#print('裁剪完毕')
return img2
cropImg(img)
函数主要是为了裁剪含有数字的区域,通过设置参数
#表达式区域的顶部处于整张图片的位置(307/854=0.359)
'exp_area_top_rate': 0.36,
#表达式区域的底部处于整张图片的位置(478/854=0.559)
'exp_area_bottom_rate': 0.56,
如果觉得设置比例太麻烦,可以直接写死位置(
img2=img[int(307):int(478),:]
)。得到如下图:
def binaryImg(img):
"""二值化图片"""
ret, thresh1 = cv2.threshold(img, config.config['binary_threshold'], 255, cv2.THRESH_BINARY)
# ret, thresh1 = cv2.threshold(img, config.config['binary_threshold'], 255, cv2.THRESH_BINARY_INV)
#print('二值化完毕')
return thresh1
binaryImg(img)
函数主要是为了将图片二值化,可以参考
Python+OpenCV教程6:阈值分割
。得到的图片如下图:
def cropAgain(img):
"""再次裁剪"""
height = img.shape[
0]
img1 = img[0:int(0.5 * height), :]
img2 = img[int(0.5 * height):height, :]
#print('再次裁剪完毕')
return img1, img2
cropAgain(img)
函数主要是为了将图片分成上下两部分
def cutImg(img, filename):
"""水平分割图片"""
sb = np.array(img)
print(sb.shape)
sum_list = np.array(img).sum(axis=0)
start_index = -1
res = []
names = []
index = 0
for sum in sum_list:
if sum > 255 * 4:
if start_index == -1:
start_index = index
else:
if start_index != -1:
if config.config['type'] == 0:
sigleCharWidth = config.config['abd_single_char_width']
else:
sigleCharWidth = config.config['pc_single_char_width']
#为了防止字符粘连,需要在此处宽度进行判断
if index - start_index > sigleCharWidth * 2:
res.append((start_index,start_index + (index - start_index) // 2))
res.append((start_index + (index - start_index) // 2, index))
else:
res.append((start_index, index))
start_index = -1
index += 1
imgs = []
count = 0
for single_char in res:
start = single_char[0]
end = single_char[1
]
sub_img = img[:, start:end]
sub_img = cv2.resize(sub_img, (120, 240), interpolation=cv2.INTER_CUBIC)
#cv2.imwrite('SingleChar/%s_%d.png' % (filename, count), sub_img)
#names.append('%s_%d.png' % (filename, count))
# cv2.imshow(str(count), sub_img)
imgs.append(sub_img)
count += 1
# cv2.waitKey()
#print('分割,重新设置大小 %s 完毕' %filename)
return imgs
设置
pc_single_char_width
参数值,得到如下图:
c = 0
def v_cut(img):
global c
"""竖直方向切割图片"""
sb1 = np.array(img)
print(sb1.shape)
sum_list = np.array(img).sum(axis=1)
start_index = -1
end = -1
index = 0
for sum in sum_list:
if sum > 255 * 2:
start_index = index
break
index += 1
for i in range(1, len(sum_list) + 1):
if sum_list[-i] > 255 * 2:
end = len(sum_list) + 1 - i
break
img = img[start_index:end, :]
img = cv2.resize(img, (30, 60), interpolation=cv2.INTER_CUBIC)
#cv2.imwrite('SingleChar/%d.png' %c, img)
c += 1
return img
重新固定图片的大小(30x60),得到如下图: