自己平時可能會收各種各樣的截圖,班級同學在圖片上編輯上學號姓名都會,但是讓同學們將圖片命名成學號姓名後再發過來,他(她)們就有點困難了,因為大部分人都是習慣用手機操作,而對於文件管理不熟悉。為了簡化班級同學以及方便自己,正好學這 python,於是就開始嘗試。首先想到的是騰訊每個月免費的 1000 次圖片文字識別,最後又瞭解百度免費額度更多,於是兩者就都使用上了。最後經過一番折騰有了以下功能。
基本功能如下:
1. 截圖中發現多個學號姓名時,則取面積最大的。(自我感覺編輯的時候字體會比截圖上大)
2. 截圖中發現學號姓名後,會進行糾正,例如:識別出來的是 1817171101 張王,但是我班同學其實叫 1817171101 張三,此時會進行和相似度表進行比對,取出正確的學號姓名。
3. 截圖中沒有發現學號姓名,則會進行全部返回值相似度比對,例如返回值中是包括:“你好 青年 17110 張王” 三個字符串,將進行於相似度表進行對比,取出於學號姓名最高的字符串並找出與之對應的學號姓名,為了降低出現無用字符串匹配出學號姓名的概率,特地設置了最低相似度設置,只有高於最低相似度才會返回。
4. 候補功能。將第一邊未重命名未學號姓名的圖片再次的通過騰訊文字識別進行檢驗,因為本程序首先採用的百度的文字識別(因為免費額度高),所以再候補功能中採用騰訊的文字識別進行識別,以此看看能不能找到百度未識別出來的。
5. 本地先壓縮圖片,減小上傳所浪費時間,同時因為百度 QPS 每秒只有兩次,所以為了防止過度請求,增加了動態調節,根據代碼執行時間來判斷需要阻塞的時間。
6. 為自己的照顧朋友使用,所以將所有的關鍵信息以及學號姓名的相似表都是表格儲存的,程序也轉為通過 exe, 只需要點一下就能運行了。採用的 pip install pyinstaller 來進行的轉 exe, 命令為 pyinstaller -F test.py
表格內容:
代碼塊:
<code>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")/<code>
閱讀更多 半葉子 的文章