OpenCV 尝试分配 10 艾字节

OpenCV tries to allocate 10 Exabyte

我有一个程序正在使用 opencv。 opencv 部分没什么特别的, 它只是从网络摄像头接收图像,在其中找到一些标记并估计它们的姿势。 但是,我可靠地收到错误

OpenCV Error: Insufficient memory (Failed to allocate 9892156749154358672 bytes) in OutOfMemoryError, file /home/XYZ/opencv/modules/core/src/alloc.cpp, line 52

这几乎是 10 艾字节,我非常怀疑我在做任何如此大的事情,即使它耗尽内存并试图通过重新分配将其加倍。我还注意到:

我之前有过同样的错误,但在我评论了 3 行代码后它莫名其妙地消失了,基本上(在不依赖于 opencv 的程序代码中):

std::cout << "This is an int: " << something->getInt() << std::endl;

所以和opencv一点关系都没有。因为这发生了,并且在评论这些行后错误消失了,我现在真的很困惑是什么原因造成的。我觉得我的任何一行代码都可能是原因,但我无法识别。这就是为什么不能为您提供一个最小的例子来重现这一点。 我现在将向您展示一段实际使用 opencv 执行某些操作的代码;我删除了进行标记跟踪的部分,假设这里的所有内容都已定义:

int PoseEstimator::trackMarkers(bool estimatePose, int camId, string camParams)
{       
    cv::VideoCapture inputVideo;
    int waitTime = 10;
    inputVideo.open(camId);

    cv::Mat inputImage, inputImageCopy; 
    inputVideo >> inputImage;

    iThreshParam1 = markerDetector.getParams()._thresParam1;
    iThreshParam2 = markerDetector.getParams()._thresParam2;
    cv::namedWindow("threshold");
    cv::createTrackbar("ThresParam1", "threshold", &iThreshParam1, 25, callTrackBarCallback, (void*) &iThreshParam1);
    cv::createTrackbar("ThresParam2", "threshold", &iThreshParam2, 13, callTrackBarCallback, (void*) &iThreshParam2);

      do {
        inputVideo.retrieve(inputImage);
        //This is 620x480, not gigantic

        inputImage.copyTo(inputImageCopy);

        for(unsigned int i = 0; i < markers.size(); i++)
        {
            //Code to track the markers with arucuo library            

            cv::Mat transformMatrix = markerTracker[id].getRTMatrix();
            //This is only a 4x4 matrix



        }

        cv::imshow("input", inputImageCopy);
        cv::imshow("threshold", markerDetector.getThresholdedImage());
        inputImageCopy.release();
        inputImage.release();


        key = cv::waitKey(waitTime);
        if(key == 's')
            waitTime = waitTime == 0 ? 10:0;



    } while (key != 27 && (inputVideo.grab()));

    return 0;
}

我认为整个循环应该为每次交互分配大约 2*620*480+4*4*markerCount 位,并且在每次新迭代时释放内存。我不认为这可能是原因,但有没有其他人知道或经历过这种情况?

感谢任何提示!如果需要,我很乐意为您提供更多详细信息。

编辑:我最接近的缩小范围: 我是 运行 使用 boost::async 的东西。

这是错误发生前立即执行的代码:

bool MarkerTracker::doSomething()
{

    boost::unique_future<bool> future = boost::async(boost::launch::async,[this]()
    {

            bool planAgain = true;
            bool success;
            int c = 0;
            int planLimit = 1;
            double totalPlanningTime = 0.0;
            auto startTotal = std::chrono::system_clock::now();
            while(planAgain && c < planLimit && (printf("DEBUG loop\n") || true))
            {

                TrajectoryPlanner planner = TrajectoryPlanner(GetEnv());                    
                std::cout << "planning now " << std::endl;
                auto start = std::chrono::system_clock::now();
                success = planner.plan();
                std::chrono::duration<double> diff = std::chrono::system_clock::now() - start;
                totalPlanningTime += diff.count();


                if(success)
                {
                    planAgain = !robotController->receiveFoundPath(planner.getLastSuccessfullPath());
                    std::cout << "DEBUG sent Path" << std::endl;
                } else
                {
                    planAgain = false;
                }
                c++;
            }


            std::cout << "DEBUG final steps" << std::endl;
            std::chrono::duration<double> diffTotal = std::chrono::system_clock::now() - startTotal;
            std::cout << "DEBUG got time" << std::endl;


            std::cout << std::endl << std::endl << "Planned " << c << " times." << std::endl << std::endl ;



            return success && !planAgain;
        }
    });

    return future.get();


}

那么最后打印的是什么? "DEBUG sent Path" 是我最后看到的东西。我相信代码的下一步将是循环条件的评估(编辑:最后的增量执行没有问题)。然而,"DEBUG loop" 语句没有被打印出来(也许编译器优化了它?但它不应该因为它不知道 printf 不会有任何副作用)。 我非常怀疑比较 int 和 bool 会导致分配 10 艾字节。无论如何,该语句的计算结果应该为 false,因此应该打印 "DEBUG final steps",但事实并非如此。

指针在 C++ 中不会自动初始化为 0。 TrajectoryPlanner 对象的析构函数类似于

DebugDrawer *debugDrawer;

TrajectoryPlanner::~TrajectoryPlanner()
{
    if(debugDrawer)
    {
        delete debugDrawer;
    }
}

但是,指针从未被初始化,因此指针被设置为内存中的随机字节。由于 C++ 将非零整数计算为真,因此进行了删除调用。 (参见 Why aren't pointers initialized with NULL by default?

这导致对来自另一个库的 DebugDrawer 析构函数内部的 cv::Mat 的释放调用,因此我不需要再次 link OpenCV 来使用它。显然,首先尝试释放不属于自己的内存会导致此分配请求。