介绍
自己平时可能会收各种各样的截图,班级同学在图片上编辑上学号姓名都会,但是让同学们将图片命名成学号姓名后再发过来,他(她)们就有点困难了,因为大部分人都是习惯用手机操作,而对于文件管理不熟悉。为了简化班级同学以及方便自己,正好学这python,于是就开始尝试。首先想到的是腾讯每个月免费的1000次图片文字识别,最后又了解百度免费额度更多,于是两者就都使用上了。最后经过一番折腾有了以下功能。
自己初学,代码写的不规范,还请指教。
功能和注意点
1.截图中发现多个学号姓名时,则取面积最大的。(自我感觉编辑的时候字体会比截图上大)
2.截图中发现学号姓名后,会进行纠正,例如:识别出来的是1817171101张王,但是我班同学其实叫1817171101张三,此时会进行和相似度表进行比对,取出正确的学号姓名。
3.截图中没有发现学号姓名,则会进行全部返回值相似度比对,例如返回值中是包括:“你好 青年 17110张王”三个字符串,将进行于相似度表进行对比,取出于学号姓名最高的字符串并找出与之对应的学号姓名,为了降低出现无用字符串匹配出学号姓名的概率,特地设置了最低相似度设置,只有高于最低相似度才会返回。
4.候补功能。将第一边未重命名未学号姓名的图片再次的通过腾讯文字识别进行检验,因为本程序首先采用的百度的文字识别(因为免费额度高),所以再候补功能中采用腾讯的文字识别进行识别,以此看看能不能找到百度未识别出来的。
5.本地先压缩图片,减小上传所浪费时间,同时因为百度QPS每秒只有两次,所以为了防止过度请求,增加了动态调节,根据代码执行时间来判断需要阻塞的时间。
6.为自己的照顾朋友使用,所以将所有的关键信息以及学号姓名的相似表都是表格储存的,程序也转为通过exe,只需要点一下就能运行了。
采用的pip install pyinstaller
来进行的转exe,命令为pyinstaller -F test.py
7.如果运行一下闪退,可以考虑是表格的内容出现错误。因为本人没考虑那么多错误因素,如果出现的问题无法解决,还请告诉我改正。
下载链接
下载链接:蓝奏云下载
密码:byz
表格内容
例如班级如18171711
,则表格内容如下:
百度api | 注意: | |
APP_ID | XXXXXXX | 1.不要改变前两列的任何位置 |
API_KEY | XXXXXXX | 2.认真正确的填写基本的信息 |
SECRET_KEY | XXXXXXX | 3.保存后退出再打开软件开始执行。 |
腾讯api | ||
SecretId | SecretKey | APP_ID |
SECRET_KEY | XXXXXXX | |
其他基本信息 | ||
res | 18171711[0-9]{2}[\u4e00-\u9fa5]{2,} | 正则表达式,不懂请只改前面[0-9]的班级代码 |
contrastnum | 50 | 最低相似度限制 |
filepath | ../test/ | 填写截图文件夹路径 |
学号 | 姓名 | 学号姓名下填写你班所有人的学号姓名 |
1817171101 | 张三 | |
1817171102 | 李四 | |
XXXX | XXXX | |
.... | .... |
代码区域
代码如下:
import os
import re
import json
import time
from aip import AipOcr #百度api
from tencentcloud.common import credential#腾讯api
from tencentcloud.common.profile.client_profile import ClientProfile#腾讯api
from tencentcloud.common.profile.http_profile import HttpProfile#腾讯api
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException#腾讯api
from tencentcloud.ocr.v20181119 import ocr_client, models#腾讯api
import base64#腾讯api需要
from fuzzywuzzy import fuzz#相似度对比
from fuzzywuzzy import process#相似度对比
import xlrd
from xlrd import xldate_as_tuple
from PIL import Image
import shutil
def get_size(file):
# 获取文件大小:KB
size = os.path.getsize(file)
return size/ 1024
#文件打开返回
def file_open(fpaths):
with open(fpaths, 'rb') as f:
return (f.read())
def compress_image(file_name,fpaths, outfile='', mb=150, step=10, quality=90):
"""不改变图片尺寸压缩到指定大小
:param fpaths: 压缩源文件
:param outfile: 压缩文件保存地址
:param mb: 压缩目标,KB
:param step: 每次调整的压缩比率
:param quality: 初始压缩比率
:return: 压缩文件地址,压缩文件大小
"""
o_size = get_size(fpaths)
if o_size <= mb:
return fpaths
outfile=outfile+file_name
while o_size > mb:
im = Image.open(fpaths)
im.save(outfile, quality=quality)
if quality - step > 0:
quality -= step
o_size = get_size(outfile)
else:
break
return outfile
#取文件后缀
def file_suffix(fpaths):
try:
portion = os.path.splitext(fpaths)
suffix=portion[1].lower()
if suffix=='.NULL':
return(".jpg")
else:
return (suffix)
except:
return('.jpg')
def file_rename_check(word):#名称检查
contrastall=[]#记录每个相似度
contrastmaxs=[]#记录相似度最大的
contraststr=[]
contrastallstr=[]
for contrast in range(len(contrast_lists[0])):
if contrast_lists[1][contrast]!=1:
contrastall.append(fuzz.ratio(contrast_lists[0][contrast], word))
contrastallstr.append(contrast_lists[0][contrast])
contrastmax=max(contrastall)
if contrastmax>=contrastnum:
for i in range(len(contrastall)):
if contrastall[i]==contrastmax:
contrastmaxs.append(i)
contraststr.append(contrastallstr[i])
if len(contrastmaxs)==1:
contrast_lists[1][contrast_lists[0].index(contraststr[0])]=1
return (contraststr[0])
else:
print("名称纠正出现多个相似值,将结合后命名")
return ('!MORE')
else:
print("相似度匹配未超过最低值:")
return ('!NULL')
def file_rename_search(noword):#未搜到学号姓名,进行全相似度审核以及拼音核对,时间消耗过长。
contrastall=[]
contrastmaxs=[]
contraststr=[]
contrastallstr=[]
contrastmax=0
for noi in noword:#进行相似度对比
for contrast in range(len(contrast_lists[0])):
if contrast_lists[1][contrast]!=1:
contrastall.append(fuzz.ratio(contrast_lists[0][contrast], noi))#储存相似度
contrastallstr.append(contrast_lists[0][contrast])#储存相似度的学号姓名
if len(contrastall)!=0:
contrastmax=max(contrastall)#取出最大的相似度
if contrastmax>=contrastnum:#判断最大相似度是否大于限制
for i in range(len(contrastall)):#判断和最大的相似度有多少相同的组,并进行储存
if contrastall[i]==contrastmax:
contrastmaxs.append(i)
contraststr.append(contrastallstr[i])
if len(contrastmaxs)==1:
contrast_lists[1][contrast_lists[0].index(contraststr[0])]=1
return(contraststr[0])
else:
print("名称纠正出现多个相似值,进行候补")
return ('!MORE')
else:
print("相似度匹配未超过最低值")
return ('!NULL')
def bdocrapi(file_name,fpath,lag=0):
fpaths=fpath+file_name
global start_time
global end_time
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
name_max_area=0
name_max=''
bdocrapi_num=0
#防止学号姓名进行记录所有返回值
noword=[]
""" 读取图片 """
image=file_open(compress_image(file_name,fpaths,fpath+'out/'))
for i in range(2):
if i==0:
end_time=time.clock()
if end_time-start_time<0.5:
time.sleep(0.5-(end_time-start_time))
start_time=time.clock()
dic=client.basicGeneral(image)
for it in dic['words_result']:
#删去空格
strname = re.sub(r'\s+', '', it["words"]).strip()
#文本替换
strname=strname.replace('|', '1')
noword.append(strname)
fileok = re.search(res,strname)
if fileok:
bdocrapi_num+=1
if bdocrapi_num>1:
break
name_max=fileok.group(0)
else:
break
else:
end_time=time.clock()
if end_time-start_time<0.5:
time.sleep(0.5-(end_time-start_time))
start_time=time.clock()
dic=client.general(image)
for it in dic['words_result']:
#删去空格
strname = re.sub(r'\s+', '', it["words"]).strip()
#文本替换
strname=strname.replace('|', '1')
noword.append(strname)
fileok = re.search(res,strname)
if fileok:
x=it["location"]['width']
y=it["location"]['height']
if x*y>name_max_area:
name_max_area=x*y
name_max=fileok.group(0)
if name_max!='':
file_rename(fpath,file_name,name_max,'',lag)
else:
print("未找到学号姓名,将进行相似度对比")
file_rename(fpath,file_name,name_max,noword,lag)
def txocrapi(file_name,fpath,lag=0):
fpaths=fpath+file_name
noword=[]
name_max_area=0
name_max=''
#腾讯api准备工作
cred = credential.Credential(SecretId, SecretKey)
httpProfile = HttpProfile()
httpProfile.endpoint = "ocr.tencentcloudapi.com"
clientProfile = ClientProfile()
clientProfile.httpProfile = httpProfile
clientProfile.signMethod = "TC3-HMAC-SHA256"
client = ocr_client.OcrClient(cred, "ap-beijing", clientProfile)
req = models.GeneralBasicOCRRequest()
#对本地图片进行base64转码
image=file_open(compress_image(file_name,fpaths,fpath+'out/'))
base64_data = base64.b64encode(image)
s = base64_data.decode()
suffix=file_suffix(fpaths)[1:len(file_suffix(fpaths))]
ImageBase64_value = ('data:image/%s;base64,%s'%(suffix,s))
#params是字符串,以下进行拼接
params = '{"ImageBase64":"' + ImageBase64_value + '"}' #以图片Base64编码发送请求
req.from_json_string(params)
#dic接受json文件
resp = client.GeneralBasicOCR(req) #标准的json文本
dic = json.loads(str(resp))
#读返回值
for it in dic["TextDetections"]:
#删去空格
strname = re.sub(r'\s+', '', it["DetectedText"]).strip()
#文本替换
strname=strname.replace('|', '1')
noword.append(strname)
fileok = re.search(res,strname)
if fileok:
x=it["Polygon"][2]['X']-it["Polygon"][0]['X']
y=it["Polygon"][2]['Y']-it["Polygon"][0]['Y']
if x*y>name_max_area:
name_max_area=x*y
name_max=fileok.group(0)
if name_max!='':
file_rename(fpath,file_name,name_max,'',lag)
else:
print("未找到学号姓名,将进行相似度对比")
file_rename(fpath,file_name,name_max,noword,lag)
def file_rename(fpath,file_name,name_max,noword='',lag=0):
fpaths=fpath+file_name
suffix=file_suffix(fpaths)
if noword=='':
name_max=file_rename_check(name_max)
else:
name_max=file_rename_search(noword)
if name_max=='!MORE':
print(fpaths+"相似度个数太多,需要人工命名")
if lag==0:
contrast_lag.append(file_name)
return 0
elif name_max=='!NULL':
print(fpaths+"相似度都不匹配,需要人工命名")
if lag==0:
contrast_lag.append(file_name)
return 0
try:
os.rename(fpaths,fpath+name_max+suffix)
print(fpaths+"已改名为"+fpath+name_max+suffix)
if lag==1:
contrast_lag_remove.append(contrast_lag.index(file_name))
except:
name_max=name_max+str(time.strftime('%H%M%S',time.localtime(time.time())))
try:
os.rename(fpaths,fpath+name_max+suffix)
print(fpaths+"原名称已经存在,现已改名为"+fpath+name_max+suffix)
if lag==1:
contrast_lag_remove.append(contrast_lag.index(file_name))
except:
print(fpaths+"重命名失败")
if __name__ == '__main__':
try:
excel = xlrd.open_workbook(r'相似度.xlsx')
table = excel.sheets()[0]
except:
print("打开失败")
exit(1)
start_time =0
end_time =0
try:
APP_ID=str(int(table.cell_value(1,1)))
API_KEY=table.cell_value(2,1)
SECRET_KEY=table.cell_value(3,1)
SecretId=table.cell_value(5,1)
SecretKey=table.cell_value(6,1)
res=table.cell_value(8,1)
contrastnum=int(table.cell_value(9,1))
fpath=table.cell_value(10,1)
contrast_list=[]
except:
print("读取失败,正在退出")
exit(1)
print("将进行工作,请耐心等待:仅允许以下后缀'jpg','jpeg','png',其余将自动过滤")
allow_suffix=['.jpg','.jpeg','.png']
for rown in range(12,table.nrows):
contrast_list.append(str(int(table.cell_value(rown,0)))+table.cell_value(rown,1))
file_names = os.listdir(fpath)
for i in file_names:
if not os.path.isfile(fpath+i) or not (file_suffix(fpath+i) in allow_suffix):
file_names.remove(i)
if len(file_names)>len(contrast_list):
print("图片文件数量%d高于本班同学的人数%d,疑似存在无关文件"%(len(file_names),len(contrast_list)))
yesorno=input("输入0关闭,输入其他继续运行:")
if yesorno=='0':
exit(0)
contrast_num=[0]*len(contrast_list)#初始化学号姓名的是否被使用
file_shiyong=[0]*len(file_names)#初始化文件列表是否被使用
contrast_lag=[]#候补初始化
contrast_lag_remove=[]#候补移除
#将存在好的文件提前设置已使用contrast_num[]
for i in range(len(file_names)):
fileok = re.search(res,file_names[i])
try:
fileok=contrast_list.index(fileok.group(0))
except:
fileok=-1
if fileok!=-1:
contrast_num[fileok]=1
file_shiyong[i]=1
contrast_lists=[contrast_list,contrast_num]
isExists=os.path.exists(fpath+'out/')
# 判断结果
if not isExists:
os.makedirs(fpath+'out/')
print ('正在创建缓冲文件夹out')
else:
print ('已经存在缓冲文件夹out')
shutil.rmtree(fpath+'out/')
os.makedirs(fpath+'out/')
for i in range(len(file_names)):#fpaths为文件路径
start_time=time.clock()
if file_shiyong[i]:
print (fpath+file_names[i]+"无需改名")
else:
bdocrapi(file_names[i],fpath,)#文件夹路径和文件路径
else:
if len(contrast_lag)==0:
print("执行完毕")
elif len(contrast_lag)==1:
try:
print("将进行候补模式:")
file_rename(fpath,contrast_lag[0],contrast_lists[0][contrast_lists[1].index(0)],'',1)
print("执行完毕")
except:
print("相似表已经全部使用,请确保只有相关的截图无其他。")
else:
print("将进行候补模式(腾讯api):")
for j in range(len(contrast_lag)):
txocrapi(contrast_lag[j],fpath,1)
contrast_lag_remove.sort(reverse=True)
for j in range(len(contrast_lag_remove)):
contrast_lag.remove(contrast_lag[contrast_lag_remove[j]])
if len(contrast_lag)==1:
file_rename(fpath,contrast_lag[0],contrast_lists[1][contrast_lists[1].index(0)])
print("执行完毕")
try:
shutil.rmtree(fpath+'out/')
except:
print("缓冲文件删除失败")
os.system("pause")
很厉害哦,继续加油^ω^
共同加油呀 ( ๑´•ω•) "(ㆆᴗㆆ)