基于PaddleOCR的新冠肺炎检测结果图片个人数据脱敏
转自AI Studio,原文链接:基于PaddleOCR的新冠肺炎检测结果图片个人数据脱敏 - 飞桨AI Studio一、新冠肺炎数据脱敏1.项目简介项目来源于社区朋友的号召,具体内容如下:各位PPDE大佬们好,我们是上海疫情IT志愿者,其中有来自曾参与了武汉2020新型冠状病毒防疫信息平台建设的开发者,目前我们正在开发一款用于疫情防控的AI机器人:https://github.com/Shang
转自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最新模型来进行预测;
- 原项目批量脱敏,没考虑内存方面,容易爆内存,该版本一张一张转,避免了这个问题。
更多推荐
所有评论(0)