参考知识:https://www.runoob.com/cplusplus/cpp-files-streams.html(文件操作)
https://www.cnblogs.com/wainiwann/p/7086844.html(BMP文件详解)
数据集上网找bmp真彩色的有很多。
这篇博客紧接着我上一篇,上一篇写的是怎么打开真彩色bmp格式图像文件。其实我觉得(一)(二)两篇博客可以和在一起了。假设你和我一样想搞清楚更多的底层知识,暂时不想用opencv。
闲话少说,我们从文件拉出了图像的数据进内存,然后处理完,自然要存回文件。问题来了,我们一般处理的都是像素数组。像素数组一般是三维的数组。我用的是动态的数组。图像是二维的,但每个像素可能不止用一个字节来表示,RGB三通道的话就是三个。所以底层图像其实也就是一个三维的数组。你处理完之后也是一个三维的像素数组。那如何把三维像素数组变成真彩色bmp图像文件呢?答案就是反推,你需要提供像素数组的三维位宽,即图像的宽度,高度,还有每个像素用的字节数。你就看着BMP文件格式就行了。直接上代码
void bmp::produce_bmp_file(byte ***pixel,int image_width,int image_heigth,int byte_count,string file_name)
{
int image_size;
fstream fp;
fp.open(file_name, ios::out|ios::binary);
if (!fp.is_open())
{
cout << "文件打开失败"<<endl;
return;
}
fp.put('B');
fp.put('M');
image_size=14+40+image_width*image_heigth*byte_count;//头文件长度+位图信息图长度+位图数据长度
int_to_byte(image_size,int_temp);
for(int i=0;i<4;++i)
fp.put(int_temp[i]);
for(int i=0;i<4;++i)
fp.put(0);//保留字
int_to_byte(offset,int_temp);
for(int i=0;i<4;++i)
fp.put(int_temp[i]);//放入偏移量
int_to_byte(40,int_temp);//放入信息头开始,40是我目前用的BMP信息头格式大小
for(int i=0;i<4;++i)
fp.put(int_temp[i]);
int_to_byte(image_width,int_temp);
for(int i=0;i<4;++i)
fp.put(int_temp[i]);
int_to_byte(image_heigth,int_temp);
for(int i=0;i<4;++i)
fp.put(int_temp[i]);
fp.put(1);
fp.put(0);//放入颜色数
short_to_byte(byte_count*8,short_temp);
for(int i=0;i<2;++i)
fp.put(short_temp[i]);//放入位宽大小
for (int i = 0; i < 4; ++i)
fp.put(0);//说明压缩格式为不压缩
for(int i=0;i<4;++i)
fp.put(0);//BI_RGB格式设置为0
for (int i = 0; i < 4; ++i)
fp.put(0);//水平分辨率缺省为0
for (int i = 0; i < 4; ++i)
fp.put(0);//垂直分辨率缺省为0
for (int i = 0; i < 4; ++i)
fp.put(0);
for (int i = 0; i < 4; ++i)
fp.put(0);//真彩色图象是没有调色板的,故设置为0
for (int i = 0; i < image_width; ++i)
for (int j = 0; j < image_heigth; ++j)
for (int k = 0; k < byte_count; ++k)
{
fp.put(pixel[i][j][k]);
}
fp.close();
}
这里还是要说明下有难度的一件事情比如int a=0x12345678,如何底层编码也按照一个一个字节12,34,56,78存入文件呢?
编码角度,其实就是把多个字节合起来的数据拆开存入外存,其实很好办,就是强制类型转换加移位。比如int a=0x12345678,
强制转换为一个字节的数据类型 char,那么就得到最低为78,接着你右移8位,就得到56,依此得到34,12。然后你就可以一个一个字节的放入文件。
void bmp::int_to_byte(int p,byte *value)
{
for(int i=0;i<4;++i)
{
value[i]=unsigned char(p);
p=p>>8;
}
}
展示:
基于以上的方法(还没写图像处理的算法,所以只是简单的复制)得到了两幅图像
带reserve的是复制后的图像。用vs以二进制的方式打开文件,两幅图像底层的编码完全一样,算法成功。