OSTrack 中的边界框回归策略

news2024/11/20 12:39:27

目录

一、裁剪和标签的设置

二、模型的预测输出的边界框回归


一、裁剪和标签的设置

 1、添加偏移量,得到偏移后的边界框

jittered_anno = [self._get_jittered_box(a, s) for a in data[s + '_anno']]

2、以偏移后的边界框为中心,进行裁剪

首先以偏移边界框面积的4^{2}倍裁剪搜索区域,

crop_sz = torch.ceil(torch.sqrt(w * h) * self.search_area_factor[s])

sz=\sqrt{w*h}*4

然后进行裁剪填充

def sample_target(im, target_bb, search_area_factor, output_sz=None, mask=None):
    """ Extracts a square crop centered at target_bb box, of area search_area_factor^2 times target_bb area

    args:
        im - cv image
        target_bb - target box [x, y, w, h]
        search_area_factor - Ratio of crop size to target size
        output_sz - (float) Size to which the extracted crop is resized (always square). If None, no resizing is done.

    returns:
        cv image - extracted crop
        float - the factor by which the crop has been resized to make the crop size equal output_size
    """
    if not isinstance(target_bb, list):
        x, y, w, h = target_bb.tolist()
    else:
        x, y, w, h = target_bb
    # Crop image
    crop_sz = math.ceil(math.sqrt(w * h) * search_area_factor)  # 466

    if crop_sz < 1:
        raise Exception('Too small bounding box.')

    x1 = round(x + 0.5 * w - crop_sz * 0.5)
    x2 = x1 + crop_sz

    y1 = round(y + 0.5 * h - crop_sz * 0.5)
    y2 = y1 + crop_sz

    x1_pad = max(0, -x1)
    x2_pad = max(x2 - im.shape[1] + 1, 0)

    y1_pad = max(0, -y1)
    y2_pad = max(y2 - im.shape[0] + 1, 0)

    # Crop target
    im_crop = im[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad, :]  # ndarray:(466,466,3)
    if mask is not None:
        mask_crop = mask[y1 + y1_pad:y2 - y2_pad, x1 + x1_pad:x2 - x2_pad]  # Tensor:(466,466)

    # Pad
    im_crop_padded = cv.copyMakeBorder(im_crop, y1_pad, y2_pad, x1_pad, x2_pad, cv.BORDER_CONSTANT)  # ndarray:(466,466,3) 如果裁剪区域超出边界则填充
    # deal with attention mask
    H, W, _ = im_crop_padded.shape  # 446, 446, 3
    att_mask = np.ones((H,W))  # ndarray:(466,466)
    end_x, end_y = -x2_pad, -y2_pad  # 0, 0
    if y2_pad == 0:
        end_y = None
    if x2_pad == 0:
        end_x = None
    att_mask[y1_pad:end_y, x1_pad:end_x] = 0
    if mask is not None:  # True
        mask_crop_padded = F.pad(mask_crop, pad=(x1_pad, x2_pad, y1_pad, y2_pad), mode='constant', value=0)

3、进行resize

    if output_sz is not None:  # True
        resize_factor = output_sz / crop_sz
        im_crop_padded = cv.resize(im_crop_padded, (output_sz, output_sz))  # ndarray:(128,128,3)
        att_mask = cv.resize(att_mask, (output_sz, output_sz)).astype(np.bool_)  # ndarray:(128,128,3)  bool型
        if mask is None:
            return im_crop_padded, resize_factor, att_mask
        mask_crop_padded = \
        F.interpolate(mask_crop_padded[None, None], (output_sz, output_sz), mode='bilinear', align_corners=False)[0, 0]  # Tensor:(128,128)
        return im_crop_padded, resize_factor, att_mask, mask_crop_padded

 resize成输入大小,这里记录了 output_sz/crop_sz的大小,后面要用。这一步已经确定了裁剪的输入图像,但是标签还没对齐。

4、对齐标签

def transform_image_to_crop(box_in: torch.Tensor, box_extract: torch.Tensor, resize_factor: float,
                            crop_sz: torch.Tensor, normalize=False) -> torch.Tensor:
    """ Transform the box co-ordinates from the original image co-ordinates to the co-ordinates of the cropped image
    args:
        box_in - the box for which the co-ordinates are to be transformed
        box_extract - the box about which the image crop has been extracted.
        resize_factor - the ratio between the original image scale and the scale of the image crop
        crop_sz - size of the cropped image

    returns:
        torch.Tensor - transformed co-ordinates of box_in
    """
    box_extract_center = box_extract[0:2] + 0.5 * box_extract[2:4]

    box_in_center = box_in[0:2] + 0.5 * box_in[2:4]

    box_out_center = (crop_sz - 1) / 2 + (box_in_center - box_extract_center) * resize_factor
    box_out_wh = box_in[2:4] * resize_factor

    box_out = torch.cat((box_out_center - 0.5 * box_out_wh, box_out_wh))
    if normalize:
        return box_out / crop_sz[0]
    else:
        return box_out

首先计算偏移边界框的中心坐标和ground truth 边界框的中心坐标

x_1,y_1=x+0.5*w,y+0.5*w

x_0,y_0=x+0.5*w,y+0.5*w

其中x和y为边界框的左上角顶点坐标。

接下来对齐标签

gt_{center}=(outputsz-1)/2+(x_0-x_1,y_0-y_1)*resizefactor

outputsz为需要输入的大小,

之后将中心坐标形式转成了左顶点坐标的形式 (x,y,w,h),然后进行了归一化

return box_out / crop_sz[0]

都除以了 输入的尺寸,比如384,256

5、生成head需要预测的标签

经过上述操作还没完,只是对齐了gt bbox 和裁剪输入,还需要生成模型预测的标签。

1)分类标签,

由 gt bbox的中心坐标生成高斯图

def generate_heatmap(bboxes, patch_size=320, stride=16):  # Tensor:(1,4,4), 256, 16
    """
    Generate ground truth heatmap same as CenterNet
    Args:
        bboxes (torch.Tensor): shape of [num_search, bs, 4]

    Returns:
        gaussian_maps: list of generated heatmap

    """
    gaussian_maps = []
    heatmap_size = patch_size // stride  # 16
    for single_patch_bboxes in bboxes:  # Tensor:(4,4)
        bs = single_patch_bboxes.shape[0]  # 4
        gt_scoremap = torch.zeros(bs, heatmap_size, heatmap_size)  # Tensor:(4,16,16)
        classes = torch.arange(bs).to(torch.long)  # tensor:([0,1,2,3])
        bbox = single_patch_bboxes * heatmap_size  # Tensor:(4,4)
        wh = bbox[:, 2:]  # Tensor:(4,2)
        centers_int = (bbox[:, :2] + wh / 2).round()  # Tensor:(4,2)  中心点
        CenterNetHeatMap.generate_score_map(gt_scoremap, classes, wh, centers_int, 0.7)
        gaussian_maps.append(gt_scoremap.to(bbox.device))

    return gaussian_maps

2) 回归标签

就是 gt bbox本身,但是,需要注意的是,这里的gt bbox已经归一化。

而且网络的输出是 得分图,size 和 offset,所以回归标签不是直接的,而是间接的。

二、模型的预测输出的边界框回归

经过输出头的输出包含三个

score_map_ctr, size_map, offset_map = self.get_score_map(x)  # Tensor:(4,1,16,16) , Tensor:(4,2,16,16), Tensor:(4,2,16,16)

回归边界框

    def cal_bbox(self, score_map_ctr, size_map, offset_map, return_score=False):
        max_score, idx = torch.max(score_map_ctr.flatten(1), dim=1, keepdim=True)  # shape都是 Tensor:(4,1) 按 batch 拿出最大的得分和所对应的索引
        idx_y = idx // self.feat_sz  # Tensor:(4,1)
        idx_x = idx % self.feat_sz  # Tensor:(4,1)

        idx = idx.unsqueeze(1).expand(idx.shape[0], 2, 1)  # Tensor:(4,2,1)
        size = size_map.flatten(2).gather(dim=2, index=idx)  # Tensor:(4,2,1)
        offset = offset_map.flatten(2).gather(dim=2, index=idx).squeeze(-1)  # Tensor:(4,2)

        # bbox = torch.cat([idx_x - size[:, 0] / 2, idx_y - size[:, 1] / 2,
        #                   idx_x + size[:, 0] / 2, idx_y + size[:, 1] / 2], dim=1) / self.feat_sz
        # cx, cy, w, h
        bbox = torch.cat([(idx_x.to(torch.float) + offset[:, :1]) / self.feat_sz,
                          (idx_y.to(torch.float) + offset[:, 1:]) / self.feat_sz,
                          size.squeeze(-1)], dim=1)  # Tensor:(4,4)

        if return_score:
            return bbox, max_score
        return bbox

这里的是中心坐标的形式。训练阶段直接用他们呢计算损失函数。

推理阶段,

pred_box = (pred_boxes.mean(
            dim=0) * self.params.search_size / resize_factor).tolist()  # (cx, cy, w, h) [0,1]  乘上search size去规一化

去规一化,将预测的bbox 转换成 裁剪图片的尺度,并且注意这里实现的是将裁剪图片的尺度与原图片保持在同一尺度上。

    def map_box_back(self, pred_box: list, resize_factor: float):
        cx_prev, cy_prev = self.state[0] + 0.5 * self.state[2], self.state[1] + 0.5 * self.state[3]
        cx, cy, w, h = pred_box
        half_side = 0.5 * self.params.search_size / resize_factor
        cx_real = cx + (cx_prev - half_side)
        cy_real = cy + (cy_prev - half_side)
        return [cx_real - 0.5 * w, cy_real - 0.5 * h, w, h]

这里的self.state为前一帧的预测 bbox。此时,预测的bbox为在裁剪图片中的坐标,所以想要将他返回原img上的坐标需要 计算裁剪图片的坐标系与原img的坐标系的相对坐标变换,因此,用前一阵预测的bbox的中心坐标减去裁剪图片的中心坐标就得到了相对坐标变换,直接加上相对坐标即可得到预测的原img的坐标。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/562409.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Apache Pulsar入门指南

1.概述 Apache Pulsar 是灵活的发布-订阅消息系统&#xff08;Flexible Pub/Sub messaging&#xff09;&#xff0c;采用计算与存储分离的架构。雅虎在 2013 年开始开发 Pulsar &#xff0c;于 2016 年首次开源&#xff0c;目前是 Apache 软件基金会的顶级项目。Pulsar 具有支…

面试官:写一个单例模式

1. 什么是单例模式 了解单例模式之前&#xff0c;我们需要先了解什么是设计模式。 设计模式是一种抽象的编程思想&#xff0c;不局限于编程语言&#xff0c;简单来说&#xff0c;就是一些大佬程序猿针对一些典型的场景&#xff0c;给出一些典型的解决方案&#xff0c;只要按照这…

04-CSS3-渐变色、2D转换、3D转换

一、渐变色 CSS渐变色&#xff08;Gradient&#xff09;是指在元素背景中使用两种或多种不同的颜色进行过渡&#xff0c;超过两个颜色可以形成更为细腻的渐变效果。常见的CSS渐变色有线性渐变和径向渐变。 1. 线性渐变&#xff1a;Linear Gradients 向下/向上/向左/向右/对角…

SVN 修改URL路径-使用重新定位(relocate)命令和找不到问题解决

当svn服务器url发生变更,又不想在本地重新进行checkout操作,这时候可以使用svn relocate命令进行url的重新定位; 在windows下以TortoiseSVN为例,在仓库文件夹上右键,TortoiseSVN-(重新定位)relocate, 1、Windows TortoiseSVN客户端: 在工作复本的根目录上右键->TortoiseSV…

DOUBLETROUBLE: 1

文章目录 DOUBLETROUBLE: 1实战演练一、前期准备1、相关信息 二、信息收集1、nmap探测目标靶机端口2、扫描目标网址目录3、访问网站&#xff0c;发现secret下有个图片4、将图片下载5、查看图片所含内容6、破解密码并查看7、登陆邮箱8、创建反弹shell9、上传反弹shell10、监听11…

Jeecg-Boot 未授权SQL注入漏洞(CVE-2023-1454)

本文转载于&#xff1a;https://blog.csdn.net/qq_27536045/article/details/129944987 环境搭建 JDK: 1.8 (小于11) Maven: 3.5 MySql: 5.7 Redis: 3.2 Node Js: 10.0 Npm: 5.6.0 Yarn: 1.21.1 下载源码 后端源码 https://github.com/jeecgboot/jeecg-boot/tree/v…

MongoDB安装教程—Ubuntu

为啥用MongoDB&#xff0c;问就是客户要求。 为啥用Ubuntu&#xff0c;问就是客户只有Ubuntu的机器。 0. 环境 操作系统&#xff1a; Ubuntu 22.04.1 LTS (GNU/Linux 5.19.0-41-generic x86_64) 不同版本系统差异不同&#xff0c;其他版本系统未测试。 1. 安装 1.1 包管理公…

深入探索SDL游戏开发

前言 欢迎来到小K的SDL专栏第二小节&#xff0c;本节将为大家带来基本窗口构成、渲染器、基本图形绘制、贴图、事件处理等的详细讲解&#xff0c;看完后希望对你有收获 文章目录 前言一、简单窗口二、渲染器三、基本图形绘制1、点2、线3、矩形4、圆和椭圆 四、贴图五、事件处理…

XR交互技术趋势:6DoF追踪、手势识别、眼动跟踪……

XR交互技术提供了用户与虚拟环境进行交互的方式和手段&#xff0c;而实时云渲染则提供了真三维、可交互、高沉浸的图形渲染和计算能力。结合这两者&#xff0c;用户可以通过XR设备获得更真实、更沉浸的虚拟体验&#xff0c;同时享受到优质的图形效果和流畅的交互响应。本篇文章…

关于开发中对端口(port)的几点理解

一、服务端的端口是固定的&#xff0c;客户端的端口是随机的 客户端端口是随机的&#xff0c;比如访问百度&#xff0c;系统为浏览器分配了个端口1024。过一会重开电脑&#xff0c;访问了新浪&#xff0c;可能还是用1024端口&#xff0c;我不关浏览器&#xff0c;还要再开一个浏…

CenterFusion数据处理函数__getitem__()解析

CenterFusion数据处理函数__getitem__解析 1. 图像数据处理1.1 通过利用nuScence_COCO实例化对象获取图像以及相关数据的信息1.2 获取图像数据增强的相关参数&#xff1a;中心点c&#xff0c;尺度scale&#xff0c;旋转rotia和翻转flip1.3 根据生成的参数生成仿射矩阵来对图像进…

spring boot 集成 swagger3

Swagger 3是一种开源的API描述工具&#xff0c;它可以帮助开发人员设计、构建、文档化和测试API。Swagger 3支持多种编程语言和框架&#xff0c;包括Java、Node.js、Python、Ruby等&#xff0c;并提供了许多集成工具和插件&#xff0c;例如Postman、Apigee等。 Swagger 3使用Op…

北京君正应用案例:双镜头双画面乔安枪球联动摄像头

你是否遇到过这种问题&#xff1f; 既要看店铺又要看柜台 既要看车又要看大门 雷龙发展提供原厂技术支持&#xff0c;并提供君正集成电路完整解决方案&#xff0c;大大降低你的开发难度及开发时间。 单镜头摄像头一台不够广 出现监控盲区&#xff0c;让小偷有可趁之机 只能装两…

sql语句---left join or right join

1068. 产品销售分析 I 销售表 Sales&#xff1a; -------------------- | Column Name | Type | -------------------- | sale_id | int | | product_id | int | | year | int | | quantity | int | | price | int | -------------------- (s…

JS文字转语音技术实现

前言 最近在做排队叫号系统&#xff0c;涉及到文字转语音播报&#xff0c;因此总结了几种前端文字转语音发声的方法。 一、Web Speech API h5新提供的一个原生语音识别技术的API&#xff0c;可以将文本转成语音并播放。 作为官方的api&#xff0c;实现的效果是比较符合理想的…

Windows平台下用例图中包含(include)、扩展(extend)和泛化(generalization)介绍

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天总结一下Windows平台下用例图中包含(include)、扩展(extend)和泛化(generalization&#xff09;介绍。 用例图是解决用户需求的图&#xff0c;画好用例图一定要理清用例之间的关系。用例之间有三种关系&…

LabVIEWCompactRIO 开发指南33 测试和调试LabVIEW FPGA代码

LabVIEWCompactRIO 开发指南33 测试和调试LabVIEW FPGA代码 如前所述&#xff0c;应在仿真模式下开发LabVIEWFPGA VI&#xff0c;以快速迭代设计并避免冗长的编译时间。当需要测试和调试VI时&#xff0c;可以保持仿真模式或利用其他几个选项。应该根据功能验证与性能的要求以…

【LeetCode】 复制带随机指针的链表

Leetcode 138.复制带随机指针的链表 文章目录 题目描述解题思路运行代码 题目描述 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全…

C语言中这么骚的退出程序方式你知道几个?

前言 在本篇文章当中主要给大家介绍C语言当中一些不常用的特性&#xff0c;比如在main函数之前和之后设置我们想要执行的函数&#xff0c;以及各种花式退出程序的方式。 1、main函数是最先执行和最后执行的函数吗&#xff1f; 1&#xff09;C语言构造和析构函数 通常我们在…

Python数据分析案例27——PCA-K均值-轮廓系数客户聚类

本案例适合应用统计&#xff0c;数据科学&#xff0c;电商专业 K均值对客户进行分类的案例都做烂了......但我认为这个案例还是有一定的价值的&#xff0c;使用了pca&#xff0c;还有轮廓系数寻找最优的聚类个数。 下面来看看 代码准备 导入包 import numpy as np import pa…