实验目的:

利用c/c++ 作为编程环境进行图像处理的编程实践,掌握Windows下的BMP图像的存储格式和编程方法。先用C语言熟悉编程环境进行图像的简单处理。

实验要求:

掌握Windows 下的BMP图像的存储格式和基本的处理方法;

实验指导

一、BMP文件结构

二、  BMP图像文件的读写

三、显示图像的数据

   对于读入的图像文件,显示位图数据(选择一部分区域显示即可)。用256色或256级灰度图像进行验证。有两种显示方式:从上到下,从下到上。自己验证。

 

四、计算图像的直方图(0的不显示;每行最大显示50,直方图先归一化,再乘以50)

对于256级灰度级的图像进行计算。存入一个256元素的数组中,并显示其直方图数据。示意图显示方式:用行表示灰度级,在列上用“*”的多少表示直方图数据的大小。(数据为0的不显示,如果值太大,按比例缩小一下)

 

五、图像的增亮或减暗

输入一个数字,如果是正数对图像进行增亮,如果是负数对图像进行减暗。

用其他软件进行查看,源图像和被增亮或减暗的图像进行对比,是不是达到了预想的效果。

 

六、main() 函数的要求

main()函数将指定BMP文件读入内存,将图像信息打印输出,最后又原样存入指定文件中。并进行计算需要的数据。

界面:

必做:

0----------结束

1----------读图像8/24位)

2-----------写图像8/24位)

3-----------显示图像数据(1行到10行,1列到10列,10*10的大小)8/24位)

4-----------计算直方图(100-200之间的灰度,1-10行,1-10列,10*10的大小)(8)

5-----------对图像进行增亮或减暗(如加上50或减去50等)(8)

6-----------图像反色8/24位)

选做:

7-----------彩色图变成灰度图(8/24位)

8-----------显示调色板(8位)

9-----------24位彩色图像转换为8位灰度图像

10-----------24位彩色图像转换为8位彩色图像

用户界面

 

显示图像数据

 

计算直方图(8位图像)

仅仅使用一个通道:rgbBlue

蓝 灰度192

红 灰度64

 

调整图像亮度

 

图像反色

代码:

#include<iostream>
#include<windows.h>
#include <fstream>

using namespace std;

unsigned char *pBmpBuf;//读入图像数据的指针
int bmpWidth;//图像的宽
int bmpHeight;//图像的高
RGBQUAD* pColorTable;//颜色表指针
int biBitCount;//图像类型,每像素位数  

char readPath[] = "1.BMP";
char writePath[] = "2.BMP";

double pixelCount;

bool readBmp(char *bmpName)
{
    //二进制读方式打开指定的图像文件 
    FILE* fp = fopen(bmpName, "rb");
    if (fp == 0) return 0;
    //跳过位图文件头结构BITMAPFILEHEADER 
    fseek(fp, sizeof(BITMAPFILEHEADER), 0);
    //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中 
    BITMAPINFOHEADER head;
    fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);
    //获取图像宽、高、每像素所占位数等信息 
    bmpWidth = head.biWidth;
    bmpHeight = head.biHeight;
    biBitCount = head.biBitCount;
    //定义变量,计算图像每行像素所占的字节数(必须是4的倍数) 
    int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
    //灰度图像有颜色表,且颜色表表项为256 
    if (biBitCount == 8) {
        //申请颜色表所需要的空间,读颜色表进内存 
        pColorTable = new RGBQUAD[256];
        fread(pColorTable, sizeof(RGBQUAD), 256, fp);
    }
    //申请位图数据所需要的空间,读位图数据进内存 
    pBmpBuf = new unsigned char[lineByte * bmpHeight];
    fread(pBmpBuf, 1, lineByte * bmpHeight, fp);
    cout<<"像素:"<<pixelCount<<endl;
    //关闭文件 
    fclose(fp);
    return 1;
}

bool saveBmp(char *bmpName,unsigned char* imgBuf, int width, int height,int biBitCount, RGBQUAD* pColorTable)
{
    
    //如果位图数据指针为0,则没有数据传入,函数返回 
    if (!imgBuf)
        return 0;
    //颜色表大小,以字节为单位,灰度图像颜色表为1024字节,彩色图像颜色表大小为0 
    int colorTablesize = 0;
    if (biBitCount == 8)
        colorTablesize = 1024;
    //待存储图像数据每行字节数为4的倍数 
    int lineByte = (width * biBitCount / 8 + 3) / 4 * 4;
    //以二进制写的方式打开文件 
    FILE* fp = fopen(bmpName, "wb");
    if (fp == 0) return 0;
    //申请位图文件头结构变量,填写文件头信息 
    BITMAPFILEHEADER fileHead;
    fileHead.bfType = 0x4D42;//bmp类型 
    //bfSize是图像文件4个组成部分之和 
    fileHead.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
        + colorTablesize + lineByte * height;
    fileHead.bfReserved1 = 0;
    fileHead.bfReserved2 = 0;
    //bfOffBits是图像文件前3个部分所需空间之和 
    fileHead.bfOffBits = 54 + colorTablesize;
    //写文件头进文件 
    fwrite(&fileHead, sizeof(BITMAPFILEHEADER), 1, fp);
    //申请位图信息头结构变量,填写信息头信息 
    BITMAPINFOHEADER head;
    head.biBitCount = biBitCount;
    head.biClrImportant = 0;
    head.biClrUsed = 0;
    head.biCompression = 0;
    head.biHeight = height;
    head.biPlanes = 1;
    head.biSize = 40;
    head.biSizeImage = lineByte * height;
    head.biWidth = width;
    head.biXPelsPerMeter = 0;
    head.biYPelsPerMeter = 0;
    //写位图信息头进内存 
    fwrite(&head, sizeof(BITMAPINFOHEADER), 1, fp);
    //如果灰度图像,有颜色表,写入文件 
    if (biBitCount == 8)
        fwrite(pColorTable, sizeof(RGBQUAD), 256, fp);
    //写位图数据进文件 
    fwrite(imgBuf, height * lineByte, 1, fp);
    //关闭文件 
    fclose(fp);
    cout<<"图像已保存"<<endl; 
    return 1;
}

int outBMP(char *bmpName)
{
	 //二进制读方式打开指定的图像文件 
    FILE* fp = fopen(bmpName, "rb");
    if (fp == 0) return 0;
    //跳过位图文件头结构BITMAPFILEHEADER 
    fseek(fp, sizeof(BITMAPFILEHEADER), 0);
    //定义位图信息头结构变量,读取位图信息头进内存,存放在变量head中 
    BITMAPINFOHEADER head;
    fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);
    //获取图像宽、高、每像素所占位数等信息 
    bmpWidth = head.biWidth;
    bmpHeight = head.biHeight;
    biBitCount = head.biBitCount;
	
	pixelCount=bmpWidth*bmpHeight; 
	//cout<<"像素:"<<pixelCount<<endl;
    //定义变量,计算图像每行像素所占的字节数(必须是4的倍数) 
    int lineByte = (bmpWidth * biBitCount / 8 + 3) / 4 * 4;
    //灰度图像有颜色表,且颜色表表项为256 
    if (biBitCount == 8) {
        //申请颜色表所需要的空间,读颜色表进内存 
        pColorTable = new RGBQUAD[256];
        fread(pColorTable, sizeof(RGBQUAD), 256, fp);
    }
    //申请位图数据所需要的空间,读位图数据进内存 
    pBmpBuf = new unsigned char[lineByte * bmpHeight];
    fread(pBmpBuf, 1, lineByte * bmpHeight, fp);
    
 	double tmp[100][100],max=0; 
 	for (int i = 0; i < 100; i++)
  		for (int t = 0; t < 100; t++)
  			tmp[i][t] = pBmpBuf[i * bmpHeight + t * lineByte]; 


 	for (int i = 0; i < 100; i++)
 	{ 
  		for (int t = 0; t < 100; t++)
   			cout << tmp[i][t] << " ";
  		cout << endl;
  	    //关闭文件 
    fclose(fp);
    return 1;
 	}
}



void printChart(int i,double grayFrequency)
{
	double grayCount=grayFrequency*50;
	cout<<i<<" "<<int(grayCount)<<" ";
	for(int j=1;j<=int(grayCount);j++)
	{
		cout<<"*";
		if(j==50)break;
	 }
	cout<<endl;
}

int Histogram(char *bmpName,int biBitCount)
{
	if(biBitCount!=8)
	{
		cout<<"图片不是8位!"<<endl;
		cout<<biBitCount;
		system("pause");return 0;	
	}
	
	BITMAPFILEHEADER bmpFileHeader;
	BITMAPINFOHEADER bmpInfoHeader;
	RGBQUAD bmpColorTable[256];
	BYTE bmpValue[500 * 500];
	FILE *fp;
	//打开lena.bmp图像文件
	fp = fopen(bmpName, "rb");
	//读取图像信息
	fread(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, fp);
	fread(&bmpInfoHeader, sizeof(BITMAPINFOHEADER), 1, fp);
	fread(bmpColorTable, sizeof(RGBQUAD), 256, fp);
	bmpWidth = bmpInfoHeader.biWidth;
    bmpHeight = bmpInfoHeader.biHeight;	
    pixelCount=bmpWidth*bmpHeight; 
	fread(bmpValue, 1,pixelCount, fp);
	cout<<"像素:"<<pixelCount<<endl;
	//将图像灰度值存入一位数组中
	int grayValue[500 * 500] = { 0 };
	for (int i = 0; i < pixelCount; i++)
	{
		grayValue[i] = bmpColorTable[bmpValue[i]].rgbBlue;
	}
	//统计直方图 
	int grayCount[256] = { 0 };
	double grayFrequency[256] = { 0.0 };
	for (int i = 0; i < pixelCount; i++)
	{
		grayCount[grayValue[i]]++;
	}
	for (int i = 0; i < 256; i++)
	{
		if (grayCount[i])
		{
			grayFrequency[i] = grayCount[i] / pixelCount;
			printChart(i,grayFrequency[i]);
			//printf("灰度值%3d 频数为%6d 频率为%f\n", i, grayCount[i], grayFrequency[i]);
		}	
	}
	//关闭图像文件
	fclose(fp);
}

int SetColor(int i,RGBQUAD* &pColorTable,int delta)
{
	if(pColorTable[i].rgbBlue+delta<0)pColorTable[i].rgbBlue=0;
	else 	pColorTable[i].rgbBlue+=delta;
	if(pColorTable[i].rgbGreen+delta<0)pColorTable[i].rgbGreen=0;
	else	pColorTable[i].rgbGreen+=delta; 
	if(pColorTable[i].rgbRed+delta<0)pColorTable[i].rgbRed=0;
	else 	pColorTable[i].rgbRed+=delta;
	if(pColorTable[i].rgbBlue+delta>255)pColorTable[i].rgbBlue=255;
	else 	pColorTable[i].rgbBlue+=delta;
	if(pColorTable[i].rgbGreen+delta>255)pColorTable[i].rgbGreen=255;
	else	pColorTable[i].rgbGreen+=delta; 
	if(pColorTable[i].rgbRed+delta>255)pColorTable[i].rgbRed=255;
	else 	pColorTable[i].rgbRed+=delta; 
}

int Lightness(int biBitCount,RGBQUAD* &pColorTable)
{
	if(biBitCount!=8)
	{
		cout<<"图片不是8位!"<<endl;
		system("pause");return 0;	
	}
	int delta=0;
	cout<<"请输入修改亮度的参数:";
	cin>>delta;
	for(int i=0;i<=255;i++)
	{
		SetColor(i,pColorTable,delta);
	}
	saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
}

int SetColor2(int i,RGBQUAD* &pColorTable)
{
	pColorTable[i].rgbBlue=255-pColorTable[i].rgbBlue;
	pColorTable[i].rgbGreen=255-pColorTable[i].rgbGreen;
	pColorTable[i].rgbRed=255-pColorTable[i].rgbRed;
}

int invertColor(RGBQUAD* &pColorTable)
{
	for(int i=0;i<=255;i++)
	{
		SetColor2(i,pColorTable);
	}
	saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
}

void printMenu()
{
	cout<<"------------------------------------------------------------------"<<endl; 
	cout<<"Menu"<<endl;
	cout<<"1)读图像(8/24位)"<<endl;
	cout<<"2)写图像(8/24位)"<<endl;
	cout<<"3)显示图像数据(1行到10行,1列到10列,10*10的大小)(8/24位)"<<endl;
	cout<<"4)计算直方图(100-200之间的灰度,1-10行,1-10列,10*10的大小)(8位)"<<endl;
	cout<<"5)对图像进行增亮或减暗(如加上50或减去50等)(8位)"<<endl;
	cout<<"6)图像反色(8/24位)"<<endl;
	cout<<"7)彩色图变成灰度图(8/24位)"<<endl;
	cout<<"8)显示调色板(8位)"<<endl;
	cout<<"9)24位彩色图像转换为8位灰度图像"<<endl;
	cout<<"0)24位彩色图像转换为8位彩色图像"<<endl;
	cout<<"a)退出"<<endl;
	cout<<"------------------------------------------------------------------"<<endl; 
	char ch;
	cin>>ch;
	switch(ch) 
	{
		case '1':	
				    //用一个函数,把指定BMP文件读入内存 
					readBmp(readPath);system("cls");
					cout<<"------------------------------------------------------------------"<<endl; 
					cout<<"状态:"; 
					cout<<"已读入图像"<<endl; 
					break;
					
		case '2':	
				    saveBmp(writePath, pBmpBuf, bmpWidth, bmpHeight, biBitCount, pColorTable);
				    //清除缓冲区,p和pColorTable是全局变量,在文件读入时申请的空间 
				    delete[]pBmpBuf;
				    if (biBitCount == 8)
				        delete[]pColorTable;
				    system("cls");
					cout<<"------------------------------------------------------------------"<<endl; 
				    cout<<"状态:"; 
				    cout<<"已写入图像"<<endl; 
					break;
		case '3':	
					system("cls");
					cout<<"------------------------------------------------------------------"<<endl; 
				    cout<<"状态:"; 
				    cout<<"显示图像数据"<<endl; 
				    outBMP(readPath);
					//pixelShow(); 
					break;
		case '4':	system("cls");
					cout<<"------------------------------------------------------------------"<<endl; 
				    cout<<"状态:"; 
				    cout<<"显示直方图"<<endl; 
					Histogram(readPath,biBitCount);
					break;
		case '5':	system("cls");
					cout<<"------------------------------------------------------------------"<<endl; 
				    cout<<"状态:"; 
				    cout<<"调整亮度"<<endl; 
					Lightness(biBitCount,pColorTable); 
					break;
		case '6':	system("cls");
					cout<<"------------------------------------------------------------------"<<endl; 
				    cout<<"状态:"; 
				    cout<<"反色"<<endl; 
					invertColor(pColorTable);
					break;
		case '7':break;
		case '8':break;
		case '9':break;
		case '0':	system("cls");
					cout<<"状态:"; 
					printf("width=%d,height=%d, biBitCount=%d/n", bmpWidth, bmpHeight, biBitCount);
					cout<<endl;
					break;
		case 'a':break;
	}
}


int main()
{
	while(1)
	{
		printMenu();
	}
    return 0;
}

 

posted on 2020-03-27 18:10  海月CSDN  阅读(1338)  评论(0编辑  收藏  举报