首页 新闻 会员 周边 捐助

Qt 中的vector类

0
悬赏园豆:100 [已解决问题] 解决于 2016-04-21 17:21

基于Qt框架在做双摄像头的立体视觉重建,程序在VS 2013的Win32 Console运行没有问题,我最近在移植到Qt中就有问题。先上一下相关部分的程序:

相关变量在MainWindow的私有员中定义

1 //初始化标定变量
2 cv::Mat cameraMatLeft, cameraMatRight, distCoeffLeft, \
3 distCoeffRight, R, T, R1, P1, R2, P2;
4 vector<cv::Mat> rvecs, tvecs; double rmsLeft, rmsRight, rmsStereo;
5 cv::Size boardSize, imageSize; vector<cv::Point3f> corners;
6 vector<vector<cv::Point2f>> imagePointsLeft, imagePointsRight;
7 vector<vector<cv::Point3f>> objectPoints;

 

然后是出问题的标定函数函数体部分:

 1 void MainWindow::calibrate(cv::Mat& cameraMat, cv::Mat& distCoeff, \
 2                            vector<vector<cv::Point2f>>& imagePoints,
 3                            const int nImages, const QStringList fileList,
 4                            double& rms)
 5 {
 6     cv::Mat view, viewGray;
 7     vector<cv::Point2f> pointBuf;
 8     for(int i = 0; i < nImages; i++)
 9     {
10         view = cv::imread(fileList.at(i).toStdString(), 1);
11         cv::cvtColor(view, viewGray, cv::COLOR_BGR2GRAY);
12         bool found = cv::findChessboardCorners(view, boardSize, pointBuf, \
13                                                CV_CALIB_CB_ADAPTIVE_THRESH | \
14                                                CV_CALIB_CB_FAST_CHECK | \
15                                                CV_CALIB_CB_NORMALIZE_IMAGE);
16         if(found)
17         {
18             cv::cornerSubPix(viewGray, pointBuf, cv::Size(11, 11), cv::Size(-1, -1), \
19                              cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
20             imagePoints.push_back(pointBuf);
21         }
22     }
23 
24     objectPoints.resize(imagePoints.size(), corners);
25     rms = cv::calibrateCamera(objectPoints, imagePoints, imageSize, cameraMat, \
26                               distCoeff, rvecs, tvecs);
27 }

标定函数的调用过程:

 1 corners.resize(1);
 2     for(int i = 0; i < w; i++)
 3     {
 4         for(int j = 0; j < h; j++)
 5         {
 6             corners.push_back(cv::Point3f(j*squareSize, i*squareSize, 0));
 7         }
 8     }
 9 
10     //标定
11     calibrate(cameraMatLeft, distCoeffLeft, imagePointsLeft, nLeftImages, \
12               leftFilelist, rmsLeft);

我调试发现是执行到这一步出了问题:

imagePoints.push_back(pointBuf);

然后执行到这一步显示这样的信息

然后程序跳到这里vector文件的这里

__declspec(noreturn) void _Xlen() const
    {    // report a length_error
    _Xlength_error("vector<T> too long");
    }

OS : win 10 64bit

Qt Vision: 5.6 + msvc 2012 32-bit

nano_zombie.uestc的主页 nano_zombie.uestc | 初学一级 | 园豆:113
提问于:2016-04-21 15:21
< >
分享
最佳答案
2

 

超过 vector 所能容纳元素的最大数目了。

收获园豆:100
Launcher | 高人七级 |园豆:45050 | 2016-04-21 15:49

循环的一开始就这样报错了,那个时候,vector为空啊。并且我这段程序在Win32 console中编译却没有问题。

nano_zombie.uestc | 园豆:113 (初学一级) | 2016-04-21 15:54

@nano_zombie.uestc: 你看下 imagePoints 的 size() 和 max_size()

Launcher | 园豆:45050 (高人七级) | 2016-04-21 16:00

@Launcher: imagePoints.size()=0; imagePoints.max_size()=268435455;

nano_zombie.uestc | 园豆:113 (初学一级) | 2016-04-21 16:23

@nano_zombie.uestc: 能多提供一点信息么?

异常从 _Xlen() 函数抛出,你看下调用堆栈,调用 _Xlen() 的函数是哪个?

Launcher | 园豆:45050 (高人七级) | 2016-04-21 16:25

@Launcher: 

调用堆栈如下,我自己分析不出来错误的原因

nano_zombie.uestc | 园豆:113 (初学一级) | 2016-04-21 16:36

@nano_zombie.uestc: 你双击 std::vector<cv:Point<float>>::_Buy 行,然后看看里面的语句中

else if (max_size() < _Capacity) 这一条语句的 max_size() 和 _Capacity 的值。

 

你这个错误是出现在 imagePoints.push_back(pointBuf); 语句中 pointBuf 的拷贝构造中.

Launcher | 园豆:45050 (高人七级) | 2016-04-21 16:44

@Launcher: _Capacity = 4289879494; 

pointBuf定义是这样的 vector<cv::Point2f> pointBuf; Point2f是OpenCV中的类。我并没有手动写任何构造和析构函数。

nano_zombie.uestc | 园豆:113 (初学一级) | 2016-04-21 16:51

@nano_zombie.uestc: 这个打不出表情符号真是郁闷。我还得给你讲 C++ 的基础知识。

imagePoints.push_back(pointBuf); 调用的是 void push_back(const value_type& _Val) 函数,根据语义,需要对 pointBuf 进行拷贝构造,而你的 pointBuf 是 vector<cv::Point2f> 类型的,那么它会先执行 vector(const _Myt& _Right),然后把你的 pointBuf 的所有数据拷贝到新创建的 vector<cv::Point2f> 对象中。所以我说的不是你的 Point2f 的拷贝构造,而是 vector<cv::Point2f> 的拷贝构造。

 

而且我们通常都不这么写,在 C++ 11 之前,我们先在 imagePoints 中增加一个 vector<cv::Point2f> 元素,然后引用该元素:

vector<cv::Point2f>& pointBuf = imagePoints[size() -1];

然后再调用 cv::cornerSubPix(...,pointBuf),这样减少一次对 pointBuf 的拷贝构造。

假设 pointBuf 占用 20M 空间,按照你原来的写法,你需要 40 M 空间完成此操作,而改用我提供给你的方法后,你只需要 20 M。

如果能使用 C++ 11 的话,可以利用右值语义优雅解决,其它代码逻辑都不用动,只是修改 push_back 语句为:

imagePoints.push_back(std::move(pointBuf));

Launcher | 园豆:45050 (高人七级) | 2016-04-21 17:04

@nano_zombie.uestc: _Capacity 的值是这么计算的:_Capacity = max_size() - _Capacity / 2 < _Capacity
   ? 0 : _Capacity + _Capacity / 2;

所以,通常 _Capacity 都会比 size() 大,也有可能比 max_size() 大,max_size() 的值是这么计算的:

((size_t)(-1) / sizeof (_Ty))。

由于你对一个元素数目(size())较大的 vector<_Ty> 执行拷贝构造,所以造成 max_size() < _Capacity,因此引发 _Xlen() 异常。

Launcher | 园豆:45050 (高人七级) | 2016-04-21 17:11

@Launcher: 嗯,由于并没有系统学过C++,我先消化下先,不过修改语句 magePoints.push_back(std::move(pointBuf)); 的确解决了问题。

多谢。

nano_zombie.uestc | 园豆:113 (初学一级) | 2016-04-21 17:20

@Launcher: 但是为什么我在Win32 Console中运行这段程序没有问题呢??这段程序我是参考opencv/samples中的示例程序写的。

nano_zombie.uestc | 园豆:113 (初学一级) | 2016-04-21 17:24

@nano_zombie.uestc: 有没有问题,你的看 max_size() 和 _Capacity 这两个值是多少。

Launcher | 园豆:45050 (高人七级) | 2016-04-21 17:26
其他回答(1)
0

你看一下imread执行时候view是否为空

灵枢 | 园豆:297 (菜鸟二级) | 2016-04-21 16:11

不为空,jpg文件读取正常。

支持(0) 反对(0) nano_zombie.uestc | 园豆:113 (初学一级) | 2016-04-21 16:13

@nano_zombie.uestc: 还是加一个imshow()看一下吧,在Win32 Console运行没问题,那vector这部分肯定没问题的,都是标准库的。

支持(0) 反对(0) 灵枢 | 园豆:297 (菜鸟二级) | 2016-04-21 16:19

@MissingAnObject: 我看了的,view和viewGray正常显示

支持(0) 反对(0) nano_zombie.uestc | 园豆:113 (初学一级) | 2016-04-21 16:22
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册