CVPR:A Two-point Method for PTZ Camera Calibration in Sports的C++程序分析(5)

CVPR:A Two-point Method for PTZ Camera Calibration in Sports的C++程序分析(5)

今天接着分析,函数preemptiveRANSACOneToMany()的step2,

来看这一段代码的含义,

            // count outliers as energy measurement
            for (int i = 0; i<hypotheses.size(); i++) {
                // check accuracy by project pan, tilt to image space
                vector<vector<Eigen::Vector2d> > projected_pan_tilt = projectPanTilt(hypotheses[i].ptz_, pp, sampled_pan_tilt);
                
                // check minimum distance from projected points to image coordinate
                for (int j = 0; j<projected_pan_tilt.size(); j++) { 

                     //.................  

                }
            } // end of i

在分析这段代码前,回想一下,一共进行了两次抽样操作,第一次抽样得到Hypotheses集,第二次抽样得到一个random set。第一个for语句容易理解,就是遍历整个Hypotheses集,那么函数projectPanTilt()是什么意思呢?来看一下

    // @brief project pan, tilt ray to image space
    static vector<vector<Eigen::Vector2d> > projectPanTilt(const Eigen::Vector3d& ptz,
                                                           const Eigen::Vector2d& pp,
                                                           const vector<vector<Eigen::Vector2d> > & input_pan_tilt)
    {
        vector<vector<Eigen::Vector2d> > image_pts(input_pan_tilt.size());
        for (int i = 0; i<input_pan_tilt.size(); i++) {
            for (int j = 0; j<input_pan_tilt[i].size(); j++) {
                Eigen::Vector2d point = cvx_pgl::panTilt2Point(pp, ptz, input_pan_tilt[i][j]);
                image_pts[i].push_back(point);
            }
        }
        return image_pts;
    }

这里又需要了解一下panTilt2Point的作用(如果看论文会好懂一些)

    Eigen::Vector2d panTilt2Point(const Eigen::Vector2d& pp,
                                  const Eigen::Vector3d& ptz,
                                  const Eigen::Vector2d& point_pan_tilt)
    {
        double delta_pan  = (point_pan_tilt[0] - ptz[0]) * M_PI/180.0;
        double delta_tilt = (point_pan_tilt[1] - ptz[1]) * M_PI/180.0;
        double fl = ptz[2];
        double delta_x = fl * tan(delta_pan);
        double delta_y = fl * tan(delta_tilt);
        
        Eigen::Vector2d point(pp.x() + delta_x, pp.y() - delta_y); // oppositive direction of y
        return point;
    }

那么,vector<vector<Eigen::Vector2d> > projected_pan_tilt = projectPanTilt (hypotheses[i].ptz_, pp, sampled_pan_tilt);是什么意思呢?对于一个假设hypotheses[i],怎样验证这个假设是好是坏呢?

于是,sampled_pan_tilt就派上用场了,相当于测试集的作用

(PS:关于sampled_pan_tilt还有几句话要说。首先,sampled_pan_tilt由candidate_pan_tilt组成。

 其次,candidate_pan_tilt是一个vector<vector<Eigen::Vector2d> >,即一帧图片有多个特征点,每个特征点又有多个预测值,再罗嗦一句,一帧图像特征点的数目等于candidate_pan_tilt的size() )

所以,hypotheses[i]作用在测试集sampled_pan_tilt上就得到一组结果projected_pan_tilt

那么,怎样根据hypotheses[i]作用的结果projected_pan_tilt来判断这个假设到底是好还是坏呢?

接着向下看,

  // check minimum distance from projected points to image coordinate
                for (int j = 0; j<projected_pan_tilt.size(); j++) {
                    double min_dis = threshold * 2;
                    int min_index = -1;
                    for (int k = 0; k<projected_pan_tilt[j].size(); k++) {
                        Eigen::Vector2d dif = sampled_image_pts[j] - projected_pan_tilt[j][k];
                        double dis = dif.norm();
                        if (dis < min_dis) {
                            min_dis = dis;
                            min_index = k;
                        }
                    } // end of k
                    
                    if (min_dis > threshold) {
                        hypotheses[i].loss_ += 1.0;
                    }
                    else {
                        hypotheses[i].inlier_indices_.push_back(sampled_indices[j]);
                        hypotheses[i].inlier_candidate_pan_tilt_indices_.push_back(min_index);
                    }
                } // end of j

其中,sampled_image_pts[j]指这一帧图像第j个特征点的像素坐标,那么double型变量dis就是重投影误差。最后两行代码是什么意思呢?(把最后两行代码弄懂有助于理解上面这一段代码,哈哈)

                        hypotheses[i].inlier_indices_.push_back(sampled_indices[j]);
                        hypotheses[i].inlier_candidate_pan_tilt_indices_.push_back(min_index);

hypotheses[i]作用在这帧图像的第j个特征点上。第j个特征点有M个预测值,其中第m个预测值与hypotheses[i]作用得到的第j个特征点的像素坐标。用这个估计的像素坐标减去这个点真实的像素坐标得到重投影误差。假设第m个预测值算得的重投影误差最小,那么min_index等于m

总之,上面的两个for语句,迭代变量 i 遍历hypotheses,迭代变量 j 遍历特征点

那么就接着向下看吧,

            // remove half of the hypotheses
            std::sort(hypotheses.begin(), hypotheses.end());
            hypotheses.resize(hypotheses.size()/2);

看注释不难发现,这是要删除一半的假设集。一开始假设集有1024个,一次大循环后剩下512,第二次后剩下256,如此反复,最后只剩下1个,RANSAC做的就是这样的事情

可是,Hypotheses是一个类,这个类中定义了“大于”或者“小于”的符号吗?(不然没法使用sort)

这个是有的,

            bool operator < (const Hypothesis & other) const
            {
                return loss_ < other.loss_;
            }

可是loss指什么呢?在之前的讨论中,可以发现一个细节,就是

                    if (min_dis > threshold) {
                        hypotheses[i].loss_ += 1.0;
                    }
                    else {
                        hypotheses[i].inlier_indices_.push_back(sampled_indices[j]);
                        hypotheses[i].inlier_candidate_pan_tilt_indices_.push_back(min_index);
                    }

如果min_dis > threshold,那么就没有hypotheses[i]的赋值操作,相反,不但没有赋值,反而hypotheses[i]的loss变量加1。这是惩罚的意思。比如,按时完成作业,就会把你添加在“三好学生”候选名单里,如果没有写作业,就给你扣5分,大概就是这个意思。一个学期下来,有的学生是100分,有的学生十次没交作业,就只有50分。这个班假设只有一半的人可以评为少先队员,于是就用sort函数给全班排序,选一半的人出来。

假设集舍弃一半之后,还有一些操作,

            // refine by inliers
            for (int i = 0; i<hypotheses.size(); i++) {

                      //......................

            }

下次再来看这个循环的第一部分,哈哈 :)






























  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值