OpenCV和字节数组的比较

3
我正在开发一个简单的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在考虑所有函数调用、解析等方面是否更快?

2
我会说这取决于您的需求。如果您需要绝对最高的性能、SIMD、最大帧率视频和复杂处理,并且准备花时间进行安装、配置和学习,那么请选择OpenCV。如果您需要一个易于安装、易于使用的库,无需配置并提供巨大的功能,请选择CImg——它只是一个直接包含的头文件。 - Mark Setchell
1个回答

2

位图文件头实际上有54个字节,您不能跳过它。您必须读取它以查找宽度、高度、位数等信息...如果需要的话还要计算填充...以及其他信息。

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

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

头文件检查和OpenCV所做的小改变不会对性能产生显著影响。瓶颈主要在于从磁盘读取文件。除非你正在执行非常特定的任务,例如只想要一个非常大的文件中的3个字节,并且你不想读取整个文件,否则很难测量性能的变化。
对于这个任务来说,OpenCV有些过于复杂了,您可以选择其他库,例如评论中建议的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;
}

我的任务是一个应用程序,它将卷积矩阵和平移应用于图像。在我当前的构建中,我使用头信息来计算高度和步幅。我可以处理翻转的图像,这不是问题。 - Dragoș Circa
1
我使用纯C++和OpenCV进行了一项测试。对于较大的文件,几乎没有区别。对于较小的文件,纯C++读取需要0.00013秒,而OpenCV需要0.00040秒。该测试是在SSD上进行的,文件被操作系统缓存,实际应用中差异会更小。如果应用程序已经在使用OpenCV,则建议继续使用它。 - Barmak Shemirani
你的应用程序测试结果如何? - Dragoș Circa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接