笔记记录下来,以免东西到处都是,最后忘得一干二净。
先简单说一下我想实现一个什么功能:
最近不是有个微视吗,里面有红包视频(虽然只有一分两分的),我就想自动抢微视里面的红包(哈哈哈,发家致富第一步)
控制手机滑动视频
获取手机信息
判断是不是红包视频
打开红包
(大概是这样的)
百度了一下就发现,要控制手机需要这个东东。于是网上下载了一个进行安装:http://adbdriver.com/downloads
不过安装了之后并不会用,又百度资料
如何给手机指令,请自行百度adb命令,我这里只用到也只会这几个指令:
1、adb shell input tap x y
:触摸一下屏幕的x,y位置。直接给数字就行。
2、abd shell input swipe x y x1 y1
:滑动屏幕,具体如何滑动就要看x,y,x1,y1的值了,例如我要向上滑动那我x = x1= 300随便给个值,y>y1就行了。因为默认的图像的左上角为坐标原点,直接上图,从x,y滑动到x1,y1,y>y1向上,y
上代码:
os.system('adb shell input swipe 300 800 300 600')
这里用到了os这个库。所以最开始的位置要import os。
既然控制了手机了,那我就需要知道手机在干什么了,那么我就需要截图上传,并且进行图片的判断和处理。
os.system("adb shell /system/bin/screencap -p /sdcard/3.png")# 命令1:在手机上截图并保存为3.png os.system("adb pull /sdcard/3.png d:/3.png")#命令2:将手机上的图片上传到电脑 d:/3.png
当然也有一步到位的方法就是直接把截图上传到电脑,不在手机上存储了:os.system("adb shell /system/bin/screencap -p d:\\3.png")
安装pytesseract让我花了很多时间,因为这里面涉及到了很多东西,变量的配置,需要安装Tesseract-OCR,
Thttp://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-setup-4.00.00dev.exe
直接下载安装,然后需要配置一下环境变量,增加一个TESSDATA_PREFIX变量名,变量值还是我的安装路径C:\Program Files (x86)\Tesseract-OCR\tessdata这是将语言字库文件夹添加到变量中;
接下来就是实现图片转换文字,需要另一个库CV2和image 的PIL这样能够打开图片并进行相关操作。这些东西对于我来说太陌生了,但是为了实现功能,我决定先用起来。但是一旦用起来就发现了各种错误,显示找不到CV2,然后是pytesserace报了一些奇怪的错误说什么版权问题。查了半天发现是python相关库的问题,一个是opencv-contrib-python 这个库用来最新版本,涉及到版权问题,建议用3.3.0.10足够, 一个是opencv-python用了最新版,里面没有cv2了,建议用3.4.2.16足够。这绝对是个坑啊。
好吧接下来应该进行图文转换了吧。
这里我不需要全部的图文转换,只需要针对指定区域的文字识别即可,然后我通过各种方法定位了“互动红包***已领取”的区域,这里我找到了个工具img_file.crop(box1),box1放需要截取的图片两个点的坐标(两个点可以确定一个区域了)
然后就是针对这个东西进行图文转换了,上面为什么我要用到10801920分辨率,而不用更低分辨率来提高速度呢,这里就是关键了,分辨率太小识别出来的误差会很大,目前没找到第二种方法,先用这个方法跑起来再说。
那么用到
img_file1 = img_file.crop(box1)#截取“互动红包”字样出现的区域 #img_file1.show() text1 = pytesseract.image_to_string(img_file1,lang='chi_sim')#转换成文字‘chi_sim’指简体中文 text1 = text1.replace(" ", "") #去空格
通过高分辨率和指定区域的方法,我发现转换过来的文字并不是百分百,当然我也试过CV2的’L’灰度,反正等方法,不过还是不理想。最后我发现虽然有误差但是“红包”这两个字的正确率在这里是百分之百。所以我就直接用if “红包” in text1:来判定这个视频就是红包视频。简单粗暴
简单粗暴的判断之后,就是对抢红包了,程序运行到这里,视频大概已经播放了3-5秒了,也就是说我这个从开始截图到这一步就已经花了很多时间了,如果我在用同样的方法去判断红包是否出现,那就太麻烦了,况且红包出现的时间和区域是随机的,怎么办。之前说过如果能够制定区域截图就太好了,adb命令没找到,但是我找到了ImageGrab.grab(bbox);bbox = (0, 30, 380, 690)#截取到红包图片可能出现的区域;这个东西 ,这可帮了我大忙了,而且刚好我也没用手机,而是模拟器,那么就简单了。我把视频暂停下来并且截屏(速度快多了),判断是不是有红包出现,有就抢了,没有就让他在播放一会儿然后又暂停截图判断。是不是很暴力!!!
到了这里我又卡住了,上面说过,电脑分辨率和手机的无关,截图下来识别文字不太可能(分辨率太低),况且这tm红包上面居然写的是个繁体字。实现代码的时候觉得这不肯能,但是笔记写到这里我知道了上面图转文字可以选择繁体字包。不过分辨率太低,估计有点悬。
然后我想到了人脸识别,百度了很多例子,里面基本上都没有我需要的哪一种,然后又找啊找,终于找到一个FLANN的什么鬼,翻代码,找说明,反正吃不准,不如就自己试一下。各种捣鼓,终于明白了大大概,
sift = cv2.xfeatures2d.SIFT_create()
SIFT这个原来是个特征器。把图片中的信息转换为特征点,更详细的不知道,只知道可以从另一个图片中找到与上面这个红包图相匹配的东西。所以我就把红包扣出来,单独存放。代码实现如下
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks = 50)
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1,des2,k=2)# store all the good matches as per Lowe's ratio test.
good = []
for m,n in matches:
if m.distance < 0.7*n.distance:
good.append(m)
搬到别人的代码。
如图,这么大的两个相似处,你给我就只找到了两处,太坑了。不过貌似这个已经很不错了,再要精确就需要弄什么二值之类的了,太高深,目前就这样吧。
那么知道红包出现了,就需要确认红包的位置并且点开咯。
这就害得我又翻资料,才发现matches里面居然放着两个图片的坐标pt。那我就不客气了。直接把
img2_idx = m.trainIdx (x2 , y2) = kp2[img2_idx].pt#获取电脑截图的红包坐标,不过打印出来是float,需要转换成整形,并且要找到对应的手机位置 x2 = int(x2 / 380 * 1080) y2 = int(y2 / 690 * 1920) #380,690是我模拟器屏幕的坐标,通过上面的乘除得到红包在手机中的具体位置
知道位置了就直接让系统给指令点击吧。开始用的是:os.system("adb shell input tap x2 y2)"系统一顿报错,别笑。弄半天别人不认识你这个x2,y2,认为是非法输入。然后我就又用另一个方法把指令存到另个地方
tap_the_point = "adb shell input tap "+ str(x2) +" " + str(y2) os.system(tap_the_point)
哈哈聪明如我。
抢到红包延时1秒,关闭红包界面,滑动到下一个视频。
初学者,用不来while、for、break、continue等等,只能试了又试,这就是不好好学习基础的后果,没学会爬就想学飞。最后把我的代码附上,大家就知道我这改了一周才凑出来是多么不容易。
跑了两小时,还不错抢了好几毛的红包,阔以阔以
# -*- coding:utf-8 -*-
from PIL import ImageGrab
import os
from PIL import Image
import cv2
import time
import pytesseract
bbox = (0, 30, 380, 690) #截取到红包图片可能出现的区域
box1 = (35,1470,380,1510) #截取到互动红包字样区域(左上为原点 原点->右,原点->向下,原点->右,原点->下 )
#box2 = (35,1370,380,1410) #截取到互动红包字样区域(左上为原点 原点->右,原点->向下,原点->右,原点->下 )
MIN_MATCH_COUNT = 10
img1=cv2.imread('D:\\1.png') #读取红包图片源码
sift = cv2.xfeatures2d.SIFT_create() #建立sift特征器
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None) #获取红包特征点
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks = 20)
flann = cv2.FlannBasedMatcher(index_params, search_params) #特征筛选
flag = True
count = 0
while(flag):
flag2 = True
print("新视频打开,判断是否为互动红包视频,请稍等...")
os.system("adb shell /system/bin/screencap -p /sdcard/3.png") # 命令1:在手机上截图3.png为图片名
os.system("adb pull /sdcard/3.png d:/3.png") #命令2:将图片保存到电脑 d:/3.png为要保存到电脑的路径
img_file = Image.open("D:\\3.png") #打开图片并截取重要部分
#print(img_file.size) #打印图片大小(手机分辨率越高越清晰,但是传输速度越慢)
#img_file.show()
img_file1 = img_file.crop(box1) #截取“互动红包”字样出现的区域
#img_file1.show()
text1 = pytesseract.image_to_string(img_file1,lang='chi_sim') #转换成文字
text1 = text1.replace(" ", "") #去空格
if "红包"in text1:
#print(text1)
print('这个视频有红包,正在查找红包位置...')
while(flag2):
os.system('adb shell input tap 100 1000') #暂停视频
img = ImageGrab.grab(bbox) #截图当前暂停的视频
img.save("pixel.png")
#img.show()
img2 = cv2.imread("pixel.png")
kp2, des2 = sift.detectAndCompute(img2, None) #提取当前截图特征点
matches = flann.knnMatch(des1, des2, k=2) #对比特征点找到红包区域
#print(kp2[img2].pt)
good = []
for m, n in matches:
if m.distance < 0.7 * n.distance and flag2 == True:
good.append(m)
img2_idx = m.trainIdx # 获取红包特征点坐标img2_idx = good.trainIdx;(x2 , y2) = kp2[img2_idx].pt
if len(good) >= 2: #如果特征点大于2,表示图片中有红包执行找到红包并退出该次循环
print("特征点达到2个,确定红包的位置,领取中...")
(x2 , y2) = kp2[img2_idx].pt
#print(x2, y2) #(打印红包某个特征点的坐标)
#print(int(x2),int(y2)) #输出红包位置
x2 = int(x2 / 380 * 1080)
y2 = int(y2 / 690 * 1920)
#print(x2 , y2) #换算到实际手机中位置
flag2 = False
tap_the_point = "adb shell input tap "+ str(x2) +" " + str(y2)
os.system(tap_the_point) #打开红包
print("已领取红包,打开下一个视频")
time.sleep(1)
count = count + 1
tap_close = "adb shell input tap 570 1410"
os.system(tap_close) #关闭红包
break
elif len(good) < 1:
os.system('adb shell input tap 100 1000')
#time.sleep(2)
print("未找到特征点,截取本视频的下一个画面...")
continue
#os.system('adb shell input tap 100 1000')#未找到红包则继续播放视频停顿三秒继续循环
#time.sleep(2)
else:
print("这个视频没有红包。打开下一个视频中...\n------------------------")
os.system('adb shell input swipe 300 800 300 600')
time.sleep(1)
print("已经为你抢了%d个红包"%count)
flag = True
暂时先这样吧,跑起来的感觉还是很不错的。
后续加一个每周提现一次,每天达到观看时间领取固定红包的功能上去。