本文需要达成的目的,是完成将本地的bmp图片读取到程序内的rgb图像数组,以及将rgb图像数组保存为bmp图片。这一操作虽然可以用opencv完成,但是有时需要更加轻量的库,EasyBMP提供了读写BMP图片的接口,在本文的程序中,通过调用其完成了将图像文件读入到rgb图像数组以及反向写入的过程。
目录
0 - 前期准备
下载EasyBMP库,其可以通过官方网站下载(不推荐)以及github上进行下载(推荐)
官方网站地址:http://easybmp.sourceforge.net/
Github地址:https://github.com/aburgh/EasyBMP
使用EasyBMP比较简单,只需要包含其头文件即可,其他操作可以参考EasyBMP的官方手册(http://easybmp.sourceforge.net/documentation.html)
在使用前我们还需要对EasyBMP的库进行下修改。
在 EasyBMP.cpp 文件中,包含memory头文件
#include <memory>
不知为何原先的代码中没有添加,不添加此头文件则会导致无法使用 unique_ptr 智能指针,相关的issues地址(https://github.com/aburgh/EasyBMP/issues/1)
1 - 代码
#include "./EasyBMP/EasyBMP.h"
#include "iostream"
#include <memory>
#include "time.h"
using namespace std;
void WritePix2PicArray(unsigned char* buffer,BMP &bmp,int pixCol,int pixRow,RGBApixel pixData)
{
buffer[pixCol*3 + pixRow*bmp.TellWidth()*3] = pixData.Red;
buffer[pixCol*3 + pixRow*bmp.TellWidth()*3 + 1] = pixData.Green;
buffer[pixCol*3 + pixRow*bmp.TellWidth()*3 + 2] = pixData.Blue;
}
RGBApixel GetPixFromPicArray(unsigned char* buffer,BMP &bmp,int pixCol,int pixRow)
{
RGBApixel _pixData;
_pixData.Red = buffer[pixCol*3 + pixRow*bmp.TellWidth()*3];
_pixData.Green = buffer[pixCol*3 + pixRow*bmp.TellWidth()*3 + 1];
_pixData.Blue = buffer[pixCol*3 + pixRow*bmp.TellWidth()*3 + 2];
return _pixData;
}
int main()
{
clock_t _clkStart;
BMP _InputBmp;
_InputBmp.ReadFromFile("test.bmp");
/* show the inform of inputbmp */
cout<<"BitDepth "<<_InputBmp.TellBitDepth()<<endl
<<"NumberOfColor "<<_InputBmp.TellNumberOfColors()<<endl
<<"Width "<<_InputBmp.TellWidth()<<endl
<<"Height "<<_InputBmp.TellHeight()<<endl;
/* create the picBuffer */
int _bufferSize = _InputBmp.TellWidth() * _InputBmp.TellHeight() * 3;
cout<<"bufferSize "<<_bufferSize<<endl;
unsigned char* _picBuffer = new unsigned char[_bufferSize];
/* write bmp to picBuffer */
cout<<"WritePix2PicArray";
_clkStart = clock();
for(int j = 0 ; j < _InputBmp.TellHeight() ; j++)
{
for(int i = 0 ; i < _InputBmp.TellWidth() ; i++)
{
WritePix2PicArray(_picBuffer,_InputBmp,i,j,_InputBmp(i,j));
}
}
cout<<" used "<<clock() - _clkStart<<" ms"<<endl;
/* do some changes on the picBuffer */
cout<<"Change some pix data";
_clkStart = clock();
for(int j = 100 ; j < 500 ; j++)
{
for(int i = 10 ; i < 500 ; i++)
{
RGBApixel _pixData;
_pixData.Red = 0;
_pixData.Green = 0;
_pixData.Blue = 255;
WritePix2PicArray(_picBuffer,_InputBmp,i,j,_pixData);
}
}
cout<<" used "<<clock() - _clkStart<<" ms"<<endl;
RGBApixel _pix = GetPixFromPicArray(_picBuffer,_InputBmp,15,150);
cout<<(int)_pix.Red<<" "<<(int)_pix.Green<<" "<<(int)_pix.Blue<<endl;
/* write picBuffer back to the bmp */
cout<<"WritePicArrayToBMP";
_clkStart = clock();
for(int j = 0 ; j < _InputBmp.TellHeight() ; j++)
{
for(int i = 0 ; i < _InputBmp.TellWidth() ; i++)
{
_InputBmp(i,j) = GetPixFromPicArray(_picBuffer,_InputBmp,i,j);
}
}
cout<<" used "<<clock() - _clkStart<<" ms"<<endl;
_InputBmp.WriteToFile("test-out.bmp");
delete[] _picBuffer;
return 0;
}
使用下面的语句进行编译。program.cpp为上述源代码,.\EasyBMP 文件夹中存放了下载的EasyBMP代码文件。
g++ -std=c++11 .\program.cpp .\EasyBMP\EasyBMP.cpp
由于使用了c++11标准里的智能指针,所以这里需要使用命令告诉编译器使用c++11标准进行编译。
这里代码主要完成的有三个功能:
- 将图片文件读入到程序内BMP类型对象中,并通过循环转换为rgb数组
- 在rgb数组中画一个矩形
- 将rgb数组写回BMP对象,写出到文件
其实这里用循环转换到rgb数组有点蠢。尽管EasyBMP的代码是开源的,但是又不太好去改它的程序。
原始测试图片
修改后写出的图片