【问题标题】:OpenCV vs byte arrayOpenCV 与字节数组
【发布时间】:2019-04-20 21:36:45
【问题描述】:

我正在开发一个简单的 C++ 图像处理应用程序,并决定是否使用 OpenCV 来加载图像和访问单个像素。 我目前的方法是简单地使用fopen 加载图像,读取 54 字节标题并将其余字节加载到 char* 数组中。

要访问我使用的特定像素

long q = (long*)(bmpData + x*3 + (bmpSize.height - y - 1) * bmpSize.stride);

执行简单的颜色检查,例如。 “是蓝色的吗?”

if (((long*)q | 0xFF000000) == 0xFFFF0000) //for some reason RGB is reversed to BGR
  //do something here

考虑到所有的函数调用、解析等,OpenCV 是否更快?

【问题讨论】:

  • 我会说这取决于您的需求。如果您需要绝对最高的性能、SIMD、最大帧率视频和复杂的处理,并准备花时间安装、配置和学习它,请选择 OpenCV。如果您需要一个易于安装、易于使用且无需配置并提供大量功能的库,请选择 CImg - 它只是您包含的一个简单的头文件。

标签: c++ c opencv image-processing bmp


【解决方案1】:

位图文件头实际上是 54 字节,你不能跳过它。您必须阅读它才能找到宽度、高度、位数...必要时计算填充...和其他信息。

根据文件的打开方式,OpenCV 将读取文件头并将像素直接读取到缓冲区中。唯一的变化是行被翻转,所以图像是正面朝上的。

cv::Mat mat = cv::imread("filename.bmp", CV_LOAD_IMAGE_COLOR);
uint8_t* data = (uint8_t*)mat.data;

OpenCV 所做的标头检查和微小更改不会显着影响性能。瓶颈主要在于从磁盘读取文件。性能的变化将很难衡量,除非您正在执行一项非常具体的任务,例如您希望在一个非常大的文件中只占用 3 个字节,并且您不想读取整个文件。

OpenCV 对于这个任务来说太过分了,所以你可以选择其他库,例如 cmets 中建议的 CImg。如果您使用加载速度更快的较小库,则在您的程序启动时可能会很明显。


以下代码是在 Windows 上运行的测试。

对于 16MB 的大位图文件,opencv 与普通 c++ 的结果几乎相同。

对于一个 200kb 的小位图文件,读取纯 C++ 的结果是 0.00013 秒,而 opencv 读取结果是 0.00040 秒。请注意,除了读取字节之外,普通的 c++ 并没有做太多事情。

class stopwatch
{
    std::chrono::time_point<std::chrono::system_clock> time_start, time_end;
public:
    stopwatch() { reset();}
    void reset(){ time_start = std::chrono::system_clock::now(); }
    void print(const char* title)
    {
        time_end = std::chrono::system_clock::now();
        std::chrono::duration<double> diff = time_end - time_start;
        if(title) std::cout << title;
        std::cout << diff.count() << "\n";
    }
};

int main()
{
    const char* filename = "filename.bmp";

    //I use `fake` to prevent the compiler from over-optimization 
    //and skipping the whole loop. But it may not be necessary here
    int fake = 0;

    //open the file 100 times
    int count = 100;

    stopwatch sw;
    for(int i = 0; i < count; i++)
    {
        //plain c++
        std::ifstream fin(filename, std::ios::binary);
        fin.seekg(0, std::ios::end);
        int filesize = (int)fin.tellg();
        fin.seekg(0, std::ios::beg);
        std::vector<uint8_t> pixels(filesize - 54);

        BITMAPFILEHEADER hd;
        BITMAPINFOHEADER bi;
        fin.read((char*)&hd, sizeof(hd));
        fin.read((char*)&bi, sizeof(bi));
        fin.read((char*)pixels.data(), pixels.size());

        fake += pixels[i];
    }
    sw.print("time fstream: ");

    sw.reset();
    for(int i = 0; i < count; i++)
    {
        //opencv:
        cv::Mat mat = cv::imread(filename, CV_LOAD_IMAGE_COLOR);
        uint8_t* pixels = (uint8_t*)mat.data;
        fake += pixels[i];
    }
    sw.print("time opencv:  ");

    printf("show some fake calculation: %d\n", fake);

    return 0;
}

【讨论】:

  • 我的任务是将卷积矩阵和平移应用于图像的应用程序。在我当前的构建中,我确实使用标题信息来计算高度和步幅。我可以处理没有问题的翻转图像。
  • 我使用纯 C++ 和 OpenCV 进行了测试。对于较大的文件,几乎没有区别。对于较小的文件,用纯 C++ 读取需要 0.00013 秒,而 OpenCV 需要 0.00040 秒。测试是在 SSD 上对操作系统缓存的同一文件进行的,在实际应用中差异会更小。如果应用程序已经在使用 OpenCV,那么我会坚持使用。
  • 你的应用测试是什么?
猜你喜欢
  • 2015-11-08
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-11
  • 2010-12-16
  • 2016-03-01
相关资源
最近更新 更多