赞
踩
源代码路径:
https://github.com/breezedeus/CnOCR
OCR英文全称是Optical Character Recognition,中文叫做光学字符识别。它是通过扫描等光学技术与计算机技术结合的方式将各种证件、票据、文件及其它印刷品的文字转化为图像信息,再利用文字识别技术将图像信息转化为可以使用的计算机输入技术。也就是说,ocr识别技术 直接从影像中提取各类数据,省去人工录入,节约成本。
目前许多开源OCR技术不断出现,如paddleOCR,百度OCR,阿里OCR等等,OCR技术在我们生活中的运用范围十分广泛:比如一个手机APP就能帮忙扫描名片、身份证,并识别出里面的信息;汽车进入停车场、收费站都不需要人工登记了,都是用车牌识别技术;我们看书时看到不懂的题,拿个手机一扫,APP就能在网上帮你找到这题的答案等。
CnOCR是Python 3下的文字识别(Optical Character Recognition,简称OCR)工具包,支持简体中文、繁体中文(部分模型)、英文和数字的常见字符识别,支持竖排文字的识别。有适用于PyTorch版本与ONNX版本的模型。该开源算法自带了20+个训练好的识别模型,适用于不同应用场景。
基本原理说明——为了识别一张图片中的文字,通常包含两个步骤:
检测的代码部分比较简单,对输入的图像数据做一些简单的处理后输入模型
支持对单个图片或者多个图片(列表)的检测
可接受参数为图片文件路径,或PIL格式,numpy格式的图像数据对应格式——RGB 3通道 shape:(height, width, 3)取值:[0, 255]
- img_list: Union[
- str,
- Path,
- Image.Image,
- np.ndarray,
- List[Union[str, Path, Image.Image, np.ndarray]],
- ],
前处理简述:
对批量传入的图像数据按照定义的参数batch进行打包,后对每个batch的图像数据以PIL格式进行读取,转化为PIL格式的RGB图像输入到模型中进行检测。
- def read_img(img_fp) -> Image.Image:
- img = Image.open(img_fp)
- img = ImageOps.exif_transpose(img).convert('RGB') # 识别旋转后的图片
- return img
返回一个字典或字典的列表,包含一张图片的检测结果:
* 'rotated_angle': float, 整张图片旋转的角度。
* 'detected_texts': list, 每个元素存储了检测出的一个框的信息,使用词典记录,包括以下几个值:
'box':检测出的文字对应的矩形框;np.ndarray, shape: (4, 2),对应 box 4个点的坐标值 (x, y) ;
'score':得分;float 类型;分数越高表示越可靠;
'cropped_img':对应'box'中的图片patch(RGB格式),会把倾斜的图片旋转为水平。
np.ndarray 类型,shape: (height, width, 3), 取值范围:[0, 255];
示例:
- >>>out
- {'rotated_angle': 0.0,
- 'detected_texts': [{'box': array([[ 199, 183],
- [ 469, 183],
- [ 469, 237],
- [ 199, 237]], dtype=float32),
- 'score': 0.8020596971160255,
- 'cropped_img': array([[[253, 236, 229],
- [253, 243, 234],
- [252, 242, 233],
- ...,
- [232, 222, 213],
- [234, 224, 215],
- [234, 224, 215]],
-
- ...,
-
- [[255, 200, 184],
- [255, 221, 206],
- [255, 232, 219],
- ...,
- [255, 237, 232],
- [255, 235, 230],
- [255, 236, 237]]], dtype=uint8)}]}
后处理部分:
对检测到的文本区域图像进行角度分类,并更新每个文本区域对应的图像
- for out in outs:
- crop_img_list = [info['cropped_img'] for info in out['detected_texts']]
- try:
- crop_img_list, angle_list = self.angle_clf(crop_img_list)
- for info, crop_img in zip(out['detected_texts'], crop_img_list):
- info['cropped_img'] = crop_img
- except Exception as e:
- logger.info(traceback.format_exc())
- logger.info(e)
遍历检测到的文本信息的输出列表中的每一个元素并提取['cropped_img']字段,即对应的图像数据。后调用self.angle_clf()
方法对crop_img_list
中的文本区域图像进行角度分类,该方法返回分类后的文本区域图像列表crop_img_list
和对应的角度列表angle_list
。
接下来,使用zip()
函数将out['detected_texts']
和crop_img_list
进行打包,然后通过for
循环遍历打包后的元素,将crop_img
赋值给对应的文本信息字典info
的'cropped_img'
字段,从而更新了每个文本区域对应的图像。
可接受的参数同样为Path, torch.Tensor, np.ndarray
代码将输入的图像列表转化为numpy格式的图像数据——shape(height, width, 1), dtype uint8, 取值:[0, 255] 后转换图像数据维度:[H, W, C]->[C, H, W]并转换为torch类型数据
- img = img.transpose((2, 0, 1))
- img = torch.from_numpy(img)
对图像数据列表按宽度从小到大排列以提升效率
- # sorted_idx_list返回的是一个排序后的索引列表
- sorted_idx_list = sorted(range(len(img_list)), key=lambda i: img_list[i].shape[2])
- sorted_img_list = [img_list[i] for i in sorted_idx_list]
按照batch_size大小对图像进行批量处理,先通过pad_img_seq完成对图像序列进行填充,这一步骤的目的是使得序列中的所有图像具有相同的宽度,输入图像列表中每个张量的形状为[C, H, W]
,其中W
是可变的宽度。函数使用指定的填充值padding_value
对图像序列进行填充。
首先,代码将图像列表中的每个图像张量的维度顺序进行转置,变为[W, C, H]
的形式。然后,使用pad_sequence
函数对转置后的图像列表进行填充,使得所有图像具有相同的宽度。填充的值为padding_value
。填充后的结果形状为[B, W_max, C, H]
,其中B
是图像序列的长度,W_max
是图像序列中最大的宽度。最后,代码再次对填充后的结果进行维度转置,变为[B, C, H, W_max]
的形式,并将结果返回。
- def pad_img_seq(img_list: List[torch.Tensor], padding_value=0) -> torch.Tensor:
- img_list = [img.permute((2, 0, 1)) for img in img_list] # [W, C, H]
- imgs = pad_sequence(
- img_list, batch_first=True, padding_value=padding_value
- ) # [B, W_max, C, H]
- return imgs.permute((0, 2, 3, 1)) # [B, C, H, W_max]
输入模型即可得出文本识别输出结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。