OpenCV vs字节数组

时间:2018-11-18 08:42:43

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

我正在研究一个简单的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会更快吗?

1 个答案:

答案 0 :(得分: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;
}