【数据关联】基于Patch的对应特征关联,关联当前帧->参考帧,帧间追踪

news2024/9/28 9:20:26

在这里插入图片描述

帧间追踪与数据关联

      • 1. WarpPixelWise(求当前帧特征点位置)
        • 1.1 函数功能
        • 1.2 函数输入输出
        • 1.3 算法步骤
      • 2. GetWarpMatrixAffine(计算 当前帧->参考帧 仿射变换矩阵)
        • 2.1 函数功能
        • 2.2 函数输入输出
        • 2.3 算法步骤
      • 3. GetWarpMatrixAffine(计算 当前帧->参考帧 仿射变换矩阵)
        • 3.1 函数功能
        • 3.2 函数输入输出
        • 3.3 算法步骤

1. WarpPixelWise(求当前帧特征点位置)

1.1 函数功能

这个是将参考帧中的一个特征点周围的像素按照当前帧中的相机姿态投影到当前帧上,并将其像素值存储在一个给定的数组中。

1.2 函数输入输出

输入:函数的输入包括当前帧、参考帧、参考帧中的特征点、参考帧和当前帧的金字塔层级、半补丁尺寸
输出:一个指向输出像素值数组的指针。

1.3 算法步骤

  1. 计算参考帧中特征点到参考帧相机的距离和到当前帧相机的距离;
  2. 将特征点在参考帧相机坐标系下的坐标反投影到三维空间中,并根据到相机的距离缩放得到三维坐标;
  3. 将三维坐标变换到当前帧相机坐标系下,并投影到当前帧图像上得到像素坐标;
  4. 将像素坐标缩放到搜索层级,并对半补丁尺寸内的每个像素执行以下操作:
    • 将像素坐标变换到参考帧相机坐标系下的三维坐标;
    • 将三维坐标投影到参考帧图像上得到像素坐标;
    • 将像素坐标缩放到参考帧金字塔层级;
    • 根据双线性插值计算该像素在参考帧图像上的值,并将其存储在输出数组中。

数学公式描述如下:

p c u r = T c u r w o r l d T r e f w o r l d − 1 p r e f \mathbf{p}_{cur} = \mathbf{T}_{cur}^{world} \mathbf{T}_{ref}^{world^{-1}} \mathbf{p}_{ref} pcur=TcurworldTrefworld1pref

p r e f = d r e f ∥ p r e f c a m ∥ p r e f c a m \mathbf{p}_{ref} = \frac{d_{ref}}{\|\mathbf{p}_{ref}^{cam}\|}\mathbf{p}_{ref}^{cam} pref=prefcamdrefprefcam

p c u r s e a r c h = p c u r 2 l e v e l c u r \mathbf{p}_{cur}^{search} = \frac{\mathbf{p}_{cur}}{2^{level_{cur}}} pcursearch=2levelcurpcur

p e l e s e a r c h = p e l e p a t c h + p c u r s e a r c h \mathbf{p}_{ele}^{search} = \mathbf{p}_{ele}^{patch} + \mathbf{p}_{cur}^{search} pelesearch=pelepatch+pcursearch

p e l e c a m = p e l e s e a r c h 2 l e v e l c u r \mathbf{p}_{ele}^{cam} = \frac{\mathbf{p}_{ele}^{search}}{2^{level_{cur}}} pelecam=2levelcurpelesearch

p e l e w o r l d = T r e f w o r l d T c u r w o r l d − 1 p e l e c a m \mathbf{p}_{ele}^{world} = \mathbf{T}_{ref}^{world} \mathbf{T}_{cur}^{world^{-1}} \mathbf{p}_{ele}^{cam} peleworld=TrefworldTcurworld1pelecam

p e l e r e f = 1 2 l e v e l r e f K r e f p e l e c a m \mathbf{p}_{ele}^{ref} = \frac{1}{2^{level_{ref}}}\mathbf{K}_{ref}\mathbf{p}_{ele}^{cam} peleref=2levelref1Krefpelecam

I ( p e l e r e f ) = w 00 I ( ⌊ p e l e , x ⌋ , ⌊ p e l e , y ⌋ ) + w 01 I ( ⌊ p e l e , x ⌋ , ⌊ p e l e , y ⌋ + 1 ) + w 10 I ( ⌊ p e l e , x ⌋ + 1 , ⌊ p e l e , y ⌋ ) + w 11 I ( ⌊ p e l e , x ⌋ + 1 , ⌊ p e l e , y ⌋ + 1 ) I(\mathbf{p}_{ele}^{ref}) = \\ w_{00}I(\lfloor \mathbf{p}_{ele,x}\rfloor,\lfloor \mathbf{p}_{ele,y}\rfloor) + w_{01}I(\lfloor \mathbf{p}_{ele,x}\rfloor,\lfloor \mathbf{p}_{ele,y}\rfloor+1) + \\w_{10}I(\lfloor \mathbf{p}_{ele,x}\rfloor+1,\lfloor \mathbf{p}_{ele,y}\rfloor) + w_{11}I(\lfloor \mathbf{p}_{ele,x}\rfloor+1,\lfloor \mathbf{p}_{ele,y}\rfloor+1) I(peleref)=w00I(⌊pele,x,pele,y⌋)+w01I(⌊pele,x,pele,y+1)+w10I(⌊pele,x+1,pele,y⌋)+w11I(⌊pele,x+1,pele,y+1)

其中, T \mathbf{T} T 表示相机位姿, p \mathbf{p} p 表示像素坐标, d d d 表示距离, ∥ ⋅ ∥ \|\cdot\| 表示向量的模, K \mathbf{K} K 表示相机内参矩阵, I ( ⋅ ) I(\cdot) I() 表示图像上某个像素的值, w 00 , w 01 , w 10 , w 11 w_{00},w_{01},w_{10},w_{11} w00,w01,w10,w11 表示双线性插值权重。

bool WarpPixelWise(const Frame& cur_frame, const Frame& ref_frame, const FeatureWrapper& ref_ftr,
    const int level_ref, const int level_cur, const int half_patch_size, uint8_t* patch) {
  double depth_ref = (ref_frame.pos() - ref_ftr.landmark->pos()).norm();
  double depth_cur = (cur_frame.pos() - ref_ftr.landmark->pos()).norm();

  // back project to 3D points in reference frame
  Eigen::Vector3d xyz_ref;
  ref_frame.cam()->backProject3(ref_ftr.px, &xyz_ref);
  xyz_ref = xyz_ref.normalized() * depth_ref;

  // project to current frame and convert to search level
  Eigen::Vector3d xyz_cur = cur_frame.T_cam_world() * (ref_frame.T_cam_world().inverse()) * xyz_ref;
  Eigen::Vector2d px_cur;
  cur_frame.cam()->project3(xyz_cur, &px_cur);
  Eigen::Vector2d px_cur_search = px_cur / (1 << level_cur);

  // for each pixel in the patch(on search level):
  // - convert to image level
  // - back project to 3D points
  // - project to ref frame and find pixel value in ref level
  uint8_t* patch_ptr = patch;
  const cv::Mat& img_ref = ref_frame.img_pyr_[level_ref];
  const int stride = img_ref.step.p[0];

  for (int y = -half_patch_size; y < half_patch_size; ++y) {
    for (int x = -half_patch_size; x < half_patch_size; ++x, ++patch_ptr) {
      const Eigen::Vector2d ele_patch(x, y);
      Eigen::Vector2d ele_search = ele_patch + px_cur_search;
      Eigen::Vector3d ele_xyz_cur;
      cur_frame.cam()->backProject3(ele_search * (1 << level_cur), &ele_xyz_cur);
      ele_xyz_cur = ele_xyz_cur.normalized() * depth_cur;
      Eigen::Vector3d ele_xyz_ref =
          ref_frame.T_cam_world() * (cur_frame.T_cam_world().inverse()) * ele_xyz_cur;
      Eigen::Vector2d ele_ref;
      ref_frame.cam()->project3(ele_xyz_ref, &ele_ref);
      ele_ref = ele_ref / (1 << level_ref);

      const int xi = std::floor(ele_ref[0]);
      const int yi = std::floor(ele_ref[1]);
      if (xi < 0 || yi < 0 || xi + 1 >= img_ref.cols || yi + 1 >= img_ref.rows) {
        VLOG(200) << "ref image: col-" << img_ref.cols << ", row-" << img_ref.rows;
        VLOG(200) << "xi: " << xi << ", "
                  << "yi: " << yi;
        return false;
      } else {
        const float subpix_x = ele_ref[0] - xi;
        const float subpix_y = ele_ref[1] - yi;
        const float w00 = (1.0f - subpix_x) * (1.0f - subpix_y);
        const float w01 = (1.0f - subpix_x) * subpix_y;
        const float w10 = subpix_x * (1.0f - subpix_y);
        const float w11 = 1.0f - w00 - w01 - w10;
        const uint8_t* const ptr = img_ref.data + yi * stride + xi;
        *patch_ptr = static_cast<uint8_t>(
            w00 * ptr[0] + w01 * ptr[stride] + w10 * ptr[1] + w11 * ptr[stride + 1]);
      }
    }
  }

  return true;
}

2. GetWarpMatrixAffine(计算 当前帧->参考帧 仿射变换矩阵)

2.1 函数功能

函数作用是计算从当前帧到参考帧的仿射变换矩阵,使得参考帧中的一个特征点在当前帧中的投影与当前帧中的相应补丁重合。

2.2 函数输入输出

输入:函数的输入包括参考帧和当前帧的相机参数、参考帧中的特征点、特征点的方向向量、特征点到参考帧相机的距离、当前帧和参考帧之间的位姿变换、参考帧的金字塔层级。
输出:一个指向输出仿射变换矩阵的指针。

2.3 算法步骤

函数的实施步骤如下:

  1. 根据特征点的方向向量和距离计算三维坐标;
  2. 在参考帧中沿着水平和垂直方向各移动半个补丁大小,将移动后的像素坐标反投影到三维空间中得到两个方向上的三维向量;
  3. 将三维向量变换到当前帧相机坐标系下,并将其投影到当前帧上得到三个像素坐标;
  4. 根据三个像素坐标计算仿射变换矩阵。

数学公式描述如下:

x r e f = f r e f d r e f x d u , r e f = J d u , r e f x r e f x d v , r e f = J d v , r e f x r e f x c u r = T c u r _ r e f x r e f x d u , c u r = T c u r _ r e f x d u , r e f x d v , c u r = T c u r _ r e f x d v , r e f A c u r _ r e f = [ x d u , c u r − x c u r k H a l f P a t c h S i z e x d v , c u r − x c u r k H a l f P a t c h S i z e ] \begin{aligned} \mathbf{x}_{ref} &= \mathbf{f}_{ref} d_{ref} \\ \mathbf{x}_{du,ref} &= \mathbf{J}_{du,ref} \mathbf{x}_{ref} \\ \mathbf{x}_{dv,ref} &= \mathbf{J}_{dv,ref} \mathbf{x}_{ref} \\ \mathbf{x}_{cur} &= T_{cur\_ref} \mathbf{x}_{ref} \\ \mathbf{x}_{du,cur} &= T_{cur\_ref} \mathbf{x}_{du,ref} \\ \mathbf{x}_{dv,cur} &= T_{cur\_ref} \mathbf{x}_{dv,ref} \\ \mathbf{A}_{cur\_ref} &= \begin{bmatrix}\frac{\mathbf{x}_{du,cur}-\mathbf{x}_{cur}}{kHalfPatchSize} & \frac{\mathbf{x}_{dv,cur}-\mathbf{x}_{cur}}{kHalfPatchSize}\end{bmatrix} \end{aligned} xrefxdu,refxdv,refxcurxdu,curxdv,curAcur_ref=frefdref=Jdu,refxref=Jdv,refxref=Tcur_refxref=Tcur_refxdu,ref=Tcur_refxdv,ref=[kHalfPatchSizexdu,curxcurkHalfPatchSizexdv,curxcur]

其中, f r e f \mathbf{f}_{ref} fref 表示特征点的方向向量, d r e f d_{ref} dref 表示特征点到参考帧相机的距离, x r e f \mathbf{x}_{ref} xref 表示特征点在参考帧相机坐标系下的三维坐标, x d u , r e f \mathbf{x}_{du,ref} xdu,ref x d v , r e f \mathbf{x}_{dv,ref} xdv,ref 表示在水平和垂直方向上移动半个补丁尺寸后在参考帧中的三维坐标, J d u , r e f \mathbf{J}_{du,ref} Jdu,ref J d v , r e f \mathbf{J}_{dv,ref} Jdv,ref 分别表示在水平和垂直方向上移动半个补丁尺寸后对应的像素坐标在参考帧相机坐标系下对应的三维向量, T c u r _ r e f T_{cur\_ref} Tcur_ref 表示当前帧到参考帧之间的位姿变换, x c u r \mathbf{x}_{cur} xcur x d u , c u r \mathbf{x}_{du,cur} xdu,cur x d v , c u r \mathbf{x}_{dv,cur} xdv,cur 分别表示将 x r e f \mathbf{x}_{ref} xref x d u , r e f \mathbf{x}_{du,ref} xdu,ref x d v , r e f \mathbf{x}_{dv,ref} xdv,ref 变换到当前帧相机坐标系下后得到的三维坐标, x d u , c u r − x c u r k H a l f P a t c h S i z e \frac{\mathbf{x}_{du,cur}-\mathbf{x}_{cur}}{kHalfPatchSize} kHalfPatchSizexdu,curxcur x d v , c u r − x c u r k H a l f P a t c h S i z e \frac{\mathbf{x}_{dv,cur}-\mathbf{x}_{cur}}{kHalfPatchSize} kHalfPatchSizexdv,curxcur 分别表示在水平和垂直方向上移动半个补丁尺寸后对应像素坐标在当前帧相机坐标系下对应的三维向量, A c u r _ r e f \mathbf{A}_{cur\_ref} Acur_ref 表示从当前帧到参考帧的仿射变换矩阵。

void GetWarpMatrixAffine(const CameraPtr& cam_ref, const CameraPtr& cam_cur,
    const Eigen::Ref<Keypoint>& px_ref, const Eigen::Ref<BearingVector>& f_ref,
    const double depth_ref, const Transformation& T_cur_ref, const int level_ref,
    AffineTransform* A_cur_ref) {
  CHECK_NOTNULL(A_cur_ref);

  // Compute affine warp matrix A_ref_cur
  const int kHalfPatchSize = 5;
  const Position xyz_ref = f_ref * depth_ref;
  Position xyz_du_ref, xyz_dv_ref;
  // NOTE: project3 has no guarantee that the returned vector is unit length
  // - for pinhole: z component is 1 (unit plane)
  // - for omnicam: norm is 1 (unit sphere)
  cam_ref->backProject3(
      px_ref + Eigen::Vector2d(kHalfPatchSize, 0) * (1 << level_ref), &xyz_du_ref);
  cam_ref->backProject3(
      px_ref + Eigen::Vector2d(0, kHalfPatchSize) * (1 << level_ref), &xyz_dv_ref);
  if (cam_ref->getType() == Camera::Type::kPinhole) {
    xyz_du_ref *= xyz_ref[2];
    xyz_dv_ref *= xyz_ref[2];
  } else {
    xyz_du_ref.normalize();
    xyz_dv_ref.normalize();
    xyz_du_ref *= depth_ref;
    xyz_dv_ref *= depth_ref;
  }

  Keypoint px_cur, px_du_cur, px_dv_cur;
  cam_cur->project3(T_cur_ref * xyz_ref, &px_cur);
  cam_cur->project3(T_cur_ref * xyz_du_ref, &px_du_cur);
  cam_cur->project3(T_cur_ref * xyz_dv_ref, &px_dv_cur);
  A_cur_ref->col(0) = (px_du_cur - px_cur) / kHalfPatchSize;
  A_cur_ref->col(1) = (px_dv_cur - px_cur) / kHalfPatchSize;
}



3. GetWarpMatrixAffine(计算 当前帧->参考帧 仿射变换矩阵)

3.1 函数功能

这个函数的作用是计算在哪个金字塔层级上搜索匹配点可以获得最佳性能

3.2 函数输入输出

输入:它的输入包括一个仿射变换矩阵和一个最大金字塔层级。
输出:输出为一个金字塔层级。

3.3 算法步骤

  1. 计算仿射变换矩阵的行列式D;
  2. 如果D大于3.0并且搜索层级小于最大金字塔层级,则将搜索层级加1,同时将D乘以0.25,直到D小于等于3.0或者搜索层级达到最大金字塔层级。

数学公式描述如下:

s e a r c h _ l e v e l = min ⁡ ( max ⁡ _ l e v e l , max ⁡ { n ∣ D ( A c u r _ r e f ) > 3. 0 n } ) search\_level = \min(\max\_level, \max\{n|D(A_{cur\_ref}) > 3.0^n\}) search_level=min(max_level,max{nD(Acur_ref)>3.0n})

其中, D ( A c u r _ r e f ) D(A_{cur\_ref}) D(Acur_ref) 表示仿射变换矩阵 A c u r _ r e f A_{cur\_ref} Acur_ref 的行列式。

这个函数的原理是根据仿射变换矩阵的不确定性来选择搜索的金字塔层级。当仿射变换矩阵越不确定时,需要在更高的金字塔层级上进行搜索,以获得更好的匹配性能。而当仿射变换矩阵越确定时,可以在更低的金字塔层级上进行搜索,以提高计算效率。


int GetBestSearchLevel(const AffineTransform& A_cur_ref, const int max_level) {
  // Compute patch level in other image
  int search_level = 0;
  double D = A_cur_ref.determinant();
  while (D > 3.0 && search_level < max_level) {
    search_level += 1;
    D *= 0.25;
  }
  return search_level;
}

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

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

相关文章

modbus TCP协议讲解及实操

具体讲解 前言正文modbus tcp主机请求数据基本讲解Modbus Poll工具简单使用讲解 modbus tcp从机响应数据Modbus Slave工具简单使用讲解 前言 关于modbus tcp从0到1的讲解&#xff0c;案例结合讲解&#xff0c;详细了解整个modbus的可以参考这个&#xff1a;详解Modbus通信协议…

【吃透网络安全】2023软考网络管理员考点网络安全(一)安全基础篇

涉及知识点 软考网络管理员&#xff0c;软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 后面还有更多续篇希望大家能给个赞哈&#xff0c;这边提供个快捷入口&#xff01; 第一节 网络管理员考点网络安全&#xff08;1&#…

【广州华锐互动】钢厂轧钢事故3D虚拟体验还原真实事故场景

由于钢厂生产过程中涉及到高温、高压、高负荷等危险因素&#xff0c;一旦出现操作不当、设备故障等问题&#xff0c;就可能导致严重的事故。因此&#xff0c;对于钢厂员工来说&#xff0c;接受事故教育、了解安全知识非常重要&#xff0c;可以提高他们的安全意识&#xff0c;避…

大数据行业对学历要求高么

《2020中国大数据产业发展白皮书》显示&#xff0c;2019年中国大数据产业规模达5397亿元&#xff0c;同比增长23.1%&#xff0c;随后稳定增长&#xff0c;预计到2022年将突破万亿元。 根据LinkedIn、赛迪智库、拉勾网等机构的统计结果&#xff0c;大数据时代下的数据人才总体缺…

【软考程序员学习笔记】——程序设计语言

目录 &#x1f34a;一、常见的程序设计语言 &#x1f34a;二、程序设计语言组成 &#x1f34a;三、后缀表达式 &#x1f34a;四、传值调用和传址调用 &#x1f34a;五、语言处理程序 &#x1f34a;六、解释程序 &#x1f34a;七、链接程序 &#x1f34a;八、编译程序 &…

国产替代FT232RL-USB到UART桥接控制器 GP232RNL

GP232RNL是一款高度集成的USB到UART桥接控制器&#xff0c;提供了一种简单的解决方案&#xff0c;可以使用最少的元器件和PCB空间&#xff0c;将RS232接口转换为USB接口。GP232RNL包括一个USB 2.0全速功能控制器、USB收发器、振荡器、EEPROM和带有完整的调制解调器控制信号的异…

Java GUI开发的几个小工具:apk/aab签名,验证签名,aab转apk

平时经常给apk/aab签名&#xff0c;验证签名&#xff0c;aab转apk等操作&#xff0c;每次输入命令行十分繁琐。于是利用JAVA GUI简单开发了几个jar包界面化工具&#xff0c;提供给大家一起使用。 工具功能JarSignerTool.jar为apk/aab签名ApkSignerTool.jar为apk签名AppSignVer…

Cloud Studio 浏览器插件来啦

当谈到Cloud Studio浏览器插件的优势时&#xff0c;最显著的就是它的便捷性。通过安装Cloud Studio浏览器插件&#xff0c;用户可以在浏览器中直接打开Cloud Studio的开发环境&#xff0c;无需切换到其他应用程序&#xff0c;从而提高了开发效率。 另一个优势是插件对于Github…

Logstash入门简介

目录 Logstash简介介绍用途部署安装测试配置详解输入过滤输出 读取自定义日志日志结构编写配置文件输出到Elasticsearch Logstash简介 介绍 Logstash是一个开源的服务器端数据处理管道&#xff0c;能够同时从多个来源采集数据&#xff0c;转换数据&#xff0c;然后将数据发送到…

了解一下EPC模式和它的优势

目录 什么是EPCEPC的优势有哪些&#xff1f;BT、BOT、EPC分别是什么模式&#xff1f;总结 什么是EPC EPC是Engineering&#xff08;工程&#xff09;&#xff1a;代表设计、采购和施工总承包。Procurement&#xff08;采购&#xff09;&#xff1a;代表采购和物资管理。Constru…

Stable Diffusion提示词总结

提示词基本语法 一、提示词类别 1、内容型提示词 人物及主体特征 服饰穿搭 white dress 发型发色 blonde hair&#xff0c;long hair 五官特征 small eye&#xff0c;big mouth 面部表情 smiling 肢体动作 stretching arms beautiful detailed eyes 美丽细致的眼睛 highl…

数字化如何推动快消品企业实现营销变革

近几年&#xff0c;不确定性在各行各业上演。尤其伴随新一代信息技术的快速发展&#xff0c;消费者的需求和购买渠道也在不断变化。这就要求企业需要通过对消费者潜在需求进行更加深度的挖掘&#xff0c;为消费者提供“更佳的体验”&#xff0c;从而释放消费能力。 在这样的大背…

HTTP协议中的GET和POST接口测试的区别

&#x1f482; 个人网站:【海拥】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 目录 前言HTTP协议基础GET请…

CVPR2023中的数据集工作(共46篇)

本文搜集了CVPR2023中所有的以数据集发布为主的工作&#xff0c;共搜集到46篇。所有标题都附带文章超链接&#xff0c;请君享用&#xff5e; An Image Quality Assessment Dataset for PortraitsLOGO: A Long-Form Video Dataset for Group Action Quality AssessmentTowards …

C++学习 数据类型

数据类型存在的意义&#xff1a; 给变量分配合适的内存空间&#xff0c;避免资源浪费。 整型&#xff1a; 整型变量表示的是整数类型的数据 long类型 在 windows 中4字节 linux 中 32位4字节 64位8字节&#xff0c;占用空间的不同&#xff0c;可以表示的取值范围就越广&…

hello TypeScript

在上一章节中我们介绍了typescript的产生背景&#xff0c;和使用typescript开发需要环境和工具&#xff0c;这一节我们就来感受一下typescript吧 一、第一个typescript程序&#xff0c;‘hello ts’ 1. 安装TypeScript编译器 在开始编译TypeScript文件之前&#xff0c;需要先…

LeetCode算法题---两数相加(二)

给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff0c;并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外&#xff0c;这两个数都不会以 0 …

Python嵌套列表处理「有问必答系列1」

1. 提问&#x1f64b; teacher&#xff0c;如果想把列表里的子列表&#xff0c;拆出来&#xff0c;让他们变成一个列表&#xff0c;可以用什么[可怜] 解答 如果你有一个列表包含子列表&#xff0c;你可以使用Python的extend()函数或列表推导式来实现。下面是两种方法的例子&a…

Dart 3.0 语法新特性 | switch 匹配加强

theme: cyanosis 一、 重新审视 switch 关键字 众所周知&#xff0c; switch 关键字用于流程控制&#xff1a; 可以基于一个对象进行匹配&#xff0c;并通过 case 关键字产生分支语句&#xff0c;进行不同的逻辑处理。其中有一个非常值得注意&#xff0c;使用者很容易忽略的一点…

Jetpack Compose —— ProgressBar

Jetpack Compose的ProgressBar是一种用户界面组件&#xff0c;用于向用户展示长时间操作的当前进度。ProgressBar可以有两种形式&#xff1a;线性和环形&#xff0c;这两种形式都可以通过Jetpack Compose轻松实现。 注意&#xff1a;从Jetpack Compose 1.0版本开始&#xff0c…