Advertisement

DIP-图像增强 (Digital Image Enhancement)

阅读量:

DIP-图像增强

第二节:图像增强(Digital Image Enhancement)


文章目录

  • DIP-图像增强
  • 前言
  • 一、图像增强是什么?
  • 二、方法介绍
    • 1.线性对比度展宽
    • 2.非线性动态范围调整
    • 3.非线性动态范围调整灰度直方图均衡化

前言

遇到一些朦胧图片显示效果不够清晰怎么办?如大雾天气下细节缺失的图片,或夜间成像过于黑暗而丢失很多细节的图片等。图像增强可以有效解决这个问题。


一、图像增强是什么?

图像增强是在处理前对原始数据进行质量和信息量的提高。
常见的做法包括对比度增强、空间滤波、密度切片和FCC。
对比度增强或拉伸是通过线性变换扩大原有的灰度范围来实现的。
空间滤波改进了自然发生的线性特征,如断层、剪切带和轮廓线。
密度切片将连续的灰色调范围转换为一系列密度间隔,用单独的颜色或符号来表示不同的特征。
这里我们着重讲解对比度增强以及其中常用的三种方法:线性对比度展宽、非线性动态范围调整、灰度直方图均衡化


二、方法介绍

1.线性对比度展宽

目的:通过将亮暗差异(即对比度)扩大,来把人所关心的部分强调出来。

算法思想:f(i,j)为旧的位图矩阵函数,g(i,j)为新的位图矩阵函数。他们的对应关系如图所示。
在这里插入图片描述
在这里插入图片描述

代码如下(示例):

复制代码
    void linearContrastStretch(RGBQUAD** dataOfBmp_src, RGBQUAD** dataOfBmp_dst, DWORD width, DWORD height)
    {
    	double ka = 0.2,kb = 8,kc = 0.2;
    	int a = 60,b = 120;//范围不应过小 
    	double ga = a*ka;
    	double gb = b*kb+ga;
    	   for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    			//printf("%d ",dataOfBmp_dst[i][j].rgbRed);
    		if(dataOfBmp_src[i][j].rgbRed<a)
    			dataOfBmp_dst[i][j].rgbRed  = (dataOfBmp_dst[i][j].rgbRed * ka + 0.5); 
    		if(dataOfBmp_src[i][j].rgbGreen<a)
    			dataOfBmp_dst[i][j].rgbGreen = (dataOfBmp_dst[i][j].rgbGreen * ka + 0.5);
    		if(dataOfBmp_src[i][j].rgbBlue<a)
    			dataOfBmp_dst[i][j].rgbBlue  = (dataOfBmp_dst[i][j].rgbBlue * ka + 0.5);
    			
    		if(dataOfBmp_src[i][j].rgbRed >= b)
    			dataOfBmp_dst[i][j].rgbRed = (kc*(dataOfBmp_src[i][j].rgbRed-b) + gb + 0.5);
    		if(dataOfBmp_src[i][j].rgbGreen >= b)
    			dataOfBmp_dst[i][j].rgbGreen = (kc*(dataOfBmp_src[i][j].rgbGreen-b) + gb + 0.5);
    		if(dataOfBmp_src[i][j].rgbBlue >= b)
    			dataOfBmp_dst[i][j].rgbBlue = (kc*(dataOfBmp_src[i][j].rgbBlue-b) + gb + 0.5);
    	
    		if(dataOfBmp_src[i][j].rgbRed >= a && dataOfBmp_src[i][j].rgbRed < b)
    			dataOfBmp_dst[i][j].rgbRed = (kb*(dataOfBmp_src[i][j].rgbRed-a) + ga + 0.5);
    		if(dataOfBmp_src[i][j].rgbGreen >= a && dataOfBmp_src[i][j].rgbGreen < b)
    			dataOfBmp_dst[i][j].rgbGreen = (kb*(dataOfBmp_src[i][j].rgbGreen-a) + ga + 0.5);
    		if(dataOfBmp_src[i][j].rgbBlue >= a && dataOfBmp_src[i][j].rgbBlue < b)
    			dataOfBmp_dst[i][j].rgbBlue = (kb*(dataOfBmp_src[i][j].rgbBlue-a) + ga + 0.5);
    		}           
    }}

效果图:
在这里插入图片描述

2.非线性动态范围调整

目的:将暗的部分扩展,而将亮的部分抑制。
算法思想:通过动态范围的压缩,可以将所关心部分的灰度级的变化范围扩大。
动态范围调整方法分为以下两种:
1.线性动态范围调整
2.非线性动态范围调整
线性动态范围调整与上文第一种方法大同小异,这里着重介绍非线性动态范围调整方法
在这里插入图片描述
在这里插入图片描述

代码如下:

复制代码
    void dynamicRangeAdjustment(RGBQUAD** dataOfBmp_src, RGBQUAD** dataOfBmp_dst, DWORD width, DWORD height)
    {
    	double c = 105.8865;//数值较低时,将暗的部分扩展,将亮的部分抑制      数值高的时候相反 
    	   for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    		 dataOfBmp_dst[i][j].rgbRed = (c*log10(dataOfBmp_src[i][j].rgbRed + 1) + 0.5);  
    		 dataOfBmp_dst[i][j].rgbGreen = (c*log10(dataOfBmp_src[i][j].rgbGreen + 1) + 0.5);
    		 dataOfBmp_dst[i][j].rgbBlue = (c*log10(dataOfBmp_src[i][j].rgbBlue + 1) + 0.5);    
    		}	        
    }

效果图:
在这里插入图片描述

3.非线性动态范围调整灰度直方图均衡化

算法思想:对图像中像素个数多的灰度级进行展宽,而对像素个数少的灰度级进行缩减,从而达到清晰图像的目的。在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

复制代码
    void histogramEqualization(RGBQUAD** dataOfBmp_src, RGBQUAD** dataOfBmp_dst, DWORD width, DWORD height)
    {
    	printf("%d x %d\n",width,height);
    	DWORD Nf = width*height;//图像总体像素个数
    	printf("%d\n",Nf);  
    	DWORD greyRange_R[256] = {0};//灰度分级 0-255     起初设置int 造成溢出 
    	DWORD greyRange_G[256] = {0};
    	DWORD greyRange_B[256] = {0}; 
    	   for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    		 greyRange_R[dataOfBmp_src[i][j].rgbRed]++;//统计所有灰度分级的频数 
    		 greyRange_G[dataOfBmp_src[i][j].rgbGreen]++;
    		 greyRange_B[dataOfBmp_src[i][j].rgbBlue]++; 
    		}
    	double hsR[256] = {0.0};//每个灰度级的分布概率 R G B
    	double hsG[256] = {0.0};
    	double hsB[256] = {0.0}; 	
    	for(int i = 0;i<256;i++){
    		hsR[i] = greyRange_R[i] /(Nf*1.0);
    		hsG[i] = greyRange_G[i]/(Nf*1.0);
    		hsB[i] = greyRange_B[i]/(Nf*1.0);
    	}
    	//求直方图 
    	double temp1 = 0,temp2 = 0,temp3 = 0; 
    	for(int i=0;i<256;i++){
    		hsR[i] += temp1;
    		temp1 = hsR[i];
    		hsG[i] += temp2;
    		temp2 = hsG[i];
    		hsB[i] += temp3;
    		temp3 = hsB[i];
    	}
    	 //hs中存放R G B各灰度级的累积分布hp
    	for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    			if(dataOfBmp_src[i][j].rgbRed == 0)
    				 dataOfBmp_dst[i][j].rgbRed = 0;
    			else if(dataOfBmp_src[i][j].rgbRed != 0)
    				dataOfBmp_dst[i][j].rgbRed = (255*hsR[dataOfBmp_src[i][j].rgbRed] + 0.5);
    				
    			if(dataOfBmp_src[i][j].rgbGreen == 0)
    				 dataOfBmp_dst[i][j].rgbGreen = 0;
    			else if(dataOfBmp_src[i][j].rgbGreen != 0)
    				 dataOfBmp_dst[i][j].rgbGreen = (255*hsG[dataOfBmp_src[i][j].rgbGreen] + 0.5);
    				 
    			if(dataOfBmp_src[i][j].rgbBlue == 0)
    				 dataOfBmp_dst[i][j].rgbBlue = 0;
    			else if(dataOfBmp_src[i][j].rgbBlue != 0)
    				 dataOfBmp_dst[i][j].rgbBlue = (255*hsB[dataOfBmp_src[i][j].rgbBlue] + 0.5);
    		}  
    }

效果图:
在这里插入图片描述
在这里插入图片描述
完整代码:

复制代码
    //ReadBitMap
    //
    #include<math.h>   
    #include<stdio.h>   
    #include<stdlib.h>   
    #include <malloc.h>
    #include <memory.h>
    #include <math.h>
    
    
    #define   WIDTHBYTES(bits) (((bits)+31)/32*4)
    typedef unsigned char BYTE;
    typedef unsigned short WORD;
    typedef unsigned long DWORD;
    typedef long LONG;
    
    #pragma pack(1) //强制内存以1字节为单位对齐
    
    //位图文件头信息结构定义
    //其中不包含文件类型信息(由于结构体的内存结构决定,要是加了的话将不能正确读取文件信息)
    typedef struct tagBITMAPFILEHEADER {
    WORD   bfType;
    DWORD  bfSize;               //文件大小
    WORD   bfReserved1; //保留字,不考虑
    WORD   bfReserved2; //保留字,同上
    DWORD bfOffBits;         //实际位图数据的偏移字节数,即前三个部分长度之和
    } BITMAPFILEHEADER; 
    
    //信息头BITMAPINFOHEADER,也是一个结构,其定义如下:
    typedef struct tagBITMAPINFOHEADER{
    //public:
    DWORD   biSize;                  //指定此结构体的长度,为40
    LONG    biWidth;        //位图宽
    LONG    biHeight;       //位图高
    WORD    biPlanes;        //平面数,为1
    WORD    biBitCount;       //采用颜色位数,可以是1,2,4,8,16,24,新的可以是32
    DWORD   biCompression;           //压缩方式,可以是0,1,2,其中0表示不压缩
    DWORD   biSizeImage;             //实际位图数据占用的字节数
    LONG    biXPelsPerMeter;   //X方向分辨率
    LONG    biYPelsPerMeter;   //Y方向分辨率
    DWORD   biClrUsed;                  //使用的颜色数,如果为0,则表示默认值(2^颜色位数)
    DWORD   biClrImportant;             //重要颜色数,如果为0,则表示所有颜色都是重要的
    } BITMAPINFOHEADER; 
    
    //调色板Palette,当然,这里是对那些需要调色板的位图文件而言的。24位和32位是不需要调色板的。
    //(似乎是调色板结构体个数等于使用的颜色数。)
    typedef struct tagRGBQUAD { 
    //public:
    BYTE     rgbBlue; //该颜色的蓝色分量
    BYTE     rgbGreen; //该颜色的绿色分量
    BYTE     rgbRed; //该颜色的红色分量
    BYTE     rgbReserved; //保留值
    } RGBQUAD;
    
    
    /*函数功能:位图文件头显示
      输入参数:BITMAPFILEHEADER* pBmpHead 指向位图文件头结构的指针
    (即内存地址,实现主调函数实参和被调函数形参的内存共享)
      输出值:没有
    */
    
    void showBmpHead(BITMAPFILEHEADER* pBmpHead)
    {
    	printf("位图文件头:\n");
    	printf("文件类型:%x\n",pBmpHead->bfType);
    	printf("文件大小:%d\n",pBmpHead->bfSize);
    	printf("保留字:%d\n",pBmpHead->bfReserved1);
    	printf("保留字:%d\n",pBmpHead->bfReserved2);
    	printf("实际位图数据的偏移字节数:%d\n",pBmpHead->bfOffBits);
    }
    
    /*函数功能:位图信息头显示
    输入参数:BITMAPINFOHEADER* pBmpInforHead 指向位图文件信息头结构的指针
    (即内存地址,实现主调函数实参和被调函数形参的内存共享)
      输出值:没有
    */
    void showBmpInforHead(BITMAPINFOHEADER* pBmpInforHead)
    {
    	printf("位图信息头:\n");
    	printf("结构体的长度:%d\n",pBmpInforHead->biSize);
    	printf("位图宽:%d\n",pBmpInforHead->biWidth);
    	printf("位图高:%d\n",pBmpInforHead->biHeight);
    	printf("biPlanes平面数:%d\n",pBmpInforHead->biPlanes);
    	printf("biBitCount采用颜色位数:%d\n",pBmpInforHead->biBitCount);
    	printf("压缩方式:%d\n",pBmpInforHead->biCompression);
    	printf("biSizeImage实际位图数据占用的字节数:%d\n",pBmpInforHead->biSizeImage);
    	printf("X方向分辨率:%d\n",pBmpInforHead->biXPelsPerMeter);
    	printf("Y方向分辨率:%d\n",pBmpInforHead->biYPelsPerMeter);
    	printf("使用的颜色数:%d\n",pBmpInforHead->biClrUsed);
    	printf("重要颜色数:%d\n",pBmpInforHead->biClrImportant);
    }
    
    /*函数功能:颜色表(索引模式)或位图数据区各像素RGB值(真彩模式)显示
      输入参数:RGBQUAD* pRGB --- RGBAlpha 四元素结构体指针变量
            DWORD num --- 要显示的RGBAlpha 四元素结构体个数,
    	    即颜色表长度或要显示的像素个数
      输出值:  没有
    */
    void showRgbQuan(RGBQUAD* pRGB, DWORD num)
    { 
    	for (DWORD i=0; i<num; i++)
    	{
    	   if (i%5==0)
    	   {
    		printf("\n");
    	   }
    	   printf("(%-3d,%-3d,%-3d)   ",(pRGB+i)->rgbRed,(pRGB+i)->rgbGreen,(pRGB+i)->rgbBlue);
    	}
    	printf("\n");
    
    }
    
    /*函数功能:图像反色
      输入参数:RGBQUAD* dataOfBmp_src --- 原图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
    	        RGBQUAD* dataOfBmp_dst --- 反色后的图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
            DWORD width, DWORD height --- 原图像和输出图像的宽度和高度
            (以像素为单位)
      输出值:  没有
    */
    void reverseColor(RGBQUAD** dataOfBmp_src, RGBQUAD** dataOfBmp_dst, DWORD width, DWORD height)
    {
    	   for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    		 dataOfBmp_dst[i][j].rgbRed = 255-dataOfBmp_src[i][j].rgbRed;  
    		 dataOfBmp_dst[i][j].rgbGreen = 255-dataOfBmp_src[i][j].rgbGreen;   
    		 dataOfBmp_dst[i][j].rgbBlue = 255-dataOfBmp_src[i][j].rgbBlue;    
    		}            
    }
    
    /*函数功能:彩色图像转化为灰度图象
      输入参数:RGBQUAD** dataOfBmp_src --- 原图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
    	        RGBQUAD** dataOfBmp_dst --- 转化为灰度图象后的图像所有像素(以行为序)对应的RGBAlpha 四元素结构体指针;
    	        BYTE** dataOfBmp_gray --- 转化为灰度图象后的图像所有像素(以行为序)对应的灰度值;
            DWORD width, DWORD height --- 原图像和输出图像的宽度和高度
            (以像素为单位)
      输出值:  没有
    */
    void RGB2Gray(RGBQUAD** dataOfBmp_src, RGBQUAD** dataOfBmp_dst, BYTE** dataOfBmp_gray, DWORD width, DWORD height)
    {
    	double gray;
    	   
    	for(DWORD i=0;i<height;i++)
    	{
    		for(DWORD j=0;j<width;j++)
    		{
    		 gray = 0.299*dataOfBmp_src[i][j].rgbRed+0.587*dataOfBmp_src[i][j].rgbGreen+0.114*dataOfBmp_src[i][j].rgbBlue;
    		 dataOfBmp_gray[i][j] = (BYTE)gray;
    		 dataOfBmp_dst[i][j].rgbRed = (BYTE)gray;   
    		 dataOfBmp_dst[i][j].rgbGreen = (BYTE)gray;   
    		 dataOfBmp_dst[i][j].rgbBlue = (BYTE)gray;    
    		} 
    	}	           
    }
    
    /*函数功能:灰度图象四近邻(flag=0)或八近邻(flag=1)对比度
      输入参数:BYTE* dataOfBmp_gray --- 灰度图像所有像素(以行为序)对应的灰度值;
            DWORD width, DWORD height --- 原图像和输出图像的宽度和高度
            (以像素为单位)
    			bool flag --- 四近邻或八近邻标志, flag=0为四近邻,flag=1为八近邻
      输出值:  四近邻(flag=0)或八近邻(flag=1)对比度
    */
    double contrast(BYTE** dataOfBmp_gray, DWORD width, DWORD height, bool flag)
    {
    	DWORD i, j;
    	double contrast_sum = 0;
    	int tmp0 = 2, tmp1 = 3, tmp2 = 4;
    	int num = 0;
    	
    	if(flag)
    	{
    		tmp0 = 3;
    		tmp1 = 5;
    		tmp2 = 8;
    	}
    	num = 4*tmp0+((width-2)+(height-2))*2*tmp1+((width-2)*(height-2))*tmp2; 
    
    	for(i=0;i<height;i++)
    	{
    		for(j=0;j<width;j++)
    		{
    			 if(i>0)
    			 {
    				 contrast_sum += pow((dataOfBmp_gray[i-1][j]-dataOfBmp_gray[i][j]),2.0);
    				 if(flag)
    				 {
    					if(j>0)
    					{
    						contrast_sum += pow((dataOfBmp_gray[i-1][j-1]-dataOfBmp_gray[i][j]),2.0);
    					}
    					if(j<width-1)
    					{
    						contrast_sum += pow((dataOfBmp_gray[i-1][j+1]-dataOfBmp_gray[i][j]),2.0);
    					}
    				 }
    			 }
    			 if(i<height-1)
    			 {
    				 contrast_sum += pow((dataOfBmp_gray[i+1][j]-dataOfBmp_gray[i][j]),2.0);
    				 if(flag)
    				 {
    					if(j>0)
    					{
    						contrast_sum += pow((dataOfBmp_gray[i+1][j-1]-dataOfBmp_gray[i][j]),2.0);
    					}
    					if(j<width-1)
    					{
    						contrast_sum += pow((dataOfBmp_gray[i+1][j+1]-dataOfBmp_gray[i][j]),2.0);
    					}
    				 }
    			 }
    			 
    			 if(j>0)
    			 {
    				 contrast_sum += pow((dataOfBmp_gray[i][j-1]-dataOfBmp_gray[i][j]),2.0); 
    			 }
    
    			 if(j<width-1)
    			 {
    				 contrast_sum += pow((dataOfBmp_gray[i][j+1]-dataOfBmp_gray[i][j]),2.0); 
    			 }
    
    		}
    	}
    		
    	return contrast_sum/num;
    }
    
    
    /*函数功能:写(32位)位图(即保存)
      输入参数:RGBQUAD* dataOfBmp --- 待存储图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
            DWORD width, DWORD height --- 待存储图像的宽度和高度
            (以像素为单位)
      输出值:  没有
    */
    void saveBmp(RGBQUAD** dataOfBmp, DWORD width, DWORD height)
    {
    	DWORD i, j;
    	BITMAPFILEHEADER   bitHead;
    	BITMAPINFOHEADER bitInfoHead; 
    	WORD biBitCount = 32;
    	FILE* pfile;
    	char strFile[50];
    	printf("please input the .bmp destination file name:\n");
    	scanf("%s",strFile);
    	pfile = fopen(strFile,"wb");//打开文件
    	if(pfile!=NULL)
    	{
    	   printf("file %s open success.\n", strFile);
    	   //写位图文件头信息
    	   bitHead.bfType = 0x4d42;
    	   bitHead.bfSize = 0;
    	   bitHead.bfReserved1 = 0;
    	   bitHead.bfReserved2 = 0;
    	   bitHead.bfOffBits = 54;
    	   if(biBitCount<=8)
    			bitHead.bfOffBits += (DWORD)pow(2, biBitCount)*4;
    	   fwrite(&bitHead,1,sizeof(tagBITMAPFILEHEADER),pfile);
    
    	   bitInfoHead.biSize = 40;
    	   bitInfoHead.biWidth = width;
    	   bitInfoHead.biHeight = height;
    	   bitInfoHead.biPlanes = 1;
    	   bitInfoHead.biBitCount = biBitCount;
    	   bitInfoHead.biCompression = 0;
    	   bitInfoHead.biSizeImage = 0;
    	   bitInfoHead.biXPelsPerMeter = 0;
    	   bitInfoHead.biYPelsPerMeter = 0;
    	   bitInfoHead.biClrImportant = 0;
    	   bitInfoHead.biClrUsed = 0;
    	   fwrite(&bitInfoHead,1,sizeof(tagBITMAPINFOHEADER),pfile);
    
    	   if(biBitCount<=8)
    	   {
    		   BYTE tmp=0;
    
    		   for(i=0; i<(DWORD)pow(2, biBitCount); i++)
    		   {
    			   tmp = (BYTE)i;
    			   fwrite(&tmp,1,4,pfile);
    		   }
    	   }
    
    	   int l_width   = WIDTHBYTES(width * biBitCount)-width*4;//计算为确保位图数据区的实际宽度为32字节的整数倍需添加的0字节个数
    	   for( i=0; i<height; i++)
    	   {
    		   for( j=0; j<width; j+=1) 
    		   {
    			   fwrite(&dataOfBmp[height-i-1][j],1,4,pfile);
    			   
    		   }
    
    		   BYTE tmp=0;
    		   for(j=0; j<l_width; j++)
    			   fwrite(&tmp,1,1,pfile);
    
    	   }
    	}
    
    	fclose(pfile);
    
    }
    /*函数功能:图像线性对比度展宽 
      输入参数:RGBQUAD* dataOfBmp_src --- 原图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
    	        RGBQUAD* dataOfBmp_dst --- 线性展宽后的图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
            DWORD width, DWORD height --- 原图像和输出图像的宽度和高度
            (以像素为单位)
      输出值:  没有
    */
    void linearContrastStretch(RGBQUAD** dataOfBmp_src, RGBQUAD** dataOfBmp_dst, DWORD width, DWORD height)
    {
    	double ka = 0.4,kb = 2.3,kc = 0.5;
    	int a = 75,b = 150; 
    	double ga = a*ka;
    	double gb = b*kb+ga;
    	   for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    		if(dataOfBmp_src[i][j].rgbRed<a)
    			dataOfBmp_dst[i][j].rgbRed *= ka; 
    		if(dataOfBmp_src[i][j].rgbGreen<a)
    			dataOfBmp_dst[i][j].rgbGreen *= ka;
    		if(dataOfBmp_src[i][j].rgbBlue<a)
    			dataOfBmp_dst[i][j].rgbBlue *= ka;
    			
    		if(dataOfBmp_src[i][j].rgbRed >= b)
    			dataOfBmp_dst[i][j].rgbRed = kc*(dataOfBmp_src[i][j].rgbRed-b) + gb;
    		if(dataOfBmp_src[i][j].rgbGreen >= b)
    			dataOfBmp_dst[i][j].rgbGreen = kc*(dataOfBmp_src[i][j].rgbGreen-b) + gb;
    		if(dataOfBmp_src[i][j].rgbBlue >= b)
    			dataOfBmp_dst[i][j].rgbBlue = kc*(dataOfBmp_src[i][j].rgbBlue-b) + gb;
    	
    		if(dataOfBmp_src[i][j].rgbRed >= a && dataOfBmp_src[i][j].rgbRed < b)
    			dataOfBmp_dst[i][j].rgbRed = kb*(dataOfBmp_src[i][j].rgbRed-a) + ga;
    		if(dataOfBmp_src[i][j].rgbGreen >= a && dataOfBmp_src[i][j].rgbGreen < b)
    			dataOfBmp_dst[i][j].rgbGreen = kb*(dataOfBmp_src[i][j].rgbGreen-a) + ga;
    		if(dataOfBmp_src[i][j].rgbBlue >= a && dataOfBmp_src[i][j].rgbBlue < b)
    			dataOfBmp_dst[i][j].rgbBlue = kb*(dataOfBmp_src[i][j].rgbBlue-a) + ga;
    		}           
    }
    /*函数功能:图像动态范围非线性调整 
      输入参数:RGBQUAD* dataOfBmp_src --- 原图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
    	        RGBQUAD* dataOfBmp_dst --- 线性展宽后的图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
            DWORD width, DWORD height --- 原图像和输出图像的宽度和高度
            (以像素为单位)
      输出值:  没有
    */
    void dynamicRangeAdjustment(RGBQUAD** dataOfBmp_src, RGBQUAD** dataOfBmp_dst, DWORD width, DWORD height)
    {
    	double c = 105.8865; 
    	   for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    		 dataOfBmp_dst[i][j].rgbRed = (c*log10(dataOfBmp_src[i][j].rgbRed + 1) + 0.5);  
    		 dataOfBmp_dst[i][j].rgbGreen = (c*log10(dataOfBmp_src[i][j].rgbGreen + 1) + 0.5);
    		 dataOfBmp_dst[i][j].rgbBlue = (c*log10(dataOfBmp_src[i][j].rgbBlue + 1) + 0.5);    
    		}	        
    }
    /*函数功能:图像直方图均衡化 
      输入参数:RGBQUAD* dataOfBmp_src --- 原图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
    	        RGBQUAD* dataOfBmp_dst --- 线性展宽后的图像所有像素(以行为序)对应的
            RGBAlpha 四元素结构体指针;
            DWORD width, DWORD height --- 原图像和输出图像的宽度和高度
            (以像素为单位)
      输出值:  没有
    */
    void histogramEqualization(RGBQUAD** dataOfBmp_src, RGBQUAD** dataOfBmp_dst, DWORD width, DWORD height)
    {
    	printf("%d x %d\n",width,height);
    	DWORD Nf = width*height;//图像总体像素个数
    	printf("%d\n",Nf);  
    	DWORD greyRange_R[256] = {0};//灰度分级 0-255     起初设置int 造成溢出 
    	DWORD greyRange_G[256] = {0};
    	DWORD greyRange_B[256] = {0}; 
    	   for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    		 greyRange_R[dataOfBmp_src[i][j].rgbRed]++;//统计所有灰度分级的频数 
    		 greyRange_G[dataOfBmp_src[i][j].rgbGreen]++;
    		 greyRange_B[dataOfBmp_src[i][j].rgbBlue]++; 
    		}
    	double hsR[256] = {0.0};//每个灰度级的分布概率 R G B
    	double hsG[256] = {0.0};
    	double hsB[256] = {0.0}; 	
    	for(int i = 0;i<256;i++){
    		hsR[i] = greyRange_R[i] /(Nf*1.0);
    		hsG[i] = greyRange_G[i]/(Nf*1.0);
    		hsB[i] = greyRange_B[i]/(Nf*1.0);
    	}
    	//求直方图 
    	double temp1 = 0,temp2 = 0,temp3 = 0; 
    	for(int i=0;i<256;i++){
    		hsR[i] += temp1;
    		temp1 = hsR[i];
    		hsG[i] += temp2;
    		temp2 = hsG[i];
    		hsB[i] += temp3;
    		temp3 = hsB[i];
    	}
    	 //hs中存放R G B各灰度级的累积分布hp
    	for(DWORD i=0;i<height;i++)
    		for(DWORD j=0;j<width;j++)
    		{
    			if(dataOfBmp_src[i][j].rgbRed == 0)
    				 dataOfBmp_dst[i][j].rgbRed = 0;
    			else if(dataOfBmp_src[i][j].rgbRed != 0)
    				dataOfBmp_dst[i][j].rgbRed = (255*hsR[dataOfBmp_src[i][j].rgbRed] + 0.5);
    				
    			if(dataOfBmp_src[i][j].rgbGreen == 0)
    				 dataOfBmp_dst[i][j].rgbGreen = 0;
    			else if(dataOfBmp_src[i][j].rgbGreen != 0)
    				 dataOfBmp_dst[i][j].rgbGreen = (255*hsG[dataOfBmp_src[i][j].rgbGreen] + 0.5);
    				 
    			if(dataOfBmp_src[i][j].rgbBlue == 0)
    				 dataOfBmp_dst[i][j].rgbBlue = 0;
    			else if(dataOfBmp_src[i][j].rgbBlue != 0)
    				 dataOfBmp_dst[i][j].rgbBlue = (255*hsB[dataOfBmp_src[i][j].rgbBlue] + 0.5);
    		}  
    }
    int main()
    {
    	BITMAPFILEHEADER   bitHead;
    	BITMAPINFOHEADER bitInfoHead; 
    	int i, j;
    
    	FILE* pfile;
    	char strFile[50];
    	printf("please input the .bmp source file name:\n");
    	scanf("%s",strFile);
    	pfile = fopen(strFile,"rb");//打开文件
    	if(pfile!=NULL)
    	{
    	   printf("file %s open success.\n", strFile);
    	   //读取位图文件头信息
    	   fread(&bitHead,1,sizeof(BITMAPFILEHEADER),pfile);
    	   if(bitHead.bfType != 0x4d42)
    	   {
    		printf("file is not .bmp file!");
    		return 0;
    	   }
      
    	   showBmpHead(&bitHead);
    	   printf("\n\n");
    	   //读取位图信息头信息
    	   fread(&bitInfoHead,1,sizeof(BITMAPINFOHEADER),pfile);
    	   showBmpInforHead(&bitInfoHead);
    	   printf("\n");
    	}
    	else
    	{
    	   printf("file open fail!\n");
    	   return 0;
    	}
    	
    	RGBQUAD* pRgb=NULL;
    
    	if(bitInfoHead.biBitCount < 24)//有调色板
    	{ 
    	   //读取调色盘结信息
    	   long nPlantNum = bitInfoHead.biClrUsed;
       if(!nPlantNum)
           	nPlantNum = long(pow(2,double(bitInfoHead.biBitCount)));    //   Mix color Plant Number;
    	   pRgb=new RGBQUAD[nPlantNum*sizeof(RGBQUAD)]; 
    	   memset(pRgb,0,nPlantNum*sizeof(RGBQUAD));
    	   int num = fread(pRgb,4,nPlantNum,pfile);
      
    	   printf("Color Plate Number: %d\n",nPlantNum);
    	   printf("颜色板信息:\n");
    	   showRgbQuan(pRgb, nPlantNum);
      
    	}
    
    	int width = bitInfoHead.biWidth;
    	int height = bitInfoHead.biHeight;
    	//分配内存空间把源图存入内存   
    	int l_width   = WIDTHBYTES(width* bitInfoHead.biBitCount);//计算位图的实际宽度并确保它为32的倍数
    	long nData = height*l_width;
    	BYTE    *pColorData= new BYTE[nData];   
    	memset(pColorData,0,nData);   
    
    	//把位图数据信息读到数组里   
    	fread(pColorData,1,nData,pfile); 
    
    	//将位图数据转化为RGB数据
    	RGBQUAD** dataOfBmp_src=NULL; //用于保存各像素对应的RGB数据
    	
    	dataOfBmp_src = new RGBQUAD*[height]; 
    	for(i=0; i < height;i++) 
    	   dataOfBmp_src[i] =new RGBQUAD[width]; 
    
    	if(bitInfoHead.biBitCount<24)//有调色板,即位图为非真彩色 
    	{
    	   int k;
    
    	   if(bitInfoHead.biBitCount <= 8 && !bitInfoHead.biCompression)
    	   {
    
    		   int pnum = 8/bitInfoHead.biBitCount;
    		   int mbnum = 8-bitInfoHead.biBitCount;
    		
    		   for(int i=0;i<height;i++)
    		   {
    				int k0 = (height-i-1)*l_width;//k:取得该像素颜色数据在实际数据数组中的序号
    				for(int j=0;j<width;j++)
    				{
    					  BYTE mixIndex= 0;
    					  k = k0+(j/pnum);
    					  mixIndex = pColorData[k];
    					  //mixIndex:提取当前像素的颜色的在颜色表中的索引值    
    					  if(bitInfoHead.biBitCount < 8)
    					  {
    						  mixIndex = mixIndex<<((j%pnum)*bitInfoHead.biBitCount);
    						  mixIndex = mixIndex>>mbnum;
    					  }
    
    					  //将像素颜色数据(RGBA)保存到数组中对应的位置
    					  dataOfBmp_src[i][j].rgbRed = pRgb[mixIndex].rgbRed;
    					  dataOfBmp_src[i][j].rgbGreen = pRgb[mixIndex].rgbGreen;
    					  dataOfBmp_src[i][j].rgbBlue = pRgb[mixIndex].rgbBlue;
    					  dataOfBmp_src[i][j].rgbReserved = pRgb[mixIndex].rgbReserved;
    				}
    
    			}
    	   }
    
     
    	   if(bitInfoHead.biBitCount == 16)
    	   {
    			   if(!bitInfoHead.biCompression)
    			   {
    					for( i=0;i<height;i++)
    					{
    						int k0 = (height-i-1)*l_width;
    						for( j=0;j<width;j++)
    						{
    							WORD mixIndex= 0;
    							k = k0+j*2;
    							WORD shortTemp;
    							shortTemp = pColorData[k+1];
    							shortTemp = shortTemp<<8;
    
    							mixIndex = pColorData[k] + shortTemp;
    							dataOfBmp_src[i][j].rgbRed = pRgb[mixIndex].rgbRed;
    							dataOfBmp_src[i][j].rgbGreen = pRgb[mixIndex].rgbGreen;
    							dataOfBmp_src[i][j].rgbBlue = pRgb[mixIndex].rgbBlue;
    							dataOfBmp_src[i][j].rgbReserved = pRgb[mixIndex].rgbReserved;
    						}
    					}
    			   }
    		 }
    	}
    	else//位图为24/32位真彩色
    	{
    	   int k;
    	   int index = 0;
    	   
       if(bitInfoHead.biBitCount == 16)
    	   {
    			for( i=0;i<height;i++)
    			{
    				int k0 = (height-i-1)*l_width;
    				for( j=0;j<width;j++)
    				{
    					k = k0+j*2;		
    					if(!bitInfoHead.biCompression)//555格式
    					{
    						dataOfBmp_src[i][j].rgbBlue=pColorData[k]&0x1F; 
    						dataOfBmp_src[i][j].rgbGreen=(((pColorData[k+1]<<6)&0xFF)>>3)+(pColorData[k]>>5); 
    						dataOfBmp_src[i][j].rgbRed=(pColorData[k+1]<<1)>>3;			
    						dataOfBmp_src[i][j].rgbReserved = 0;
    			
    	   				}
    				}
    			}
       }
    	   if(bitInfoHead.biBitCount == 24 && !bitInfoHead.biCompression)
    	   {
    			for( i=0;i<height;i++)
    			{
    				int k0 = (height-i-1)*l_width;
    				for( j=0;j<width;j++)
    				{
    					 k = k0+(j*3);
    					 dataOfBmp_src[i][j].rgbRed = pColorData[k+2];   
    					 dataOfBmp_src[i][j].rgbGreen = pColorData[k+1];   
    					 dataOfBmp_src[i][j].rgbBlue = pColorData[k];    
    					 dataOfBmp_src[i][j].rgbReserved = 0;    
    				 
    				} 
    			}
    	   }
    	   if(bitInfoHead.biBitCount == 32 && !bitInfoHead.biCompression)
    	   {
    			for( i=0;i<height;i++)
    			{
    				int k0 = (height-i-1)*l_width;
    				for( j=0;j<width;j++)
    				{
    					 k = k0+(j*4);
    					 dataOfBmp_src[i][j].rgbRed = pColorData[k+2];   
    					 dataOfBmp_src[i][j].rgbGreen = pColorData[k+1];   
    					 dataOfBmp_src[i][j].rgbBlue = pColorData[k];    
    					 dataOfBmp_src[i][j].rgbReserved = pColorData[k+3];    
    				 
    				} 
    			}
    
    	   }
    
    	}
    
    	//printf("像素数据信息:\n");
    	RGBQUAD** dataOfBmp_dst=NULL;
    	dataOfBmp_dst = new RGBQUAD*[height]; //反色后的图象中每个像素的RGBAlpha
    	for(i=0; i<height; i++)
    		dataOfBmp_dst[i] = new RGBQUAD[width];
    
    	BYTE** dataOfBmp_gray=NULL;
    	dataOfBmp_gray = new BYTE*[height];
    	for(i=0; i<height; i++)
    		dataOfBmp_gray[i] = new BYTE[width];
    
    	//reverseColor(dataOfBmp_src, dataOfBmp_dst, width, height);
    	//RGB2Gray(dataOfBmp_src, dataOfBmp_dst, dataOfBmp_gray, width, height);
    	//double contrast8nn = contrast(dataOfBmp_gray, width, height, 1);
    	
    	linearContrastStretch(dataOfBmp_src, dataOfBmp_dst, width, height);
    	//dynamicRangeAdjustment(dataOfBmp_src, dataOfBmp_dst, width, height);
    	//histogramEqualization(dataOfBmp_src, dataOfBmp_dst, width, height);
    	
    	//printf("the 8nn contrast of the gray image is %f\n", contrast8nn);
    
    	saveBmp(dataOfBmp_dst, width, height);
    
    	fclose(pfile); 
    	if (bitInfoHead.biBitCount<24 && pRgb)
    	{
    	   delete []pRgb;
    	}
    	for(i=0; i<height; i++)
    		if(dataOfBmp_src[i])
    			delete dataOfBmp_src[i];
    	if(dataOfBmp_src)
    		delete dataOfBmp_src;
    
    	for(i=0; i<height; i++)
    		if(dataOfBmp_dst[i])
    			delete dataOfBmp_dst[i];
    	if(dataOfBmp_dst)
    		delete dataOfBmp_dst;
    
    	for(i=0; i<height; i++)
    		if(dataOfBmp_gray[i])
    			delete dataOfBmp_gray[i];
    	if(dataOfBmp_gray)
    		delete dataOfBmp_gray;
    
    	if(pColorData)
    		delete []pColorData;
    
    }

全部评论 (0)

还没有任何评论哟~