首页 > 其他分享 >25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值

时间:2022-09-28 11:31:46浏览次数:93  
标签:Baidu 25 img int det 验证码 im position rec


基本思想:随手记录一下,验证码需要计算之后才能登陆的py脚本开发~

一、下载 paddle 检测和识别模型

​https://github.com/PaddlePaddle/PaddleOCR/blob/develop/doc/doc_ch/models_list.md​

检测模型:​​https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_det_infer.tar​

识别模型:​​https://paddleocr.bj.bcebos.com/dygraph_v2.0/ch/ch_ppocr_mobile_v2.0_rec_infer.tar​

python -m pip install paddlepaddle==2.0.1 -i https://mirror.baidu.com/pypi/simple

样例图片:来自百度测试sample的图片

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_paddle

首先先测试一下

from paddleocr import PaddleOCR, draw_ocr
from PIL import Image
img_path = r'F:\tt\source\1.png'
ocr = PaddleOCR(cls_thresh=0,use_gpu=False,det_model_dir=r'F:\tt\ch_ppocr_mobile_v2.0_det_infer', rec_model_dir=r'F:\tt\ch_ppocr_mobile_v2.0_rec_infer') # need to run only once to download and load model into memory

result = ocr.ocr(img_path, cls=True)
print(result)
for line in result:
print(line)
image = Image.open(img_path).convert('RGB')
boxes = [line[0] for line in result]
txts = [line[1][0] for line in result]
scores = [line[1][1] for line in result]
im_show = draw_ocr(image, boxes, txts, scores)
im_show = Image.fromarray(im_show)
im_show.save('result.jpg')

结果

"D:\Program Files\Python36\python.exe" D:/nanodet-main/test.py
Namespace(cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='C:\\Users\\sxj/.paddleocr/2.1/cls', cls_thresh=0, det=True, det_algorithm='DB', det_db_box_thresh=0.5, det_db_thresh=0.3, det_db_unclip_ratio=1.6, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0.8, det_limit_side_len=960, det_limit_type='max', det_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_det_infer', drop_score=0.5, enable_mkldnn=False, gpu_mem=8000, image_dir='', ir_optim=True, label_list=['0', '180'], lang='ch', max_text_length=25, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='./ppocr/utils/ppocr_keys_v1.txt', rec_char_type='ch', rec_image_shape='3, 32, 320', rec_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_rec_infer', use_angle_cls=False, use_dilation=False, use_gpu=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, use_zero_copy_run=False)
[2021/04/17 15:42:58] root WARNING: Since the angle classifier is not initialized, the angle classifier will not be uesd during the forward process
[2021/04/17 15:42:59] root INFO: dt_boxes num : 36, elapse : 0.9523482322692871
[2021/04/17 15:43:01] root INFO: rec_res num : 36, elapse : 1.8610682487487793
[[[[704.0, 17.0], [820.0, 17.0], [820.0, 57.0], [704.0, 57.0]], ('PASS', 0.9926876)], [[[158.0, 30.0], [351.0, 26.0], [352.0, 66.0], [159.0, 71.0]], ('登机牌', 0.99803185)], [[[424.0, 27.0], [653.0, 23.0], [654.0, 56.0], [425.0, 61.0]], ('BOARDING', 0.9355928)], [[[678.0, 101.0], [740.0, 100.0], [740.0, 117.0], [678.0, 119.0]], ('座位号', 0.9993448)], [[[490.0, 106.0], [648.0, 102.0], [648.0, 119.0], [491.0, 122.0]], ('序号SERIALNO', 0.9721721)], [[[397.0, 107.0], [455.0, 105.0], [455.0, 122.0], [397.0, 124.0]], ('CLASS', 0.99292123)], [[[340.0, 109.0], [384.0, 107.0], [385.0, 122.0], [341.0, 124.0]], ('舱位', 0.95519966)], [[[749.0, 100.0], [830.0, 97.0], [831.0, 114.0], [750.0, 116.0]], ('SEAT NO', 0.91536474)], [[[215.0, 111.0], [255.0, 110.0], [256.0, 125.0], [216.0, 127.0]], ('日期', 0.99764645)], [[[66.0, 114.0], [189.0, 111.0], [190.0, 128.0], [66.0, 131.0]], ('航班FLIGHT', 0.9937089)], [[[248.0, 110.0], [314.0, 110.0], [314.0, 125.0], [248.0, 125.0]], ('DATE', 0.98909116)], [[[509.0, 131.0], [566.0, 131.0], [566.0, 156.0], [509.0, 156.0]], ('035', 0.9830131)], [[[406.0, 135.0], [430.0, 135.0], [430.0, 157.0], [406.0, 157.0]], ('W', 0.99706143)], [[[84.0, 142.0], [212.0, 139.0], [213.0, 158.0], [84.0, 162.0]], ('MU 2379', 0.9289481)], [[[211.0, 141.0], [324.0, 139.0], [325.0, 156.0], [211.0, 158.0]], ('03DEG', 0.8540861)], [[[489.0, 175.0], [572.0, 173.0], [572.0, 193.0], [489.0, 195.0]], ('登机口', 0.9996843)], [[[568.0, 176.0], [612.0, 176.0], [612.0, 191.0], [568.0, 191.0]], ('GATE', 0.99684405)], [[[345.0, 177.0], [409.0, 177.0], [409.0, 194.0], [345.0, 194.0]], ('始发地', 0.9996207)], [[[400.0, 177.0], [466.0, 173.0], [467.0, 191.0], [401.0, 194.0]], ('FROM', 0.9926705)], [[[68.0, 181.0], [168.0, 178.0], [168.0, 199.0], [69.0, 203.0]], ('目的地TO', 0.98151416)], [[[680.0, 172.0], [806.0, 166.0], [807.0, 186.0], [681.0, 192.0]], ('登机时间BD1', 0.9584261)], [[[98.0, 208.0], [168.0, 208.0], [168.0, 227.0], [98.0, 227.0]], ('福州', 0.8741772)], [[[339.0, 220.0], [474.0, 216.0], [475.0, 235.0], [339.0, 239.0]], ('TAIYUAN', 0.93135375)], [[[507.0, 217.0], [552.0, 214.0], [553.0, 232.0], [508.0, 235.0]], ('G11', 0.84185356)], [[[90.0, 231.0], [200.0, 229.0], [200.0, 247.0], [90.0, 250.0]], ('FUZHOU', 0.98411864)], [[[347.0, 243.0], [481.0, 239.0], [482.0, 254.0], [347.0, 258.0]], ('身份识别IDNO', 0.9800327)], [[[67.0, 253.0], [170.0, 250.0], [170.0, 267.0], [68.0, 270.0]], ('姓名NAME', 0.9965892)], [[[77.0, 279.0], [262.0, 275.0], [262.0, 294.0], [78.0, 299.0]], ('ZHANGQIWET', 0.92218363)], [[[464.0, 299.0], [576.0, 297.0], [577.0, 314.0], [464.0, 316.0]], ('票号TKTNO', 0.9938587)], [[[103.0, 314.0], [208.0, 313.0], [208.0, 334.0], [104.0, 336.0]], ('张祺伟', 0.945729)], [[[70.0, 345.0], [164.0, 343.0], [165.0, 362.0], [71.0, 365.0]], ('票价FARE', 0.99907106)], [[[347.0, 350.0], [659.0, 349.0], [659.0, 366.0], [348.0, 367.0]], ('ETKT7813699238489/1', 0.97859323)], [[[101.0, 459.0], [829.0, 442.0], [829.0, 462.0], [102.0, 478.0]], ('登机口于起飞前10分钟关闭GATESCLOSE10MINUTESBEFOREDEPARTURETIME', 0.9942007)]]
[[[704.0, 17.0], [820.0, 17.0], [820.0, 57.0], [704.0, 57.0]], ('PASS', 0.9926876)]
[[[158.0, 30.0], [351.0, 26.0], [352.0, 66.0], [159.0, 71.0]], ('登机牌', 0.99803185)]
[[[424.0, 27.0], [653.0, 23.0], [654.0, 56.0], [425.0, 61.0]], ('BOARDING', 0.9355928)]
[[[678.0, 101.0], [740.0, 100.0], [740.0, 117.0], [678.0, 119.0]], ('座位号', 0.9993448)]
[[[490.0, 106.0], [648.0, 102.0], [648.0, 119.0], [491.0, 122.0]], ('序号SERIALNO', 0.9721721)]
[[[397.0, 107.0], [455.0, 105.0], [455.0, 122.0], [397.0, 124.0]], ('CLASS', 0.99292123)]
[[[340.0, 109.0], [384.0, 107.0], [385.0, 122.0], [341.0, 124.0]], ('舱位', 0.95519966)]
[[[749.0, 100.0], [830.0, 97.0], [831.0, 114.0], [750.0, 116.0]], ('SEAT NO', 0.91536474)]
[[[215.0, 111.0], [255.0, 110.0], [256.0, 125.0], [216.0, 127.0]], ('日期', 0.99764645)]
[[[66.0, 114.0], [189.0, 111.0], [190.0, 128.0], [66.0, 131.0]], ('航班FLIGHT', 0.9937089)]
[[[248.0, 110.0], [314.0, 110.0], [314.0, 125.0], [248.0, 125.0]], ('DATE', 0.98909116)]
[[[509.0, 131.0], [566.0, 131.0], [566.0, 156.0], [509.0, 156.0]], ('035', 0.9830131)]
[[[406.0, 135.0], [430.0, 135.0], [430.0, 157.0], [406.0, 157.0]], ('W', 0.99706143)]
[[[84.0, 142.0], [212.0, 139.0], [213.0, 158.0], [84.0, 162.0]], ('MU 2379', 0.9289481)]
[[[211.0, 141.0], [324.0, 139.0], [325.0, 156.0], [211.0, 158.0]], ('03DEG', 0.8540861)]
[[[489.0, 175.0], [572.0, 173.0], [572.0, 193.0], [489.0, 195.0]], ('登机口', 0.9996843)]
[[[568.0, 176.0], [612.0, 176.0], [612.0, 191.0], [568.0, 191.0]], ('GATE', 0.99684405)]
[[[345.0, 177.0], [409.0, 177.0], [409.0, 194.0], [345.0, 194.0]], ('始发地', 0.9996207)]
[[[400.0, 177.0], [466.0, 173.0], [467.0, 191.0], [401.0, 194.0]], ('FROM', 0.9926705)]
[[[68.0, 181.0], [168.0, 178.0], [168.0, 199.0], [69.0, 203.0]], ('目的地TO', 0.98151416)]
[[[680.0, 172.0], [806.0, 166.0], [807.0, 186.0], [681.0, 192.0]], ('登机时间BD1', 0.9584261)]
[[[98.0, 208.0], [168.0, 208.0], [168.0, 227.0], [98.0, 227.0]], ('福州', 0.8741772)]
[[[339.0, 220.0], [474.0, 216.0], [475.0, 235.0], [339.0, 239.0]], ('TAIYUAN', 0.93135375)]
[[[507.0, 217.0], [552.0, 214.0], [553.0, 232.0], [508.0, 235.0]], ('G11', 0.84185356)]
[[[90.0, 231.0], [200.0, 229.0], [200.0, 247.0], [90.0, 250.0]], ('FUZHOU', 0.98411864)]
[[[347.0, 243.0], [481.0, 239.0], [482.0, 254.0], [347.0, 258.0]], ('身份识别IDNO', 0.9800327)]
[[[67.0, 253.0], [170.0, 250.0], [170.0, 267.0], [68.0, 270.0]], ('姓名NAME', 0.9965892)]
[[[77.0, 279.0], [262.0, 275.0], [262.0, 294.0], [78.0, 299.0]], ('ZHANGQIWET', 0.92218363)]
[[[464.0, 299.0], [576.0, 297.0], [577.0, 314.0], [464.0, 316.0]], ('票号TKTNO', 0.9938587)]
[[[103.0, 314.0], [208.0, 313.0], [208.0, 334.0], [104.0, 336.0]], ('张祺伟', 0.945729)]
[[[70.0, 345.0], [164.0, 343.0], [165.0, 362.0], [71.0, 365.0]], ('票价FARE', 0.99907106)]
[[[347.0, 350.0], [659.0, 349.0], [659.0, 366.0], [348.0, 367.0]], ('ETKT7813699238489/1', 0.97859323)]
[[[101.0, 459.0], [829.0, 442.0], [829.0, 462.0], [102.0, 478.0]], ('登机口于起飞前10分钟关闭GATESCLOSE10MINUTESBEFOREDEPARTURETIME', 0.9942007)]

Process finished with exit code 0

图片

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_paddle_02

二、但是识别验证码,就是碎了一地的效果,

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_百度_03

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_ide_04

"D:\Program Files\Python36\python.exe" D:/nanodet-main/test.py
Namespace(cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='C:\\Users\\sxj/.paddleocr/2.1/cls', cls_thresh=0, det=True, det_algorithm='DB', det_db_box_thresh=0.5, det_db_thresh=0.3, det_db_unclip_ratio=1.6, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0.8, det_limit_side_len=960, det_limit_type='max', det_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_det_infer', drop_score=0.5, enable_mkldnn=False, gpu_mem=8000, image_dir='', ir_optim=True, label_list=['0', '180'], lang='ch', max_text_length=25, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='./ppocr/utils/ppocr_keys_v1.txt', rec_char_type='ch', rec_image_shape='3, 32, 320', rec_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_rec_infer', use_angle_cls=False, use_dilation=False, use_gpu=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, use_zero_copy_run=False)
[2021/04/17 14:57:31] root WARNING: Since the angle classifier is not initialized, the angle classifier will not be uesd during the forward process
[2021/04/17 14:57:31] root INFO: dt_boxes num : 1, elapse : 0.5834400653839111
[2021/04/17 14:57:31] root INFO: rec_res num : 1, elapse : 0.03889632225036621
[]

Process finished with exit code 0

三、如果图稍微截取的大一点,就可以识别,但是识别的存在错误

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_百度_05

"D:\Program Files\Python36\python.exe" D:/nanodet-main/test.py
Namespace(cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='C:\\Users\\sxj/.paddleocr/2.1/cls', cls_thresh=0.9, det=True, det_algorithm='DB', det_db_box_thresh=0.5, det_db_thresh=0.3, det_db_unclip_ratio=1.6, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0.8, det_limit_side_len=960, det_limit_type='max', det_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_det_infer', drop_score=0.5, enable_mkldnn=False, gpu_mem=8000, image_dir='', ir_optim=True, label_list=['0', '180'], lang='ch', max_text_length=25, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='./ppocr/utils/ppocr_keys_v1.txt', rec_char_type='ch', rec_image_shape='3, 32, 320', rec_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_rec_infer', use_angle_cls=False, use_dilation=False, use_gpu=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, use_zero_copy_run=False)
[2021/04/17 15:50:32] root WARNING: Since the angle classifier is not initialized, the angle classifier will not be uesd during the forward process
[2021/04/17 15:50:32] root INFO: dt_boxes num : 1, elapse : 0.6196780204772949
[2021/04/17 15:50:32] root INFO: rec_res num : 1, elapse : 0.02003645896911621
[[[[340.0, 269.0], [432.0, 272.0], [432.0, 302.0], [339.0, 299.0]], ('2789', 0.8799714)]]
[[[340.0, 269.0], [432.0, 272.0], [432.0, 302.0], [339.0, 299.0]], ('2789', 0.8799714)]

Process finished with exit code 0

四、做一下处理,首先参考了代码,进行修改。Python验证码识别 - 老板丶鱼丸粗面 

from PIL import Image
from pytesseract import *
from fnmatch import fnmatch
from queue import Queue
import cv2
import os
def clear_border(img,img_name):
'''去除边框
'''

h, w = img.shape[:2]
for y in range(0, w):
for x in range(0, h):
# if y ==0 or y == w -1 or y == w - 2:
if y < 4 or y > w -4:
img[x, y] = 255
# if x == 0 or x == h - 1 or x == h - 2:
if x < 4 or x > h - 4:
img[x, y] = 255

return img


def interference_line(img, img_name):
'''
干扰线降噪
'''

h, w = img.shape[:2]
# !!!opencv矩阵点是反的
# img[1,2] 1:图片的高度,2:图片的宽度
for y in range(1, w - 1):
for x in range(1, h - 1):
count = 0
if img[x, y - 1] > 245:
count = count + 1
if img[x, y + 1] > 245:
count = count + 1
if img[x - 1, y] > 245:
count = count + 1
if img[x + 1, y] > 245:
count = count + 1
if count > 2:
img[x, y] = 255
return img

def interference_point(img,img_name, x = 0, y = 0):
"""点降噪
9邻域框,以当前点为中心的田字框,黑点个数
:param x:
:param y:
:return:
"""
# todo 判断图片的长宽度下限
cur_pixel = img[x,y]# 当前像素点的值
height,width = img.shape[:2]

for y in range(0, width - 1):
for x in range(0, height - 1):
if y == 0: # 第一行
if x == 0: # 左上顶点,4邻域
# 中心点旁边3个点
sum = int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y + 1])
if sum <= 2 * 245:
img[x, y] = 0
elif x == height - 1: # 右上顶点
sum = int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x - 1, y]) \
+ int(img[x - 1, y + 1])
if sum <= 2 * 245:
img[x, y] = 0
else: # 最上非顶点,6邻域
sum = int(img[x - 1, y]) \
+ int(img[x - 1, y + 1]) \
+ int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y + 1])
if sum <= 3 * 245:
img[x, y] = 0
elif y == width - 1: # 最下面一行
if x == 0: # 左下顶点
# 中心点旁边3个点
sum = int(cur_pixel) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y - 1]) \
+ int(img[x, y - 1])
if sum <= 2 * 245:
img[x, y] = 0
elif x == height - 1: # 右下顶点
sum = int(cur_pixel) \
+ int(img[x, y - 1]) \
+ int(img[x - 1, y]) \
+ int(img[x - 1, y - 1])

if sum <= 2 * 245:
img[x, y] = 0
else: # 最下非顶点,6邻域
sum = int(cur_pixel) \
+ int(img[x - 1, y]) \
+ int(img[x + 1, y]) \
+ int(img[x, y - 1]) \
+ int(img[x - 1, y - 1]) \
+ int(img[x + 1, y - 1])
if sum <= 3 * 245:
img[x, y] = 0
else: # y不在边界
if x == 0: # 左边非顶点
sum = int(img[x, y - 1]) \
+ int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x + 1, y - 1]) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y + 1])

if sum <= 3 * 245:
img[x, y] = 0
elif x == height - 1: # 右边非顶点
sum = int(img[x, y - 1]) \
+ int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x - 1, y - 1]) \
+ int(img[x - 1, y]) \
+ int(img[x - 1, y + 1])

if sum <= 3 * 245:
img[x, y] = 0
else: # 具备9领域条件的
sum = int(img[x - 1, y - 1]) \
+ int(img[x - 1, y]) \
+ int(img[x - 1, y + 1]) \
+ int(img[x, y - 1]) \
+ int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x + 1, y - 1]) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y + 1])
if sum <= 4 * 245:
img[x, y] = 0
return img

def _get_dynamic_binary_image(filedir, img_name):
'''
自适应阀值二值化
'''

img_name =os.path.join(filedir,img_name)
print('.....' + img_name)
im = cv2.imread(img_name)
im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
th1 = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)
return th1

def _get_static_binary_image(img, threshold = 140):
'''
手动二值化
'''

img = Image.open(img)
img = img.convert('L')
pixdata = img.load()
w, h = img.size
for y in range(h):
for x in range(w):
if pixdata[x, y] < threshold:
pixdata[x, y] = 0
else:
pixdata[x, y] = 255

return img


def cfs(im,x_fd,y_fd):
'''用队列和集合记录遍历过的像素坐标代替单纯递归以解决cfs访问过深问题
'''

# print('**********')

xaxis=[]
yaxis=[]
visited =set()
q = Queue()
q.put((x_fd, y_fd))
visited.add((x_fd, y_fd))
offsets=[(1, 0), (0, 1), (-1, 0), (0, -1)]#四邻域

while not q.empty():
x,y=q.get()

for xoffset,yoffset in offsets:
x_neighbor,y_neighbor = x+xoffset,y+yoffset

if (x_neighbor,y_neighbor) in (visited):
continue # 已经访问过了

visited.add((x_neighbor, y_neighbor))

try:
if im[x_neighbor, y_neighbor] == 0:
xaxis.append(x_neighbor)
yaxis.append(y_neighbor)
q.put((x_neighbor,y_neighbor))

except IndexError:
pass
# print(xaxis)
if (len(xaxis) == 0 | len(yaxis) == 0):
xmax = x_fd + 1
xmin = x_fd
ymax = y_fd + 1
ymin = y_fd

else:
xmax = max(xaxis)
xmin = min(xaxis)
ymax = max(yaxis)
ymin = min(yaxis)
#ymin,ymax=sort(yaxis)

return ymax,ymin,xmax,xmin

def detectFgPix(im,xmax):
'''搜索区块起点
'''

h,w = im.shape[:2]
for y_fd in range(xmax+1,w):
for x_fd in range(h):
if im[x_fd,y_fd] == 0:
return x_fd,y_fd

def CFS(im):
'''切割字符位置
'''

zoneL=[]#各区块长度L列表
zoneWB=[]#各区块的X轴[起始,终点]列表
zoneHB=[]#各区块的Y轴[起始,终点]列表

xmax=0#上一区块结束黑点横坐标,这里是初始化
for i in range(10):

try:
x_fd,y_fd = detectFgPix(im,xmax)
# print(y_fd,x_fd)
xmax,xmin,ymax,ymin=cfs(im,x_fd,y_fd)
L = xmax - xmin
H = ymax - ymin
zoneL.append(L)
zoneWB.append([xmin,xmax])
zoneHB.append([ymin,ymax])

except TypeError:
return zoneL,zoneWB,zoneHB

return zoneL,zoneWB,zoneHB


def cutting_img(destdir,im,im_position,img,xoffset = 1,yoffset = 1):
filename = os.path.join(destdir,img.split('.')[0])
# 识别出的字符个数
im_number = len(im_position[1])
# 切割字符
img = Image.new('RGB', (100, 100), (0, 0, 0))
pre_im_start_y=im_position[2][0][0]- yoffset
pre_im_end_Y =im_position[2][0][1]+ yoffset
for i in range(im_number):
im_start_X = im_position[1][i][0] - xoffset
im_end_X = im_position[1][i][1] + xoffset
im_start_Y = min(im_position[2][i][0] - yoffset,pre_im_start_y)
im_end_Y = max(im_position[2][i][1] + yoffset,pre_im_end_Y)
#print(im_start_Y," ",im_end_Y," ", im_start_X," ",im_end_X)
pre_im_start_y=im_position[2][i][0] - yoffset
pre_im_end_Y=im_position[2][i][1] + yoffset
cropped = im[im_start_Y:im_end_Y, im_start_X:im_end_X]
cropped = cv2.resize(cropped, (0, 0), fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
cropped = cv2.bitwise_not(cropped)
#腐蚀图片进行处理,paddle 检测效果更好
cv2.imwrite(filename + str(i) + '.jpg', cropped)
img1 = Image.open(filename + str(i) + '.jpg')
img.paste(img1, (int(35), int(35), int(35) + img1.size[0], int(35) + img1.size[1]))
img.save(filename + str(i) + '.jpg')
img1.close()

return im_number

def preprocess(desdir):
for item in os.listdir(desdir):
img = cv2.imread(os.path.join(desdir,item))
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
erode = cv2.erode(hsv, None, iterations=1)
dilate = cv2.dilate(erode, None, iterations=1)
dilate = cv2.cvtColor(dilate, cv2.COLOR_HSV2RGB)
cv2.imwrite(os.path.join(desdir,item), dilate)

def main():
filedir = r'F:\tt\source'
destdir=r'F:\tt\destination'
for file in os.listdir(filedir):
if fnmatch(file, '*.png') or fnmatch(file, '*.jpg'):
img_name = file

# 自适应阈值二值化
im = _get_dynamic_binary_image(filedir, img_name)

# 去除边框
im = clear_border(im,img_name)

# 对图片进行干扰线降噪
im = interference_line(im,img_name)

# 对图片进行点降噪
im = interference_point(im,img_name)

# 切割的位置
im_position = CFS(im)

maxL = max(im_position[0])
minL = min(im_position[0])

# 如果有粘连字符,如果一个字符的长度过长就认为是粘连字符,并从中间进行切割
if(maxL > minL + minL * 0.7):
maxL_index = im_position[0].index(maxL)
minL_index = im_position[0].index(minL)
# 设置字符的宽度
im_position[0][maxL_index] = maxL // 2
im_position[0].insert(maxL_index + 1, maxL // 2)
# 设置字符X轴[起始,终点]位置
im_position[1][maxL_index][1] = im_position[1][maxL_index][0] + maxL // 2
im_position[1].insert(maxL_index + 1, [im_position[1][maxL_index][1] + 1, im_position[1][maxL_index][1] + 1 + maxL // 2])
# 设置字符的Y轴[起始,终点]位置
im_position[2].insert(maxL_index + 1, im_position[2][maxL_index])

# 切割字符,要想切得好就得配置参数,通常 1 or 2 就可以
cutting_img_num=cutting_img(destdir,im,im_position,img_name,1,1)
preprocess(destdir)


print('切图:%s' % cutting_img_num)


if __name__ == '__main__':
main()

处理结果,

      

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_python_06

    

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_paddle_07

    

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_python_08

   

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_paddle_09

    

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_python_10

检测效果仍然很差 运算符检测不出来~~~~mmp,怎么办 怎么办?真的懒得去训练。。。我在思考 paddleOCR如果是蓝底白字是不是效果会变好呢?试试吧~~~

from PIL import Image
import numpy as np
from fnmatch import fnmatch
from queue import Queue
import cv2
import os
from paddleocr import PaddleOCR, draw_ocr




def clear_border(img,img_name):
'''去除边框
'''

h, w = img.shape[:2]
for y in range(0, w):
for x in range(0, h):
# if y ==0 or y == w -1 or y == w - 2:
if y < 4 or y > w -4:
img[x, y] = 255
# if x == 0 or x == h - 1 or x == h - 2:
if x < 4 or x > h - 4:
img[x, y] = 255

return img


def interference_line(img, img_name):
'''
干扰线降噪
'''

h, w = img.shape[:2]
# !!!opencv矩阵点是反的
# img[1,2] 1:图片的高度,2:图片的宽度
for y in range(1, w - 1):
for x in range(1, h - 1):
count = 0
if img[x, y - 1] > 245:
count = count + 1
if img[x, y + 1] > 245:
count = count + 1
if img[x - 1, y] > 245:
count = count + 1
if img[x + 1, y] > 245:
count = count + 1
if count > 2:
img[x, y] = 255
return img

def interference_point(img,img_name, x = 0, y = 0):
"""点降噪
9邻域框,以当前点为中心的田字框,黑点个数
:param x:
:param y:
:return:
"""
# todo 判断图片的长宽度下限
cur_pixel = img[x,y]# 当前像素点的值
height,width = img.shape[:2]

for y in range(0, width - 1):
for x in range(0, height - 1):
if y == 0: # 第一行
if x == 0: # 左上顶点,4邻域
# 中心点旁边3个点
sum = int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y + 1])
if sum <= 2 * 245:
img[x, y] = 0
elif x == height - 1: # 右上顶点
sum = int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x - 1, y]) \
+ int(img[x - 1, y + 1])
if sum <= 2 * 245:
img[x, y] = 0
else: # 最上非顶点,6邻域
sum = int(img[x - 1, y]) \
+ int(img[x - 1, y + 1]) \
+ int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y + 1])
if sum <= 3 * 245:
img[x, y] = 0
elif y == width - 1: # 最下面一行
if x == 0: # 左下顶点
# 中心点旁边3个点
sum = int(cur_pixel) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y - 1]) \
+ int(img[x, y - 1])
if sum <= 2 * 245:
img[x, y] = 0
elif x == height - 1: # 右下顶点
sum = int(cur_pixel) \
+ int(img[x, y - 1]) \
+ int(img[x - 1, y]) \
+ int(img[x - 1, y - 1])

if sum <= 2 * 245:
img[x, y] = 0
else: # 最下非顶点,6邻域
sum = int(cur_pixel) \
+ int(img[x - 1, y]) \
+ int(img[x + 1, y]) \
+ int(img[x, y - 1]) \
+ int(img[x - 1, y - 1]) \
+ int(img[x + 1, y - 1])
if sum <= 3 * 245:
img[x, y] = 0
else: # y不在边界
if x == 0: # 左边非顶点
sum = int(img[x, y - 1]) \
+ int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x + 1, y - 1]) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y + 1])

if sum <= 3 * 245:
img[x, y] = 0
elif x == height - 1: # 右边非顶点
sum = int(img[x, y - 1]) \
+ int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x - 1, y - 1]) \
+ int(img[x - 1, y]) \
+ int(img[x - 1, y + 1])

if sum <= 3 * 245:
img[x, y] = 0
else: # 具备9领域条件的
sum = int(img[x - 1, y - 1]) \
+ int(img[x - 1, y]) \
+ int(img[x - 1, y + 1]) \
+ int(img[x, y - 1]) \
+ int(cur_pixel) \
+ int(img[x, y + 1]) \
+ int(img[x + 1, y - 1]) \
+ int(img[x + 1, y]) \
+ int(img[x + 1, y + 1])
if sum <= 4 * 245:
img[x, y] = 0
return img

def _get_dynamic_binary_image(filedir, img_name):
'''
自适应阀值二值化
'''

img_name =os.path.join(filedir,img_name)
print('.....' + img_name)
im = cv2.imread(img_name)
im = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
th1 = cv2.adaptiveThreshold(im, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 21, 1)
return th1

def _get_static_binary_image(img, threshold = 140):
'''
手动二值化
'''

img = Image.open(img)
img = img.convert('L')
pixdata = img.load()
w, h = img.size
for y in range(h):
for x in range(w):
if pixdata[x, y] < threshold:
pixdata[x, y] = 0
else:
pixdata[x, y] = 255

return img


def cfs(im,x_fd,y_fd):
'''用队列和集合记录遍历过的像素坐标代替单纯递归以解决cfs访问过深问题
'''

# print('**********')

xaxis=[]
yaxis=[]
visited =set()
q = Queue()
q.put((x_fd, y_fd))
visited.add((x_fd, y_fd))
offsets=[(1, 0), (0, 1), (-1, 0), (0, -1)]#四邻域

while not q.empty():
x,y=q.get()

for xoffset,yoffset in offsets:
x_neighbor,y_neighbor = x+xoffset,y+yoffset

if (x_neighbor,y_neighbor) in (visited):
continue # 已经访问过了

visited.add((x_neighbor, y_neighbor))

try:
if im[x_neighbor, y_neighbor] == 0:
xaxis.append(x_neighbor)
yaxis.append(y_neighbor)
q.put((x_neighbor,y_neighbor))

except IndexError:
pass
# print(xaxis)
if (len(xaxis) == 0 | len(yaxis) == 0):
xmax = x_fd + 1
xmin = x_fd
ymax = y_fd + 1
ymin = y_fd

else:
xmax = max(xaxis)
xmin = min(xaxis)
ymax = max(yaxis)
ymin = min(yaxis)
#ymin,ymax=sort(yaxis)

return ymax,ymin,xmax,xmin

def detectFgPix(im,xmax):
'''搜索区块起点
'''

h,w = im.shape[:2]
for y_fd in range(xmax+1,w):
for x_fd in range(h):
if im[x_fd,y_fd] == 0:
return x_fd,y_fd

def CFS(im):
'''切割字符位置
'''

zoneL=[]#各区块长度L列表
zoneWB=[]#各区块的X轴[起始,终点]列表
zoneHB=[]#各区块的Y轴[起始,终点]列表

xmax=0#上一区块结束黑点横坐标,这里是初始化
for i in range(10):

try:
x_fd,y_fd = detectFgPix(im,xmax)
# print(y_fd,x_fd)
xmax,xmin,ymax,ymin=cfs(im,x_fd,y_fd)
L = xmax - xmin
H = ymax - ymin
zoneL.append(L)
zoneWB.append([xmin,xmax])
zoneHB.append([ymin,ymax])

except TypeError:
return zoneL,zoneWB,zoneHB

return zoneL,zoneWB,zoneHB


def cutting_img(destdir,im,im_position,img,xoffset = 1,yoffset = 1):
filename = os.path.join(destdir,img.split('.')[0])
# 识别出的字符个数
im_number = len(im_position[1])
# 切割字符
img = Image.new('RGB', (100, 100), (0, 0, 0))
pre_im_start_y=im_position[2][0][0]- yoffset
pre_im_end_Y =im_position[2][0][1]+ yoffset
for i in range(im_number):
im_start_X = im_position[1][i][0] - xoffset
im_end_X = im_position[1][i][1] + xoffset
im_start_Y = min(im_position[2][i][0] - yoffset,pre_im_start_y)
im_end_Y = max(im_position[2][i][1] + yoffset,pre_im_end_Y)
#print(im_start_Y," ",im_end_Y," ", im_start_X," ",im_end_X)
pre_im_start_y=im_position[2][i][0] - yoffset
pre_im_end_Y=im_position[2][i][1] + yoffset
cropped = im[im_start_Y:im_end_Y, im_start_X:im_end_X]
cropped = cv2.resize(cropped, (0, 0), fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
cropped = cv2.bitwise_not(cropped)
#cropped = cv2.medianBlur(cropped, 5)# 中值滤波
#腐蚀图片进行处理,paddle 检测效果更好
cv2.imwrite(filename + str(i) + '.jpg', cropped)
img1 = Image.open(filename + str(i) + '.jpg')
img.paste(img1, (int(35), int(35), int(35) + img1.size[0], int(35) + img1.size[1]))
img.save(filename + str(i) + '.jpg')
img1.close()

return im_number

#R:5;G:39;B:175
def image2label(dilate):
data = np.array(dilate, dtype='int32')
# 修改B通道的像素值
for i in range(data[:, :, 0].shape[0]):
for j in range(data[:, :, 0].shape[1]):
if data[:, :, 0][i][j] > 155:
data[:, :, 0][i][j] = 255
else:
data[:, :, 0][i][j] = 175
# 修改G通道的像素值
for i in range(data[:, :, 1].shape[0]):
for j in range(data[:, :, 1].shape[1]):
if data[:, :, 1][i][j] > 155:
data[:, :, 1][i][j] = 255
else:
data[:, :, 1][i][j] = 39
# 修改R通道的像素值
for i in range(data[:, :, 2].shape[0]):
for j in range(data[:, :, 2].shape[1]):
if data[:, :, 2][i][j] > 155:
data[:, :, 2][i][j] = 255
else:
data[:, :, 2][i][j] = 5

return data

def preprocess(desdir):
for item in os.listdir(desdir):
img = cv2.imread(os.path.join(desdir,item))
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
erode = cv2.erode(hsv, None, iterations=1)#开运算
dilate = cv2.dilate(erode, None, iterations=1)#闭运算
dilate = cv2.cvtColor(dilate, cv2.COLOR_HSV2RGB)
dilate=image2label(dilate)

cv2.imwrite(os.path.join(desdir,item), dilate)

def main():
filedir = r'F:\tt\source'
destdir=r'F:\tt\destination'
ocr = PaddleOCR(use_angle_cls=True, cls_thresh=0, det_east_score_thresh=0, use_gpu=False,
det_model_dir=r'F:\tt\ch_ppocr_mobile_v2.0_det_infer',
rec_model_dir=r'F:\tt\ch_ppocr_mobile_v2.0_rec_infer') # need to run only once to download and load model into memory
for file in os.listdir(filedir):
if fnmatch(file, '*.png') or fnmatch(file, '*.jpg'):
img_name = file

# 自适应阈值二值化
im = _get_dynamic_binary_image(filedir, img_name)

# 去除边框
im = clear_border(im,img_name)

# 对图片进行干扰线降噪
im = interference_line(im,img_name)

# 对图片进行点降噪
im = interference_point(im,img_name)

# 切割的位置
im_position = CFS(im)

maxL = max(im_position[0])
minL = min(im_position[0])

# 如果有粘连字符,如果一个字符的长度过长就认为是粘连字符,并从中间进行切割
if(maxL > minL + minL * 0.7):
maxL_index = im_position[0].index(maxL)
minL_index = im_position[0].index(minL)
# 设置字符的宽度
im_position[0][maxL_index] = maxL // 2
im_position[0].insert(maxL_index + 1, maxL // 2)
# 设置字符X轴[起始,终点]位置
im_position[1][maxL_index][1] = im_position[1][maxL_index][0] + maxL // 2
im_position[1].insert(maxL_index + 1, [im_position[1][maxL_index][1] + 1, im_position[1][maxL_index][1] + 1 + maxL // 2])
# 设置字符的Y轴[起始,终点]位置
im_position[2].insert(maxL_index + 1, im_position[2][maxL_index])

# 切割字符,要想切得好就得配置参数,通常 1 or 2 就可以
cutting_img_num=cutting_img(destdir,im,im_position,img_name,1,1)
preprocess(destdir)
for item in os.listdir(destdir):
filename=os.path.join(destdir,item)
result = ocr.ocr(filename, cls=True)
for line in result:
print(line[-1][0])



if __name__ == '__main__':
main()

产生的图片为

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_开发语言_11

   

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_paddle_12

   

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_python_13

  

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_开发语言_14

果不其然 可以识别了 符号和数字了 ~~

0

"D:\Program Files\Python36\python.exe" D:/nanodet-main/test.py
Namespace(cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='C:\\Users\\sxj/.paddleocr/2.1/cls', cls_thresh=0, det=True, det_algorithm='DB', det_db_box_thresh=0.5, det_db_thresh=0.3, det_db_unclip_ratio=1.6, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0, det_limit_side_len=960, det_limit_type='max', det_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_det_infer', drop_score=0.5, enable_mkldnn=False, gpu_mem=8000, image_dir='', ir_optim=True, label_list=['0', '180'], lang='ch', max_text_length=25, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='./ppocr/utils/ppocr_keys_v1.txt', rec_char_type='ch', rec_image_shape='3, 32, 320', rec_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_rec_infer', use_angle_cls=True, use_dilation=False, use_gpu=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, use_zero_copy_run=False)
[2021/04/18 09:40:36] root INFO: dt_boxes num : 1, elapse : 0.4519474506378174
[2021/04/18 09:40:36] root INFO: cls num : 1, elapse : 0.01795220375061035
[2021/04/18 09:40:36] root INFO: rec_res num : 1, elapse : 0.006981849670410156
[[[[39.0, 38.0], [71.0, 40.0], [69.0, 79.0], [37.0, 77.0]], ('0', 0.7298239)]]
[[[39.0, 38.0], [71.0, 40.0], [69.0, 79.0], [37.0, 77.0]], ('0', 0.7298239)]

Process finished with exit code 0

+

"D:\Program Files\Python36\python.exe" D:/nanodet-main/test.py
Namespace(cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='C:\\Users\\sxj/.paddleocr/2.1/cls', cls_thresh=0, det=True, det_algorithm='DB', det_db_box_thresh=0.5, det_db_thresh=0.3, det_db_unclip_ratio=1.6, det_east_cover_thresh=0.1, det_east_nms_thresh=0.2, det_east_score_thresh=0, det_limit_side_len=960, det_limit_type='max', det_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_det_infer', drop_score=0.5, enable_mkldnn=False, gpu_mem=8000, image_dir='', ir_optim=True, label_list=['0', '180'], lang='ch', max_text_length=25, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='./ppocr/utils/ppocr_keys_v1.txt', rec_char_type='ch', rec_image_shape='3, 32, 320', rec_model_dir='F:\\tt\\ch_ppocr_mobile_v2.0_rec_infer', use_angle_cls=True, use_dilation=False, use_gpu=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, use_zero_copy_run=False)
[2021/04/18 09:37:24] root INFO: dt_boxes num : 1, elapse : 0.42177367210388184
[2021/04/18 09:37:24] root INFO: cls num : 1, elapse : 0.015623092651367188
[2021/04/18 09:37:24] root INFO: rec_res num : 1, elapse : 0.015619516372680664
[[[[37.0, 46.0], [71.0, 47.0], [70.0, 78.0], [36.0, 77.0]], ('十', 0.72421145)]]
[[[37.0, 46.0], [71.0, 47.0], [70.0, 78.0], [36.0, 77.0]], ('十', 0.72421145)]

Process finished with exit code 0

但是 仍然存在一些识别错误的问题~~~  心塞, 进步调查原因,难道是没有检测到吗??? 换了服务器版本的模型也不可以。。。看样子无药可救了

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_python_15

    

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_开发语言_16

   

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_开发语言_17

    

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_ide_18

  

六、首先先爬虫点数据集吧~,

      (1)查看一下自己的google浏览器的版本号

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_python_19

    

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_ide_20

然后下载​​https://sites.google.com/a/chromium.org/chromedriver/downloads​​ ,放入F:\\EXEDIR\\

因为下载google刷新网页驱动需要翻墙下载,请自行下载,let's go 爬验证码图片吧~~

import urllib.request
import time
import os
from selenium import webdriver

def refresh(exedir,url,second):
driver = webdriver.Chrome(os.path.join(exedir,"chromedriver.exe"))
driver.get(url)
time.sleep(second)
driver.refresh()
driver.close()


def getHtml(url):
html = urllib.request.urlopen(url).read()
return html

def saveHtml(destdir, file_content,i):
# 注意windows文件命名的禁用符,比如 /
with open(os.path.join(destdir,".".join([str(i),"jpg"])), "wb") as f:
# 写文件用bytes而不是str,所以要转码
f.write(file_content)
destdir="F:\\TESTIMG"
exedir="F:\\EXEDIR"
second=1
num=10000
for i in range(num):
aurl = "https://******.cn/m/tmri/captcha/math?nocache=1618204715553"
html = getHtml(aurl)
saveHtml(destdir, html,i)
refresh(exedir,aurl,second)
print("下载成功")

下载成功的样子大概这样,有500张吧

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_开发语言_21

直接标注原图吧,不分割单个字符标注在训练了(也可以简单的处理一下)

from fnmatch import fnmatch
import cv2
import os

def _get_dynamic_binary_image(img_name):
print('.....' + img_name)
im = cv2.imread(img_name)
frame = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
height = frame.shape[0]
weight = frame.shape[1]
print("weight : %s, height : %s" % (weight, height))
for row in range(height): # 遍历高
for col in range(weight): # 遍历宽
pv = frame[row, col]
# print(pv)
if pv > 100:
frame[row, col] = 255
return frame
def clear_border(img):
'''去除边框
'''
h, w = img.shape[:2]
for y in range(0, w):
for x in range(0, h):
# if y ==0 or y == w -1 or y == w - 2:
if y < 4 or y > w -4:
img[x, y] = 255
# if x == 0 or x == h - 1 or x == h - 2:
if x < 4 or x > h - 4:
img[x, y] = 255
return img


def main():
filedir = r'F:\tt\source'
destdir = r'F:\tt\destination'
for file in os.listdir(filedir):
if fnmatch(file, '*.png') or fnmatch(file, '*.jpg'):
img_name = os.path.join(filedir, file)
img = _get_dynamic_binary_image(img_name)
img_out=clear_border(img)
cv2.imwrite(os.path.join(destdir,file),img_out)



if __name__ == '__main__':
main()

25、使用Baidu的paddle自动进行验证码的识别、并计算验证码的数值_百度_22

训练自己的paddleOCR数据,这里按照灰度图进行训练吧,先下载源码进行数据标注,标注仍然以切分数字图片和运算符为主,色彩随机设置,以丰富数据集~(注:本项目的某一部分仅需要这样的功能,其它需求暂不考虑)

ubuntu@ubuntu:~$ git clone https://github.com/PaddlePaddle/PaddleOCR
ubuntu@ubuntu:~$ cd PaddleOCR
ubuntu@ubuntu:~$ pip install -r requirements.txt
ubuntu@ubuntu:~PaddleOCR$ cd PPOCRLabel
ubuntu@ubuntu:~PaddleOCR/PPOCRLabel$ python PPOCRLabel.py --lang ch

未完待续

标签:Baidu,25,img,int,det,验证码,im,position,rec
From: https://blog.51cto.com/u_12504263/5719090

相关文章