有没有使用 OpenCV 的 imdecode 的替代方法?太慢了

Posted

技术标签:

【中文标题】有没有使用 OpenCV 的 imdecode 的替代方法?太慢了【英文标题】:Are there any alternatives to using OpenCV's imdecode? It is too slow 【发布时间】:2015-05-07 20:48:36 【问题描述】:

我创建了一个 DLL,用户可以在其中从文件名或流中读取图像,如下所示:

std::string filePath = "SomeImage.bmp";

// (1) Reading from a file
Image2D img1;
img1.readImage(filePath);

// (2) Reading from a stream
std::ifstream imgStream (filePath.c_str(), std::ios::binary);
Image2D img2;
img2.readImage(imgStream);

第一个readImage(filePath) 是使用cv::imread(filePath) 实现的,速度相当快(对于600 x 900 的图像,平均需要0.001 秒)。然而,第二个版本readImage(fileStream) 是使用cv::imdecode 实现的,这相当慢(对于相同的图像平均需要2.5 秒)。

是否有任何替代 cv::imdecode 的方法,我可以从内存缓冲区中解码图像而无需花费这么长时间?这是针对经常使用的应用程序的核心组件,所以它必须快速。

我们将不胜感激。提前致谢。

编辑:

我使用计时器测量时间。这对我来说也没有意义。我不明白为什么在时间上有这么大的差距。 Image2D 只是一个以 OpenCV 矩阵为成员的类。 readImage函数的实现简化如下:

int Image2D::readImage(std::ifstream& input)
       
    input.seekg(0, std::ios::end);
    size_t fileSize = input.tellg();
    input.seekg(0, std::ios::beg);

    if (fileSize == 0) 
        return 1;
    

    std::vector<unsigned char> data(fileSize);
    input.read(reinterpret_cast<char*>(&data[0]), sizeof(unsigned char) * fileSize);

    if (!input) 
        return 1;
    

    StopWatch stopWatch;
    mImg = cv::imdecode(cv::Mat(data), CV_LOAD_IMAGE_COLOR);
    std::cout << "Time to decode: " << stopWatch.getElapsedTime() << std::endl;

    return 0;



int Image2D::readImage(const std::string& fileName)

    StopWatch stopWatch;
    mImg = cv::imread(fileName, CV_LOAD_IMAGE_COLOR);

    std::cout << "Time to read image: " << stopWatch.getElapsedTime() << std::endl;
    return 0;

【问题讨论】:

你如何衡量时间?这似乎没有多大意义:imread 在内部使用imdecode,而您只是在读取实际上根本没有解码的位图文件。您还应该显示您的类 Image2D 和方法 readImage 实现的代码(2 个重载选项)。 查看我的编辑@Antonio。 秒表是如何实现的?自从您第一次测量 imread 以来,也许它是某种单例且未重置? 用时钟测量(我知道这是 cpu 时间,而不是 wall 时间),流版本在我的系统上要快一些(但它只是解码)。 @Micka 不,这绝对不是单例。只是一个使用 Windows _ftime64_s 的简单轻量级类。我不明白流版本在您的机器上如何更快,但在我的机器上却慢得多。事实上,在我测试过的几台机器上,它的速度更慢。 【参考方案1】:

这就是我测试您的代码的方式,也许您可​​以尝试相同的方法(在一个干净的项目中)来比较结果。

对我来说,时间测量(CPU 时间,它不是墙上时间)表明,仅解码字节流比读取图像要快一点(这是有道理的)-Windows-VC 2010 OpenCV 2.49

#include <fstream>

cv::Mat MreadImage(std::ifstream& input)
       
    input.seekg(0, std::ios::end);
    size_t fileSize = input.tellg();
    input.seekg(0, std::ios::beg);

    if (fileSize == 0) 
        return cv::Mat();
    

    std::vector<unsigned char> data(fileSize);
    input.read(reinterpret_cast<char*>(&data[0]), sizeof(unsigned char) * fileSize);

    if (!input) 
        return cv::Mat();
    

    clock_t startTime = clock();
    cv::Mat mImg = cv::imdecode(cv::Mat(data), CV_LOAD_IMAGE_COLOR);
    clock_t endTime = clock();
    std::cout << "Time to decode image: " << (float)(endTime-startTime)/(float)CLOCKS_PER_SEC << std::endl;

    return mImg;



cv::Mat MreadImage(const std::string& fileName)

    clock_t startTime = clock();
    cv::Mat mImg = cv::imread(fileName, CV_LOAD_IMAGE_COLOR);
    clock_t endTime = clock();

    std::cout << "Time to read image: " << (float)(endTime-startTime)/(float)CLOCKS_PER_SEC << std::endl;
    return mImg;


// test speed of imread vs imdecode
int main()


    //std::string path = "../inputData/Lenna.png";
    //std::string path = "../inputData/Aachen_Germany_Imperial-Cathedral-01.jpg";
    std::string path = "../inputData/bmp.bmp";

    cv::Mat i1 = MreadImage(path);


    std::ifstream imgStream (path.c_str(), std::ios::binary);
    cv::Mat i2 = MreadImage(imgStream);

    cv::imshow("input 1", i1);
    cv::imshow("input 2", i2);
    cv::waitKey(0);
    return 0;

【讨论】:

所以我在一个干净的项目中测试了上面的代码,时间和你提到的差不多。我真的不明白为什么在我的生产级应用程序中运行imdecode 需要更长的时间。我将不得不更深入地研究这一点。我可能会遗漏一些东西。任何建议都会有所帮助。谢谢。 您是否在生产代码中尝试过替代时间测量方法? 是的,我做到了。我不明白为什么需要这么长时间。我为这个问题创建了一个解决方法,但我仍然对时间差异感到困惑。我不知道为什么当我明确调用cv::imdecode 时需要更长的时间。不过感谢您的帮助。

以上是关于有没有使用 OpenCV 的 imdecode 的替代方法?太慢了的主要内容,如果未能解决你的问题,请参考以下文章

关于OpenCV imread和imdecode读取图片是BGR的证明

cv::imdecode 图像从 JS 到 C++ (opencv, emscripten)

opencv中imdecode的几行代码备份

opencv imdecode和imencode用法

PIL Image.open 和 cv2.imdecode 的区别

opencv python图片编码解码