实现位图的读取显示保存,能完成24位位图的转换,是一个典型的图像处理基础程序,程序很好,很简单清晰,容易看懂,但是所有图像信息头和数据的处理全在响应函数和ondrow函数里!
将24位真彩色图转换为灰度图
在图像处理中,我们经常需要将真彩色图像转换为黑白图像。严格的讲应该是灰度图,因为真正的黑白图像是二色,即只有纯黑,纯白二色。开始之前,我们先简单补充一下计算机中图像的表示原理。
计算机中的图像大致可以分成两类:位图(Bitmap)和矢量图(Metafile)。 位图可以视为一个二维的网格,整个图像就是由很多个点组成的,点的个数等于位图的宽乘以高。每个点被称为一个像素点,每个像素点有确定的颜色,当很多个像素合在一起时就形成了一幅完整的图像。
我们通常使用的图像大部分都是位图,如数码相机拍摄的照片,都是位图。因为位图可以完美的表示图像的细节,能较好的 还原图像的原景。
但位图也有缺点:第一是体积比较大,所以人们开发了很多压缩图像格式来储存位图图像,目前应用最广的是JPEG格式,在WEB上得到了广泛应用,另外还有GIF,PNG等 等。第二是位图在放大时,不可避免的会出现“锯齿”现象,这也由位图的本质特点决定的。
所以在现实中,我们还需要使用到另一种图像格式:矢量图。同位图不 同,矢量图同位图的原理不同,矢量图是利用数学公式通过圆,线段等绘制出来的,所以不管如何放大都不会出现变形,但矢量图不能描述非常复杂的图像。所以矢量图都是用来描述图形图案,各种CAD软件等等都是使用矢量格式来保存文件的。
(C语言实现)
//最近在学习图像处理有关的基础知识,并试着编程实践,这样有助于自己的理解和学习。首先遇到的第一个问题就是bmp位图的基础知识、bmp位图的C语言读入、操作、存入等。以下便是有关这期间学习的知识经验总结:欢迎分享!欢迎建议!谢谢!
//要理解的基础问题:bmp位图文件格式(掌握了bmp位图文件的具体格式后,才有可能更好的对其进行编程操作实践!):
位图文件(bitmap file)保存顺序如下:
位图头文件(BITMAPFILEHEADER)
位图信息头文件(BITMAPINFOHEADER)
调色板RGBQUAD(真彩色位图没有调色板)
图像数据
##释义1##位图头文件(BITMAPFILEHEADER):
typedef struct tagBITMAPFILEHEADER
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
}BITMAPFILEHEADER,*PBITMAPFILEHEADER;
##释义2##位图信息头文件(BITMAPINFOHEADER):
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER,*PBITMAPINFOHEADER;
##释义3##调色板RGBQUAD(真彩色位图没有调色板):
typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
}RGBQUAD;
##释义4##图像数据:
对于用到调色板的位图,图像数据就是该像素颜色在调色板中的索引值。对于真彩色图像,图像数据就是实际的R、G、B值,一个像素由3个字节24位组成,第一个字节表示B,第二个字节表示G,第三个字节表示R。
注意:BMP文件是从下到上、从左都右排列的。读文件时,最先读到的是图像的最下面一行的左边的第一个像素,最后读到的是最上面一行的最右一个像素。
//C源程序:本C程序由两部分组成(.c文件和.h文件)。(注:VC6编译链接运行通过)
*********************************************************************************************
rgbtogray.h文件:
*****************
#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
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
}BITMAPFILEHEADER,*PBITMAPFILEHEADER;
#pragma pack()
#pragma pack(1)
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER,*PBITMAPINFOHEADER;
#pragma pack()
#pragma pack(1)
typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
}RGBQUAD;
#pragma pack()
#pragma pack(1)
typedef struct tagBITMAPIMAGE
{
BITMAPFILEHEADER bmiHeader;
RGBQUAD bmiColors[1];
}BITMAPIMAGE;
#pragma pack()
#endif
*********************************************************************************************
rgbtogray.h文件:
******************
/*******************************************************************************/
#include
#include
#include
#include
/********************************************************************/
//自定义的有关图像处理的头文件为rgbtogray.h
//系统定义有关图像处理的头文件为windows.h
//目前,引用系统的windows.h程序工作正常,但自己的头文件有问题,待改正!
//最终实现引用自己的头文件rgbtogray.h
//太棒了:头文件的问题终于解决了
//#include
#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 { 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指定值之间,较小的那个进行。猜你喜欢
最新文章