OpenCV 向量访问错误

Posted

技术标签:

【中文标题】OpenCV 向量访问错误【英文标题】:OpenCV vector access error 【发布时间】:2011-01-19 20:34:41 【问题描述】:

我正在使用来自 FingertipTuio3D 项目的代码

std::vector<cv::Point2i> detectFingertips(cv::Mat1f z, float zMin = 0.0f, float zMax = 0.75f, cv::Mat1f& debugFrame = cv::Mat1f()) 
    using namespace cv;
    using namespace std;    
    bool debug = !debugFrame.empty();

    vector<Point2i> fingerTips;

    Mat handMask = z < zMax & z > zMin;

    std::vector<std::vector<cv::Point>> contours;
    findContours(handMask.clone(), contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); // we are cloning here since method will destruct the image

    if (contours.size()) 
        for (int i=0; i<contours.size(); i++) 
            vector<Point> contour = contours[i];
            Mat contourMat = Mat(contour);
            double area = cv::contourArea(contourMat);

            if (area > 3000)   // possible hand
                Scalar center = mean(contourMat);
                Point centerPoint = Point(center.val[0], center.val[1]);

                vector<Point> approxCurve;
                cv::approxPolyDP(contourMat, approxCurve, 20, true);

                vector<int> hull;
                cv::convexHull(Mat(approxCurve), hull);

                // find upper and lower bounds of the hand and define cutoff threshold (don't consider lower vertices as fingers)
                int upper = 640, lower = 0;
                for (int j=0; j<hull.size(); j++) 
                    int idx = hull[j]; // corner index
                    if (approxCurve[idx].y < upper) upper = approxCurve[idx].y;
                    if (approxCurve[idx].y > lower) lower = approxCurve[idx].y;
                
                float cutoff = lower - (lower - upper) * 0.1f;

                // find interior angles of hull corners
                for (int j=0; j<hull.size(); j++) 
                    int idx = hull[j]; // corner index
                    int pdx = idx == 0 ? approxCurve.size() - 1 : idx - 1; //  predecessor of idx
                    int sdx = idx == approxCurve.size() - 1 ? 0 : idx + 1; // successor of idx

                    Point v1 = approxCurve[sdx] - approxCurve[idx];
                    Point v2 = approxCurve[pdx] - approxCurve[idx];

                    float angle = acos( (v1.x*v2.x + v1.y*v2.y) / (norm(v1) * norm(v2)) );

                    // low interior angle + within upper 90% of region -> we got a finger
                    if (angle < 1 && approxCurve[idx].y < cutoff) 
                        int u = approxCurve[idx].x;
                        int v = approxCurve[idx].y;

                        fingerTips.push_back(Point2i(u,v));

                        if (debug) 
                            cv::circle(debugFrame, approxCurve[idx], 10, Scalar(1), -1);
                        
                    
                

                if (debug) 
                    // draw cutoff threshold
                    cv::line(debugFrame, Point(center.val[0]-100, cutoff), Point(center.val[0]+100, cutoff), Scalar(1.0f));

                    // draw approxCurve
                    for (int j=0; j<approxCurve.size(); j++) 
                        cv::circle(debugFrame, approxCurve[j], 10, Scalar(1.0f));
                        if (j != 0) 
                            cv::line(debugFrame, approxCurve[j], approxCurve[j-1], Scalar(1.0f));
                         else 
                            cv::line(debugFrame, approxCurve[0], approxCurve[approxCurve.size()-1], Scalar(1.0f));
                        
                    

                    // draw approxCurve hull
                    for (int j=0; j<hull.size(); j++) 
                        cv::circle(debugFrame, approxCurve[hull[j]], 10, Scalar(1.0f), 3);
                        if(j == 0) 
                            cv::line(debugFrame, approxCurve[hull[j]], approxCurve[hull[hull.size()-1]], Scalar(1.0f));
                         else 
                            cv::line(debugFrame, approxCurve[hull[j]], approxCurve[hull[j-1]], Scalar(1.0f));
                        
                    
                
            
        
    

    return fingerTips;

当代码到达这一点 vector&lt;Point&gt; contour = contours[i]; 时,它会因 AccessViolation 失败:

在 0x00b85039 处未处理的异常 指尖Tuio3d.exe:0xC0000005: 访问冲突读取位置 0x00000008.

该位置在 std::vector 的 size_type size() const 函数中。

知道是什么导致了问题,以及如何解决?

【问题讨论】:

findContours的原型是什么? CV_EXPORTS void findContours( Mat&amp; image, vector&lt;vector&lt;Point&gt; &gt;&amp; contours, int mode, int method, Point offset=Point()); 嗯,假设成立。 复制时是否要复制向量:vector contour = contours[i]; ?我建议这样尝试:vector &contour = contours[i];这样您就不会对数据进行任何不必要的复制,因为您似乎只是想访问它。还有,调用函数时克隆handMask有什么意义? 这不是我的代码,我正在尝试修改别人的但我不完全理解。 【参考方案1】:

您的 findContours 实际上是否在每个轮廓中添加了任何内容?

您正在检查数组是否存在,但不是各个元素有效

【讨论】:

我实际上无法访问轮廓向量内的向量内的任何数据。任何访问它们的尝试都会导致访问冲突。 在调试器中能不能在函数调用后查看contours[]的每个元素? 没有。抱怨未知运营商或歧义 那么 findContours 正在做一些非常糟糕的事情。走进去看看是什么!【参考方案2】:

您可以通过迭代器访问元素吗? IOW,如果你在调用loadContours 之后立即添加以下代码,你会得到什么输出?

int i = 0;
for (std::vector<std::vector<cv::Point> >::iterator it = contours.begin();
     it != contours.end();
     ++it)

  std::cout << "contours[" << i << "].size() == " << it->size() << std::endl;

【讨论】:

【参考方案3】:

因为 contours 是向量的向量 (std::vector> contours;)

而轮廓是点的向量(向量轮廓)

所以它不能做向量轮廓=轮廓[i];

如果要复制轮廓[i],则需要获取另一个向量向量。

【讨论】:

【参考方案4】:

这是构建链接错误。看看这个:

--#ifdef _DEBUG 
--#pragma comment(lib,"opencv_core249d.lib")
--#else
--#pragma comment(lib,"opencv_core249.lib")    <<---- your checked!!
--#endif  

:-)

【讨论】:

这是无关的,不是答案。请删除它,然后自己开始提问。

以上是关于OpenCV 向量访问错误的主要内容,如果未能解决你的问题,请参考以下文章

Malloc 错误:OpenCV/C++ 而 push_back 向量

错误的梯度向量场OpenCV C++

c++和opencv中的向量下标超出范围错误

opencv“向量迭代器不兼容”

在 OpenCV 中使用 PCA 进行降维,特征向量的维数错误

(opencv) 调试断言失败,向量下标超出范围