1、红外图谱文件由文件头和温度数据两部分组成,其中文件头 64 个字节,其余字节为温度数据。每个像素用两个字节表示温度(16 位有符号短整数),低字节在前,高字节在后,温度数据单位为 0.1℃,温度数据共 w× h× 2 字节。文件头定义 如下:
从文件的25-26、27-28位可以获取谱图的高度和宽度,进而可以获取温度数据。
2、BMP文件由
- bmp文件头(bmp file header):共14字节;
- 位图信息头(bitmap information):共40字节;
- 调色板(color palette):可选;
- 位图数据;
- 结束符:共2个字节;
为了便于理解,可用photoshop工具生成一个只有一个像素且为白色的bmp文件,用EditPlus等工具以16进制方式打开,内容如下:
42 4D 3C 00 00 00 00 00 00 00 36 00 00 00 28 00
00 00 01 00 00 00 01 00 00 00 01 00 18 00 00 00
00 00 06 00 00 00 12 0B 00 00 12 0B 00 00 00 00
00 00 00 00 00 00 FF FF FF 00 00 00
内容解释
42 4D :BM字母
3C 00 00 00 :整个文件大小 60
00 00 00 00:保留,必须为0
36 00 00 00 :从文件开始到位图数据开始之间的数据之间的偏移量 54
28 00 00 00 :位图信息头的长度 40
01 00 00 00 :以像素为单位说明图像的宽度
01 00 00 00 :以像素为单位说明图像的高度,同时如果为正,说明位图倒立(即数据表示从图像的左下角到右上角),如果为负说明正向
01 00 :为目标设备说明颜色平面数,总被设置为1
18 00 :说明比特数/像素数,值有1、2、4、8、16、24、32 (x018=24)
00 00 00 00 :说明图像的压缩类型,最常用的就是0(BI_RGB),表示不压缩
06 00 00 00 :说明位图数据的大小,当用BI_RGB格式时,可以设置为0(6个字节)
12 0B 00 00 :表示水平分辨率,单位是像素/米,有符号整数
12 0B 00 00 :表示垂直分辨率,单位是像素/米,有符号整数
00 00 00 00 :说明位图使用的调色板中的颜色索引数,为0说明使用所有
00 00 00 00 :说明对图像显示有重要影响的颜色索引数,为0说明都重要
FF FF FF 00 :位图数据,最后一个00为4字节对齐补0
00 00
这样就可以定义一个结构体表示一个BMP文件,定义如下:
typedef struct _BMPFILE
{
//bmp文件头
char bfType[2]; //文件类型0x4D42
char bfSize[4]; //文件大小
char bfReserved1[2]; //保留,必须设置为0
char bfReserved2[2]; //保留,必须设置为0
char bfOffBits[4]; //从头到位图数据的偏移54
//位图信息头
char biSize[4]; //位图信息头的长度 40
char biWidth[4]; //以像素为单位说明图像的宽度
char biHeight[4]; //以像素为单位说明图像的高度,同时如果为正,说明位图倒立(即数据表示从图像的左下角到右上角),如果为负说明正向
char biPlanes[2]; //为目标设备说明颜色平面数,总被设置为1
char biBitCount[2]; //说明比特数/像素数,值有1、2、4、8、16、24、32 (x018=24)
char biCompression[4]; //说明图像的压缩类型,最常用的就是0(BI_RGB),表示不压缩
char biSizeImages[4]; //说明位图数据的大小,当用BI_RGB格式时,可以设置为0(6个字节)
char biXPelsPerMeter[4];//表示水平分辨率,单位是像素/米,有符号整数
char biYPelsPerMeter[4];//表示垂直分辨率,单位是像素/米,有符号整数
char biClrUsed[4]; //说明位图使用的调色板中的颜色索引数,为0说明使用所有
char biClrImportant[4]; //说明对图像显示有重要影响的颜色索引数,为0说明都重要
//位图数据
char* biDataImage; //数据数组
//结束标志
char biFinish[2]; //结束标志
_BMPFILE()
{
bfType[0] = 'B';
bfType[1] = 'M';
bfReserved1[0] = 0x00;
bfReserved1[1] = 0x00;
bfReserved2[0] = 0x00;
bfReserved2[1] = 0x00;
bfOffBits[0] = 0x36;
bfOffBits[1] = 0x00;
bfOffBits[2] = 0x00;
bfOffBits[3] = 0x00;
biSize[0] = 0x28;
biSize[1] = 0x00;
biSize[2] = 0x00;
biSize[3] = 0x00;
biPlanes[0] = 0x01;
biPlanes[1] = 0x00;
biBitCount[0] = 0x18;
biBitCount[1] = 0x00;
biCompression[0] = 0x00;
biCompression[1] = 0x00;
biCompression[2] = 0x00;
biCompression[3] = 0x00;
biSizeImages[0] = 0x00;
biSizeImages[1] = 0x00;
biSizeImages[2] = 0x00;
biSizeImages[3] = 0x00;
biXPelsPerMeter[0]= 0x12;
biXPelsPerMeter[1]= 0x0B;
biXPelsPerMeter[2]= 0x00;
biXPelsPerMeter[3]= 0x00;
biYPelsPerMeter[0]= 0x12;
biYPelsPerMeter[1]= 0x0B;
biYPelsPerMeter[2]= 0x00;
biYPelsPerMeter[3]= 0x00;
biClrUsed[0] = 0x00;
biClrUsed[1] = 0x00;
biClrUsed[2] = 0x00;
biClrUsed[3] = 0x00;
biClrImportant[0] = 0x00;
biClrImportant[1] = 0x00;
biClrImportant[2] = 0x00;
biClrImportant[3] = 0x00;
biFinish[0] = 0x00;
biFinish[1] = 0x00;
biDataImage = NULL;
}
_BMPFILE(int size,int width,int height,int datasize)
{
bfType[0] = 'B';
bfType[1] = 'M';
bfSize[0] = (size & 0x000000FF);
bfSize[1] = (size & 0x0000FF00)>>8;
bfSize[2] = (size & 0x00FF0000)>>16;
bfSize[3] = (size & 0xFF000000)>>24;
bfReserved1[0] = 0x00;
bfReserved1[1] = 0x00;
bfReserved2[0] = 0x00;
bfReserved2[1] = 0x00;
bfOffBits[0] = 0x36;
bfOffBits[1] = 0x00;
bfOffBits[2] = 0x00;
bfOffBits[3] = 0x00;
biSize[0] = 0x28;
biSize[1] = 0x00;
biSize[2] = 0x00;
biSize[3] = 0x00;
biWidth[0] = (width & 0x000000FF);
biWidth[1] = (width & 0x0000FF00)>>8;
biWidth[2] = (width & 0x00FF0000)>>16;
biWidth[3] = (width & 0xFF000000)>>24;
biHeight[0] = (height & 0x000000FF);
biHeight[1] = (height & 0x0000FF00)>>8;
biHeight[2] = (height & 0x00FF0000)>>16;
biHeight[3] = (height & 0xFF000000)>>24;
biPlanes[0] = 0x01;
biPlanes[1] = 0x00;
biBitCount[0] = 0x18;
biBitCount[1] = 0x00;
biCompression[0] = 0x00;
biCompression[1] = 0x00;
biCompression[2] = 0x00;
biCompression[3] = 0x00;
biSizeImages[0] = 0x00;
biSizeImages[1] = 0x00;
biSizeImages[2] = 0x00;
biSizeImages[3] = 0x00;
biXPelsPerMeter[0]= 0x12;
biXPelsPerMeter[1]= 0x0B;
biXPelsPerMeter[2]= 0x00;
biXPelsPerMeter[3]= 0x00;
biYPelsPerMeter[0]= 0x12;
biYPelsPerMeter[1]= 0x0B;
biYPelsPerMeter[2]= 0x00;
biYPelsPerMeter[3]= 0x00;
biClrUsed[0] = 0x00;
biClrUsed[1] = 0x00;
biClrUsed[2] = 0x00;
biClrUsed[3] = 0x00;
biClrImportant[0] = 0x00;
biClrImportant[1] = 0x00;
biClrImportant[2] = 0x00;
biClrImportant[3] = 0x00;
biFinish[0] = 0x00;
biFinish[1] = 0x00;
biDataImage = new char[datasize];
memset(biDataImage,0,datasize);
}
~_BMPFILE()
{
if(biDataImage != NULL)
{
delete biDataImage;
biDataImage = NULL;
}
}
}BMPFILE,*pBMPFILE;
3、颜色与温度对照表
struct BASECOLOR
{
uchar Blue;
uchar Green;
uchar Red;
};
struct BASECOLOR BaseColor[256] =
{
{0x5E,0x00,0x05},
{0x60,0x01,0x07},
{0x63,0x01,0x0A},
{0x67,0x01,0x0E},
{0x6A,0x01,0x11},
{0x6B,0x01,0x13},
{0x6E,0x01,0x16},
{0x71,0x00,0x1A},
{0x74,0x00,0x1D},
{0x75,0x00,0x1F},
{0x78,0x00,0x22},
{0x7B,0x00,0x25},
{0x7D,0x00,0x29},
{0x7E,0x01,0x2B},
{0x80,0x01,0x2F},
{0x82,0x01,0x32},
{0x84,0x01,0x35},
{0x85,0x01,0x38},
{0x87,0x01,0x3B},
{0x89,0x01,0x3E},
{0x8A,0x01,0x42},
{0x8C,0x01,0x46},
{0x8C,0x01,0x47},
{0x8D,0x01,0x4B},
{0x8E,0x00,0x4E},
{0x8F,0x00,0x51},
{0x90,0x00,0x53},
{0x91,0x00,0x56},
{0x92,0x00,0x59},
{0x93,0x00,0x5C},
{0x93,0x00,0x5E},
{0x95,0x00,0x60},
{0x95,0x00,0x64},
{0x96,0x00,0x67},
{0x96,0x00,0x68},
{0x97,0x00,0x6B},
{0x97,0x00,0x6D},
{0x98,0x01,0x70},
{0x99,0x01,0x73},
{0x99,0x01,0x74},
{0x99,0x01,0x77},
{0x9A,0x01,0x79},
{0x9A,0x01,0x7C},
{0x9A,0x01,0x7D},
{0x9A,0x01,0x80},
{0x9B,0x01,0x83},
{0x9B,0x01,0x85},
{0x9B,0x01,0x87},
{0x9B,0x01,0x8A},
{0x9B,0x00,0x8D},
{0x9B,0x00,0x8F},
{0x9B,0x00,0x91},
{0x9B,0x00,0x94},
{0x9B,0x00,0x97},
{0x9B,0x00,0x9A},
{0x9B,0x00,0x9D},
{0x9B,0x00,0x9F},
{0x9A,0x00,0xA2},
{0x9A,0x00,0xA4},
{0x9A,0x00,0xA7},
{0x9A,0x00,0xA8},
{0x99,0x00,0xAB},
{0x99,0x01,0xAE},
{0x99,0x01,0xB0},
{0x98,0x01,0xB1},
{0x98,0x02,0xB3},
{0x97,0x02,0xB5},
{0x96,0x02,0xB7},
{0x96,0x03,0xB8},
{0x95,0x03,0xB9},
{0x95,0x04,0xBB},
{0x93,0x05,0xBD},
{0x92,0x06,0xBF},
{0x92,0x06,0xBF},
{0x91,0x07,0xC1},
{0x8F,0x08,0xC3},
{0x8E,0x09,0xC4},
{0x8E,0x09,0xC5},
{0x8C,0x0A,0xC6},
{0x8A,0x0B,0xC8},
{0x89,0x0D,0xC9},
{0x88,0x0D,0xCA},
{0x86,0x0E,0xCB},
{0x84,0x0F,0xCD},
{0x81,0x11,0xCE},
{0x80,0x11,0xCE},
{0x7D,0x13,0xD0},
{0x7A,0x14,0xD1},
{0x77,0x16,0xD2},
{0x75,0x16,0xD2},
{0x72,0x17,0xD3},
{0x6F,0x19,0xD4},
{0x6B,0x1B,0xD5},
{0x67,0x1C,0xD6},
{0x66,0x1D,0xD6},
{0x62,0x1F,0xD7},
{0x5E,0x20,0xD8},
{0x5A,0x22,0xD9},
{0x59,0x23,0xD9},
{0x55,0x25,0xDA},
{0x51,0x27,0xDB},
{0x4D,0x29,0xDB},
{0x4B,0x2A,0xDC},
{0x48,0x2C,0xDD},
{0x45,0x2E,0xDD},
{0x41,0x30,0xDE},
{0x40,0x31,0xDE},
{0x3C,0x33,0xDF},
{0x39,0x35,0xDF},
{0x36,0x38,0xE0},
{0x33,0x39,0xE1},
{0x31,0x3A,0xE1},
{0x2F,0x3D,0xE2},
{0x2C,0x3E,0xE3},
{0x29,0x41,0xE3},
{0x28,0x41,0xE4},
{0x25,0x44,0xE5},
{0x23,0x45,0xE5},
{0x21,0x47,0xE6},
{0x1F,0x48,0xE6},
{0x1D,0x4A,0xE7},
{0x1B,0x4B,0xE8},
{0x19,0x4D,0xE8},
{0x18,0x4E,0xE9},
{0x16,0x50,0xEA},
{0x13,0x52,0xEA},
{0x12,0x54,0xEB},
{0x10,0x56,0xEC},
{0x0F,0x57,0xEC},
{0x0D,0x59,0xEC},
{0x0B,0x5B,0xED},
{0x0A,0x5C,0xEE},
{0x09,0x5E,0xEE},
{0x08,0x5F,0xEF},
{0x07,0x61,0xEF},
{0x06,0x63,0xF0},
{0x05,0x64,0xF0},
{0x05,0x66,0xF0},
{0x03,0x67,0xF1},
{0x03,0x69,0xF2},
{0x02,0x6A,0xF2},
{0x02,0x6C,0xF2},
{0x01,0x6D,0xF3},
{0x01,0x6F,0xF3},
{0x01,0x71,0xF3},
{0x01,0x72,0xF4},
{0x00,0x74,0xF4},
{0x00,0x76,0xF4},
{0x00,0x78,0xF5},
{0x00,0x79,0xF5},
{0x00,0x7B,0xF6},
{0x00,0x7D,0xF6},
{0x00,0x7E,0xF6},
{0x00,0x80,0xF7},
{0x00,0x81,0xF7},
{0x00,0x84,0xF7},
{0x00,0x85,0xF8},
{0x00,0x86,0xF8},
{0x00,0x88,0xF8},
{0x01,0x8A,0xF8},
{0x01,0x8D,0xF9},
{0x01,0x8E,0xF9},
{0x01,0x8F,0xF9},
{0x01,0x91,0xFA},
{0x01,0x93,0xFA},
{0x01,0x95,0xFA},
{0x01,0x96,0xFA},
{0x01,0x99,0xFA},
{0x01,0x9A,0xFB},
{0x01,0x9D,0xFB},
{0x00,0x9D,0xFB},
{0x00,0x9F,0xFB},
{0x00,0xA1,0xFC},
{0x00,0xA3,0xFC},
{0x00,0xA4,0xFC},
{0x00,0xA6,0xFC},
{0x00,0xA8,0xFD},
{0x00,0xAA,0xFD},
{0x00,0xAB,0xFD},
{0x00,0xAD,0xFD},
{0x00,0xAF,0xFE},
{0x00,0xB1,0xFE},
{0x00,0xB3,0xFE},
{0x01,0xB4,0xFF},
{0x01,0xB6,0xFF},
{0x01,0xB8,0xFF},
{0x01,0xBA,0xFF},
{0x01,0xBB,0xFF},
{0x01,0xBD,0xFF},
{0x01,0xBF,0xFF},
{0x02,0xC1,0xFF},
{0x02,0xC2,0xFF},
{0x02,0xC4,0xFF},
{0x03,0xC5,0xFF},
{0x03,0xC7,0xFE},
{0x03,0xC8,0xFE},
{0x05,0xCA,0xFE},
{0x05,0xCC,0xFE},
{0x06,0xCD,0xFE},
{0x07,0xCE,0xFE},
{0x08,0xD0,0xFE},
{0x0A,0xD1,0xFE},
{0x0B,0xD2,0xFE},
{0x0D,0xD4,0xFE},
{0x0E,0xD5,0xFE},
{0x10,0xD6,0xFE},
{0x12,0xD7,0xFE},
{0x15,0xD9,0xFF},
{0x16,0xDA,0xFF},
{0x1A,0xDB,0xFF},
{0x1D,0xDD,0xFF},
{0x20,0xDE,0xFF},
{0x23,0xDF,0xFF},
{0x27,0xE1,0xFF},
{0x2B,0xE2,0xFF},
{0x30,0xE3,0xFF},
{0x35,0xE5,0xFF},
{0x37,0xE6,0xFF},
{0x3D,0xE7,0xFF},
{0x42,0xE9,0xFF},
{0x48,0xEA,0xFF},
{0x4B,0xEB,0xFF},
{0x51,0xEC,0xFF},
{0x57,0xEE,0xFF},
{0x5E,0xEF,0xFF},
{0x61,0xF0,0xFF},
{0x68,0xF1,0xFF},
{0x6F,0xF2,0xFF},
{0x75,0xF3,0xFF},
{0x79,0xF3,0xFF},
{0x80,0xF4,0xFF},
{0x86,0xF4,0xFF},
{0x8D,0xF4,0xFF},
{0x93,0xF4,0xFF},
{0x96,0xF4,0xFF},
{0x9D,0xF4,0xFF},
{0xA3,0xF5,0xFF},
{0xA9,0xF6,0xFF},
{0xAC,0xF6,0xFF},
{0xB2,0xF7,0xFF},
{0xB7,0xF7,0xFF},
{0xBC,0xF8,0xFF},
{0xBF,0xF8,0xFF},
{0xC4,0xFA,0xFF},
{0xC8,0xFA,0xFF},
{0xCC,0xFB,0xFF},
{0xCD,0xFC,0xFF},
{0xD1,0xFC,0xFF},
{0xD4,0xFD,0xFF},
{0xD6,0xFE,0xFF},
{0xD7,0xFF,0xFF},
{0xD8,0xFF,0xFF},
{0xD9,0xFF,0xFF},
{0xD9,0xFF,0xFF},
{0xFF,0xFF,0xFF},
{0xFF,0xFF,0xFF}
};
4、代码实现
QFile firfile(firfileName);
if(firfile.exists() && firfile.open(QIODevice::ReadOnly))
{
QByteArray bytearray = firfile.readAll();
if(bytearray.size() < 28) continue;
ushort height = (uchar)bytearray[25]*256 + (uchar)bytearray[24];//图像高度
ushort width = (uchar)bytearray[27]*256 + (uchar)bytearray[26];//图像宽度
if(bytearray.size() < 64+2*height*width) continue;
//计划最大最小值
int max = (uchar)bytearray[65]*256 + (uchar)bytearray[64];
int min = (uchar)bytearray[65]*256 + (uchar)bytearray[64];
for(int row=0;row<height;row++)
{
for(int col=0;col<width;col++)
{
int index = 64 + 2*(row*width + col);
int value = (uchar)bytearray[index+1]*256 + (uchar)bytearray[index];
if(value > max) max = value;
if(value < min) min = value;
}
}
uint colSize = 4 * (24*width)/32 + (24*width%32 > 0 ? 4 : 0); //一行有多少字节(4字节对齐)
uint biSize = colSize * height; //数据区总共字节
uint bfSize = 14 + 40 + biSize + 2; //图像总共字节
BMPFILE bmpFile(bfSize,width,height,biSize);
//图片BGR赋值
for(int i=0,row=height-1;row>=0;row--)
{
for(int col=0;col<width;col++)
{
int index = 64 + 2*(row*width + col);
int value = (uchar)bytearray[index+1]*256 + (uchar)bytearray[index];
int bgrIndex = (int)(256 * (value-min+1) / (max-min+1));
bmpFile.biDataImage[i++] = BaseColor[bgrIndex].Blue;
bmpFile.biDataImage[i++] = BaseColor[bgrIndex].Green;
bmpFile.biDataImage[i++] = BaseColor[bgrIndex].Red;
}
//非4字节对齐时补0
for(uint col=3*width;col<colSize;col++)
{
bmpFile.biDataImage[i++] = 0x00;
}
}
//写bmp文件
QString bmpfileName = firfileName.replace(".fir",".bmp");
QFile bmpfile(bmpfileName);
if(bmpfile.open(QIODevice::WriteOnly))
{
bmpfile.write(bmpFile.bfType, 2);
bmpfile.write(bmpFile.bfSize, 4);
bmpfile.write(bmpFile.bfReserved1, 2);
bmpfile.write(bmpFile.bfReserved2, 2);
bmpfile.write(bmpFile.bfOffBits, 4);
bmpfile.write(bmpFile.biSize, 4);
bmpfile.write(bmpFile.biWidth, 4);
bmpfile.write(bmpFile.biHeight, 4);
bmpfile.write(bmpFile.biPlanes, 2);
bmpfile.write(bmpFile.biBitCount, 2);
bmpfile.write(bmpFile.biCompression, 4);
bmpfile.write(bmpFile.biSizeImages, 4);
bmpfile.write(bmpFile.biXPelsPerMeter,4);
bmpfile.write(bmpFile.biYPelsPerMeter,4);
bmpfile.write(bmpFile.biClrUsed, 4);
bmpfile.write(bmpFile.biClrImportant, 4);
bmpfile.write(bmpFile.biDataImage,biSize);
bmpfile.write(bmpFile.biFinish, 2);
bmpfile.close();
}
firfile.close();
}