用BCCD数据集学习rcnn家族(一)——介绍BCCD数据集及预处理

本文介绍了BCCD血细胞数据集的读取和预处理,包括XML标签数据解析、图片处理、数据增强和可视化,为深度学习模型训练做准备。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

rcnn家族其实已经是一个“非常老”的算法,虽然一开始提出是2014。但是深度学习用于图像识别的开山之作,我打算从rcnn开始学习,网上对于网络和论文的讲解很详细,我这系列就不说理论了,主要是记录我学习过程和写代码跳过的坑。

一、bccd数据介绍

bccd血细胞数据集是一个比较老的数据集,也不大,可以在这下载 https://public.roboflow.com/object-detection/bccd

该数据集共有三类364张图像:(WBC白细胞),RBC(红细胞)和Platelets。3个类别中有4888个标签(有0个空示例)。下图是网站得到的可视化数据(三个类别细胞标注数量计数)。这个网站的教程里还有很多可视化,比如各个细胞分布的热点图等,这里就不全放了。
在这里插入图片描述

二、读取数据

1.读xml标签数据

xml的格式如下图所示,需要重点关注的是框起来的部分,从上往下分别是,图片名称和图片位置、图片size(416,416,3)、真实框的标签、真实框的difficult、真实框的位置。
为了读该xml文件,以下是一个相对框架式的代码:

import os
import numpy as np
import xml.etree.ElementTree as ET
CELL_NAMES = ['RBC', 'WBC', 'Platelets']

# 返回一个字典,将类别转为数字
# {'RBC': 0, 'WBC': 1, 'Platelets': 2}
def get_cell_names():
    cell_category2id = {
   }
    for i, item in enumerate(CELL_NAMES):
        cell_category2id[item] = i
    return cell_category2id

 # 获得数据集列表
def get_annotations(cname2cid, datadir):
    filenames = os.listdir(datadir)
    ct = 0
    records = []
    for fname in filenames:
        fib = fname.split('.')
        if fib[3]=='jpg':
            continue
        elif fib[3]=='xml':
            fpath = os.path.join(datadir, fname)
            img_file = os.path.join(datadir, fib[0]+'.'+fib[1]+'.'+fib[2]+'.jpg')
            tree = ET.parse(fpath)
    
        objs = tree.findall('object')
        im_w = float(tree.find('size').find('width').text)
        im_h = float(tree.find('size').find('height').text)
        gt_bbox = np.zeros((len(objs), 4), dtype=np.float32)
        gt_class = np.zeros((len(objs), ), dtype=np.int32)
        is_crowd = np.zeros((len(objs), ), dtype=np.int32)
        difficult = np.zeros((len(objs), ), dtype=np.int32)
        for i, obj in enumerate(objs):
            cname = obj.find('name').text
            gt_class[i] = cname2cid[cname]
            _difficult = int(obj.find('difficult').text)
            x1 = float(obj.find('bndbox').find('xmin').text)
            y1 = float(obj.find('bndbox').find('ymin').text)
            x2 = float(obj.find('bndbox').find('xmax').text)
            y2 = float(obj.find('bndbox').find('ymax').text)
            x1 = max(0, x1)
            y1 = max(0, y1)
            x2 = min(im_w - 1, x2)
            y2 = min(im_h - 1, y2)
            # 这里使用xywh格式来表示目标物体真实框
            gt_bbox[i] = [(x1+x2)/2.0 , (y1+y2)/2.0, x2-x1+1., y2-y1+1.]
            is_crowd[i] = 0
            difficult[i] = _difficult

        voc_rec = {
   
            'im_file': img_file,
            'h': im_h,
            'w': im_w,
            'is_crowd': is_crowd,
            'gt_class': gt_class,
            'gt_bbox': gt_bbox,
            'gt_poly': [],
            'difficult': difficult
            }
        if len(objs) != 0:
            records.append(voc_rec)
        ct += 1
    return records
 
train_path = '/content/gdrive/My Drive/bccd/train'
val_path = '/content/gdrive/My Drive/bccd/valid'
test_path = '/content/gdrive/My Drive/bccd/test'
cname2cid = get_cell_names()
records = get_annotations(cname2cid,train_path)

读取后的示例

{‘difficult’: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32),
‘gt_bbox’: array([[188.5, 269.5, 68. , 80. ],
[142.5, 40.5, 68. , 80. ],
[277.5, 135.5, 68. , 96. ],
[364. , 152. , 81. , 107. ],
[164.5, 123.5, 74. , 88. ],
[ 37.5, 109. , 72. , 87. ],
[264. , 231.5, 67. , 100. ],
[ 88. , 195. , 75. , 109. ],
[341.5, 326. , 76. , 103. ],
[102.5, 375.5, 68. , 80. ],
[112.5, 300.5, 36. , 38. ],
[155. , 232.5, 29. , 38. ],
[235.5, 280. , 30. , 41. ],
[246.5, 360.5, 104. , 110. ]], dtype=float32),
‘gt_class’: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 1], dtype=int32),
‘gt_poly’: [],
‘h’: 416.0,
‘im_file’: ‘/content/gdrive/My Drive/bccd/train/BloodImage_00145_jpg.rf.a265e7f4f0aab5586c6aa5258bb03966.jpg’,
‘is_crowd’: array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32),
‘w’: 416.0}

2.读图片数据

import cv2

# 对于一般的检测任务来说,一张图片上往往会有多个目标物体
# 设置参数MAX_NUM = 50, 即一张图片最多取50个真实框;如果真实
# 框的数目少于50个,则将不足部分的gt_bbox, gt_class和gt_score的各项数值全设置为0
def get_bbox(gt_bbox, gt_class):
    MAX_NUM = 50
    gt_bbox2 = np.zeros((MAX_NUM, 4))
    gt_class2 = np.zeros((MAX_NUM,))
    for i in range(len(gt_bbox)):
        gt_bbox2[i, :] = gt_bbox[i, :]
        gt_class2[i] = gt_class[i]
        if i >= MAX_NUM:
            break
    return gt_bbox2, gt_class2

def get_img_data_from_file(record):
    im_file = record['im_file']
    h = record['h']
    w = record['w']
    is_crowd = record['is_crowd']
    gt_class = record['gt_class']
    gt_bbox = record['gt_bbox']
    difficult = record['difficult']

    img = cv2.imread(im_file)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    gt_boxes, gt_labels = get_bbox(gt_bbox, gt_class)

    # gt_bbox 用相对值
    gt_boxes[:, 0] = gt_boxes[:, 0] / float(w)
    gt_boxes[:, 1] = gt_boxes[:, 
<think>好的,我现在需要帮助用户了解如何在uni-app实现静默登录。根据用户提供的引用内容,他们可能遇到了微信授权登录的混乱教程,并且提到了存放wgt文件的路径。静默登录通常指的是用户无感知的自动登录,比如通过本地存储的tokensession进行验证,而不需要用户手动输入账号密码进行授权操作。 首先,我需要回忆一下uni-app的登录机制。uni-app支持多端发布,所以静默登录的实现可能需要考虑不同平台的兼容性,尤其是微信小程序和H5。在微信小程序中,可以通过wx.login获取code,然后发送到后端换取openid和session_key,这属于一种静默登录,因为用户无需授权个人信息。但严格来说,这可能需要用户已使用过小程序,系统自动获取code。 接着,用户提到的引用[1]指出,关于微信授权登录的文章存在混乱,所以需要提供一个清晰的流程。静默登录的关键步骤可能包括:检测本地是否有有效token,如果有则直接登录,否则进行静默获取(如微信的code登录),失败后再转向显式授权。 然后,引用[2]提到了wgt文件的存放位置,这可能与资源更新有关,但和登录流程关系不大,可能用户误引用了相关内容,需要专注于登录部分的实现。 现在需要考虑uni-app中如何实现静默登录的具体步骤。首先,检查本地存储是否存在登录状态,比如uni.getStorageSync('token')。如果存在且未过期,则直接进入应用。如果不存在已过期,则调用uni.login获取code,发送到后端服务器,后端通过code向微信服务器请求openid和session_key,生成并返回自定义的token给前端保存。如果静默登录失败(比如code无效),再引导用户进行显式授权,获取用户信息。 示例代码需要展示如何调用uni.login,处理返回的code,以及与后端的交互。同时,需要注意错误处理,比如网络请求失败的情况,需要捕获异常并处理。 另外,需要考虑用户是否已经授权过,如果之前已经授权,静默登录可能可以直接获取信息;否则可能需要弹出授权窗口。但静默登录应尽量避免用户交互,所以优先使用不需要用户确认的方法,如wx.login。 最后,需要生成相关问题,比如静默登录与显式授权的区别、如何处理token过期、多端适配问题等。 总结步骤: 1. 检查本地token是否存在且有效。 2. 不存在则调用uni.login获取code。 3. 发送code到后端换取token。 4. 处理成功失败的情况,失败则转显式登录。 5. 示例代码展示这个过程。</think>### 如何在 uni-app实现静默登录? #### 实现原理 静默登录的核心是通过 **本地存储的登录态**(如 token) **平台提供的无感登录能力**(如微信小程序`uni.login`获取 code)实现自动登录,无需用户手动授权输入账号密码。关键流程如下: 1. **检测本地登录态**:启动时检查本地缓存是否存在有效 token 2. **静默获取身份标识**:若无有效 token,调用平台接口(如微信的`uni.login`)获取临时凭证 code 3. **后端验证**:将 code 发送至服务端,换取用户唯一标识(如 openid)并生成 token[^1] 4. **失败降级策略**:若静默登录失败,引导用户进入显式授权流程 --- #### 示例代码 ```javascript // 1. 检查本地存储的 token let token = uni.getStorageSync('auth_token'); if (!token) { // 2. 静默获取微信 code uni.login({ provider: 'weixin', success: (loginRes) => { // 3. 发送 code 到服务端 uni.request({ url: 'https://api.example.com/auth/silent', method: 'POST', data: { code: loginRes.code }, success: (res) => { if (res.data.token) { uni.setStorageSync('auth_token', res.data.token); } else { // 4. 静默失败转显式登录 this.explicitLogin(); } } }); }, fail: () => this.explicitLogin() }); } // 显式授权登录 explicitLogin() { uni.getUserProfile({ desc: '获取信息用于登录', success: (res) => { // 处理授权信息... } }); } ``` --- #### 关键配置说明 1. **微信开放平台配置**:需配置 appid 和 AppSecret,确保 code 验证流程正常 2. **token 过期策略**:服务端应返回 token 有效期,前端定时刷新重新静默登录 3. **多端兼容**:通过`uni.getSystemInfo`判断平台,H5 端可使用 cookie 替代 code --- #### 注意事项 1. **用户首次使用**:静默登录只能获取 openid,需显式授权后才能获取昵称、头像等用户信息 2. **安全限制**:微信小程序 code 有效期 5 分钟,且只能使用一次 3. **网络容错**:弱网环境下需添加重试机制,避免直接阻塞用户
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值