位图文件头实际上有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";
int fake = 0;
int count = 100;
stopwatch sw;
for(int i = 0; i < count; i++)
{
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++)
{
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;
}