当前位置: 首页 > news >正文

【多模态融合】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的融合)这方面研究甚少。最近借助和朋友们讨论论文的契机接触了一下这方面的知识&#xff0c;起步是晚了一点&#xff0c;但好歹是开了个头。下面就借助TransFusion论文…...

(二)正点原子STM32MP135移植——TF-A移植

目录 一、TF-A概述 二、编译官方代码 2.1 解压源码 2.2 打补丁 2.3 编译准备 &#xff08;1&#xff09;修改Makfile.sdk &#xff08;2&#xff09;设置环境变量 &#xff08;3&#xff09;编译 三、移植 3.1 复制官方文件 3.2 修改电源 3.3 修改TF卡和emmc 3.4 添…...

将二叉搜索树转化为排序的双向链表

链接&#xff1a; ​​​​​​LCR 155. 将二叉搜索树转化为排序的双向链表 题解&#xff1a; /* // 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&#xff08;Dynamic Link Library&#xff0c;动态链接库&#xff09;是一种可执行文件&#xff0c;它包含了在程序运行时需要调用的代码和资源。DLL 文件的主要作用是实现代码和资源的共享&#xff0c;这样在多个程序之间就可以避免重复的代码和资源&#xff0c;从而节省系…...

通达信和同花顺能否实现程序化自动交易股票,量化交易如何实现?

以下写给正在寻找自动交易接口的朋友&#xff0c;首先&#xff0c;不是那种设置个简单条件的条件单&#xff0c;或者某些客户端上形同鸡肋的策略交易&#xff0c;那些策略根本称不上策略&#xff0c;还有各种限制&#xff0c;不支持这个不支持那个&#xff0c;可设置的参数也不…...

基于Kylin的数据统计分析平台架构设计与实现

目录 1 前言 2 关键模块 2.1 数据仓库的搭建 2.2 ETL 2.3 Kylin数据分析系统 2.4 数据可视化系统 2.5 报表模块 3 最终成果 4 遇到问题 1 前言 这是在TP-LINK公司云平台部门做的一个项目&#xff0c;总体包括云上数据统计平台的架构设计和组件开发&#xff0c;在此只做…...

Linux CentOS7 vim寄存器

计算机中通常所说的寄存器Register一般指的是CPU中的寄存器&#xff0c;用来暂存CPU处理所需要的指令、数据等。 vim中同样也有寄存器&#xff0c;使用的方式和CPU非常类似。 vim中的寄存器(register)作用和windows中的剪切板类似&#xff0c;不过vim中的寄存器不止一个&…...

摄影后期图像编辑软件Lightroom Classic 2023 mac中文特点介绍

Lightroom Classic 2023 mac是一款图像处理软件&#xff0c;是数字摄影后期制作的重要工具之一&#xff0c;lrc2023 mac适合数字摄影后期制作、摄影师、设计师等专业人士使用。 Lightroom Classic 2023 mac软件特点 高效的图像管理&#xff1a;Lightroom Classic提供了强大的图…...

一种4g扫码付费通电控制器方案

之前开发了一款扫码付款通电控制器 功能&#xff1a;用户扫码付款后设备通电&#xff0c;开始倒计时&#xff0c;倒计时结束后设备断电&#xff0c;资金到账商家的商家助手里面&#xff0c;腾讯会收取千分之6手续费。 产品主要应用场景 本产品主要应用于各类无人值守或者自助…...

桌面自动化工具总结

引言:产品经理提出桌面程序需要自动化的测试,避免繁琐的人肉点击。说干就干。 现有自动化工具是五花八门,我找了两个框架。 这两个框架都是基于微软的UIA 框架,链接地址 https://learn.microsoft.com/en-us/windows/win32/winauto/uiauto-providerportal?source=recommen…...

Python入门教程 | Python 常用标准库概览

Python3 标准库概览 Python 标准库非常庞大&#xff0c;所提供的组件涉及范围十分广泛&#xff0c;使用标准库我们可以让您轻松地完成各种任务。 以下是一些 Python3 标准库中的模块&#xff1a; os 模块&#xff1a;os 模块提供了许多与操作系统交互的函数&#xff0c;例如创…...

【JavaScript】读取本地json文件并绘制表格

本文为避免跨域问题&#xff0c;使用了改造过的本地json文件的方法实现读取json数据并绘制表格。 如果发起http请求获取本地 json文件中数据&#xff0c;需要架设本地服务器&#xff0c;本文不做阐述。 概述 1、json在本地&#xff0c;并不需要从服务器下载。 2、采用jquery…...

前端笔试题总结,带答案和解析(一)

1. 执行以下程序&#xff0c;输出结果为&#xff08;&#xff09; 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&#xff0c;y的值为20&#xff0c;x < y返回结果为tru…...

LeetCode 202 快乐数

今天再次做到需要int转化成String&#xff0c;从而方便运算的题目。&#xff08;当然还可以直接使用int运算也是没问题的&#xff09; 再次出现了我容易弄混淆的问题&#xff0c;Integer.valueOf和ASCII码转化的差异&#xff1f; 其实之前我以及有记录过该问题&#xff0c;详…...

国庆作业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#整个流程是&#xff0c;1.生成标准数据集&#xff0c;包括训练数据和测试数据 # 2.定义线性模型训练 # 模型初始化&#xff08;函…...

堆--数组中第K大元素

如果对于堆不是太认识&#xff0c;请点击&#xff1a;堆的初步认识-CSDN博客 解题思路&#xff1a; /*** <h3>求数组中第 K 大的元素</h3>* <p>* 解体思路* <ol>* 1.向小顶堆放入前k个元素* 2.剩余元素* 若 < 堆顶元素, 则略过* …...

ipad使用技巧

1、goodnotes中批量导入pdf文件 法一&#xff1a; 直接参考视频&#xff1a; 【目前为止所知iPad上goodnotes批量导入网盘文件最快的方法】 大致步骤&#xff1a;pdf文件传到百度网盘&#xff0c;然后ES软件登录百度网盘&#xff0c;在goodnotes中导入&#xff0c;选择ES&a…...

Windows系统上使用CLion远程开发Linux程序

CLion远程开发Linux程序 情景说明Ubuntu配置CLion配置同步 情景说明 在Windows系统上使用CLion开发Linux程序&#xff0c;安装CLion集成化开发环境时会自动安装cmake、mingw&#xff0c;代码提示功能也比较友好。 但是在socket开发时&#xff0c;包含sys/socket.h头文件时&am…...

github搜索技巧

指定语言 language:java 比如我要找用java写的含有blog的内容 搜索项目名称包含关键词的内容 vue in:name 其他如项目描述跟项目文档&#xff0c;如下 组合使用 vue in:name,description,readme 根据Star 或者fork的数量来查找 总结 springboot vue stars:>1000 p…...

Python生成器

生成器 Generators 要理解生成器&#xff0c;首先要理解迭代器&#xff0c;迭代器由以下三个部分组成&#xff1a; 可迭代对象&#xff08;iterable&#xff09;迭代器&#xff08;iterator&#xff09;迭代&#xff08;iteration&#xff09; 1. 可迭代对象 只要定义了可以…...

flutter开发实战-使用FutureBuilder异步数据更新Widget

flutter开发实战-使用FutureBuilder异步数据更新Widget 在开发过程中&#xff0c;经常遇到需要依赖异步数据更新Widget的情况&#xff0c;如下载图片后显示Widget&#xff0c;获取到某个数据时候&#xff0c;显示在对应的UI界面上&#xff0c;都可以使用FutureBuilder异步数据…...

1.2 数据模型

思维导图&#xff1a; 前言&#xff1a; **1.2.1 什么是模型** - **定义**&#xff1a;模型是对现实世界中某个对象特征的模拟和抽象。例如&#xff0c;一张地图、建筑设计沙盘或精致的航模飞机都可以视为具体的模型。 - **具体模型与现实生活**&#xff1a;具体模型可以很容…...

【实用工具】谷歌浏览器插件开发指南

谷歌浏览器插件开发指南涉及以下几个方面&#xff1a; 1. 开发环境准备&#xff1a;首先需要安装Chrome浏览器和开发者工具。进入Chrome应用商店&#xff0c;搜索“Extensions Reloader”和“Manifest Viewer”两个插件进行安装&#xff0c;这两个插件可以方便开发和调试。 2…...

应用层协议——DNS、DHCP、HTTP、FTP

目录 1、DNS 协议 1-1&#xff09;Hosts 文件 1-2&#xff09;DNS 系统 1-3&#xff09;域名的组成、分类和树状结构 1-4&#xff09;DNS 域名服务器类型 1-5&#xff09;DNS 查询方式 1-6&#xff09;DNS 域名解析的一般步骤 1-7&#xff09;对象类型与资源记录 2、D…...

XML文件读写

0、.pro文件添加依赖 QT xml1、使用 QDomDocument 方式 #include <QtXml/QDomDocument> #include <QtXml/QDomProcessingInstruction> #include <QtXml/QDomElement> #include <QFile> #include <QTextStream> #include <QDebug>bo…...

Win11 安装 Vim

安装包&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1Ru7HhTSotz9mteHug-Yhpw?pwd6666 提取码&#xff1a;6666 双击安装包&#xff0c;一直下一步。 配置环境变量&#xff1a; 先配置系统变量中的path&#xff1a; 接着配置用户变量&#xff1a; 在 cmd 中输入…...

Mac电脑BIM建模软件 Archicad 26 for Mac最新

ARCHICAD 软件特色 智能化 在2D CAD中&#xff0c;所有的建筑构件都由线条构成和表现&#xff0c;仅仅是一些线条的组合而已&#xff0c;当我们阅读图纸的时候是按照制图规范来读取这些信息。我们用一组线条表示平面中的窗&#xff0c;再用另一组不同的线条在立面中表示同一个…...

JavaEE-网络编程套接字(UDP/TCP)

下面写一个简单的UDP客户端服务器流程 思路&#xff1a; 对于服务器端&#xff1a;读取请求&#xff0c;并解析–> 根据解析出的请求&#xff0c;做出响应(这里是一个回显&#xff0c;)–>把响应写回客户端 对于客户端&#xff1a;从控制台读取用户输入的内容–>从控制…...

微服务技术栈-Gateway服务网关

文章目录 前言一、为什么需要网关二、Spring Cloud Gateway三、断言工厂和过滤器1.断言工厂2.过滤器3.全局过滤器4.过滤器执行顺序 四、跨域问题总结 前言 在之前的文章中我们已经介绍了微服务技术中eureka、nacos、ribbon、Feign这几个组件&#xff0c;接下来将介绍另外一个组…...

宣传 网站建设/怎么找精准客户资源

原文发布时间为&#xff1a;2009-09-30 —— 来源于本人的百度文章 [由搬家工具导入]Handler.ashx文件&#xff1a;<% WebHandler Language"C#" Class"Handler" %>using System;using System.Web;using System.Data;public class Handler : IHttpHan…...

设计类的网站和简介/百度企业号

全套“WordPress主题开发建站视频教程 ” 包括5套&#xff1a;《WordPress零基础入门到提高视频教程》《WordPress主题模板开发视频教程》《WordPress网站SEO优化教程》《WordPress主题仿站视频教程》《WordPress高级实战教程》《DIVCSS入门实战视频教程》WordPress零基础入门到…...

淄博北京网站建设/指数基金怎么选

转载于:https://www.cnblogs.com/island/archive/2009/02/18/1393189.html...

不用买服务器可以做网站/线上推广哪个平台最好

1. 不要使用mysql_函数 这一天终于来了&#xff0c;从此你不仅仅“不应该”使用mysql_函数。PHP 7 已经把它们从核心中全部移除了&#xff0c;也就是说你需要迁移到好得多的mysqli_函数&#xff0c;或者更灵活的 PDO 实现。 2. 不要编写垃圾代码 这一条可能易于理解&#xf…...

电子商务网站建设影响因素/如何让百度收录

来源 | Python数据科学&#xff08;ID:PyDataScience&#xff09;本文为不同阶段的Python学习者从不同角度量身定制了49个学习资源。初学者Welcome to Python.orghttps://www.python.org/官方Python站点提供了一个开始使用Python生态系统和学习Python的好方法&#xff0c;包括官…...

720全景网站怎么做/郑州疫情最新动态

1、 简历了主键之后&#xff0c;是不是就自动生成了一个索引&#xff1f; ZC: 网上查到&#xff0c;建立 唯一约束 和 主键约束 时&#xff0c;系统会自动建立索引。 ZC: 应该就是对应 sqldevelop中&#xff0c;某表-->右击-->编辑(E)...-->主键 界面中 所显示的 索引…...