使用到的第三方依赖
首先是pyautogui,比起pyqt,它的确不占优势,但他的优点就在于方便,我不需要知道使用者电脑上的应用是是什么,也不需要关注应用的exe文件的位置,毕竟女朋友不是学计算机的。
然后是time和datime,这个是我生成图片名称的时候用的,time生成时间戳作为jpg文件的前缀,datetime作为最后数据流入的csv文件的前缀。
第三个是modelscope的两个依赖,pipeline和tasks,也就是下图这两个:
不过在使用modelscope之前,需要提前按照官方文档的说明,将pytorch,Tensorflow安装好,然后再将ModelScope对应领域的依赖库安装上,本次使用的是cv领域,所以可以用如下命令进行安装:
pip install "modelscope[cv]" -f https://modelscope.oss-cn-beijing.aliyuncs.com/releases/repo.html
再之后是cv2,是为了裁剪全屏截图;最后再来一个os,删除已经解析出数据的图片,基本这些依赖就足够搞定最基本的信息获取。
整体思路
- 首先,通过pyautogui截取整个屏幕的图片,如果你有多屏,对不起,我还没有考虑到
- 然后将截取到的屏幕通过modescope中的文字检测行检测模型获得文字所在位置
- 这个时候我们可以获得二维数组,其中就包含了每一行文字的四个点,根据xy,使用cv2将每一行文字单独裁剪成一张图片
- 再使用modescope中的文字识别模型识别出对应的数据
- 再将获得的文字数据追加写入到对应目录下的csv文件,并删除掉解析完数据的图片
整体代码
因为上面已经说过整体流程,这里就直接把代码粘贴进来,里面有很多草稿注释和print打印,可以自行忽略
# coding=utf-8# 问题1:在window使用文字识别,因为格式报错,需要把报错ocr_recognition_pipeline.py中52行的open加上encoding加上utf8# 问题2:使用pyautogui截图无法被识别,尝试根据鼠标位置截取一个长条可识别图片# 问题3:尝试修改图片获得方式,根据应用窗口获得数据# 问题4:先使用模型获得文字信息,然后使用cv2裁剪图片,对裁剪后的文字再进行解析# 问题5:cv2.error: OpenCV(4.6.0) D:\a\opencv-python\opencv-python\opencv\modules\imgcodecs\src\loadsave.cpp:801: error: (-215:Assertion failed) !_img.empty() in function 'cv::imwrite'importpyautoguiimporttimefrommodelscope.pipelinesimportpipelinefrommodelscope.utils.constantimportTasksimportdatetimeimportosimportcv2# pyautogui截取桌面图片defgetMap(map_path): # mouse = pyautogui.position()im=pyautogui.screenshot() im.save(map_path) print("生成图片"+map_path) # cv2裁剪图片defgetTmpMap(map_path, tmp_map_path, point_tuple): print("开始裁剪图片") img=cv2.imread(map_path) # img_path为图片所在路径print(point_tuple[0], point_tuple[1], point_tuple[2], point_tuple[3]) crop_img=img[point_tuple[1]:point_tuple[3], point_tuple[0] :point_tuple[2]] # x0,y0为裁剪区域左上坐标;x1,y1为裁剪区域右下坐标cv2.imwrite(tmp_map_path, crop_img) # save_path为保存路径# 解析图片信息defgetMessage(p, map_path): print("解析图片信息") result=p(map_path) returnresult# 写入csv文件defwriteMessage(map_message, timestamp): today=datetime.date.today() file_path="./"+str(today)+"log.csv"fp=open(file_path, 'a+', encoding='utf8') fp.write(timestamp+","+map_message+"\n") print("写入完成") # 获得需要截取图片的左表defsnip_map(map_message): print(map_message) # 左上角xleft_x_id= (map_message[0]-7) if (map_message[0]-7) >0else0# 左上角yleft_y_id= (map_message[1]-7) if (map_message[1]-7) >0else0# 右下角xright_x_id=map_message[2]+7# 又下角yright_y_id=map_message[5]+7return (left_x_id, left_y_id, right_x_id, right_y_id) # 入口方法if__name__=="__main__": p=pipeline('ocr-detection', 'damo/cv_resnet18_ocr-detection-line-level_damo') t_p=pipeline('ocr-recognition', 'damo/cv_convnextTiny_ocr-recognition-general_damo') print("任务开始") whileTrue: now=str(int(time.time())) map_path="./allmap/"+now+".jpg"getMap(map_path) map_message=getMessage(p, map_path)['polygons'] # print(map_message)arr_len=len(map_message) foriinrange(arr_len): # print(i)tmp_map_path="./allmap/"+now+str(i)+".jpg"point_tuple=snip_map(map_message[i]) print(point_tuple) if (point_tuple[2]-point_tuple[0])*3< (point_tuple[3]-point_tuple[1]) or (point_tuple[3]-point_tuple[1])*3< (point_tuple[2]-point_tuple[0]): passelse: getTmpMap(map_path, tmp_map_path, point_tuple) tmp_map_message=getMessage(t_p, tmp_map_path) writeMessage(str(tmp_map_message['text']), now+str(i)) os.remove(tmp_map_path) time.sleep(10) os.remove(map_path)
弊端和后续思路
之所以截屏后不直接解析文字,是因为使用的模型无法解析出整个屏幕的文字信息,当然,我有想过将图片的清晰度提高来规避无法识别出信息的问题,但是很可惜,我没有找到合适的办法,至于动pyautogui的代码,本领还没有那么高。
然后我在模型中找到识别文字行的模型,发现其可以识别到截屏图片的行,就将思路转化,从截屏到文字识别多了两步,这也意味着需要的性能会更高,违背了最初轻量级的想法,但是这个问题的解决估计会很困难。
目前截取的图片再解析出文字,当图片的长宽差异巨大,会无法解析出数据,这也是为什么main方法中有一个*3的判定。
最后解析出来的文字,信息如下图,可以明细看出来解析出来的文字不是想象中的句子,而是一个个词组,这是因为上面限制了需要识别的图片大小。
下一步,也就是下周,我应该会进行两个调整,一个是在getMessage方法后,将上一张图片已经有的数据不再进行循环,将判断改为异常抛出,加上为空不运行的判定以及提高文字识别的准确率。