单目标跟踪:模型测试

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


CNN:RCNN、SPPNet、Fast RCNN、Faster RCNN、YOLO V1 V2 V3、SSD、FCN、SegNet、U-Net、DeepLab V1 V2 V3、Mask RCNN

单目标跟踪SiamMask:特定目标车辆追踪 part1

单目标跟踪SiamMask:特定目标车辆追踪 part2

单目标跟踪 Siamese系列网络:SiamFC、SiamRPN、one-shot跟踪、one-shotting单样本学习、DaSiamRPN、SiamRPN++、SiamMask

单目标跟踪:跟踪效果

单目标跟踪:数据集处理

单目标跟踪:模型搭建

单目标跟踪:模型训练

单目标跟踪:模型测试


1.6 test

学习目标:

  • 了解网络测试的过程
  • 能够实现网络的训练代码编写

网络的测试test主要在tools中test.py中实现,该文件中包含的内容如下图所示:

接下来,我们对以上内容进行介绍。

1.main

main函数是进行网络训练的程序入口,它的执行流程是读取配置信息->设置日志输出到日志文件中->加载网络模型->加载权重文件->加载数据->进行跟踪,在进行跟踪时,还要判断是否进行目标分割,如下图所示:

实现代码如下所示:

def main():
    # 获取命令行参数信息
    global args, logger, v_id
    args = parser.parse_args()
    # 获取配置文件中配置信息:主要包括网络结构,超参数等
    cfg = load_config(args)
    # 初始化logxi信息,并将日志信息输入到磁盘文件中
    init_log('global', logging.INFO)
    if args.log != "":
        add_file_handler('global', args.log, logging.INFO)
    # 将相关的配置信息输入到日志文件中
    logger = logging.getLogger('global')
    logger.info(args)

    # setup model
    # 加载网络模型架构
    if args.arch == 'Custom':
        from custom import Custom
        model = Custom(anchors=cfg['anchors'])
    else:
        parser.error('invalid architecture: {}'.format(args.arch))
    # 加载网络模型参数
    if args.resume:
        assert isfile(args.resume), '{} is not a valid file'.format(args.resume)
        model = load_pretrain(model, args.resume)
    # 使用评估模式,将drop等激活
    model.eval()
    # 硬件信息
    device = torch.device('cuda' if (torch.cuda.is_available() and not args.cpu) else 'cpu')
    model = model.to(device)
    # 加载数据集 setup dataset
    dataset = load_dataset(args.dataset)

    # 这三种数据支持掩膜 VOS or VOT?
    if args.dataset in ['DAVIS2016', 'DAVIS2017', 'ytb_vos'] and args.mask:
        vos_enable = True  # enable Mask output
    else:
        vos_enable = False

    total_lost = 0  # VOT
    iou_lists = []  # VOS
    speed_list = []
    # 对数据进行处理
    for v_id, video in enumerate(dataset.keys(), start=1):
        if args.video != '' and video != args.video:
            continue
        # true 调用track_vos
        if vos_enable:
            # 如测试数据是['DAVIS2017', 'ytb_vos']时,会开启多目标跟踪
            iou_list, speed = track_vos(model, dataset[video], cfg['hp'] if 'hp' in cfg.keys() else None,
                                 args.mask, args.refine, args.dataset in ['DAVIS2017', 'ytb_vos'], device=device)
            iou_lists.append(iou_list)
        # False 调用track_vot
        else:
            lost, speed = track_vot(model, dataset[video], cfg['hp'] if 'hp' in cfg.keys() else None,
                             args.mask, args.refine, device=device)
            total_lost += lost
        speed_list.append(speed)

    # report final result
    if vos_enable:
        for thr, iou in zip(thrs, np.mean(np.concatenate(iou_lists), axis=0)):
            logger.info('Segmentation Threshold {:.2f} mIoU: {:.3f}'.format(thr, iou))
    else:
        logger.info('Total Lost: {:d}'.format(total_lost))

    logger.info('Mean Speed: {:.2f} FPS'.format(np.mean(speed_list)))

3.get_subwindow_tracking

该函数获取跟踪目标的图像窗口,对目标框进行调整,若目标框在图像之外,则扩充图像,并修改目标框的坐标,其代码如下所示:

def get_subwindow_tracking(im, pos, model_sz, original_sz, avg_chans, out_mode='torch'):
    """
    获取跟踪目标的信息(图像窗口)
    :param im:跟踪的模板图像
    :param pos:目标位置
    :param model_sz:模型要求输入的目标尺寸
    :param original_sz: 扩展后的目标尺寸
    :param avg_chans:图像的平均值
    :param out_mode: 输出模式
    :return:
    """
    if isinstance(pos, float):
        # 目标中心点坐标
        pos = [pos, pos]
    # 目标的尺寸
    sz = original_sz
    # 图像尺寸
    im_sz = im.shape
    # 扩展背景后边界到中心的距离
    c = (original_sz + 1) / 2
    # 判断目标是否超出图像边界,若超出边界则对图像进行填充
    context_xmin = round(pos[0] - c)
    context_xmax = context_xmin + sz - 1
    context_ymin = round(pos[1] - c)
    context_ymax = context_ymin + sz - 1
    left_pad = int(max(0., -context_xmin))
    top_pad = int(max(0., -context_ymin))
    right_pad = int(max(0., context_xmax - im_sz[1] + 1))
    bottom_pad = int(max(0., context_ymax - im_sz[0] + 1))
    # 图像填充使得图像的原点发生变化,计算填充后图像块的坐标
    context_xmin = context_xmin + left_pad
    context_xmax = context_xmax + left_pad
    context_ymin = context_ymin + top_pad
    context_ymax = context_ymax + top_pad

    # zzp: a more easy speed version
    r, c, k = im.shape
    # 若进行填充需对目标位置重新赋值
    if any([top_pad, bottom_pad, left_pad, right_pad]):
        # 生成与填充后图像同样大小的全零数组
        te_im = np.zeros((r + top_pad + bottom_pad, c + left_pad + right_pad, k), np.uint8)
        # 对原图像区域进行赋值
        te_im[top_pad:top_pad + r, left_pad:left_pad + c, :] = im
        # 将填充区域赋值为图像的均值
        if top_pad:
            te_im[0:top_pad, left_pad:left_pad + c, :] = avg_chans
        if bottom_pad:
            te_im[r + top_pad:, left_pad:left_pad + c, :] = avg_chans
        if left_pad:
            te_im[:, 0:left_pad, :] = avg_chans
        if right_pad:
            te_im[:, c + left_pad:, :] = avg_chans
        # 根据填充结果修改目标的位置
        im_patch_original = te_im[int(context_ymin):int(context_ymax + 1), int(context_xmin):int(context_xmax + 1), :]
    else:
        im_patch_original = im[int(context_ymin):int(context_ymax + 1), int(context_xmin):int(context_xmax + 1), :]
    # 若跟踪目标块的尺寸与模型输入尺寸不同,则利用opencv修改图像尺寸
    if not np.array_equal(model_sz, original_sz):
        im_patch = cv2.resize(im_patch_original, (model_sz, model_sz))
    else:
        im_patch = im_patch_original
    # cv2.imshow('crop', im_patch)
    # cv2.waitKey(0)
    # 若输出模式是Torch,则将其通道调换,否则直接输出im_patch
    return im_to_torch(im_patch) if out_mode in 'torch' else im_patch

4.generate_anchor

该方法生成目标的anchor,利用anchor对目标进行跟踪,并对anchor的坐标进行修改。

代码如下所示:

def generate_anchor(cfg, score_size):
    """
    生成锚点:anchor
    :param cfg: anchor的配置信息
    :param score_size:分类的评分结果
    :return:生成的anchor
    """
    # 初始化anchor
    anchors = Anchors(cfg)
    # 得到生成的anchors
    anchor = anchors.anchors
    # 得到每一个anchor的左上角和右下角坐标
    x1, y1, x2, y2 = anchor[:, 0], anchor[:, 1], anchor[:, 2], anchor[:, 3]
    # 将anchor转换为中心点坐标和宽高的形式
    anchor = np.stack([(x1+x2)*0.5, (y1+y2)*0.5, x2-x1, y2-y1], 1)
    # 获取生成anchor的范围
    total_stride = anchors.stride
    # 获取锚点的个数
    anchor_num = anchor.shape[0]
    # 将对锚点组进行广播,并设置其坐标。
    anchor = np.tile(anchor, score_size * score_size).reshape((-1, 4))
    # 加上ori偏移后,xx和yy以图像中心为原点
    ori = - (score_size // 2) * total_stride
    xx, yy = np.meshgrid([ori + total_stride * dx for dx in range(score_size)],
                         [ori + total_stride * dy for dy in range(score_size)])
    xx, yy = np.tile(xx.flatten(), (anchor_num, 1)).flatten(), \
             np.tile(yy.flatten(), (anchor_num, 1)).flatten()
    # 获取anchor
    anchor[:, 0], anchor[:, 1] = xx.astype(np.float32), yy.astype(np.float32)
    return anchor

5.siamese_init

Siamese_init中创建目标字典state,state中的内容如下图所示:

其中,TrackerConfig是配置信息,net是网络模型,window是惩罚窗口,还包括跟踪目标的系列信息。

代码实现如下所示:

def siamese_init(im, target_pos, target_sz, model, hp=None, device='cpu'):
    """
    初始化跟踪器,根据目标的信息构建state 字典
    :param im: 当前处理的图像
    :param target_pos: 目标的位置
    :param target_sz: 目标的尺寸
    :param model: 训练好的网络模型
    :param hp: 超参数
    :param device: 硬件信息
    :return: 跟踪器的state字典数据
    """

    # 初始化state字典
    state = dict()
    # 设置图像的宽高
    state['im_h'] = im.shape[0]
    state['im_w'] = im.shape[1]
    # 配置跟踪器的相关参数
    p = TrackerConfig()
    # 对参数进行更新
    p.update(hp, model.anchors)
    # 更新参数
    p.renew()
    # 获取网络模型
    net = model
    # 根据网络参数对跟踪器的参数进行更新,主要是anchors
    p.scales = model.anchors['scales']
    p.ratios = model.anchors['ratios']
    p.anchor_num = model.anchor_num
    # 生成锚点
    p.anchor = generate_anchor(model.anchors, p.score_size)
    # 图像的平均值
    avg_chans = np.mean(im, axis=(0, 1))
    # 根据设置的上下文比例,输入z 的宽高及尺寸
    wc_z = target_sz[0] + p.context_amount * sum(target_sz)
    hc_z = target_sz[1] + p.context_amount * sum(target_sz)
    s_z = round(np.sqrt(wc_z * hc_z))
    # 初始化跟踪目标 initialize the exemplar
    z_crop = get_subwindow_tracking(im, target_pos, p.exemplar_size, s_z, avg_chans)
    # 将其转换为Variable可在pythorch中进行反向传播
    z = Variable(z_crop.unsqueeze(0))
    # 专门处理模板
    net.template(z.to(device))
    # 设置使用的惩罚窗口
    if p.windowing == 'cosine':
        # 利用hanning窗的外积生成cosine窗口
        window = np.outer(np.hanning(p.score_size), np.hanning(p.score_size))
    elif p.windowing == 'uniform':
        window = np.ones((p.score_size, p.score_size))
    # 每一个anchor都有一个对应的惩罚窗口
    window = np.tile(window.flatten(), p.anchor_num)
    # 将信息更新到state字典中
    state['p'] = p
    state['net'] = net
    state['avg_chans'] = avg_chans
    state['window'] = window
    state['target_pos'] = target_pos
    state['target_sz'] = target_sz
    return state

6.siamese_track

该方法对目标进行追踪,根据siamese_init中获取的目标跟踪框,然后调用track_mask(若进行分割) 或track(不进行分割)进行目标追踪。

1.函数原型

def siamese_track(state, im, mask_enable=False, refine_enable=False, device='cpu', debug=False):
    """
    对目标进行跟踪
    :param state:目标状态
    :param im:跟踪的图像帧
    :param mask_enable:是否进行掩膜
    :param refine_enable:是否进行特征的融合
    :param device:硬件信息
    :param debug: 是否进行debug
    :return:跟踪目标的状态 state字典
    """

2.目标当前状态

获取目标的当前状态,若进行debug,可将目标的状态绘制在图像上。

  # 获取目标状态
    p = state['p']
    net = state['net']
    avg_chans = state['avg_chans']
    window = state['window']
    target_pos = state['target_pos']
    target_sz = state['target_sz']
    # 包含周边信息的跟踪框的宽度,高度,尺寸
    wc_x = target_sz[1] + p.context_amount * sum(target_sz)
    hc_x = target_sz[0] + p.context_amount * sum(target_sz)
    s_x = np.sqrt(wc_x * hc_x)
    # 模板模型输入框尺寸与跟踪框的比例
    scale_x = p.exemplar_size / s_x
    # 使用与模板分支相同的比例得到检测区域
    d_search = (p.instance_size - p.exemplar_size) / 2
    pad = d_search / scale_x
    s_x = s_x + 2 * pad
    # 对检测框进行扩展,包含周边信息
    crop_box = [target_pos[0] - round(s_x) / 2, target_pos[1] - round(s_x) / 2, round(s_x), round(s_x)]
    # 若进行debug
    if debug:
        # 复制图片
        im_debug = im.copy()
        # 产生crop_box
        crop_box_int = np.int0(crop_box)
        # 将其绘制在图片上
        cv2.rectangle(im_debug, (crop_box_int[0], crop_box_int[1]),
                      (crop_box_int[0] + crop_box_int[2], crop_box_int[1] + crop_box_int[3]), (255, 0, 0), 2)
        # 图片展示
        cv2.imshow('search area', im_debug)
        cv2.waitKey(0)

3.目标跟踪

根据是否对目标进行分割,调用track_mask或track进行目标追踪。

# 将目标位置按比例转换为要跟踪的目标
    x_crop = Variable(get_subwindow_tracking(im, target_pos, p.instance_size, round(s_x), avg_chans).unsqueeze(0))
    #调用网络进行目标跟踪
    if mask_enable:
        # 进行目标分割
        score, delta, mask = net.track_mask(x_crop.to(device))
    else:
        # 只进行目标追踪,不进行分割
        score, delta = net.track(x_crop.to(device))

4.分类和回归

目标回归和分类的结果是通过RPN网络实现的,如下图所示:

rpn网络返回的结果并不是真实的检测框的宽高位置等,而是:

其中:delta[0],delta[1],delta[2,],delta[3],是网络模型返回的结果,在以下代码中指等式右侧的delta[0],delta[1],delta[2,],delta[3]。这里我们要求目标框的预测位置,也就是Tx,Ty,Tw,Th(在以下代码中指等式左边的delta[0],delta[1],delta[2,],delta[3]),Ax,Ay,Aw,Ah表示anchor的中心点,宽,高.

以下代码中指p.anchor。在预测中转换为以下公式:

代码如下所示:

# 目标框回归结果(将其转成4*...的样式)
    delta = delta.permute(1, 2, 3, 0).contiguous().view(4, -1).data.cpu().numpy()
    # 目标分类结果(将其转成2*...的样式)
    score = F.softmax(score.permute(1, 2, 3, 0).contiguous().view(2, -1).permute(1, 0), dim=1).data[:,
            1].cpu().numpy()
    # 计算目标框的中心点坐标,delta[0],delta[1],以及宽delta[2]和高delta[3]。
    delta[0, :] = delta[0, :] * p.anchor[:, 2] + p.anchor[:, 0]
    delta[1, :] = delta[1, :] * p.anchor[:, 3] + p.anchor[:, 1]
    delta[2, :] = np.exp(delta[2, :]) * p.anchor[:, 2]
    delta[3, :] = np.exp(delta[3, :]) * p.anchor[:, 3]

5.尺度惩罚

接下来是使用cosine窗口和尺度惩罚选择最优的目标。首先进行尺度抑制,k 是超参数,r表示宽高比,s表示等效边长:

    def sz(w, h):
        """
        计算等效边长
        :param w: 宽
        :param h: 高
        :return: 等效边长
        """
        pad = (w + h) * 0.5
        sz2 = (w + pad) * (h + pad)
        return np.sqrt(sz2)

    def sz_wh(wh):
        """
        计算等效边长
        :param wh: 宽高的数组
        :return: 等效边长
        """
        pad = (wh[0] + wh[1]) * 0.5
        sz2 = (wh[0] + pad) * (wh[1] + pad)
        return np.sqrt(sz2)

下面进行惩罚,并利用非极大值抑制得到最终的目标跟踪框。

# 非极大值抑制
def change(r):
    """
        将r和1/r逐位比较取最大值
        :param r:
        :return:
        """
    return np.maximum(r, 1. / r)

# 尺寸惩罚 size penalty
    target_sz_in_crop = target_sz*scale_x
    s_c = change(sz(delta[2, :], delta[3, :]) / (sz_wh(target_sz_in_crop)))  # scale penalty
    r_c = change((target_sz_in_crop[0] / target_sz_in_crop[1]) / (delta[2, :] / delta[3, :]))  # ratio penalty
    # p.penalty_k超参数
    penalty = np.exp(-(r_c * s_c - 1) * p.penalty_k)
    # 对分类结果进行惩罚
    pscore = penalty * score

    # cos window (motion model)
    # 窗口惩罚:按一定权值叠加一个窗分布值
    pscore = pscore * (1 - p.window_influence) + window * p.window_influence
    # 获取最优权值的索引
    best_pscore_id = np.argmax(pscore)
    # 将最优的预测结果映射回原图
    pred_in_crop = delta[:, best_pscore_id] / scale_x
    # 计算lr
    lr = penalty[best_pscore_id] * score[best_pscore_id] * p.lr  # lr for OTB
    # 计算目标的位置和尺寸:根据预测偏移得到目标位置和尺寸
    res_x = pred_in_crop[0] + target_pos[0]
    res_y = pred_in_crop[1] + target_pos[1]

    res_w = target_sz[0] * (1 - lr) + pred_in_crop[2] * lr
    res_h = target_sz[1] * (1 - lr) + pred_in_crop[3] * lr
    # 目标的位置和尺寸
    target_pos = np.array([res_x, res_y])
    target_sz = np.array([res_w, res_h])

6.分割

该部分对目标进行分割,主要是根据是否使用refine模块对模块进行图像分割。

# 若进行分割
    if mask_enable:
        # 获取最优预测结果的位置索引:np.unravel_index:将平面索引或平面索引数组转换为坐标数组的元组
        best_pscore_id_mask = np.unravel_index(best_pscore_id, (5, p.score_size, p.score_size))
        delta_x, delta_y = best_pscore_id_mask[2], best_pscore_id_mask[1]
        # 是否进行特征融合
        if refine_enable:
            # 调用track_refine,运行 Refine 模块,由相关特征图上 1×1×256 的特征向量与检测下采样前的特征图得到目标掩膜
            mask = net.track_refine((delta_y, delta_x)).to(device).sigmoid().squeeze().view(
                p.out_size, p.out_size).cpu().data.numpy()
        else:
            # 不进行融合时直接生成掩膜数据
            mask = mask[0, :, delta_y, delta_x].sigmoid(). \
                squeeze().view(p.out_size, p.out_size).cpu().data.numpy()

根据分割的结果,进一步获取目标跟踪的位置和大小。

首先进行图像的仿射变换:

        def crop_back(image, bbox, out_sz, padding=-1):
            """
            对图像进行仿射变换
            :param image: 图像
            :param bbox:
            :param out_sz: 输出尺寸
            :param padding: 是否进行扩展
            :return: 仿射变换后的结果
            """
            # 构造变换矩阵
            # 尺度系数
            a = (out_sz[0] - 1) / bbox[2]
            b = (out_sz[1] - 1) / bbox[3]
            # 平移量
            c = -a * bbox[0]
            d = -b * bbox[1]
            mapping = np.array([[a, 0, c],
                                [0, b, d]]).astype(np.float)
            # 进行仿射变换
            crop = cv2.warpAffine(image, mapping, (out_sz[0], out_sz[1]),
                                  flags=cv2.INTER_LINEAR,
                                  borderMode=cv2.BORDER_CONSTANT,
                                  borderValue=padding)
            return crop

然后对分割结果进行仿射变换后,求其轮廓的最小外接矩形,得到目标的位置,这样我们得到的目标框就会随着目标的运动进行适应性的改变。

# 检测区域框长度与输入模型的大小的比值:缩放系数
        s = crop_box[2] / p.instance_size
        # 预测的模板区域框
        sub_box = [crop_box[0] + (delta_x - p.base_size / 2) * p.total_stride * s,
                   crop_box[1] + (delta_y - p.base_size / 2) * p.total_stride * s,
                   s * p.exemplar_size, s * p.exemplar_size]
        # 缩放系数
        s = p.out_size / sub_box[2]
        # 背景框
        back_box = [-sub_box[0] * s, -sub_box[1] * s, state['im_w'] * s, state['im_h'] * s]
        # 仿射变换
        mask_in_img = crop_back(mask, back_box, (state['im_w'], state['im_h']))
        # 得到掩膜结果
        target_mask = (mask_in_img > p.seg_thr).astype(np.uint8)
        # 根据cv2的版本查找轮廓
        if cv2.__version__[-5] == '4':
            # opencv4中返回的参数只有两个,其他版本有四个
            contours, _ = cv2.findContours(target_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        else:
            _, contours, _ = cv2.findContours(target_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
        # 获取轮廓的面积
        cnt_area = [cv2.contourArea(cnt) for cnt in contours]
        if len(contours) != 0 and np.max(cnt_area) > 100:
            # 获取面积最大的轮廓
            contour = contours[np.argmax(cnt_area)]  # use max area polygon
            # 转换为...*2的形式
            polygon = contour.reshape(-1, 2)
            # pbox = cv2.boundingRect(polygon)  # Min Max Rectangle
            # 得到最小外接矩形后找到该矩形的四个顶点
            prbox = cv2.boxPoints(cv2.minAreaRect(polygon))  # Rotated Rectangle

            # box_in_img = pbox
            # 获得跟踪框
            rbox_in_img = prbox
        else:  # empty mask
            # 根据预测的目标位置和尺寸得到location
            location = cxy_wh_2_rect(target_pos, target_sz)
            # 得到跟踪框的四个顶点
            rbox_in_img = np.array([[location[0], location[1]],
                                    [location[0] + location[2], location[1]],
                                    [location[0] + location[2], location[1] + location[3]],
                                    [location[0], location[1] + location[3]]])

7.跟踪结果

得到目标的位置和大小,并将信息更新到state对象中。

# 得到目标的位置和尺寸
    target_pos[0] = max(0, min(state['im_w'], target_pos[0]))
    target_pos[1] = max(0, min(state['im_h'], target_pos[1]))
    target_sz[0] = max(10, min(state['im_w'], target_sz[0]))
    target_sz[1] = max(10, min(state['im_h'], target_sz[1]))
    # 更新state对象
    state['target_pos'] = target_pos
    state['target_sz'] = target_sz
    state['score'] = score[best_pscore_id]
    state['mask'] = mask_in_img if mask_enable else []
    state['ploygon'] = rbox_in_img if mask_enable else []
    return state

6.网络测试

进行网络测试时,在终端执行:

cd $SiamMask/experiments/siammask_sharp
bash test_mask_refine.sh config_vot.json SiamMask_VOT.pth VOT2016 0

test_mask_refine.sh中的内容如下:

# 判断是否为空字符串,若为空提示需要输入参数,
if [ -z "$4" ]
  then
      # echo命令用于字符串的显示,会在终端显示该命令
    echo "Need input parameter!"
    echo "Usage: bash `basename "$0"` \$CONFIG \$MODEL \$DATASET \$GPUID"
    exit
# fi为if语句的结束,相当于end if 
fi
# 指明项目的位置,是最上层的位置
ROOT=/Users/yaoxiaoying/Documents/01-工作/03.计算机视觉/03.智慧交通/04.单目标追踪/SiamMask-master
# 设置环境变量
export PYTHONPATH=$ROOT:$PYTHONPATH
# 创建log路径
mkdir -p logs
# 设置参数
config=$1
model=$2
dataset=$3
gpu=$4
# 运行test.py,输入参数有:(1) config file: config_vot.json; (2)mode: SiamMask_VOT.pth; (3)dataset:VOT2016; (4)gpu:0
CUDA_VISIBLE_DEVICES=$gpu python -u $ROOT/tools/test.py \
    --config $config \
    --resume $model \
    --mask --refine \
    --dataset $dataset 2>&1 | tee logs/test_$dataset.log

# 2>&1:将错误定向到标准输出
# tee logs/test_$dataset.log:将标准输出的内容添加到log文件中

测试结果:

[2020-02-10 21:02:20,709-rk0-test.py#856] Total Lost: 44
[2020-02-10 21:02:20,710-rk0-test.py#858] Mean Speed: 5.85 FPS

总结:

  • 网络测试使用数据对网络的性能进行测试,流程是加载数据,模型,对数据中的目标进行跟踪
  • 网络测试代码中主要包括
    • siammese_init:跟踪初始化
    • siamese_trask:对目标进行跟踪

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

あずにゃん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值