简介
一年一度的双十一剁手节又来了,电商玩法淘箩也越来越复杂,你还在重拾丢掉多年的数学算到手价么?尤其是电商小伙伴们,还在为了算竞对到手价头疼么?!
不用怕,paddlepaddle开源模型库教你一键识别到手价
前面写过一篇飞桨的ocr识别
《PaddleHub一键OCR中文识别(超轻量8.1M模型,火爆)——本地实现》
前两天把这个算法扩展了下,应用于淘宝商品的到手价识别
识别效果展示
部分图片及结果如下图所示,测试了120张图片,一张识别错误,一张未识别出来,主图不存在预估到手价的也准确识别并提示无目标价,总体识别准确率尚可,凑合能用。
代码&逻辑
基本逻辑:
如上图所示,需要先配置到手价文案,调用飞桨ocr识别出对应文案坐标,以正则筛选符合要求的目标文本(也可不做正则匹配,主要为了降低计算距离的复杂度),计算各文本到目标文案之间的距离,取距离目标文案最近的识别结果即可。
为了保证代码运行稳定性,本代码读取本地文件进行识别,与爬取商品主图拆分开了。很多工具可以爬取商品主图,可以先爬取下来再识别,后续有时间再分享商品主图的爬虫的代码吧。
完整代码如下:
代码语言:javascript复制import os
import cv2
import re
import paddlehub as hub
# 完善版本2.0,速度慢,全部文本验证距离,因为有一部分目标参考位置会在下方
# 加载移动端预训练模型
ocr = hub.Module(name="chinese_ocr_db_crnn_mobile")
def get_txt(image_path):
return ocr.recognize_text(images=[cv2.imread(image_path)])
def handle_data(txt_data):
pass
def order_text_box_position(txt_data):
"""
文本对位置排序,从左上到右下,并选取左下和右下的纯数字|带¥符号的|以【起】结尾的
一般 带¥符号的|以【起】结尾的 可以确认为目标值,不过最好加一个距离验证
坐标顺序为:左上 右上、右下、左下,图片左上角为起始原点[0,0]
坐标值为[横坐标,纵坐标]
"""
# 预选列,剔除其他干扰文本
pre_select_list = []
for j in txt_data[0]['data']:
string = j['text'].replace(" ", "")
if re.findall("^d .d*$|^¥d .d*$|^d .d*起$|^¥d $|^d 起$|^d $", string):
pre_select_list.append(j)
else:
pass
if len(pre_select_list) == 0:
return "无目标价"
else:
# 获取参考位置坐标
reference_position = get_reference_position(txt_data)
# 计算距离求最小距离
# 注意:小数点结尾,被分割了,找下一个距离最近的文本拼接,此处目标为选出来的整数项
return cal_min_distance(reference_position, pre_select_list)
def cal_min_distance(reference_position, inner_elements):
"""
计算距离,取到最小距离的值,返回目标价
reference_position:参考目标位置
inner_elements:预选元素列表
"""
distance_list = []
distance_list1 = []
x0, y0 = reference_position[0]
for i in inner_elements:
x1, y1 = i['text_box_position'][0]
d = (x1 - x0) ** 2 (y1 - y0) ** 2 # 不开方也可,只比大小不取值
distance_list.append(d)
price = inner_elements[distance_list.index(min(distance_list))]['text'].replace(" ", "")
if (price[-1] == ".") & (len(inner_elements) > 1):
x0_, y0_ = inner_elements[distance_list.index(min(distance_list))]['text_box_position'][0]
for i in inner_elements:
x1, y1 = i['text_box_position'][0]
if (x1 != x0) & (y1 != y0): # 排除自己
d = (x1 - x0) ** 2 (y1 - y0) ** 2 # 不开方也可,只比大小不取值
distance_list1.append(d)
decimal_price = inner_elements[distance_list1.index(min(distance_list))]['text'].replace(" ", "")
return "".join([price, decimal_price])
else:
return price
def get_reference_position(txt_data):
"""获取参考位置坐标"""
# 读取目标文本
f = open("parameter.txt", encoding='utf8')
reference_txt = f.readlines()
f.close()
# print(reference_txt)
for i in reference_txt:
for j in txt_data[0]['data']:
if i.split('n')[0] in j['text']:
return j['text_box_position']
return "无目标位置,检查配置和图片"
def main():
"""主程序,循环图片路径"""
dir_path = "./picture"
pictures = os.listdir(dir_path)
for picture in pictures:
image_path = os.path.join(dir_path, picture)
txt_data = get_txt(image_path)
price = order_text_box_position(txt_data)
print(f"商品{picture.split('.')[0]} 预估到手价:{price}")
if __name__ == '__main__':
main()
# # cv2无法识别中文路径,使用英文路径
# image_path = "./picture/1.jpg"
# txt_data = get_txt(image_path)
# print(txt_data[0]['data'])
#
# # 获取参考位置坐标
# reference_position = get_reference_position(txt_data)
# print(reference_position)
#
# price = order_text_box_position(txt_data)
# print(f"预估到手价格:{price}")