OpenCV 与字节数组
OpenCV vs byte array
我正在开发一个简单的 C++ 图像处理应用程序,并决定是否使用 OpenCV 加载图像和访问单个像素。
我目前的方法是简单地使用 fopen
加载图像,读取 54 字节 header 并将其余字节加载到 char*
数组中。
访问我使用的特定像素
long q = (long*)(bmpData + x*3 + (bmpSize.height - y - 1) * bmpSize.stride);
执行简单的颜色检查,例如。 "is blue?"
if (((long*)q | 0xFF000000) == 0xFFFF0000) //for some reason RGB is reversed to BGR
//do something here
考虑到所有函数调用、解析等,OpenCV 是否更快?
位图文件header实际上是54字节,你不能跳过它。您必须阅读它才能找到宽度、高度、位数...必要时计算填充...以及其他信息。
根据文件的打开方式,OpenCV 将读取 header 并将像素直接读入缓冲区。唯一的变化是翻转了行,因此图像正面朝上。
cv::Mat mat = cv::imread("filename.bmp", CV_LOAD_IMAGE_COLOR);
uint8_t* data = (uint8_t*)mat.data;
header 检查和 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;
}
我正在开发一个简单的 C++ 图像处理应用程序,并决定是否使用 OpenCV 加载图像和访问单个像素。
我目前的方法是简单地使用 fopen
加载图像,读取 54 字节 header 并将其余字节加载到 char*
数组中。
访问我使用的特定像素
long q = (long*)(bmpData + x*3 + (bmpSize.height - y - 1) * bmpSize.stride);
执行简单的颜色检查,例如。 "is blue?"
if (((long*)q | 0xFF000000) == 0xFFFF0000) //for some reason RGB is reversed to BGR
//do something here
考虑到所有函数调用、解析等,OpenCV 是否更快?
位图文件header实际上是54字节,你不能跳过它。您必须阅读它才能找到宽度、高度、位数...必要时计算填充...以及其他信息。
根据文件的打开方式,OpenCV 将读取 header 并将像素直接读入缓冲区。唯一的变化是翻转了行,因此图像正面朝上。
cv::Mat mat = cv::imread("filename.bmp", CV_LOAD_IMAGE_COLOR);
uint8_t* data = (uint8_t*)mat.data;
header 检查和 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;
}