我有一个简单的2d数组,如下所示:
unsigned char myArray[100][100];
我不需要任何高级图像处理,我只需要在文件中写入此图像(灰度级)(它可以是任何图像格式)。
我想我可以使用图像格式:.ppm(http://rosettacode.org/wiki/Bitmap/Write_a_PPM_file#C),如下所示:
(void) fprintf(fp, "P6\n%d %d\n255\n", dimx, dimy);
for (j = 0; j < dimy; ++j)
{
for (i = 0; i < dimx; ++i)
{
static unsigned char color[3];
color[0] = i % 256; /* red */
color[1] = j % 256; /* green */
color[2] = (i * j) % 256; /* blue */
(void) fwrite(color, 1, 3, fp);
}
}
我可以为RGB编写相同的值来模拟灰度图像,但是有更好的选择吗?
答案 0 :(得分:1)
您可以使用比PPM更常见的TGA格式,并允许使用真正的灰度图像。保存它们非常容易。准备一个包含9个元素的数组:
uint16 header[9]
写入:0,3,0,0,0,0,宽度,高度,8
fwrite那18个字节,然后一次性你的100x100阵列。就是这样。
答案 1 :(得分:0)
问题是:如果您使用灰度,则只需要1个通道,因此每个通道只有8位就足够了。写一个BMP文件。 BMP格式随处可见,标题很容易自己编写。不是每个人都打开PPM或PGM。
提示:下载010 Editor(十六进制编辑器,获得试用版)并在其上加载位图。您可以浏览位图的标题。它将加快关于标题的学习。所以你可以自己写...当然,每像素1个字节。
在我的示例中,我使用了C ++ ...但是如果你愿意,可以很容易地转换为C.
#include <iostream>
#include <fstream>
#pragma pack( push, 2 ) // avoid structure padding... I am using Win32 here
struct BITMAPFILEHEADER
{
unsigned short bfType;
unsigned int bfSize;
unsigned short bfReserved1;
unsigned short bfReserved2;
unsigned int bfOffBits;
};
struct BITMAPINFOHEADER
{
unsigned int biSize;
int biWidth;
int biHeight;
unsigned short biPlanes;
unsigned short biBitCount;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
};
#pragma pack() // avoid structure padding... I am using Win32 here
using namespace std;
void saveBitmap( const string & p_output, int p_width, int p_height )
{
BITMAPFILEHEADER bitmapFileHeader;
memset( &bitmapFileHeader, 0xff, sizeof( BITMAPFILEHEADER ) );
bitmapFileHeader.bfType = ( 'B' | 'M' << 8 );
bitmapFileHeader.bfOffBits = sizeof( BITMAPFILEHEADER ) + sizeof( BITMAPINFOHEADER );
bitmapFileHeader.bfSize = bitmapFileHeader.bfOffBits + ( p_width + ( p_width % 4 ? ( 4 - p_width % 4 ) : 0 ) ) * p_height; // multiply by 3 if you wanna switch to RGB
BITMAPINFOHEADER bitmapInfoHeader;
memset( &bitmapInfoHeader, 0, sizeof( BITMAPINFOHEADER ) );
bitmapInfoHeader.biSize = sizeof( BITMAPINFOHEADER );
bitmapInfoHeader.biWidth = p_width;
bitmapInfoHeader.biHeight = p_height;
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = 8; // this means grayscale, change to 24 if you wanna switch to RGB
ofstream file( p_output, ios::binary );
file.write( reinterpret_cast< char * >( &bitmapFileHeader ), sizeof( bitmapFileHeader ) );
file.write( reinterpret_cast< char * >( &bitmapInfoHeader ), sizeof( bitmapInfoHeader ) );
// bitmaps grayscale must have a table of colors... don't write this table if you want RGB
unsigned char grayscale[ 4 ];
for ( int i( 0 ); i < 256; ++i )
{
memset( grayscale, i, sizeof( grayscale ) );
file.write( reinterpret_cast< char * >( grayscale ), sizeof( grayscale ) );
}
// here we record the pixels... I created a gradient...
// remember that the pixels ordem is from left to right, "bottom to top"...
unsigned char pixel[ 1 ]; // do pixel[ 3 ] if you want RGB
for ( int y( 0 ); y < p_height; ++y )
{
for ( int x( 0 ); x < p_width + ( p_width % 4 ? ( 4 - p_width % 4 ) : 0 ); ++x ) // + ( p_width % 4 ? ( 4 - p_width % 4 ) : 0 ) because BMP has a padding of 4 bytes per line
{
if ( x > p_width )
{
pixel[ 0 ] = 0; // this is just padding
file.write( reinterpret_cast< char * >( pixel ), sizeof( pixel ) );
}
else
{
pixel[ 0 ] = 255 * ( x * y ) / ( p_width * p_height );
file.write( reinterpret_cast< char * >( pixel ), sizeof( pixel ) );
}
}
}
file.close( );
}
int main( int argc, char * argv[] )
{
saveBitmap( "test.bmp", 1000, 1000 );
return 0;
}