转自AI Studio,原文链接:基于PaddleOCR的新冠肺炎检测结果图片个人数据脱敏 - 飞桨AI Studio

一、新冠肺炎数据脱敏

1.项目简介

项目来源于社区朋友的号召,具体内容如下:

各位PPDE大佬们好,我们是上海疫情IT志愿者,其中有来自曾参与了武汉2020新型冠状病毒防疫信息平台建设的开发者,目前我们正在开发一款用于疫情防控的AI机器人:https://github.com/ShanghaiITVolunteer/AntigenWechatBot,此项目目前获得wechaty社区以及开源社的支持。

目前我们正在开发一个抗原图片检测的功能,输入为居民图片,输出为图片类型和抗原检测图片的结果(阴性和阳性)。详细可见:https://github.com/ShanghaiITVolunteer/AntigenWechatBot/issues/44

此项目完全属于公益性质,毫无任何商业行为和规划,也希望各位大佬能够参与到此项目当中来。

目前已经将功能划分成以下四个部分:

  • 1:数据脱敏:mask掉图片中的名字序号等关键信息
  • 2:阳性图片数据增强:由于现在大部分都是阴性图片,没有阳性图片,故需要做数据增强
  • 3:抗原图片检测:检测图片中是否包含抗原检测仪
  • 4:抗原图片阴阳检测:在抗原图片中检测阴性和阳性的结果

2.数据脱敏

想想就是mask掉图片中的名字序号等关键信息,目前有以下几种:

  • 个人姓名
  • 个人住宿等信息
  • 检查日期

3.难点

处理这些信息比较难,主要有:

  • 出现的位置随机
  • 内容格式随机
  • 拍照方式随机
  • 文字有手写有P的字

这么多人困难,怎么处理成为一个让我头痛的问题,一度想到数据标注,检测试剂盒,单独图像分割出试剂盒,但是又考虑到有些字也有写到试剂盒,真的让人头痛。而且使用分隔方法,需要进行数据标注,又是一个暗无天日的时光,怕怕。

4.奇思妙想

思来想去,突然想到,其实 PaddleOCR就可以实现功能,具体如下:

  • 识别图片上所有文字
  • 检测所有文字的位置
  • 排除掉试剂盒上的文字(如序列号等),其余位置的文字全部mask 就这样实现数据脱敏,说干就干,下面看行动。

5.github地址

ShanghaiITVolunteer/AntigenClassifier github地址: GitHub - ShanghaiITVolunteer/AntigenClassifier: Deep Learning Model to classify the antigen image with Paddle*

欢迎大家一起来

6.与PaddleHub比较

基于PaddleHub的新冠肺炎检测结果图片个人数据脱敏版本相比较,有以下优势。

推荐阅读:20000+Star超轻量OCR系统PP-OCRv3效果再提升5% - 11%!

6.1 PaddleOCR v3优势

PaddleHub的OCR使用的是2020年左右的1.x的OCR模型,精度较差,目前PP-OCR v3,速度更快,效果更强。

6.2 更好的预测方式

之前预测,是批量载入图片,如果数据过多,容易造成内存溢出。目前进行了改进,单张预测,避免了内存溢出。

二、数据收集

为了准确获得所需数据,对现有的试剂盒进行收集。

新冠自测盒有哪几种

3月12日,国家药监局发布通告,批准南京诺唯赞、北京金沃夫、深圳华大因源、广州万孚生物、北京华科泰生物的新冠抗原产品自测应用申请变更,自此五款新冠抗原自测产品正式上市。

三、环境准备

In [1]

# clone PaddleOCR代码
! git  clone https://gitee.com/PaddlePaddle/PaddleOCR --depth=1 >log.log
Cloning into 'PaddleOCR'...
remote: Enumerating objects: 1237, done.
remote: Counting objects: 100% (1237/1237), done.
remote: Compressing objects: 100% (1109/1109), done.
remote: Total 1237 (delta 209), reused 695 (delta 78), pack-reused 0
Receiving objects: 100% (1237/1237), 101.41 MiB | 4.84 MiB/s, done.
Resolving deltas: 100% (209/209), done.
Checking connectivity... done.

In [3]

%cd ~
!pip install -U pip --user >log.log
!pip install -r PaddleOCR/requirements.txt  >log.log
!pip install shapely >log.log
!pip install -e PaddleOCR >log.log
/home/aistudio

In [4]

!pip list |grep paddleocr
paddleocr              2.4             /home/aistudio/PaddleOCR

四、文字检测及识别

1.调用PaddleOCR进行文字识别及定位

In [21]

import os
import cv2
import numpy as np
from paddleocr import PaddleOCR
# 加载最新的v2模型
ocr = PaddleOCR(det=True,cls=False)
/home/aistudio/PaddleOCR
[2022/05/09 22:44:29] root WARNING: version PP-OCRv2 not support cls models, auto switch to version PP-OCR
Namespace(benchmark=False, cls=False, cls_batch_num=6, cls_image_shape='3, 48, 192', cls_model_dir='/home/aistudio/.paddleocr/2.4/ocr/cls/ch_ppocr_mobile_v2.0_cls_infer', cls_thresh=0.9, cpu_threads=10, crop_res_save_dir='./output', det=True, det_algorithm='DB', det_db_box_thresh=0.6, det_db_score_mode='fast', det_db_thresh=0.3, det_db_unclip_ratio=1.5, 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='/home/aistudio/.paddleocr/2.4/ocr/det/ch/ch_PP-OCRv2_det_infer', det_pse_box_thresh=0.85, det_pse_box_type='box', det_pse_min_area=16, det_pse_scale=1, det_pse_thresh=0, det_sast_nms_thresh=0.2, det_sast_polygon=False, det_sast_score_thresh=0.5, draw_img_save_dir='./inference_results', drop_score=0.5, e2e_algorithm='PGNet', e2e_char_dict_path='./ppocr/utils/ic15_dict.txt', e2e_limit_side_len=768, e2e_limit_type='max', e2e_model_dir=None, e2e_pgnet_mode='fast', e2e_pgnet_score_thresh=0.5, e2e_pgnet_valid_set='totaltext', enable_mkldnn=False, gpu_mem=500, help='==SUPPRESS==', image_dir=None, ir_optim=True, is_visualize=True, label_list=['0', '180'], label_map_path='./vqa/labels/labels_ser.txt', lang='ch', layout_path_model='lp://PubLayNet/ppyolov2_r50vd_dcn_365e_publaynet/config', max_batch_size=10, max_seq_length=512, max_text_length=25, min_subgraph_size=15, mode='structure', model_name_or_path=None, ocr_version='PP-OCRv2', output='./output', precision='fp32', process_id=0, rec=True, rec_algorithm='CRNN', rec_batch_num=6, rec_char_dict_path='/home/aistudio/PaddleOCR/ppocr/utils/ppocr_keys_v1.txt', rec_image_shape='3, 32, 320', rec_model_dir='/home/aistudio/.paddleocr/2.4/ocr/rec/ch/ch_PP-OCRv2_rec_infer', save_crop_res=False, save_log_path='./log_output/', show_log=True, structure_version='STRUCTURE', table_char_dict_path=None, table_char_type='en', table_max_len=488, table_model_dir=None, total_process_num=1, type='ocr', use_angle_cls=False, use_dilation=False, use_gpu=False, use_mp=False, use_onnx=False, use_pdserving=False, use_space_char=True, use_tensorrt=False, use_xpu=False, vis_font_path='./doc/fonts/simfang.ttf', warmup=False)

In [20]

%cd ~
img='message-4029623152461890607-image-normal-53f95e2e-328e-4279-8ce4-08b124f43c21..jpg'
result = ocr.ocr(cv2.imread(img,1 ), det=True,cls=True)
print(result)
/home/aistudio
[2022/05/09 22:38:31] root WARNING: Since the angle classifier is not initialized, the angle classifier will not be used during the forward process
[2022/05/09 22:38:33] root DEBUG: dt_boxes num : 9, elapse : 2.0214898586273193
[2022/05/09 22:38:34] root DEBUG: rec_res num  : 9, elapse : 0.7924504280090332
[[[[0.0, 197.0], [251.0, 197.0], [251.0, 307.0], [0.0, 307.0]], ('王晶晶', 0.7189245)], [[[596.0, 327.0], [636.0, 327.0], [636.0, 359.0], [596.0, 359.0]], ('S', 0.9587832)], [[[5.0, 499.0], [293.0, 499.0], [293.0, 594.0], [5.0, 594.0]], ('金小健', 0.9890587)], [[[595.0, 650.0], [642.0, 650.0], [642.0, 691.0], [595.0, 691.0]], ('S', 0.81341845)], [[[400.0, 911.0], [877.0, 921.0], [875.0, 1008.0], [398.0, 998.0]], ('3-201,5/1', 0.9159426)]]

可见,姓名、住宿信息、日期均可正常识别

2.马赛克函数

In [37]

def mosaic(selected_image, nsize=9):
    rows, cols, _ = selected_image.shape
    dist = selected_image.copy()
    # 划分小方块,每个小方块填充随机颜色
    for y in range(0, rows, nsize):
        for x in range(0, cols, nsize):
            # dist[y:y + nsize, x:x + nsize] = (np.random.randint(0, 255))
            # 调整颜色,255白色
            dist[y:y + nsize, x:x + nsize] = 255
    return dist

3.OCR识别

In [85]

# test
%cd ~
!mkdir saved
/home/aistudio
mkdir: cannot create directory ‘saved’: File exists

In [90]

# img: 待脱敏图片
# target_dir: 脱敏后图片保存文件夹
# key_words: 检测盒的基本信息(不用mask掉文字列表)
def data_mask(img, target_dir, key_words=["2019", 'ANC', "C", "T", "S", "c", "t", "s"]):
    img_data=cv2.imread(img,1)
    result = ocr.ocr(img_data,  det=True,cls=True)
    print(result)
    print('len: ',len(result))
    print(f"*******************************************")
    for infomation in result:
        flag = True
        for word in key_words:
            myword, _ =infomation[-1]
            if word in myword:
                flag = False
                break
        if flag == True:
            cut_point = infomation[0]
            roiImg = img_data[int(cut_point[0][1]):int(cut_point[2][1]), int(cut_point[0][0]):int(cut_point[2][0])]  # 使用数组切片的方式截取载入图片上的部分,
            mosaic_result = mosaic(roiImg)
            img_data[int(cut_point[0][1]):int(cut_point[2][1]), int(cut_point[0][0]):int(cut_point[2][0])]= mosaic_result  # 然后,将截取的这部分ROI区域的图片保存在roiImg矩阵变量中
    cv2.imwrite(filename=os.path.join(target_dir, img), img=img_data)

In [91]

data_mask(img="message-4029623152461890607-image-normal-53f95e2e-328e-4279-8ce4-08b124f43c21..jpg", target_dir="saved")
[2022/05/10 00:27:24] root WARNING: Since the angle classifier is not initialized, the angle classifier will not be used during the forward process
[2022/05/10 00:27:26] root DEBUG: dt_boxes num : 9, elapse : 2.079129457473755
[2022/05/10 00:27:26] root DEBUG: rec_res num  : 9, elapse : 0.795313835144043
[[[[0.0, 197.0], [251.0, 197.0], [251.0, 307.0], [0.0, 307.0]], ('王晶晶', 0.7189245)], [[[596.0, 327.0], [636.0, 327.0], [636.0, 359.0], [596.0, 359.0]], ('S', 0.9587832)], [[[5.0, 499.0], [293.0, 499.0], [293.0, 594.0], [5.0, 594.0]], ('金小健', 0.9890587)], [[[595.0, 650.0], [642.0, 650.0], [642.0, 691.0], [595.0, 691.0]], ('S', 0.81341845)], [[[400.0, 911.0], [877.0, 921.0], [875.0, 1008.0], [398.0, 998.0]], ('3-201,5/1', 0.9159426)]]
len:  5
*******************************************

4.基本效果

原图:

mask后的图:

五、完整程序

In [ ]

# -*- coding: utf-8 -*-
# __author__:Livingbody
# 2022/5/10 19:48
import os
import cv2
import numpy as np
from paddleocr import PaddleOCR


# 加载最新的v2模型
ocr = PaddleOCR(det=True,cls=False)

def mosaic(selected_image, nsize=9):
    rows, cols, _ = selected_image.shape
    dist = selected_image.copy()
    # 划分小方块,每个小方块填充随机颜色
    for y in range(0, rows, nsize):
        for x in range(0, cols, nsize):
            # dist[y:y + nsize, x:x + nsize] = (np.random.randint(0, 255))
            # 调整颜色,255白色
            dist[y:y + nsize, x:x + nsize] = 255
    return dist


# img: 待脱敏图片
# target_dir: 脱敏后图片保存文件夹
# key_words: 检测盒的基本信息(不用mask掉文字列表)
def data_mask(img, target_dir, key_words=["2019", 'ANC', "C", "T", "S", "c", "t", "s"]):
    img_data=cv2.imread(img,1)
    result = ocr.ocr(img_data,  det=True,cls=True)
    for infomation in result:
        flag = True
        for word in key_words:
            myword, _ =infomation[-1]
            if word in myword:
                flag = False
                break
        if flag == True:
            cut_point = infomation[0]
            roiImg = img_data[int(cut_point[0][1]):int(cut_point[2][1]), int(cut_point[0][0]):int(cut_point[2][0])]  # 使用数组切片的方式截取载入图片上的部分,
            mosaic_result = mosaic(roiImg)
            img_data[int(cut_point[0][1]):int(cut_point[2][1]), int(cut_point[0][0]):int(cut_point[2][0])]= mosaic_result  # 然后,将截取的这部分ROI区域的图片保存在roiImg矩阵变量中
    cv2.imwrite(filename=os.path.join(target_dir, img), img=img_data)

if __name__ == '__main__':
    # test
    data_mask(img="message-4029623152461890607-image-normal-53f95e2e-328e-4279-8ce4-08b124f43c21..jpg", target_dir="saved")

六、总结

  • 本项目原先使用PaddleHub完成过一版,但是据说PaddleHub上的ocr模型很早了,没更新,所以采用PaddleOCR最新模型来进行预测;
  • 原项目批量脱敏,没考虑内存方面,容易爆内存,该版本一张一张转,避免了这个问题。
Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐