Faster_RCNN 血液细胞检测项目实战(三)

1.模型推理

在训练好网络后,训练好的网络权值就保存在checkpoint中,可以看到每个epoch中train和test的miou值。

这里说一嘴,在训练的时候 可以看到每个epoch的网络的loss值,loss逐渐减并收敛,当时loss值差不多稳定时,那么就确定网络已经训练好。

这时就可以在checkpoint中选择一个权重文件.pth用来推理测试了。

先看代码:

import os
import math
import numpy as np
import glob
import pandas as pd
import matplotlib.pyplot as plt
from PIL import Image
import random
import time
import cv2
import torch
import torch
import torch.nn as nn
from torch.utils.data import Dataset,DataLoader
from torchvision import transforms
import xml.etree.ElementTree as ET
import torchvision
from tqdm import tqdm


class_idx = {'WBC':0,'RBC':1,'Platelets':2}
def get_LabelFromXml(xml_file):
    an_file = open(xml_file, encoding='utf-8')  # 用utf-8的格式打开该文件
    tree = ET.parse(an_file)  # 用ET来解析an_file,得到文件内容树格式
    root = tree.getroot()  # 获取树的根目录,抓取xml中的数据,与html的爬取是一样的
    label = []
    bbox_list = []
    for object in root.findall('object'):
        cell = object.find('name').text  # 同理拿到object的name属性,可以得到细胞的类名
        cell_id = class_idx[cell]  #根据字典将类名变成类序号
        xmin = object.find('bndbox').find('xmin').text  # 拿到候选框的位置
        ymin = object.find('bndbox').find('ymin').text
        xmax = object.find('bndbox').find('xmax').text
        ymax = object.find('bndbox').find('ymax').text
        #1 位于边界的框筛选不要
        #2 边界框无大小的筛选不邀
        if int(xmin)== 0 or int(xmax)== 0 or(ymin)== 0 or(ymax)== 0:
            pass #或者continue
        elif int(xmin) ==int(xmax) or(ymin) == (ymax):
            pass
        else:
            label.append(cell_id)   #保存标签名
            bbox_list.append([int(xmin),int(ymin),int(xmax),int(ymax)])  #保存候选框位置 左上角(x1,y1)和右下角(x2,y2)

    return  label,bbox_list


#模型推理
#1.真实数据,及其标签
names = {'0':'WBC','1':'RBC','2':'Platelets'}
src_img = cv2.imread('./data/valid/BloodImage_00216_jpg.rf.d2ee375678fba0f34f0aacf8e4742b18.jpg')
#读取的图像是numpyarray形式
src_img_eval = src_img.copy()
img = cv2.cvtColor(src_img,cv2.COLOR_BGR2RGB)
#因为opencv读进来图像是BGR格式,为了方便观察,转RGB

labels,boxes = get_LabelFromXml('./data/valid/BloodImage_00216_jpg.rf.d2ee375678fba0f34f0aacf8e4742b18.xml')

boxes = np.array(boxes)
labels = np.array(labels)

print(labels)

for idx in range(boxes.shape[0]):
    x1,y1,x2,y2 = boxes[idx][0],boxes[idx][1],boxes[idx][2],boxes[idx][3]
    name = names.get(str(labels[idx].item()))
    cv2.rectangle(src_img,(x1,y1),(x2,y2),(255,0,0),thickness=1)
    cv2.putText(src_img,text=name,org=(x1,y1+10),fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                fontScale=0.5,thickness=1,lineType=cv2.LINE_AA,color=(0,0,255))
plt.imshow(src_img)
plt.show()

#建立模型并载入,预测
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(weight = None,progress = True,num_classes = 4)
weight = torch.load('./data/checkpoint/86_train_mIou_0.8809999823570251_test_mIou_0.8880000114440918.pth')
model.load_state_dict(weight)
model = model.to('cuda')
model.eval()


img_tensor = torch.from_numpy(img/255.).permute(2,0,1).float().cuda()
#这里对图像转成tensor类型,变成float,放在cuda上面。

out = model([img_tensor])  #加 [] 是因为model的输入必须是列表。

boxes_eval = out[0]['boxes'].cpu().detach().numpy().astype(int)
labels_eval = out[0]['labels'].cpu().detach().numpy()
scores_eval = out[0]['scores'].cpu().detach().numpy()

for idx in range(boxes_eval.shape[0]):
    if scores_eval[idx]>=0.05:
        x1,y1,x2,y2 = boxes_eval[idx][0],boxes_eval[idx][1],boxes_eval[idx][2],boxes_eval[idx][3]
        name = names.get(str(labels_eval[idx].item()))
        cv2.rectangle(src_img_eval,(x1,y1),(x2,y2),(255,0,0),thickness=1)
        cv2.putText(src_img_eval,text=name,org=(x1,y1+10),fontFace=cv2.FONT_HERSHEY_SIMPLEX,
                fontScale=0.5,thickness=1,lineType=cv2.LINE_AA,color=(0,0,255))
plt.imshow(src_img_eval)
plt.show()

#这个检测不出来WBC细胞,还有点出问题。faster-rcnn准确性不如retinaNet

以上是一个对比代码,在model之前主要是显示真实数据的标注情况,model后就是对输入图像进行推理,得到输出的细胞分类名及其对应检测框位置。

从valid数据集中随便找一张图片,以及对应的xml文件。绘制真实数据的标签框

在进行模型推理时,输入的图像需要做事前处理,图像数据归一化,调通道,转成浮点型,tensor型数据,并放在cuda上进行模型推理。最后从输出结果out中拿到标签和框的数据,这里由于是从网络出来的所以余姚转成numpy格式,放在cpu上。

其中,在PyTorch中,detach()方法用于创建一个新的tensor,该tensor与原始tensor共享数据但不参与梯度计算。由于pytorch是自动求导的,所以这里需要从中复制一份没有自动求导功能的数据。

后面的绘图与真实标签的绘制相似。

输出结果除了boxes,以及label之外,还有一个scores分数,即标注是该类别的概率。这里在绘制标签框时可以作为条件,不输出低可能性的结果。

以上就是代码解释。

2.模型评价

如何评价深度学习模型,这也是在学习深度学习时非常重要的一点。一下列出几点。

  1. 精确度 (Precision): 精确度衡量的是被模型正确识别为正样本(例如,正确检测到目标的实例)与所有被识别为正样本的比例。高精确度意味着较少的假阳性(false positives,即错误标记为目标的实例)。tp/(tp+fp)

  2. 召回率 (Recall): 召回率是指模型正确识别为正样本的数量与所有实际正样本的数量的比例。高召回率意味着较少的假阴性(false negatives,即未被模型检测到的目标实例)。tp/(tp+fn)

  3. F1分数 (F1 Score): F1分数是精确度和召回率的调和平均数,它试图在两者之间提供一个平衡。F1分数越高,模型的性能越好。

  4. 平均精度 (Average Precision, AP): 对于每个类别,AP是精确度与召回率曲线下面积的计算结果。它在不同的召回率水平上总结了模型的精确度。

  5. 平均精度均值 (Mean Average Precision, mAP): mAP是所有类别的AP值的平均值。这是目标检测任务中最常用的评价指标之一,因为它在所有类别上提供了一个单一的性能衡量。

  6. 交并比 (Intersection over Union, IoU): IoU是一个衡量预测边界框与真实边界框重叠度的指标。它是两个边界框的交集与并集的比例。

  7. 真正例 (True Positives, TP), 假正例 (False Positives, FP), 假阴例 (False Negatives, FN): 这些是构成精确度和召回率计算的基础指标。TP是正确检测到的目标数,FP是错误标记为目标的实例数,而FN是漏检的目标数。

  8. 接收者操作特征曲线 (Receiver Operating Characteristic, ROC) 和曲线下面积 (Area Under Curve, AUC): ROC是真正例率(True Positive Rate, TPR)与假正例率(False Positive Rate, FPR)的曲线。AUC衡量的是ROC曲线下的整体面积,它提供了一个模型性能的综合指标。

其中mAP与IoU时关键的评价指标。

 这里简要介绍一下是使用github上mAP项目来计算模型的mAP值。

GitHub - Cartucho/mAP: mean Average Precision - This code evaluates the performance of your neural net for object recognition.

这是大佬的项目。用来计算目标检测模型的mAP值。

下载文件并条件到自己的项目文件下。

为了使用该文件需要先将自己的数据集以及推理后的结果封装成txt文件。

真实标签文件。一个图片下的内容 类名,标签框,是txt格式。

这是检测结果的文件内容,在类名后增加了一个新的内容,推理的scores。

将制作好的文件分别放在input下对应的文件下,以及将对应图片数据放进images文件里。

"""
计算mAP
git上的mAP项目,对于总体数据集在模型上的mAP
修改一下数据输入的文件。
image.txt 真实数据

image1.txt预测数据
"""
import glob
import xml.etree.ElementTree as ET

import cv2
import torch
import torchvision
import numpy
#将目标检测的真实信息写进mAP.txt文件 格式 name boxes[x1 y1 x2 y2]

#定义类别字典
#分为3种血细胞,标号为0,1,2
class_idx = {'WBC':0,'RBC':1,'Platelets':2}
def get_LabelFromXml(xml_file):
    label = []
    bbox_list = []
    label_box = []
    xml_name = xml_file[13:-4]
    xml_mAP_groundTruth = './computemAP/mAP\{}.txt'.format(xml_name)
    with open(xml_mAP_groundTruth,'w') as f:
        an_file = open(xml_file,encoding = 'utf-8')
        tree = ET.parse(an_file)
        root = tree.getroot()

        for object in root.findall('object'):
            cell = object.find('name').text
            xmin = object.find('bndbox').find('xmin').text
            xmax = object.find('bndbox').find('xmax').text
            ymin = object.find('bndbox').find('ymin').text
            ymax = object.find('bndbox').find('ymax').text

            f.write(cell+'\t'+xmin+'\t'+ymin+'\t'+xmax+'\t'+ymax+'\n')


path = './data/valid/'  #设置需要爬取的文件路径,当前文件下data下的valid文件
xml_file = glob.glob(path+'*.xml') #通过glob来爬取文件中.xml结尾的文件,文件名
img_file = glob.glob(path+'*.jpg') #通过glob来爬取文件中.jpg结尾的图片,文件名
#print(xml_file)
#乱序文件调整顺序
xml_list = []
img_list = []

for i in xml_file:
    img = i[:-3]+'jpg'    #将xml文件名后三位改成jpg,就是图像的文件名
    if img in img_file:   #判断该文件名是不是在img_file中,如果在,那就加入img_list
        img_list.append(img)
        xml_list.append(i)
#print(xml_list)
#批量处理 书写groundtruth
for i in xml_list:
    get_LabelFromXml(i)

#载入模型,推理将预测结果写进mAPpred文件
model = torchvision.models.detection.retinanet_resnet50_fpn(pretrained=False,
                                                           progress=True, num_classes=4)
weights=torch.load('./data/checkpoint/166_train_mIou_0.9779999852180481_test_mIou_0.9750000238418579.pth')
model.load_state_dict(weights)
model.eval()

names ={'0':'WBC','1':'RBC','2':'Platelets'}

def getPrelable(images_file):
    src_img = cv2.imread(images_file)
    img = cv2.cvtColor(src_img,cv2.COLOR_BGR2RGB)

    img_tensor = torch.from_numpy(img/255.).permute(2,0,1).float()
    out = model([img_tensor])

    boxes = out[0]['boxes'].cpu().detach().numpy().astype(int)
    labels = out[0]['labels'].cpu().detach().numpy().astype(int)
    scores = out[0]['scores'].cpu().detach().numpy()

    img_bboxPredname = images_file[13:-4]
    ml_mAP_pred = './computemAP/mAPpred\{}.txt'.format(img_bboxPredname)

    with open(ml_mAP_pred,'w')as f:
        for idx in range(boxes.shape[0]):
            classes = names[str(labels[idx])]
            coninf_score = str(scores[idx])
            x1,y1,x2,y2 = boxes[idx][0],boxes[idx][1],boxes[idx][2],boxes[idx][2]
            f.write(classes+'\t'+coninf_score+'\t'+str(x1)+'\t'+str(y1)+'\t'+str(x2)+'\t'+str(y2)+'\n')

for i in img_list:
    getPrelable(i)

以上就是操作内容。

将准备好的文件放在input下即可。

最后打开main文件,打开终端运行main文件,即可在项目的output中找到输出结果。

但是在使用main时需要自己调。因为各种库的版本更新,可能导致报错。

这里给出修改好的main文件。

好了以上就是完整的项目。

当然在目标检测模型训练这块,可以尝试自己的数据集,可以换不同的网络模型,retina,ssd,yolo等。这里就不展开了。等后期。

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值