【多模态融合】TransFusion学习笔记(1)
工作上主要还是以纯lidar的算法开发,部署以及系统架构设计为主。对于多模态融合(这里主要是只指Lidar和Camer的融合)这方面研究甚少。最近借助和朋友们讨论论文的契机接触了一下这方面的知识,起步是晚了一点,但好歹是开了个头。下面就借助TransFusion论文及其开源代码来串一串这方面的知识。TransFusion文中指出已经存在的Lidar-Camera的融合方法大致可以分为3类:
Result-Level:这个很好理解,参考FPointNet网络图示。就是利用现有的2D检测器在图像上提取2D初始框,根据Camera成像原理,捕获2D框视锥内的点云,再利用点云分类模型(如:PointNet)做进一步分类。

这个方法的好处是显然的,遥想作者当年发论文的时候,图像的2D检测相对已经成熟,但是点云3D检测才刚刚起步(好吧,其实也是该作者开创了点云深度学习处理的先河),以2D box作为Query应该说是一个很不错的思路。很多后续论文在谈论FPointNet时说该方法受限于图像2D检测模型。如果2D检测露检则3D部分也不可能恢复。

Proposal-Level:提到Proposal我们很容易想到faster-rcnn这种经典网络,它由第一阶段中的RPN提供候Proposal,第二阶段利用proposal以及RoiPooling(或者后续该进型的RoiAlign等)操作提取proposal region-wise features后再对box做一次精修。具体到多模态的Proposal-Level的融合,你可以想象为其中一个模态的模型作为第一阶段先提供Proposal,然后各个模态以这个Proposal为媒介进行特征融合等。MV3D算是这方面的开山之作,其BEV下的lidar检测模型先提供一下proposal,然后这个proposal分别映射到Lidar BEV view,Lidar Front view以及Image View 这3张特征图上去提取region-wise features进行融合。此时的融合已经是一种基于Proposal的特征级融合了。有了这个融合后的特征,自然就可以继续再接分类,回归等任务。

Point-Level:原始lidar点云通常包含3个维度的坐标(x,y,z)信息再加上1维强度信息。但是借助Lidar和Camera之间的标定关系,可以建立point到pixel的联系。Point-Level的融合就是借助了这类联系对lidar点云的特征进行扩充。扩充的特征有可能是point对应pixel的分割label,如大名鼎鼎的PointPainting,操作又简单,又通用,提点能力也杠杠的。

后来发展到既然你可以Painting分割的label,为什么我不可以Painting分割/检测的feature。既然你可以Painting某一层的feature,我为什么不可以painting multi-scale的feature等等。当然,还有更多的复杂一些的操作,涉及到不同view下的Painting,以及由点的Painting到voxel的Painting等等,但是总体思想不变。这种Point-Level的方法存在几个问题,一个就是对标定的准确性要求很高,因为就是点对点的。另外一个点云毕竟是稀疏的,如果只是利用了point2pixel部分的图像点的信息,则图像信息的利用是严重不充分的。毕竟你是需要额外整出一个模型来提取图像的分割label或者特征的,开销不小。此外,低质量图像带来的错误的分割label或者干扰性的特征反而会影响到点云的模型效果。说了这么多那TransFusion这篇论文有何特别之处,按作者原文的说法是"Our key idea is to reposition the focus of the fusion process,from hard-association to soft-association,leading to the robustness against degenerate image quality and sensor misalignment".字面意思就是TransFusion使用一种软关联机制(soft-association)取代以往融合方法中的硬关联机制,这样使得融合算法在图像质量退化和传感器没有严格对齐的情况下能更加鲁棒。至于这种软关联机制具体怎么实现,我觉得可以结合论文和代码先分析TransFusion-L这一纯Lidar的3D检测,再分析融合了图像后的完整的框架,可能会有更好的理解。
TransFusion-L
TransFusion多模态融合框架中纯lidar检测部分称其为TransFusion-L。从下表中可见,在nuScenes测试集上,单就纯Lidar的方法PK,TransFusion-L相比CenterPoint模型mAP和NDS都有大幅提升。

TransFusion-L的pipeline如下图所示,我从多模态pipeline中去掉了图像融合的元素。乍一看就是将CenterPoint的检测头换成了TransFormer的检测头,但是其中仍然有诸多创新之处。

他借鉴了最新的基于Transfomer的图像2D检测的方法,使用稀疏的object query通过transformer的方式来聚合特征并预测最终的目标。在object query的初始化上不仅作到了input-dependent,而且还具备category-aware。从论文后的对比实验来看这是2个极其重要的特性。表格中a)为完整的TransFusion-L,b)表示去掉了category-aware。mAP和NDS分别掉了5.7%和2.8%。d)表示去掉了input-dependent,e...这个结果就完全没法看了。即使通过增加Decoder Layers的层数来学习弥补也远落后于仅有一层Decode Layer的TransFusion-L。

那Input-Depentdent和Class-Aware分别又是什么呢?
Input-Dependent:
在DETR这一将Transformer用于目标检测的开山之作中首次引入了object queries的概念。

这些个object queries是可学习的embedding,从论文代码中可见query_embed初始是一个Shape为(num_queris, hidden_dim)的embedding,在模型训练过程中再不断迭代更新参数。

一旦模型训练完成query参数也就固定了,推理过程中与当前输入图像的内容并无关系,也就是不由当前图像内容计算得到。为什么这样的object query还能work呢?首先,上面也说了object query虽然是随机初始化,但是会随着网络训练而更新。不同object queries通过self-attention建模了patter与patter之间的关系,通过cross-attention又从transformer-encoder序列中对patter相关特征做了聚合。

上面这种形式的object query称其为input-independent query。现在我们再来看TransFusion-L中的Input-Dependent的object query就好理解了,它再也不需要单独随机初始化一组object query embedding再通过训练网络来更新参数,而是直接使用LiDAR BEV Features来初始化。有个问题就是Lidar BEV Features是一个dense的feature map,而我们要选择的object query是稀疏的,最终哪些位置上的feature用来初始化query? 这个就交给heatmap来选择了。

这个操作很秀,通过heatmap筛选出热点,既保证了object query的稀疏性,同时又可以由热点位置的feature来进行初始化,同时热点的位置天然可以用于Position-Encoding(位置编码)加入到query中。输入图像的内容不同,得到的bev feature map不同,heatmap也不同,自然object query也不一样,所以就是Input-Dependent的了。通过这种方式初始化的query会更加贴近潜在目标的中心,而不需要像DETR那样通过multiple decoder layers堆叠来修正位置。
Class-Aware:heatmap中得到的热点除了位置和特征信息,同时还包含了分类信息。类似位置编码,对one-hot类别向量进行编码也加入到query特征中。加入了类别编码信息的query对self-attention阶段建模object-object之间的联系,以及cross-attention阶段建模object-context之间的联系大有裨益。
下面通过TransFusion检测头部分的代码对Input-Dependent和Class-Aware做进一步的理解。因为还是讨论TransFusion-L所以会先屏蔽图像融合部分的代码。
@HEADS.register_module()
class TransFusionHead(nn.Module):def __inti__(self,...):super(TransFusionHead,self).__init__()#......def forward_single(self, inputs, img_inputs, img_metas):#......def forward(self, feats, img_feats, img_metas):if img_feats is None:img_feats = [None]res = multi_apply(self.forward_single, feats, img_feats, [img_metas])assert len(res) == 1, "only support one level features."return res
TransFusion-L总的pipeline大该为Input-->预处理-->3D Backbone-->Height Compression-->2D Neck-->Head。为方便调试,假定batch为2,其它按默认配置设置则进入到head的feats维度为[2,512,128(H),128(W)]。其实在HeightCompression完成高度压缩以后就可以类似处理2D图像的feature map进行处理了。forward之后会立刻进入forward_single函数,也是整个head的核心。
源文件:mmdet3d/models/dense_heads/transfusion_head.py
1 def forward_single(self, inputs, img_inputs, img_metas): 2 """Forward function for CenterPoint.3 Args:4 inputs (torch.Tensor): Input feature map with the shape of5 [B, 512, 128(H), 128(W)]. (consistent with L748)6 7 Returns:8 list[dict]: Output results for tasks.9 """10 batch_size = inputs.shape[0]11 ##[2, 128, 128, 128])12 lidar_feat = self.shared_conv(inputs) ##3x3普通卷积13 14 #################################15 # 16 #################################17 lidar_feat_flatten = lidar_feat.view(batch_size, lidar_feat.shape[1], -1) # [BS, C, H*W]18 bev_pos = self.bev_pos.repeat(batch_size, 1, 1).to(lidar_feat.device) ##bev_pos只是网格坐标...19 20 if self.fuse_img:21 ##pass22 23 #################################24 # image guided query initialization25 #################################26 if self.initialize_by_heatmap:27 ##torch.Size([2, 10, 128, 128]) <==28 dense_heatmap = self.heatmap_head(lidar_feat)29 dense_heatmap_img = None30 if self.fuse_img:31 ###32 ###33 else:34 heatmap = dense_heatmap.detach().sigmoid()35 padding = self.nms_kernel_size // 236 local_max = torch.zeros_like(heatmap)37 # equals to nms radius = voxel_size * out_size_factor * kenel_size38 local_max_inner = F.max_pool2d(heatmap, kernel_size=self.nms_kernel_size, stride=1, padding=0)39 local_max[:, :, padding:(-padding), padding:(-padding)] = local_max_inner40 ## for Pedestrian & Traffic_cone in nuScenes41 if self.test_cfg['dataset'] == 'nuScenes':42 local_max[:, 8, ] = F.max_pool2d(heatmap[:, 8], kernel_size=1, stride=1, padding=0)43 local_max[:, 9, ] = F.max_pool2d(heatmap[:, 9], kernel_size=1, stride=1, padding=0)44 elif self.test_cfg['dataset'] == 'Waymo': # for Pedestrian & Cyclist in Waymo45 local_max[:, 1, ] = F.max_pool2d(heatmap[:, 1], kernel_size=1, stride=1, padding=0)46 local_max[:, 2, ] = F.max_pool2d(heatmap[:, 2], kernel_size=1, stride=1, padding=0)47 heatmap = heatmap * (heatmap == local_max)48 heatmap = heatmap.view(batch_size, heatmap.shape[1], -1)49 50 # top #num_proposals among all classes51 top_proposals = heatmap.view(batch_size, -1).argsort(dim=-1, descending=True)[..., :self.num_proposals]52 top_proposals_class = top_proposals // heatmap.shape[-1]53 54 top_proposals_index = top_proposals % heatmap.shape[-1]55 query_feat = lidar_feat_flatten.gather(index=top_proposals_index[:, None, :].expand(-1, lidar_feat_flatten.shape[1], -1), dim=-1)56 self.query_labels = top_proposals_class57 58 # add category embedding59 one_hot = F.one_hot(top_proposals_class, num_classes=self.num_classes).permute(0, 2, 1)60 query_cat_encoding = self.class_encoding(one_hot.float())61 query_feat += query_cat_encoding62 query_pos = bev_pos.gather(index=top_proposals_index[:, None, :].permute(0, 2, 1).expand(-1, -1, bev_pos.shape[-1]), dim=1)63 else:64 query_feat = self.query_feat.repeat(batch_size, 1, 1) # [BS, C, num_proposals]65 base_xyz = self.query_pos.repeat(batch_size, 1, 1).to(lidar_feat.device) # [BS, num_proposals, 2]66 67 #################################68 # transformer decoder layer (LiDAR feature as K,V)69 #################################70 ret_dicts = []71 for i in range(self.num_decoder_layers):72 prefix = 'last_' if (i == self.num_decoder_layers - 1) else f'{i}head_'73 74 # Transformer Decoder Layer75 # :param query: B C Pq :param query_pos: B Pq 3/676 query_feat = self.decoder[i](query_feat, lidar_feat_flatten, query_pos, bev_pos)77 78 # Prediction79 res_layer = self.prediction_heads[i](query_feat) ##FFN80 81 ##这个center是一个相对的偏移,所以要通过下面的方式计算出实际预测的center82 res_layer['center'] = res_layer['center'] + query_pos.permute(0, 2, 1)83 first_res_layer = res_layer84 if not self.fuse_img:85 ret_dicts.append(res_layer)86 87 # for next level positional embedding88 query_pos = res_layer['center'].detach().clone().permute(0, 2, 1)89 90 #################################91 # transformer decoder layer (img feature as K,V)92 #################################93 if self.fuse_img:94 pass95 96 if self.initialize_by_heatmap:97 ret_dicts[0]['query_heatmap_score'] = heatmap.gather(index=top_proposals_index[:, None, :].expand(-1, self.num_classes, -1), dim=-1) # [bs, num_classes, num_proposals]98 if self.fuse_img:99 ret_dicts[0]['dense_heatmap'] = dense_heatmap_img
100 else:
101 ret_dicts[0]['dense_heatmap'] = dense_heatmap
102
103 if self.auxiliary is False:
104 # only return the results of last decoder layer
105 return [ret_dicts[-1]]
106
107 # return all the layer's results for auxiliary superivison
108 new_res = {}
109 for key in ret_dicts[0].keys():
110 if key not in ['dense_heatmap', 'dense_heatmap_old', 'query_heatmap_score']:
111 new_res[key] = torch.cat([ret_dict[key] for ret_dict in ret_dicts], dim=-1)
112 else:
113 new_res[key] = ret_dicts[0][key]
114 return [new_res]
第12行,通过一个普通的3x3卷积将输入通道数从512压缩到128;
第18行,将self.bev_pos也就是bev下的feature map网格坐标复制batch份。self.bev_pos在初始__init__函数中通过create_2D_grid函数创建。create_2D_grid顾名思义就是创建2D的网格,他会返回一整张网格map的中心点坐标。
def create_2D_grid(x_size, y_size):meshgrid = [[0, x_size - 1, x_size], [0, y_size - 1, y_size]]batch_y, batch_x = torch.meshgrid(*[torch.linspace(it[0], it[1], it[2]) for it in meshgrid])batch_x = batch_x + 0.5batch_y = batch_y + 0.5coord_base = torch.cat([batch_x[None], batch_y[None]], dim=0)[None]coord_base = coord_base.view(1, 2, -1).permute(0, 2, 1)return coord_baseif __name__ == "__main__":x_size = 128y_size = 128coord_base = create_2D_grid(x_size,y_size)print('x_size:{},y_size:{}'.format(x_size,y_size))print('coord_base shape:', coord_base.shape)print('coord_base:', coord_base)
运行:
x_size:128,y_size:128
coord_base shape: torch.Size([1, 16384, 2])
coord_base: tensor([[[ 0.5000, 0.5000],[ 1.5000, 0.5000],[ 2.5000, 0.5000],...,[125.5000, 127.5000],[126.5000, 127.5000],[127.5000, 127.5000]]])
第26行,进入heatmap初始化逻辑中;
第28行,输入lidar bev特征图(2,128,128,128)通过若干卷积操作生成热力图(2,10,128,128)。我们以nuScenes数据集为例,10为类别数量;
第38行,使用torch function自带的max_pool2d函数,结合kernel_size(self.nms_kernel_size默认为3)等参数取heatmap局部邻域(kernel)内的最大之值;
第39行,因为heatmap做max_pool2d的时候padding为0,所以得到的local_max_inner的shape减了2,所以往local_max里面做填充的时候需要H,W维度需要给一个padding:(-padding)的范围;
第47行,经过该操作邻域内不是最热的地方就被置为0了;
第50行,通过对热度其实就是类别score由高到低排序,取出前self.num_proposals(默认200)的索引位置,保存到top_proposals中;
第51-52行,分别计算出top_proposal代表的类别和所在通道内的索引;
第55行,借助上一步计算得到的热点top_proposals_index从lidar_feat_flatten中收集特征,这些收集到的特征用于初始化object query。当然,在此基础上还会再sum上类别编码和位置编码特征;
第59-60行,就是完成object query的"class-aware"特性最重要的两步,将top_proposals_class的类别id做one-hot,并进行类别编码。所谓的self.class_encoding也就是一个一维的卷积;
第71-88行,这个就是经典的transformer decoder + ffn操作了。因为有了input-dependent和class-aware两大法宝的加持,decoder的层数(self.num_decoder_layers)可以直接缩减到一层了;
至此,TransFusion-L的核心部分就完成了,相比他的图像融合部分还是好理解的。我在浏览其它相关文章的时候也注意到图森有一篇思想比较相近的文章CenterFormer。

不考虑他mutli-frame的部分的话,主要是加入了一个multi-scale的概念。其实就是对2d neck网络部分以及K,V的选取方式做了调整。因为2d neck部分是一个multi scale的网络,object query就可以从不同scale的feature map上聚合K,V效果又可以有提升。
相关文章:
【多模态融合】TransFusion学习笔记(1)
工作上主要还是以纯lidar的算法开发,部署以及系统架构设计为主。对于多模态融合(这里主要是只指Lidar和Camer的融合)这方面研究甚少。最近借助和朋友们讨论论文的契机接触了一下这方面的知识,起步是晚了一点,但好歹是开了个头。下面就借助TransFusion论文…...
(二)正点原子STM32MP135移植——TF-A移植
目录 一、TF-A概述 二、编译官方代码 2.1 解压源码 2.2 打补丁 2.3 编译准备 (1)修改Makfile.sdk (2)设置环境变量 (3)编译 三、移植 3.1 复制官方文件 3.2 修改电源 3.3 修改TF卡和emmc 3.4 添…...
将二叉搜索树转化为排序的双向链表
链接: LCR 155. 将二叉搜索树转化为排序的双向链表 题解: /* // Definition for a Node. class Node { public:int val;Node* left;Node* right;Node() {}Node(int _val) {val _val;left NULL;right NULL;}Node(int _val, Node* _left…...
电脑dll丢失应该怎么解决,dll文件丢失怎么恢复方法分享
DLL(Dynamic Link Library,动态链接库)是一种可执行文件,它包含了在程序运行时需要调用的代码和资源。DLL 文件的主要作用是实现代码和资源的共享,这样在多个程序之间就可以避免重复的代码和资源,从而节省系…...
通达信和同花顺能否实现程序化自动交易股票,量化交易如何实现?
以下写给正在寻找自动交易接口的朋友,首先,不是那种设置个简单条件的条件单,或者某些客户端上形同鸡肋的策略交易,那些策略根本称不上策略,还有各种限制,不支持这个不支持那个,可设置的参数也不…...
基于Kylin的数据统计分析平台架构设计与实现
目录 1 前言 2 关键模块 2.1 数据仓库的搭建 2.2 ETL 2.3 Kylin数据分析系统 2.4 数据可视化系统 2.5 报表模块 3 最终成果 4 遇到问题 1 前言 这是在TP-LINK公司云平台部门做的一个项目,总体包括云上数据统计平台的架构设计和组件开发,在此只做…...
Linux CentOS7 vim寄存器
计算机中通常所说的寄存器Register一般指的是CPU中的寄存器,用来暂存CPU处理所需要的指令、数据等。 vim中同样也有寄存器,使用的方式和CPU非常类似。 vim中的寄存器(register)作用和windows中的剪切板类似,不过vim中的寄存器不止一个&…...
摄影后期图像编辑软件Lightroom Classic 2023 mac中文特点介绍
Lightroom Classic 2023 mac是一款图像处理软件,是数字摄影后期制作的重要工具之一,lrc2023 mac适合数字摄影后期制作、摄影师、设计师等专业人士使用。 Lightroom Classic 2023 mac软件特点 高效的图像管理:Lightroom Classic提供了强大的图…...
一种4g扫码付费通电控制器方案
之前开发了一款扫码付款通电控制器 功能:用户扫码付款后设备通电,开始倒计时,倒计时结束后设备断电,资金到账商家的商家助手里面,腾讯会收取千分之6手续费。 产品主要应用场景 本产品主要应用于各类无人值守或者自助…...
桌面自动化工具总结
引言:产品经理提出桌面程序需要自动化的测试,避免繁琐的人肉点击。说干就干。 现有自动化工具是五花八门,我找了两个框架。 这两个框架都是基于微软的UIA 框架,链接地址 https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-providerportal?source=recommen…...
Python入门教程 | Python 常用标准库概览
Python3 标准库概览 Python 标准库非常庞大,所提供的组件涉及范围十分广泛,使用标准库我们可以让您轻松地完成各种任务。 以下是一些 Python3 标准库中的模块: os 模块:os 模块提供了许多与操作系统交互的函数,例如创…...
【JavaScript】读取本地json文件并绘制表格
本文为避免跨域问题,使用了改造过的本地json文件的方法实现读取json数据并绘制表格。 如果发起http请求获取本地 json文件中数据,需要架设本地服务器,本文不做阐述。 概述 1、json在本地,并不需要从服务器下载。 2、采用jquery…...
前端笔试题总结,带答案和解析(一)
1. 执行以下程序,输出结果为() var x 10; var y 20; var z x < y ? x:y; console.log(xx;yy;zz);A x11;y21;z11 B x11;y20;z10 C x11;y21;z10 D x11;y20;z11 初始化x的值为10,y的值为20,x < y返回结果为tru…...
LeetCode 202 快乐数
今天再次做到需要int转化成String,从而方便运算的题目。(当然还可以直接使用int运算也是没问题的) 再次出现了我容易弄混淆的问题,Integer.valueOf和ASCII码转化的差异? 其实之前我以及有记录过该问题,详…...
国庆作业day6
服务器 #include <my_head.h> #define IP "192.168.101.66" #define PORT 6666 int main(int argc, const char *argv[]) {//创建套接字int fd socket(AF_INET, SOCK_STREAM, 0);if(fd < 0){ERR_MSG("socket");return -1;}struct sockaddr_in s…...
李沐深度学习记录4:12.权重衰减/L2正则化
权重衰减从零开始实现 #高维线性回归 %matplotlib inline import torch from torch import nn from d2l import torch as d2l#整个流程是,1.生成标准数据集,包括训练数据和测试数据 # 2.定义线性模型训练 # 模型初始化(函…...
堆--数组中第K大元素
如果对于堆不是太认识,请点击:堆的初步认识-CSDN博客 解题思路: /*** <h3>求数组中第 K 大的元素</h3>* <p>* 解体思路* <ol>* 1.向小顶堆放入前k个元素* 2.剩余元素* 若 < 堆顶元素, 则略过* …...
ipad使用技巧
1、goodnotes中批量导入pdf文件 法一: 直接参考视频: 【目前为止所知iPad上goodnotes批量导入网盘文件最快的方法】 大致步骤:pdf文件传到百度网盘,然后ES软件登录百度网盘,在goodnotes中导入,选择ES&a…...
Windows系统上使用CLion远程开发Linux程序
CLion远程开发Linux程序 情景说明Ubuntu配置CLion配置同步 情景说明 在Windows系统上使用CLion开发Linux程序,安装CLion集成化开发环境时会自动安装cmake、mingw,代码提示功能也比较友好。 但是在socket开发时,包含sys/socket.h头文件时&am…...
github搜索技巧
指定语言 language:java 比如我要找用java写的含有blog的内容 搜索项目名称包含关键词的内容 vue in:name 其他如项目描述跟项目文档,如下 组合使用 vue in:name,description,readme 根据Star 或者fork的数量来查找 总结 springboot vue stars:>1000 p…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...
