【问题标题】:Loop through captured images vector<cv::Mat>遍历捕获的图像 vector<cv::Mat>
【发布时间】:2018-06-10 15:48:38
【问题描述】:

我有一个奇怪的问题。 我正在通过网络摄像头和 OpenCV 拍摄一组连续事件的照片。将它们存储在向量变量中。在捕获功能结束时,我得到的只是最后一次捕获。

我认为我对向量有一个基本问题。功能如下

void eventCapture()
{
    vector<cv::Mat> capturedAll;
    getCaptures(capturedAll, 10, 500);

    int csize = capturedAll.size();
    // Here gives always the last capture
    // It is not related with imshow
    // imwrite also saves the last capture as wrong
    for (int i = 0; i < 10; i++) {
        cv::imshow("Images", capturedAll[i]);
        string imgname = "imgcaps" + to_string(i) + ".jpg";
        cv::imwrite(imgname, capturedAll[i]);
        cv::waitKey(100);
    }
}

void getCaptures(vector<cv::Mat>& capStore, int count, int tdif)
{
    QElapsedTimer capTimer;
    capTimer.start();

    for (int i = 0; i < count; i++) {
        capTimer.restart();

        // get_capture takes a photo from webcam
        cv::Mat capMat = webCam.get_capture();
        capStore.push_back(capMat);

        string imgname = "localsave" + to_string(i) + ".jpg";
        // Saved image here is giving correct result
        cv::imwrite(imgname, capMat);

        while (!capTimer.hasExpired(tdif))
            qApp->processEvents();
    }
}

我也尝试使用迭代器,但它给出了同样的错误结果。

【问题讨论】:

  • 显示get_capture()的代码。
  • 我所能做的就是猜测,但我认为你应该在 while 循环中否定 hasExpired,因为目前你得到 10 微秒的图像。难怪他们看起来一样......
  • get_capture 是一个伪代码。我有一个不同的相机类,但该功能的输出是正确的。正如我在 getCaptures 函数中所指出的,如果我直接保存捕获的图像,我会得到正确的结果。但如果我将它分配给一个向量并尝试从那里获取,我将获得最后一次捕获。
  • 它们实际上不是几微秒。我可以以毫秒为单位设置捕获之间的时间差。所以 500 毫秒是非常长的时间差,我确信相机前的场景在两次捕捉之间会发生变化。
  • 我这里复制错了,对不起。这只是捕获之间的延迟。

标签: c++ qt opencv vector mat


【解决方案1】:

我认为问题在于 cv::Mat 的指针。 更改以下部分解决了问题。 但具体我不明白。每次在循环中我都会再次初始化 capMat。

    cv::Mat capMat = webCam.get_capture();
    capStore.push_back(capMat.clone());

【讨论】:

  • 查看Mat (Mat &amp;) 的文档:docs.opencv.org/trunk/d3/d63/… 制作浅拷贝,您需要使用克隆制作深拷贝。
  • 可能在 webCam 中,数据内存被重新用于新图像。除非您深度复制或创建新的 Mat 内存,否则您的 capMat 只是提供图像数据的标题。
【解决方案2】:

如果您在 Qt 中工作(正如您的标签所建议的那样),完全避免这种情况的最佳方法是将图像深度复制到 QImage 以避免创建 cv::Mat 的副本。这是从cv::Mat 创建QImage 的安全方法,它还负责在删除最后一个QImage 引用时释放内存:

cv::Mat* capture;
size_t bufferSize = capture->cols * capture->rows * capture->channels();
auto pixelFormat = toPixelFormat(capture->format);

auto outputBuffer = new uchar[bufferSize];

// This will not work for sparse mats - you have to copy row-by-row
memcpy(outputBuffer, capture->data, bufferSize);

// Have to pass stride since QImage is padding the rows for non power-of-two sizes
QImage image(outputBuffer, capture->cols, capture->rows, capture->cols * capture->channels(), pixelFormat, DeleteImageData, outputBuffer);

您需要将cv::Mat 格式转换为正确的QImage::Format,例如:

QImage::Format ImageFilterPrivate::getOpenCVType(int openCvFormat) {
    switch(openCvFormat) {
        case CV_8UC4: return QImage::Format_ARGB32;
        case CV_8UC3: return QImage::Format_RGB888;
        // ... etc.
    }
}

一些 OpenCV 格式(例如 16 位灰度在 Qt 中没有匹配的类型)。您还需要提供一个函数,该函数将在 QImage 的最后一次引用丢失后删除分配的数据,以避免内存泄漏(可以作为 lambda 传递):

void DeleteImageData(void* data) {
  auto buffer = static_cast<unsigned char*>(data);
  delete buffer;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-26
    • 2012-04-19
    相关资源
    最近更新 更多