您的位置:首页 > 其它

24位真色位图转化为8位灰度位图

2014-12-26 14:47 405 查看
位图文件(bitmap file)保存顺序如下:

位图头文件(BITMAPFILEHEADER)
位图信息头文件(BITMAPINFOHEADER)
调色板RGBQUAD(真彩色位图没有调色板)
图像数据
##释义1##位图头文件(BITMAPFILEHEADER):

typedef struct tagBITMAPFILEHEADER

{ /*14 bytes BMP文件头数据结构含有BMP文件的类型、

文件大小和位图起始位置等信息*/

WORD bfType; /*2,位图文件的类型,必须为BM(0-1字节)*/

DWORD bfSize; /*4,位图文件的大小,以字节为单位(2-5字节)*/

WORD bfReserved1; /*2,位图文件保留字,必须为0(6-7字节)*/

WORD bfReserved2; /*2,位图文件保留字,必须为0(6-7字节)*/

DWORD bfOffBits; /*4,位图数据的起始位置,以相对于位图(10-13字节) */

}BITMAPFILEHEADER,*PBITMAPFILEHEADER;

##释义2##位图信息头文件(BITMAPINFOHEADER):

typedef struct tagBITMAPINFOHEADER

{ /*40 bytes BMP位图信息头数据用于说明位图的尺寸等信息。*/

DWORD biSize; /*4,本结构所占用字节数(14-17字节) */

LONG biWidth; /*4,位图的宽度,以像素为单位(18-21字节)*/

LONG biHeight; /*4,位图的高度,以像素为单位(22-25字节) */

WORD biPlanes; /*2,目标设备的级别,必须为1(26-27字节) */

WORD biBitCount;/*2每个像素所需的位数,必须是1(双色),(28-29字节)

4(16色),8(256色)或24(真彩色)之一 */

DWORD biCompression;/*4,位图压缩类型,必须是
0(不压缩),(30-33字节)

1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 */

DWORD biSizeImage; /*4,位图的大小,以字节为单位(34-37字节) */

LONG biXPelsPerMeter;/*4,位图水平分辨率,每米像素数(38-41字节) */

LONG biYPelsPerMeter; /*4,位图垂直分辨率,每米像素数(42-45字节) */

DWORD biClrUsed;/*4, 位图实际使用的颜色表中的颜色数(46-49字节) */

DWORD biClrImportant;/*4,位图显示过程中重要的颜色数(50-53字节) */

} BITMAPINFOHEADER,*PBITMAPINFOHEADER;

##释义3##调色板RGBQUAD(真彩色位图没有调色板):

typedef struct tagRGBQUAD

{ /*颜色表用于说明位图中的颜色,它有若干个表项

,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。*/

BYTE rgbBlue; /*蓝色的亮度(值范围为0-255)*/

BYTE rgbGreen; /*绿色的亮度(值范围为0-255) */

BYTE rgbRed;/*红色的亮度(值范围为0-255)*/

BYTE rgbReserved; /*保留,必须为0 */

}RGBQUAD;

##释义4##图像数据:

对于用到调色板的位图,图像数据就是该像素颜色在调色板中的索引值。对于真彩色图像,图像数据就是实际的R、G、B值,一个像素由3个字节24位组成,第一个字节表示B,第二个字节表示G,第三个字节表示R。

注意:BMP文件是从下到上、从左都右排列的。读文件时,最先读到的是图像的最下面一行的左边的第一个像素,最后读到的是最上面一行的最右一个像素。

rgbtogray.h文件:

*****************

/* C语言读入图像 位图文件结构声明 */

#ifndef BMP_H_INCLUDED

#define BMP_H_INCLUDED

typedef unsigned short WORD;//2*8=16

typedef unsigned long DWORD;//4*8=32

typedef long LONG;//4*8=32

typedef unsigned char BYTE;//1*8=8

#pragma pack(1)

typedef struct tagBITMAPFILEHEADER

{ /*14 bytes BMP文件头数据结构含有BMP文件的类型、

文件大小和位图起始位置等信息*/

WORD bfType; /*2,位图文件的类型,必须为BM(0-1字节)*/

DWORD bfSize; /*4,位图文件的大小,以字节为单位(2-5字节)*/

WORD bfReserved1; /*2,位图文件保留字,必须为0(6-7字节)*/

WORD bfReserved2; /*2,位图文件保留字,必须为0(6-7字节)*/

DWORD bfOffBits; /*4,位图数据的起始位置,以相对于位图(10-13字节) */

}BITMAPFILEHEADER,*PBITMAPFILEHEADER;

#pragma pack()

#pragma pack(1)

typedef struct tagBITMAPINFOHEADER

{ /*40 bytes BMP位图信息头数据用于说明位图的尺寸等信息。*/

DWORD biSize; /*4,本结构所占用字节数(14-17字节) */

LONG biWidth; /*4,位图的宽度,以像素为单位(18-21字节)*/

LONG biHeight; /*4,位图的高度,以像素为单位(22-25字节) */

WORD biPlanes; /*2,目标设备的级别,必须为1(26-27字节) */

WORD biBitCount;/*2每个像素所需的位数,必须是1(双色),(28-29字节)

4(16色),8(256色)或24(真彩色)之一 */

DWORD biCompression;/*4,位图压缩类型,必须是
0(不压缩),(30-33字节)

1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 */

DWORD biSizeImage; /*4,位图的大小,以字节为单位(34-37字节) */

LONG biXPelsPerMeter;/*4,位图水平分辨率,每米像素数(38-41字节) */

LONG biYPelsPerMeter; /*4,位图垂直分辨率,每米像素数(42-45字节) */

DWORD biClrUsed;/*4, 位图实际使用的颜色表中的颜色数(46-49字节) */

DWORD biClrImportant;/*4,位图显示过程中重要的颜色数(50-53字节) */

} BITMAPINFOHEADER,*PBITMAPINFOHEADER;

#pragma pack()

#pragma pack(1)

typedef struct tagRGBQUAD

{ /*颜色表用于说明位图中的颜色,它有若干个表项

,每一个表项是一个RGBQUAD类型的结构,定义一种颜色。*/

BYTE rgbBlue; /*蓝色的亮度(值范围为0-255)*/

BYTE rgbGreen; /*绿色的亮度(值范围为0-255) */

BYTE rgbRed;/*红色的亮度(值范围为0-255)*/

BYTE rgbReserved; /*保留,必须为0 */

}RGBQUAD;/*颜色表中RGBQUAD结构数据的个数有biBitCount来确定:

   当biBitCount=1,4,8时,分别有2,16,256个表项;

   当biBitCount=24时,没有颜色表项。*/

#pragma pack()

#pragma pack(1)

typedef struct tagBITMAPIMAGE

{ /*位图信息头和颜色表组成位图信息*/

BITMAPFILEHEADER bmiHeader; /*位图信息头*/

RGBQUAD bmiColors[1]; /*颜色表*/

}BITMAPIMAGE;

#pragma pack()

#endif

*********************************************************************************************

rgbtogray.h文件:

******************

/*******************************************************************************/

#include<stdio.h>

#include<stdlib.h>

#include<malloc.h>

#include<string.h>

/********************************************************************/

//自定义的有关图像处理的头文件为rgbtogray.h

//系统定义有关图像处理的头文件为windows.h

//目前,引用系统的windows.h程序工作正常,但自己的头文件有问题,待改正!

//最终实现引用自己的头文件rgbtogray.h

//太棒了:头文件的问题终于解决了

//#include<windows.h>

#include "rgbtogray.h"

/********************************************************************/

/*****************************************************************************/

//全局变量声明

FILE * fpSrcBmpfile;//定义文件指针,用于读入和存储图像文件

FILE * fpDestBmpfile;

/******************************************************************************/

//程序子函数声明

void GetBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER);//获得位图的文件头和信息头

void ChangeBmpHeader(PBITMAPFILEHEADER, PBITMAPINFOHEADER, WORD);//改变位图的文件头和信息头

void SetBmpHeader(const PBITMAPFILEHEADER, const PBITMAPINFOHEADER);//将修改后的文件头和信息头存入新位图文件

void SetRGBQUAD();//建立颜色板并存入灰度图文件中

int RgbToGray();//24位真色图转化为8位灰度图的主要函数

/******************************************************************************/

//主函数框架,菜单!(方便调用其他程序,以便拓展)

void main()

{

int command=1;

while(command)//菜单选项,可拓展

{

printf("\n*****************************Image Processing Menu***************************\n");

printf("|--------1:RGB To GRAY transform!--------|\n");

printf("|--------0:End!---------|\n");

printf("*****************************************************************************\n");

printf("Hint:Processor Number?\n");

scanf("%d",&command);

switch(command)

{

case 1:

RgbToGray();

break;

case 0:

printf("---Bye-bye---\n");

break;

default:

printf("---Not defined number!\n");

break;

}

}

}

/******************************************************************************/

//函数体部分(副)

void GetBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader)

{

fread(pbfheader, sizeof(BITMAPFILEHEADER), 1,fpSrcBmpfile);

fread(pbiheader, sizeof(BITMAPINFOHEADER), 1,fpSrcBmpfile);

}

void ChangeBmpHeader(PBITMAPFILEHEADER pbfheader, PBITMAPINFOHEADER pbiheader, WORD
wType)

{

pbiheader->biBitCount = wType; //
24 或者 8

pbiheader->biClrUsed = (wType == 24) ? 0 : 256;

pbfheader->bfOffBits = 54 + pbiheader->biClrUsed * sizeof(RGBQUAD);

pbiheader->biSizeImage = ((((pbiheader->biWidth * pbiheader->biBitCount) + 31) & ~31) / 8) * pbiheader->biHeight;

pbfheader->bfSize = pbfheader->bfOffBits + pbiheader->biSizeImage;

}

void SetBmpHeader(const PBITMAPFILEHEADER pbfheader, const PBITMAPINFOHEADER
pbiheader)

{

fwrite(pbfheader, sizeof(BITMAPFILEHEADER), 1, fpDestBmpfile);

fwrite(pbiheader, sizeof(BITMAPINFOHEADER), 1, fpDestBmpfile);

}

void SetRGBQUAD()

{

int i;

RGBQUAD rgbquad[256];

for(i=0;i<256;i++) {

rgbquad[i].rgbBlue = i;

rgbquad[i].rgbGreen = i;

rgbquad[i].rgbRed = i;

rgbquad[i].rgbReserved = 0;

}

fwrite(rgbquad, 256 * sizeof(RGBQUAD), 1, fpDestBmpfile);

}

/******************************************************************************/

//函数体部分(主)

int RgbToGray()

{

LONG w,h;

BYTE r,g,b;

BYTE gray;

BYTE count24,count8;

BYTE Bmpnul=0;

char SrcBmpfile[256];

char DestBmpfile[256];

BITMAPFILEHEADER bmfh; // bmp文件头

BITMAPINFOHEADER bmih; // 位图信息头

BYTE *data;

memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));//内存初始化

memset(&bmih, 0, sizeof(BITMAPINFOHEADER));

data=(BYTE *)malloc(3*sizeof(BYTE));

if(!data)

{

printf("Error:Can not allocate memory .\n");

free(data);

return -1;

}

getchar();

printf("Input the path of SrcBmpfile:\n");

gets(SrcBmpfile);

if((fpSrcBmpfile=fopen(SrcBmpfile,"rb"))==NULL)

{

printf("Error:Open the file of SrcBmpfile failed!\n");//输入源位图文件

free(data);

return -1;

}

rewind(fpSrcBmpfile);

GetBmpHeader(&bmfh,&bmih);

//ceshie_start

printf("The contents in the file header of the BMP file:\n");

printf("bfType:%ld\n",bmfh.bfType);

printf("bfSize:%ld\n",bmfh.bfSize);

printf("bfReserved1:%ld\n",bmfh.bfReserved1);

printf("bfReserved2:%ld\n",bmfh.bfReserved2);

printf("bfOffBits:%ld\n",bmfh.bfOffBits);

printf("The contents in the info header:\n");

printf("biSize:%ld\n",bmih.biSize);

//ceshi_end

if(bmfh.bfType!=0x4D42)

{

printf("Error:This file is not bitmap file!\n");

free(data);

return -1;

}

if(bmih.biBitCount!=24)

{

printf("Error:This bmpfile is not 24bit bitmap!\n");

free(data);

return -1;

}

if(bmih.biCompression!=0)

{

printf("Error:This 8bit bitmap file is not BI_RGB type!\n");

free(data);

return -1;

}

printf("Input the path of the DestBmpfile:\n");//输入目标位图文件

gets(DestBmpfile);

if((fpDestBmpfile=fopen(DestBmpfile,"wb"))==NULL)

{

printf("Error:Open the file of DestBmpfile failed!\n");

free(data);

return -1;

}

ChangeBmpHeader(&bmfh,&bmih,8);

SetBmpHeader(&bmfh,&bmih);

SetRGBQUAD();

count24=(4-(bmih.biWidth*3)%4)%4;

count8=(4-(bmih.biWidth)%4)%4;

for(h=bmih.biHeight-1;h>=0;h--)

{

for(w=0;w<bmih.biWidth;w++)

{

fread(data,3,1,fpSrcBmpfile);

if(feof(fpSrcBmpfile))

{

printf("Error:Read Pixel data failed!\n");

free(data);

return -1;

}

b=*data;

g=*(data+1);

r=*(data+2);

gray=(299*r+587*g+114*b)/1000;

//if(gray>120)gray=250;

fwrite(&gray,sizeof(gray),1,fpDestBmpfile);

}

fseek(fpSrcBmpfile,count24,SEEK_CUR);

fwrite(&Bmpnul,1,count8,fpDestBmpfile);

}

printf("Hint:Convert RGB To GRAY Successfully!\n");

free(data);//释放内存空间

fclose(fpDestBmpfile);//关闭文件指针

fclose(fpSrcBmpfile);

return 0;

}

/******************************************************************************/

*******************************************************************************************

#prama pack(n)

结构体定义;

#prama pack()

##释义##:关于struct的使用方法:

struct是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如array、struct、union等)的数据单元。对于结构体,编译器会自动进行成员变量的对齐,以提高运算效率。缺省情况下,编译器为结构体的每个成员按其自然对界(natural alignment)条件分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。

自然对界是指按结构体的成员中size最大的成员对齐。

#pragma pack规定的对齐长度,实际使用的规则是:

结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和结构体的自然对齐长度中比较小的那个进行。

也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。

结构体的对齐,按照结构体中size最大的数据成员和#pragma pack指定值之间,较小的那个进行。

*******************************************************************************************

参考资料:

书目:《Visual C++实用图像处理》;

网友:http://hi.baidu.com/mayadong7349/blog/item/1b7e2b445f8e9e1c6a63e53a.html

网站:www.cprogramming.com(解决了结构体定义的相关问题 ,即#prama pack)

网友:http://hi.baidu.com/love_mj/blog/item/c4b294fd7bb94e1a08244d31.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: