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

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

接下来要分析一个循环。所谓的sample.size()指的是这一帧图像中的特征点大小

        // predict from observation (descriptors)
        double tt = clock();
        for (int j = 0; j<samples.size(); j++) { // }

来看循环的第一个部分,

            btdtr_ptz_util::PTZSample s = samples[j];
            Eigen::VectorXf feat = s.descriptor_;
            vector<Eigen::VectorXf> cur_predictions;
            vector<float> cur_dists;
            model.predict(feat, max_check, maxTreeNum, cur_predictions, cur_dists);
            assert(cur_predictions.size() == cur_dists.size());

这一块代码容易理解,对这一帧图像的每一个特征点进行随机森林预测,预测结果放在cur_prediction中,预测偏差存放在cur_dists中。之前提及过,随机森林的预测值有多个,那么预测偏差也会有多个。例如这个特征点用随机森林预测可以得到8个结果,那么就有8个预测偏差(至于这个预测偏差是怎么定义的,还不清楚,但是应该不是和真值比较。)

这个循环的后一部分是,

            //cout<<"minimum feature distance "<<cur_dists[0]<<endl;
            if (cur_dists[0] < distance_threshold) {
                image_points.push_back(Eigen::Vector2d(s.loc_.x(), s.loc_.y()));
                vector<Eigen::Vector2d> cur_candidate;
                for (int k = 0; k<cur_predictions.size(); k++) {
                    assert(cur_predictions[k].size() == 2);
                    if (cur_dists[k] < distance_threshold) {
                        cur_candidate.push_back(Eigen::Vector2d(cur_predictions[k][0], cur_predictions[k][1]));
                    }
                }
                candidate_pan_tilt.push_back(cur_candidate);
            }

如果预测偏差小于阈值,那么认定这个特征点是正常的,把它存入image_points中。接着刚才的例子,如果8个特征点只有5个的预测偏差小于阈值,那么cur_candidate只记录那5个预测值。

分析完这个循环,接着向下走,

        // estimate camera pose
        bool is_opt = ptz_pose_opt::preemptiveRANSACOneToMany(image_points, candidate_pan_tilt, pp,
                                                param, estimated_ptz, false);
        printf("Prediction and camera pose estimation cost time: %f seconds.\n", (clock() - tt)/CLOCKS_PER_SEC);
        if (is_opt) {
            cout<<"ptz estimation error: "<<(ptz_gt - estimated_ptz).transpose()<<endl;
        }
        else {
            printf("-------------------------------------------- Optimize PTZ failed.\n");
            printf("valid feature number is %lu\n\n", image_points.size());
        }
        gt_ptz_all.row(index) = ptz_gt;
        estimated_ptz_all.row(index) = estimated_ptz;
        index++;

看到这行注释,就会明白下面的代码开始估计相机的pan角和tilt角啦。程序运行时间和结果输出的代码不必细说。主要分析函数preemptiveRANSACOneToMany()的作用。根据这个函数前面的定义域,可以迅速地找打它的源文件ptz_pose_estimation.cpp。这个源文件定义了一个类,叫做Hypothesis。

因此,在分析preemptiveRANSACOneToMany之前,必须分析类Hypothesis。先看类Hypothesis的成员变量,

        struct Hypothesis
        {
            double loss_;
            Eigen::Vector3d ptz_;
            vector<int> inlier_indices_;         // image coordinate index
            vector<int> inlier_candidate_pan_tilt_indices_; // camera coordinate pan tilt index
            
            // store all inliers from preemptive ransac
            vector<Eigen::Vector2d> image_pts_;
            vector<Eigen::Vector2d> camera_pan_tilt_;
            
                   //ignore functions..... 
          }

看注释,index的意思应该不会陌生。这段变量初始化的含义是给特征点和候选PT角分别建立索引。具体地讲,比如有5个特征点,inlier_indices_=1,2,3,4,5,对应这它的像素位置坐标。loss_指误差。

看完类Hypothesis的成员变量,再来看它的成员函数,

            Hypothesis()
            {
                loss_ = INT_MAX;
            }
            
            Hypothesis(double loss)
            {
                loss_  = loss;
            }
            
            Hypothesis(const Hypothesis& other)
            {
                if (&other == this) {
                    return;
                }
                loss_ = other.loss_;
                ptz_ = other.ptz_;
                inlier_indices_ = other.inlier_indices_;
                inlier_candidate_pan_tilt_indices_ = other.inlier_candidate_pan_tilt_indices_;
                image_pts_ = other.image_pts_;
                camera_pan_tilt_ = other.camera_pan_tilt_;
            }
            
            Hypothesis & operator = (const Hypothesis & other)
            {
                if (&other == this) {
                    return *this;
                }
                loss_ = other.loss_;
                ptz_ = other.ptz_;
                inlier_indices_ = other.inlier_indices_;
                inlier_candidate_pan_tilt_indices_ = other.inlier_candidate_pan_tilt_indices_;
                image_pts_ = other.image_pts_;
                camera_pan_tilt_ = other.camera_pan_tilt_;
                
                return *this;
            }
            
            bool operator < (const Hypothesis & other) const
            {
                return loss_ < other.loss_;
            }

类Hypothesis中的函数Hypothesis()重载了两次,而后又重载定义了运算符号“=”和“+”。这是可以学习的。

类Hypothesis讲完之后,还得再讲一个辅助函数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()

那下回再作分析!



















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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值