视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
数字图像处理文档-直方图均衡&灰度线性变换&灰度拉伸
2025-09-29 22:34:57 责编:小OO
文档
技术报告

摘要:

本文档为数字图像处理程序的技术报告。程序主要功能为读入8位或24位位图,并可选择性对其进行直方图均衡、灰度线性变换、灰度拉伸等操作。该文档从算法原理和算法实现两方面,通过对算法的文字表述、函数的功能介绍以及主要代码分析注释,阐述了该程序进行图像处理时的方法,并通过实验测试和分析实验结果,验证了程序的正确性和可靠性。

关键词:直方图均衡 灰度线性变换 灰度拉伸

1、任务说明

⏹打开一幅图像,进行直方图均衡。将灰度线性变化,将灰度拉伸。

⏹用C语言或JAVA编程序读出图像文件,并利用算法进行灰度拉伸。

2、算法原理(背景意义,基本算法,扩展算法)

1

2

2.1直方图均衡

直方图均衡化是将原图像通过某种变换,得到一幅灰度直方图为均匀分布的新图像的方法。设图像均衡化处理后,图像的直方图是平直的,即各灰度级具有相同的出现频数,那么由于灰度级具有均匀的概率分布,图像看起来就更清晰了。

在离散情况下,共有L个灰度级,其中第k个灰度级rk出现的像素个数为nk,图像的总像素个数为N,则第k个灰度级出现的概率为:

进行均匀化处理的变换函数为:

2.2灰度线性变换

灰度的线性变换就是将图像中所有的点按照线性灰度变换函数进行变换。该线性灰度变换函数f(x)是一个一维线性函数:

f(x)=fA*x+fB

灰度变换方程为:

D2=f(D1)=k*D+d

式中参数k为线性函数的斜率,d为线性函数的在y轴上的截距,D1为输入图像的灰度,D2为输出的图像灰度。

当k>1时,输出的图像的对比度增大,图像的像素值在变换后全部增大,整体显示效果增强;当02.3灰度拉伸

灰度拉伸又叫对比度拉伸,它是最基本的一种灰度变换,使用的是最简单的分段线性变换函数,它的主要思想是提高图像处理时灰度级的动态范围。

可以有选择的拉伸某段灰度区间以改善输出图像。如图,所示的变换函数的运算结果是将原图在a到b之间的灰度拉伸到c到d之间。如果一幅图像的灰度集中在较暗的区域而导致图像偏暗,可以用灰度拉伸功能来拉伸(斜率>1)物体灰度区间以改善图像;同样如果图像灰度集中在较亮的区域而导致图像偏亮,也可以用灰度拉伸功能来压缩(斜率<1)物体灰度区间以改善图像质量。

图2.1 灰度拉伸

3、算法实现

3

3.1使用语言

C++

3.2编译环境

VC++6.0

3.3数据结构

1.

2.

3.

3.2

3.3

3.3.1文件头

typedef struct tagBITMAPFILEHEADER {

WORD    bfType;

DWORD   bfSize;

WORD    bfReserved1;

WORD    bfReserved2;

DWORD   bfOffBits;

} BITMAPFILEHEADER, *PBITMAPFILEHEADER;

●bfType代表的是文件格式,所以,从BMP文件的前两个字节我们就可以判断我们要打开的图片是不是位图。

●bfSize代表的是该位图文件的大小(包含文件头、信息头、调色板(如果有)、像素数据)。它是一个DWORD类型,占4个字节。

●bfReserved1和bfReserved2都是保留量,因此它们应该都为0。它们合起来占4个字节

●bfOffBits代表的是像素数据距的偏移地址。如果我们想直接读像素数据的话,可以把文件指针偏移bfOffBits个字节,然后读取就可以了。

●在保存BMP文件的时候,保存的顺序也是按照bfType、bfSize、bfReserved1、bfReserved2、bfOffBits的顺序的。

1.

2.

3.

3.2

3.3

3.3.1

3.3.2信息头

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;

●biSize代表的是该结构体的大小,即40字节。

●biWidth代表的是位图的宽度,以像素为单位。

●biHeight代表的是位图的高度,以像素为单位。

●biPlanes代表的位图的平面数。

●biBitCount代表的是位图的位数。

●biCompression代表是位图的压缩方法,由于BMP位图是没有压缩的,所以通常情况下它的值都为0。

●biSizeImage代表的是位图像素数据的大小,就是高度乘上每行像素所占的字节数。

●biXPelsPerMeter代表的是水平方向的分辨率,以米为单位。

●biYPelsPerMeter代表的是垂直方向的分辨率,以米为单位。

●biClrUsed代表的是位图用到的颜色数,可以设置为0,表示全部用到了。

●biClrImportant代表的是位图中重要的颜色数,可以设置为0,表示全部都很重要。

1.

2.

3.

3.2

3.3

3.3.1

3.3.2

3.3.3调色板 

typedef struct tagRGBQUAD {

BYTE    rgbBlue;

BYTE    rgbGreen;

BYTE    rgbRed;

BYTE    rgbReserved;

} RGBQUAD

●只有8位位图具有调色板。

●调色板是有若干项(最多256项)构成的,而每一项都是一个RGBQUAD的结构体,也就是说每一项都有一个蓝色、绿色、红色和保留量。

3.4函数说明

3.4

3.4

3.4.1自定义函数说明

函数功能说明输入参数说明输出参数说明
void PrintMenu()打印菜单选项
int CheckFilePath(char *filepath)检查路径是否合法:文件能打开;以bmp为后缀名

filepath:预处理位图路径

路径合法返回0,否则返回-1

void ShowImage(char * filepath)显示位图filepath:预处理位图路径

void ReadFileHeader(char *filepath,BITMAPFILEHEADER *bmfh)读入位图的文件头filepath:预处理位图路径;

bmfh:位图文件头指针

void ReadInfoHeader(char *filepath,BITMAPINFOHEADER *bmih)

读入位图的信息头filepath:预处理位图路径;

bmih:位图信息头指针

void ReadPixelData(char *filepath,BYTE *imgData)读入位图的像素数据filepath:预处理位图路径;

imgData:像素数据指针

int CreatePalette(RGBQUAD pal[])创建8位位图的调色板

pal:调色板指针

创建成功返回0,否则返回-1

LONG GetLineBytes(int imgWidth,int bitCount)计算每行像素所占的字节数imgWidth:位图宽度;

bitCount:位图位数

返回每行像素所占字节数
int GrayEqualize(BYTE *image,DWORD dwWidth,DWORD dwHeight,WORD wBitCount)直方图均衡image:位图像素数据指针;

dwWidth:位图宽度;

dwHeight:位图高度;

wBitCount:位图位数

处理成功返回0,否则返回-1

int LineTranslation(BYTE *image,DWORD dwWidth,DWORD dwHeight,WORD wBitCount,double k,double d)线性灰度变换image:位图像素数据指针;

dwWidth:位图宽度;

dwHeight:位图高度;

wBitCount:位数;

k:线性变换斜率;

d:线性变换截距

处理成功返回0,否则返回-1

int GrayStretch(BYTE* image,DWORD dwWidth,DWORD dwHeight,WORD wBitCount,int pt1x,int pt1y,int pt2x,int pt2y)

灰度拉伸image:位图像素数据指针;

dwWidth:位图宽度;

dwHeight:位图高度;

wBitCount:位数;

pt1x,pt1y,pt2x,pt2y:两个参考点的坐标

处理成功返回0,否则返回-1

void PrintFileHeader(BITMAPFILEHEADER *bmfh)打印位图的文件头bmfh:文件头指针

void PrintInfoHeader(BITMAPINFOHEADER *bmih)打印位图的信息头bmih:信息头指针

void PrintPixelData(BYTE *imgData,int width,int height,int bitCount)打印位图的像素数据image:位图像素数据指针;

dwWidth:位图宽度;

dwHeight:位图高度;

wBitCount:位数

int SaveAsImage(char *filepath)另存为位图filepath:预保存图片指定路径

保存成功返回0,否则返回-1

3.4.2库函数说明

函数功能说明输入参数说明输出参数说明
int fread(void *ptr, int size, int nitems, FILE *stream)从一个流中读数据ptr:接收数据的地址;

size:单个元素的大小,单位是字节指针;

nitems:元素个数;

stream:提供数据的文件指针

返回成功读取的元素个数
int fwrite(void *ptr, int size, int nitems, FILE *stream)

向文件读入写入一个数据块ptr:输出数据的地址;

size:单个元素的大小,单位是字节指针;

nitems:元素个数;

stream:目标文件指针

返回实际写入的数据块数目
int fseek(FILE *stream, long offset, int fromwhere)

移动文件指针stream:文件指针;

offset:偏移量;

fromwhere:起始地址

指针移动成功返回0,否则返回其他值

void *memcpy(void *destin, void *source, unsigned n)由指定内存区域复制指定个字节到指定内存区域destin:目标内存区;

source:源内存区;

n:预复制字节数

3.4.3函数依赖关系

调用函数被调用的函数
ReadPixelDataReadFileHeader,ReadInfoHeader,GetLineBytes

PrintPixelDataGetLineBytes
SaveAsImageGetLineBytes
3.5核心函数算法流程

 这里只说明处理8位位图的算法,24位位图的处理基本相同,只是分别处理R、G、B三个。

3.5

3.5.1直方图均衡函数

int GrayEqualize(BYTE *image,DWORD dwWidth,DWORD dwHeight,WORD wBitCount)

if (bitCount==8) {

    for (i=0; i        for (j=0; j            g=*(temp+lineBytes*(height-1-i)+j);  //计算像素点的灰度级

            grayNum[g]++;      //计算各个灰度级个数

        }

    }

    for (n=0; n<256; n++) {     //重新定义灰度级

        c=0;

        for (m=0; m<=n; m++)

            c+=grayNum[m];

        grayMap[n]=(BYTE)(c*255/height/width);

    }

    for (i=0; i        for (j=0; j            g=*(temp+lineBytes*(height-1-i)+j);  //计算像素点原灰度级

            *(temp+lineBytes*(height-1-i)+j)=grayMap[g];   //给像素点赋上新灰度级

        }

    }

}

3.5.2线性变换函数

int LineTranslation(BYTE *image,DWORD dwWidth,DWORD dwHeight,WORD,wBitCount,double k,double d)

if (wBitCount==8) {

for (i=0; i        for (j=0; j            g=*(image+dwLineBytes*(dwHeight-1-i)+j);  //计算像素点灰度级

            f=g*k+d;                       //对灰度级进行线性变换

            if(f>255) f=255;

            if(f<0) f=0;

            *(image+dwLineBytes*(dwHeight-1-i)+j)=(BYTE)f; //重新为像素点赋上灰度级

        }

    }

}

3.5.3 灰度拉伸函数

int GrayStretch(BYTE* image,DWORD dwWidth,DWORD dwHeight,WORD wBitCount,int pt1x,int pt1y,int pt2x,int pt2y)

for (n=0; n<=pt1x; n++) {

if (pt1x>0)

        map[n]=(BYTE)pt1y*n/pt1x;   //定义0点到点pt1之间新的灰度级,线性拉伸

    else

        map[n]=0;   //定义0点之前的灰度级全为0

}

for (; n<=pt2x; n++) {

    if (pt2x!=pt1x)

        map[n]=pt1y+(BYTE)((pt2y-pt1y)*(n-pt1x)/(pt2x-pt1x));

//定义点pt1到点pt2之间新的灰度级,线性拉伸

    else

        map[n]=pt1y;

}

for (; n<256; n++) {

    if (pt2x!=255)

        map[n]=pt2y+(BYTE)((255-pt2y)*(n-pt2x)/(255-pt2x));

//定义点pt2到点(255,255)之间新的灰度级,线性拉伸

    else

        map[n]=255;

}

 

if (wBitCount==8) {

for (i=0; i        for (j=0; j            g=*(image+dwLineBytes*(dwHeight-1-i)+j);  //计算像素点的灰度级

            *(image+dwLineBytes*(dwHeight-1-i)+j)=map[g]; //为像素点赋上新的灰度级

        }

    }

}

4、实验

4

4.1直方图均衡

图4.1 直方图均衡对比图

 直方图均衡后,图像得到了锐化,对比度变得强烈,图像更加清晰。

4.2灰度线性变换

图4.2 灰度线性变换对比图1

图4.3 灰度线性变换对比图2

 由图4.2和图4.3可知,在截距不变的情况下,斜率越大,图像灰度越弱,反之亦然。

图4.4 灰度线性变换对比图3

图4.5 灰度线性变换对比图4

 由图4.4和图4.5可知,当斜率不变时,截距越大,图像的灰度越弱,反之亦然。

4.3灰度拉伸

图4.6 灰度拉伸对比图

5、结论

通过这次试验,我自学会了用C++进行简单的数字图像处理,基本掌握了对于位图文件的读写和简单操作。实验过程中也遇到很多困难,在老师推荐的一些优秀书籍以及网络的帮助之下都一一解决了,从而充分感受到了数字图像处理的乐趣所在,也得到了充沛的知识。

参考文献

•MSDN2001

•刘海波,沈晶,郭耸. 《Visual C++数字图像处理技术详解》. 机械工业出版社. 2010

•冈萨雷斯. 阮秋琦(译). 《数字图像处理(第2版)》. 电子工业出版社. 2007

•章毓晋. 图像处理和分析. 清华大学出版社. 1990下载本文

显示全文
专题