持续创作,加快生长!这是我参加「日新方案 6 月更文挑战」的第5天,点击查看活动详情

一、根据PaddleOCR的新冠肺炎检测成果图片个人数据脱敏

地址:aistudio.baidu.com/aistudio/pr…

基于PaddleOCR的新冠肺炎检测结果图片个人数据脱敏

1.项目简介

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

各位PPDE大佬们好,咱们是上海疫情IT志愿者,其中有来自曾参加了武汉2020新型冠状病毒防疫信息平台建造的开发者,现在咱们正在开发一款用于疫情防控的AI机器人:github.com/ShanghaiITV…

现在咱们正在开发一个抗原图片检测的功用,输入为居民图片,输出为图片类型和抗原检测图片的成果(阴性和阳性)。具体可见:github.com/ShanghaiITV…

此项目完全归于公益性质,毫无任何商业行为和规划,也期望各位大佬可以参加到此项目傍边来。

现在现已将功用区分成以下四个部分:

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

2.数据脱敏

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

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

3.难点

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

  • 呈现的位置随机
  • 内容格式随机
  • 摄影办法随机
  • 文字有手写有P的字

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

4.奇思妙想

思来想去,忽然想到,其实 PaddleOCR就可以完成功用,具体如下:

  • 辨认图片上一切文字
  • 检测一切文字的位置
  • 排除掉试剂盒上的文字(如序列号等),其他位置的文字悉数mask 就这样完成数据脱敏,说干就干,下面看行动。

5.github地址

ShanghaiITVolunteer/AntigenClassifier github地址: github.com/ShanghaiITV…

欢迎我们一起来

6.与PaddleHub比较

与根据PaddleHub的新冠肺炎检测成果图片个人数据脱敏版别相比较,有以下优势。

引荐阅读:20000+Star超轻量OCR系统PP-OCRv3作用再提高5% – 11%!

6.1 PaddleOCR v3优势

PaddleHub的OCR运用的是2020年左右的1.x的OCR模型,精度较差,现在PP-OCR v3,速度更快,作用更强。

基于PaddleOCR的新冠肺炎检测结果图片个人数据脱敏

6.2 更好的猜测办法

之前猜测,是批量载入图片,假如数据过多,容易形成内存溢出。现在进行了改善,单张猜测,避免了内存溢出。

二、数据收集

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

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

基于PaddleOCR的新冠肺炎检测结果图片个人数据脱敏

三、环境准备

# clone PaddleOCR代码
! git  clone https://gitee.com/PaddlePaddle/PaddleOCR --depth=1 >log.log
Cloning into 'PaddleOCR'...
remote: Enumerating objects: 1237, done.[K
remote: Counting objects: 100% (1237/1237), done.[K
remote: Compressing objects: 100% (1109/1109), done.[K
remote: Total 1237 (delta 209), reused 695 (delta 78), pack-reused 0[K
Receiving objects: 100% (1237/1237), 101.41 MiB | 4.84 MiB/s, done.
Resolving deltas: 100% (209/209), done.
Checking connectivity... done.
%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
!pip list |grep paddleocr
paddleocr              2.4             /home/aistudio/PaddleOCR

四、文字检测及辨认

1.调用PaddleOCR进行文字辨认及定位

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)
%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.马赛克函数

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辨认

# test
%cd ~
!mkdir saved
/home/aistudio
mkdir: cannot create directory ‘saved’: File exists
# 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)
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.根本作用

原图:

基于PaddleOCR的新冠肺炎检测结果图片个人数据脱敏

mask后的图:

基于PaddleOCR的新冠肺炎检测结果图片个人数据脱敏

五、完好程序

# -*- 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最新模型来进行猜测;
  • 原项目批量脱敏,没考虑内存方面,容易爆内存,该版别一张一张转,避免了这个问题。