你不知道的Bundle

Bundle基本概念

     在Android中,Bundle主要用于传递数据,它是以键值对的形式保存数据。我们经常使用Bundle在Activity之间传递数据,数据类型可以是基本类型或它们对应的数组,也可以是对象或对象数组。当Bundle传递的是对象或对象数组时,必须实现Serializable或Parcelable接口。

     根据Android的设计,同一应用的Activity可能会运行在不同进程中,所以处理数据传递时可能就会出现跨进程的情况。那么如何在进程间传递对象呢?在Android中是通过Binder来实现进程间通信的。Parcel是一个存放读取数据的容器,Android系统中的Binder通信就使用了Parcel类来进行客户端与服务端数据的交互,而且AIDL的数据也是通过Parcel来交互的。在Java空间和C++都实现了Parcel,由于它在C/C++中,直接使用了内存来读取数据,因此它更有效率。

Bundle数据传输异常

     Bundle的使用并不是我们看到的那么简单,我们在使用Bundle时会存在一些限制。下面就通过一个例子来演示这个问题。

 

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bundle bundle = new Bundle();
                int[] array = new int[1024 * 1024];
                bundle.putIntArray("array", array);
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                intent.putExtras(bundle);
                startActivity(intent);
            }
        });
    }
}

 

     上面的例子中,我们通过Bundle传递数据给SecondActivity。由于传递的是整型数组,总共传递了4MB的数据到SecondActivity。运行程序后发现SecondActivity并没有启动,日志中出现了一个错误:

 

com.viclee.myapplication E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!

     从内容可以看出这个异常与Binder有关,产生这个异常的原因是由于系统对使用Binder交换数据的buffer大小进行了限制,大小为1M。
     那么,假如把传递的数据量减少,比如传输数据量减少为512kB,是否可以安全的传递数据呢?
     再次运行程序我们发现程序发生了异常,这一次的异常内容如下:

 

F/ActivityManager( 1068): android.os.TransactionTooLargeException
F/ActivityManager( 1068): at android.os.BinderProxy.transactNative(Native Method)
F/ActivityManager( 1068): at android.os.BinderProxy.transact(Binder.java:504)
F/ActivityManager( 1068): at android.app.ApplicationThreadProxy.scheduleLaunchActivity(ApplicationThreadNative.java:808)
F/ActivityManager( 1068): at com.android.server.am.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1297)
F/ActivityManager( 1068): at com.android.server.am.ActivityStackSupervisor.attachApplicationLocked(ActivityStackSupervisor.java:632)
F/ActivityManager( 1068): at com.android.server.am.ActivityManagerService.attachApplicationLocked(ActivityManagerService.java:6572)
F/ActivityManager( 1068): at com.android.server.am.ActivityManagerService.attachApplication(ActivityManagerService.java:6637)
F/ActivityManager( 1068): at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:491)
F/ActivityManager( 1068): at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2502)
F/ActivityManager( 1068): at com.android.server.am.HwActivityManagerService.onTransact(HwActivityManagerService.java:232)
F/ActivityManager( 1068): at android.os.Binder.execTransact(Binder.java:454)

     这次又是因为什么呢?网上有人说这是由于整个应用共享了Binder用来进行数据交换的buffer。因此,我们通过Bundle在Activity之间传递的数据大小比1M还要小。

 

     至于说如何避免这个问题,我们尽量不要在intent中直接传递较大的数据,如果有这种需求,可以考虑静态传递,比如文件或共享内存。

 

Bundle原理分析

     通过查看Bundle的源码,我们发现Bundle内部是由ArrayMap实现的,而不是HashMap。Android为什么要这么设计呢?

 

     首先看一下它们的实现。

 

     ArrayMap内部是使用两个数组进行数据存储,一个数组记录key的hash值,另一个数组记录value值,内部使用二分法对key进行排序,并使用二分法进行添加、删除、查找数据,因此它只适合于小数据量操作,在数据量较大的情况下它的性能将会退化。而HashMap内部则是数组+链表的结构,在数据量较少的情况下,HashMap的Entry Array比ArrayMap占用更多的内存。

      由于使用Bundle的场景大多数为小数据量,所以相比之下,使用ArrayMap保存数据在操作速度和内存占用上都具有优势,因此使用Bundle来传递数据,可以保证更快的速度和更少的内存占用。

       欢迎关注我的公众号一起交流学习

     

<think>嗯,我现在需要理解什么是Bundle Adjustment(BA)以及它在计算机视觉中的优化技术。首先,我听说过BA在三维重建和SLAM(同步定位与地图构建)中很重要,但具体细节是很清楚。让我先回忆一下之前学过的相关知识。 BA可能和相机参数、三维点坐标的优化有关吧?记得在视觉SLAM中,通过多张图像中的特征点匹配来估计相机的位置和场景结构,但可能会有累积误差,这时候可能需要BA来优化这些估计。那BA具体是怎么工作的呢?是是一种优化算法,比如最小化重投影误差? 重投影误差应该是指将三维点投影到图像平面上的预测位置与实际检测到的特征点位置之间的差异。BA的目标就是调整相机参数和三维点的位置,使得所有点的重投影误差总和最小。这应该是一个非线性最小二乘问题,可能需要用高斯-牛顿法或者列文伯格-马夸尔特算法来求解。 那具体实现时,需要考虑哪些参数呢?每个相机的位姿(旋转和平移)、内参(焦距、主点等),还有每个三维点的坐标。这些参数都是需要优化的变量。当变量很多的时候,计算量会很大,这时候可能需要利用稀疏性来加速计算,比如使用稀疏矩阵的分解方法。 我还记得BA通常是在SFM(结构光运动恢复结构)或者SLAM的后端优化中使用。例如,在ORB-SLAM中,局部建图和闭环检测时都会用到BA来优化地图和相机轨迹。这应该能提高整个系统的精度,减少漂移误差。 另外,BA的实现可能涉及到雅可比矩阵的计算,因为优化算法需要知道每个参数对误差的影响程度。雅可比矩阵可能会很大,但由于每个观测只涉及少数参数(比如一个三维点和两个相机位姿),所以矩阵应该是稀疏的。利用这种稀疏结构可以显著提高计算效率。 过,我有点确定BA的具体数学表达是怎样的。比如,重投影误差是如何公式化的?假设有一个三维点$P_j$在相机位姿$T_i$下的投影是$p_{ij}$,而实际检测到的点是$q_{ij}$,那么误差应该是$||p_{ij} - q_{ij}||^2$。所有这样的误差加起来就是目标函数,需要最小化这个总误差。 BA的优化变量包括所有的相机位姿参数和三维点坐标。如果用李代数表示相机的旋转,可能会更方便计算导数。此外,可能还要处理同的参数化方式,比如使用四元数还是旋转矩阵,或者是否固定某些参数(比如内参是否已知)。 实现BA的时候,可能需要使用现有的库,比如ceres-solver或者g2o,这些库提供了非线性优化的框架,用户只需要定义误差函数和雅可比矩阵的计算方式。这样就能高效地处理大规模的问题。 过,关于稀疏BA的实现,可能还有更高效的方法,比如使用舒尔补来分解问题,先求解相机参数,再求解三维点参数,或者交替优化。这可能会减少计算量,因为三维点的数量通常远多于相机位姿的数量,分解后的问题规模更小。 另外,增量式BA可能也是一种优化策略,当新增相机或三维点时,只对相关部分进行优化,而是重新计算全部参数。这在实时系统中可能很有用,比如SLAM的在线建图过程。 但是,BA的计算复杂度很高,当数据量很大时,可能需要分布式计算或者使用GPU加速。这在实际应用中是一个挑战,尤其是对于需要实时处理的系统。 总结一下,Bundle Adjustment是一个通过优化相机参数和三维点坐标来最小化重投影误差的过程,属于非线性最小二乘问题,常用高斯-牛顿或LM算法求解,并利用稀疏性加速计算。在实现时需要考虑参数化、雅可比矩阵计算、稀疏求解以及高效优化库的使用。</think>### Bundle Adjustment 概念与实现方法 Bundle Adjustment(光束法平差)是计算机视觉中用于同时优化三维点坐标和相机参数的优化技术,其核心目标是最小化**重投影误差**,即三维点在图像平面上的投影位置与实际观测特征点位置之间的差异[^1]。以下是其关点: --- #### **数学原理** 1. **重投影误差定义** 对于三维点$P_j$在相机$i$的位姿$T_i$下投影到图像坐标为$p_{ij}$,而实际观测为$q_{ij}$,则误差为: $$ e_{ij} = ||\pi(T_i, P_j) - q_{ij}||^2 $$ 其中$\pi(\cdot)$为投影函数,包含相机内参(如焦距$f$、主点$(c_x, c_y)$)和畸变参数。 2. **目标函数** 最小化所有观测的总误差: $$ \min_{\{T_i\}, \{P_j\}} \sum_{i,j} \rho\left( e_{ij}^\top \Sigma_{ij}^{-1} e_{ij} \right) $$ 其中$\rho$为鲁棒核函数(如Huber函数),$\Sigma_{ij}$为协方差矩阵。 --- #### **实现步骤** 1. **参数化** - 相机位姿:使用李代数$\mathfrak{se}(3)$或四元数+平移向量表示,避免万向节锁。 - 三维点:齐次坐标或非齐次坐标。 - 内参:可固定(已知标定)或参与优化。 2. **稀疏性与雅可比矩阵** - 每个观测仅关联一个相机和一个三维点,导致雅可比矩阵高度稀疏。 - 利用稀疏性加速求解(如Schur补消元法)[^3]。 3. **优化算法** - **列文伯格-马夸尔特(LM)算法**:结合高斯-牛顿法和梯度下降,动态调整步长。 - **高斯-牛顿法**:二阶近似,适用于局部优化。 ```python # 伪代码示例:使用Ceres Solver库 problem = ceres.Problem() for each observation (i,j): cost_function = ceres.AutoDiffCostFunction(ReprojectionError, 2, 6, 3) problem.AddResidualBlock(cost_function, None, pose_i, point_j) options = ceres.SolverOptions() ceres.Solve(options, problem, summary) ``` --- #### **应用与优化** 1. **应用场景** - **SLAM**:闭环检测后全局优化位姿与地图[^2]。 - **SfM**:多视图三维重建中优化稀疏点云。 - **相机标定**:联合优化内参和外参。 2. **加速技术** - **增量式BA**:仅优化新增变量(如iSAM2)。 - **关帧选择**:减少冗余观测。 - **GPU并行化**:加速雅可比矩阵计算。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值