gaoxiang12 / slambook2

edition 2 of the slambook
MIT License
5.39k stars 2k forks source link

ch7 orb_self.cpp #243

Open crystalascii opened 2 years ago

crystalascii commented 2 years ago

系统使用配置情况: UBUNTU 18.04 OpenCV 3.1.0 Eigen 3.4.4 Cmake 3.24

运行ch7 orb_self 例程报错,报错信息如下: 段错误 (核心已转储)

跟踪代码,发现如下ComputeORB函数出错。跟踪进入函数,如下语句出错。 void ComputeORB(const cv::Mat &img, vector<cv::KeyPoint> &keypoints, vector<DescType> &descriptors) 跟踪进入函数,在如下语句之前添加打印消息,

        if (img.at<uchar>(pp.y, pp.x) < img.at<uchar>(qq.y, qq.x)) {
          d |= 1 << k;
        }   

        cout << "pp pos: " << pp.x << ", " << pp.y << endl;
        cout << "qq pos: " << qq.x << ", " << qq.y << endl;

输出结果: pp pos: 265.764, 13.7638 qq pos: 284.1, 10.6346 pp pos: 263.528, 11.5275 qq pos: 269.342, 13.3168 pp pos: 268.894, 20.9194 qq pos: 255.478, 11.9742 pp pos: 255.926, 11.0798 qq pos: 276.497, 19.1311 pp pos: 443.814, 7.93267 qq pos: 450.601, 12.2835 pp pos: 445.097, 14.206 qq pos: 436.258, 2.94193 pp pos: 440.877, 30.2121 qq pos: 437.418, 23.4274 pp pos: 436.258, 2.94193 qq pos: 438.689, -1.54023

显示qq.y坐标出现负值。导致img.at函数无法找到对应的item。 想问一下,是个人的电脑系统编译环境配置的问题,还是普遍存在的问题?谢谢~

tomgasper commented 2 years ago

It's because there's a problem with ORB Pattern: https://github.com/gaoxiang12/slambook2/issues/142 it will cause your operating area(where you compare intensity of random points in the rotated patch) to go out of bounds.

I think quick and "dirty" fix would be to slightly change the bounds here so the arguable keypoints will be filtred out: for (auto &kp: keypoints) { if (kp.pt.x < half_boundary || kp.pt.y < half_boundary || kp.pt.x >= img.cols - half_boundary || kp.pt.y >= img.rows - half_boundary) { // outside bad_points++; descriptors.push_back({}); continue; }

crystalascii commented 2 years ago

@tomgasper Thanks for your reply. I add some codes here in this function to fix this issue. It seems that works. How do you think about that?

void ComputeORB(const cv::Mat &img, vector<cv::KeyPoint> &keypoints, vector<DescType> &descriptors)

        if(pp.x < 0) pp.x = 0; else if(pp.x >= img.cols) pp.x = img.cols - 1;
        if(qq.x < 0) qq.x = 0; else if(qq.x >= img.cols) qq.x = img.cols - 1;
        if(pp.y < 0) pp.y = 0; else if(pp.y >= img.rows) pp.y = img.rows - 1;
        if(qq.y < 0) qq.y = 0; else if(qq.y >= img.rows) pp.y = img.rows - 1;

        if(img.at<uchar>(pp.y, pp.x) < img.at<uchar>(qq.y, qq.x)) {
          d |= 1 << k;
        }
tomgasper commented 2 years ago

Hmm not really because now you're choosing points that are not based on the rotated pattern.

I would add 7 to the "half_boundary" value in bad_points check, like this: for (auto &kp: keypoints) { if (kp.pt.x < half_boundary+7 || kp.pt.y < half_boundary+7 || kp.pt.x >= img.cols - (half_boundary+7) || kp.pt.y >= img.rows - (half_boundary+7)) { // outside bad_points++; descriptors.push_back({}); continue; }

crystalascii commented 2 years ago

Thank you, tomgasper! It's a good suggestion, but how can I decide what value to add, like you add 7 to the boundary?

tomgasper commented 2 years ago

out_of_bounds You have to take into account that worst case scenario when the patch is rotated 45 deg. To get the offset you could just use some basic trigonometry, something like this should work: const int patch_45_deg_offset = (int)ceil(sqrt(2)*half_boundary); and for half_boundary = 16 it's equal 23. Then subtract 16 from it and you get 7.

crystalascii commented 2 years ago

Aha!!! Thanks again for your detailed explanation, tomgasper. After you draw the schematic plot, I found that I can understand what you said now.