首页 > 编程知识 正文

像处理基本操作实验报告,基本像处理

时间:2023-05-05 13:05:33 阅读:250897 作者:2400

处理BMP图片 BMP格式实验内容头文件分析第一部分:图像处理1、反白图像2、改变调色板的数值3、彩图变灰图 第二部分:bmp2txt1、输出txt函数2、Excel作图 结语

BMP格式

bmp是一种常见的未压缩图像格式,也是大多数图像处理入门课会用到的一种引路格式。具体的BMP图像格式解析请见:BMP图像格式详解

实验内容 反白图像改变调色板的颜色值,看对图像的影响将彩色图像变为灰度图像将一灰度图像数据变为文本格式存入bmp.txt中,txt文件的一行对应图像文件的一行。将bmp.txt导入到excel中,并用至少三种可视化工具将其图形化显示。

老师已经给出了用于处理BMP格式的类的头文件以及部分函数实现代码(C/C++)。由于函数实现为老师的成果,所以我就不贴出代码了,不过我们可以一起分析一下头文件,看一看这个类有什么数据成员,能完成什么功能。

头文件分析 class BMPFILE {BYTE *Imagedata;//位图数据域public:int imagew, imageh;//图片的宽度和高度int iYRGBnum;//1:灰度,3:彩色RGBQUAD palette[256];//调色板BYTE *pDataAt(int h, int Y0R0G1B2 = 0);//指向图像第h行的位置,Y0R0G1B2表示:灰度(Y)=0,R=0,G=1,B=2BOOL AllocateMem();//为图像分配内存BOOL LoadBMPFILE(const char *fname);//从硬盘加载图像BOOL SaveBMPFILE(const char *fname);//将图像保存至硬盘BMPFILE();//构造函数,初始化~BMPFILE();//析构函数};

这里唯一需要解释的可能是pDataAt这个函数,尤其是形参中Y0R0G1B2这个让人摸不着头脑的命名。
首先说功能,这个函数的功能是获取第w列列首像素的位置,也就是求偏移量h=imageh*w,然后再用Imagedata+h去定位。
但是这里要补充一个点,那就是BMP数据在内存中的存储方式。我们知道,对24bit的彩图而言,在硬盘中每位像素会以BGR的格式排列,但这不意味着在内存中也是同样连续存储BGR的。相反,在内存中的真实状态是R、G、B被分别存储于3个矩阵中,因此我们要找到第h行的行首像素时,要分别找到其R、G、B的位置。因此实际偏移量应为:

h=imageh*w+Y0R0G1B2*imagew*imageh// 当然也可以写作 int w = imageh * h + Y0R0G1B2 * imagew * imageh,则定位到h行,行首像素 第一部分:图像处理

我们把实验分为两部分,因为bmp2txt并用excel作图那部分卡了我很久,而前面那三个却很简单,我们就先说这简单的部分吧。

1、反白图像

这里所谓的反白其实就是反色,只是对于灰度图而言我们看到的效果是黑白颠倒。我们选用的颜色量级为0-255,因此反色就是用255减去当前的颜色。下面贴出部分代码(只给了大家灰度图的反白,如何做彩图的反色呢?留给读者自行解决)

void Reverse(BMPFILE &src,BMPFILE &des)//反白函数{for (int i = 0; i < src.imageh; i++)for (int j = 0; j < src.imagew; j++){//反白图des.pDataAt(i)[j] = 255 - src.pDataAt(i)[j];}}

效果如下

原图:
反色效果:

2、改变调色板的数值

在没有要求的情况下,随意修改即可,内容没什么可讲的那我们就来说说调色板吧。

typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved;} RGBQUAD;

上面是RGBQUAD,也就是调色板所用的结构体的定义。可以看到每一个RGBQUAD中定义了蓝、绿、红和一个保留位。如果调色板中R=G=B,则显示的是灰度图;相反,如果RGB值各不相同,那么一共可以有256x256x256种颜色,不过注意,由于调色板是一个有256个RGBQUAD的数组,所以最终的图像最多也就256种颜色。对于rgbReserved这一项,stackoverflow上的这份问答大家可以读一下,相信你会有比较深刻的理解。What is rgbReserved?

3、彩图变灰图

彩图变灰图其实也没什么可说的,因为经过历代程序员的尝试我们已经有了非常完美的转换公式,Y=0.299R + 0.587G + 0.114B。我们的要求只是显示效果的彩转灰,如果真的是要变成灰度图,那么除了让像素颜色按照公式转换,我们还应该对信息头、文件头以及调色板作出修改,这里就不做了。

上个效果吧
原图:

转灰效果图:

第二部分:bmp2txt 1、输出txt函数

说实话这个把bmp数据存入txt的题目要求让我疑惑了很久,很长一段时间大概一天我都在修改类似下面的代码:

bool bmp2txt(const char *cFilename){FILE *fin,*fout;fin=fopen(cFilename, "r+b");fout = fopen("bmp.txt", "w+");int rc;unsigned char buf[1024];fseek(fin, sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER), SEEK_SET);while ((rc = fread(buf, sizeof(unsigned char), 1, fin)) != 0){fwrite(buf, sizeof(unsigned char), rc, fout);}fclose(fin);fclose(fout);}

为什么卡那么久,主要是这个代码如果把w+改成w+b,再把fseek删掉,写出的二进制文件改成bmp图像是可以正常显示的。这样就让我一度认为方法是没问题的,细节上出错了。包括改为fprintf(fout,"%4d",buf)试图转换为10进制输出也没有解决问题(输出的是重复值,原因未明)。
终于,我决定重新读题,然后我发现了这句话“txt 文件的一行对应图像的一行,按图像显示的顺序存储。”
突然间我就悟了,下面这段正确代码很快就写出来了:

bool bmp2txt(const char *cFilename)//将bmp数据转存入txt,路径为形参{//将像素数据存入TXT文件。BMPFILE bmpfile;if (!bmpfile.LoadBMPFILE(cFilename))return false;FILE *outfile;if ((outfile = fopen("bmp.txt", "w+")) == NULL){printf("ERRORn");return false;}for (int i = 0; i < bmpfile.imageh; i++)//按行写入{for (int j = 0; j < bmpfile.imagew; j++){fprintf(outfile, "%4d", bmpfile.pDataAt(i)[j]);}fprintf(outfile, "n");}fclose(outfile);return true;}//下面贴一下loadbmpfile的函数实现,毕竟挺重要的//其实就是按照文件头、信息头、数据域一一读入BOOL BMPFILE::LoadBMPFILE(const char *cFilename){FILE *f;if (strlen(cFilename) < 1)//文件不存在return FALSE;f = fopen(cFilename, "r+b");//以二进制只读打开if (f == NULL)return FALSE;BITMAPFILEHEADER fh;//文件头BITMAPINFOHEADER ih;//信息头fread(&fh, sizeof(BITMAPFILEHEADER), 1, f);//从文件中读取文件头if (fh.bfType != 0x4d42)//如果不是"BM"文件,直接退出{fclose(f);return FALSE;}fread(&ih, sizeof(BITMAPINFOHEADER), 1, f);//从文件中读取信息头if ((ih.biBitCount != 8) && (ih.biBitCount != 24))//如果不是8位灰度图,或24位彩图,则退出{fclose(f);return FALSE;}iYRGBnum = ih.biBitCount / 8;//1为灰度图,3为彩图imagew = ih.biWidth;imageh = ih.biHeight;if (!AllocateMem())//如果分配内存失败,退出{fclose(f);return FALSE;}if (iYRGBnum == 1)//灰度图需要调色板fread(palette, sizeof(RGBQUAD), 256, f);fseek(f, fh.bfOffBits, SEEK_SET);//指向像素数据包int w4b = (imagew * iYRGBnum + 3) / 4 * 4, i, j;//w4b为像素数据包大小BYTE *ptr;ptr = new BYTE[w4b];if (ptr == NULL){fclose(f);return FALSE;}if (iYRGBnum == 1){for (i = imageh - 1; i >= 0; i--)//从最下面开始往上拷贝字节{fread(ptr, w4b, 1, f);memmove(pDataAt(i), ptr, imagew);//memmove(des,src,count)}}if (iYRGBnum == 3){for (i = imageh - 1; i >= 0; i--){fread(ptr, w4b, 1, f);for (j = 0; j < imagew; j++)//分别读取R、G、B(注意磁盘里反储){*(pDataAt(i, 0) + j) = *(ptr + j * 3 + 2);*(pDataAt(i, 1) + j) = *(ptr + j * 3 + 1);*(pDataAt(i, 2) + j) = *(ptr + j * 3 + 0);}}}delete[] ptr;fclose(f);return TRUE;}

这告诉我们还是要认真读题啊。。。

2、Excel作图

这里只给出我认为有意义的一种可视化,因为老师说他只是让我们看看数据在不同表现形式下的效果,理解“有数就有图”。但实际上直方图、折线图都完全没有意义,下面介绍下色阶表示。
我们首先将bmp.txt导入到excel中穷人只能用wps了ysdqz,如图:

之后全选(ctrl+a),然后在开始——条件格式——色阶,随意选一个之后缩放到最小,就能看到神奇的画面:

当然这个灰度图的显示效果是自定义的,你只需要在其他规则中把最低值改为黑色,最高值改为白色即可。这个原理其实还是个调色板,按照数值的大小去显示介于最小值和最大值之间的一种颜色罢了。不过做出来的那一刻还是很有成就感的。

结语

这学期的第一次图像处理实验,说是三周内上交实际上已经给了快五周时间了,如果对已经给出的代码掌握熟练的话,其实一两天完成不是问题。完整项目工程可见我的gitee。

计算机毕业设计ssm基于SSM框架的众筹管理系统f5244系统+程序+源码+lw+远程部署如何在SwiftUI中使用Realm

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。