今天把拖了几周的多媒体技术的实验作业给写完了,鉴于第一次实现关于图像处理的程序,爬上来记录一下做的过程以及犯过的错误。
以下为作业的要求。
课件中可以参考的代码如下:
关于直方图的均衡化就不做赘述了。
关于老师给的ppt,果真是不能全部照抄啊。。。血与泪的教训,多付出了一两个小时用来调试真是不会开心。
那么就从老师所给出的代码入手,由于之前没有接触过关于读取图像的2进制的程序,所以老师给出的代码还是很有意义的。
以下是我的代码:
#include <windows.h>
#include <stdio.h>
#define WIDTHBYTES(i) ((i+31)/32*4)
#define MAX 2048
BITMAPFILEHEADER bf;
BITMAPINFOHEADER bi;
RGBQUAD lpRGB[256];
unsigned char ImgData[MAX][MAX];
int LineBytes;
float p[256] = {0};
//读入BMP
bool readBmp(char * BmpFileName)
{
FILE *fp;
fp = fopen(BmpFileName, "rb");
if (fp == NULL)
return 0;
if((fread(&bf, sizeof(BITMAPFILEHEADER), 1, fp)) == 0)
return 0;
if((fread(&bi, sizeof(BITMAPINFOHEADER), 1, fp)) == 0)
return 0;
if((fread(lpRGB, sizeof(RGBQUAD), 256, fp)) == 0)
return 0;
LineBytes = (DWORD)WIDTHBYTES(bi.biWidth * bi.biBitCount);
for (int i = bi.biHeight-1; i >= 0; i--)
if((fread(ImgData[i], LineBytes, 1, fp)) == 0)
return 0;
fclose(fp);
return 1;
}
//输出BMP
bool writeBmp(char * BmpFileName)
{
FILE *fp;
fp = fopen(BmpFileName, "wb");
if(fp == NULL)
return 0;
if((fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, fp)) == 0)
return 0;
if((fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, fp)) == 0)
return 0;
if((fwrite(&lpRGB, sizeof(RGBQUAD), 256, fp)) == 0)
return 0;
LineBytes = (DWORD)WIDTHBYTES(bi.biWidth * bi.biBitCount);
for (int i = bi.biHeight - 1; i >= 0; i--)
if((fwrite(ImgData[i], LineBytes, 1, fp)) == 0)
return 0;
fclose(fp);
return 1;
}
//生成直方图的每个灰度对应的值
bool histogram(int * Histog)
{
int x = 0, y = 0, color = -1;
for (x = 0; x < bi.biHeight; x++)
{
for (y = 0; y < bi.biWidth; y++)
{
color = ImgData[x][y];
Histog[color]++;
}
}
if (color == -1)
{
return 0;
}
return 1;
}
//输出直方图
bool writeHistog(int *Histog, char * FileName)
{
FILE *fp;
int numLine;
char cnumLine[10];
fp = fopen(FileName, "w");
if(fp == NULL)
return 0;
for (numLine = 0; numLine < 256; numLine++)
{
sprintf(cnumLine, "%d", numLine);//将int型转化为string类型
if((fputs(cnumLine, fp)) == EOF)
return 0;
if((fputc(' ', fp)) == EOF)
return 0;
sprintf(cnumLine, "%d", Histog[numLine]);
if((fputs(cnumLine, fp)) == EOF)
return 0;
if((fputc('\n', fp)) == EOF)
return 0;
}
fclose(fp);
return 1;
}
//直方图均衡化
void histogEqualization(int * OldHistog, int * ChangeHistog)
{
int gray = 0;
int x = 0, y = 0;
float n = (float)bi.biWidth * (float)bi.biHeight;
for (gray = 0; gray < 256; gray ++)
{
p[gray] = (float)OldHistog[gray]/n;
if (gray != 0)
{
p[gray] = p[gray] + p[gray - 1];
}
}
for (gray = 0; gray < 256; gray++)
{
ChangeHistog[gray] = (int)(255 * p[gray]);
}
gray = -1;
for(x = 0; x < bi.biHeight; x++)
for(y = 0; y < bi.biWidth; y++)
{
gray = ImgData[x][y];
ImgData[x][y] = ChangeHistog[gray]; //对每个像素点赋新值
}
}
void usage_and_exit(char * program_name)
{
printf("USAGE: %s path_for_image, path_for_oldhistogram, path_for_newhistogram, path_for_newimage\n",
program_name);
exit(1);
}
int main(int argc, char * argv[])
{
int OldHistog[256] = {0};
int NewHistog[256] = {0};
int ChangeHistog[256] = {0};
bool flag = 0;
if(argc != 5)
usage_and_exit(argv[0]);
flag = readBmp(argv[1]);
if (flag == 0)
{
printf("ERROR IN READBMP");
return 0;
}
flag = histogram(OldHistog);
if (flag == 0)
{
printf("ERROR IN HISTOGRAM FOR OLD IMAGE");
return 0;
}
flag = writeHistog(OldHistog, argv[2]);
if (flag == 0)
{
printf("ERROR IN WRITEHISTOGRAM FOR OLD IMAGE");
return 0;
}
histogEqualization(OldHistog, ChangeHistog);
flag = histogram(NewHistog);
if (flag == 0)
{
printf("ERROR IN HISTOGRAM FOR NEW IMAGE");
return 0;
}
flag = writeHistog(NewHistog, argv[3]);
if (flag == 0)
{
printf("ERROR IN WRITEHISTOGRAM FOR NEW IMAGE");
return 0;
}
flag = writeBmp(argv[4]);
if (flag == 0)
{
printf("ERROR IN WRITEBMP FOR NEW IMAGE");
return 0;
}
return 1;
}
照抄之后对于我的代码所犯的错误:
1.首先RGBQUAD *lpGRB这个指针的声明,我最开始没有注意到这个指针并没有赋值,导致我的程序在写完后运行崩溃,指向的是0x0000000这样一个地址。
2.unsigned char **ImgData的错误同1一样,依旧是没有赋值,报的错误好像是越界。
3.当把RGBQUAD *lpGRB改为RGBQUAD lpGRB并且后边的fread的第一个参数使用&lpRGB的时候,能够正常的输出结果,如果看到这篇日志的也是刚刚接触这个的你可以试一下,最后出来的结果反正我的是不知道什么的古怪颜色。因此这里事实上应该是改为lpRGB[256],似乎是用于放置灰度值的。。。这个我不是很清楚,给自己留个疑问。
4.在输出直方图这个函数中,我最开始使用fputc这个函数,输出的结果是乱码,由于读取数据的函数fputc只能读取char型,读入的整型造成了乱码,而使用sprintf函数可以将其他类型的变量转化为string类型,因此很好的帮助我输出直方图。
5.在设置变量的时候在路径的后边文件名后要加上文件后缀,第一个为.BMP 第二个为.TXT,第三个为.TXT 第四个为.BMP,否则会出错哟~
环境:VC6.0经检验,程序运行正常,结果正确。
6.新旧直方图的数组的定义我最开始定义其为全局变量,这样可以省略很多参数,但是调试的时候会发现,某些数组再进入函数之后,它本身所在地址的内容被改变了,猜测可能是被图像的某些数据所覆盖,还是要注意的一个地方。