1 直方图均衡化(Histogram Equalization)简介

  图像对比度增强的方法可以分成两类:一类是直接对比度增强方法;另一类是间接对比度增强方法。直方图拉伸和直方图均衡化是两种最常见的间接对比度增强方法。直方图拉伸是通过对比度拉伸对直方图进行调整,从而“扩大”前景和背景灰度的差别,以达到增强对比度的目的,这种方法可以利用线性或非线性的方法来实现;直方图均衡化则通过使用累积函数对灰度值进行“调整”以实现对比度的增强。

  如果一副图像的像素占有很多的灰度级而且分布均匀,那么这样的图像往往有高对比度和多变的灰度色调。直方图均衡化就是一种能仅靠输入图像直方图信息自动达到这种效果的变换函数。它的基本思想是对图像中像素个数多的灰度级进行展宽,而对图像中像素个数少的灰度进行压缩,从而扩展像原取值的动态范围,提高了对比度和灰度色调的变化,使图像更加清晰。

2 直方图均衡化原理

  设变量r代表图像中像素的灰度级,直方图变换就是假定一个变换式:

                             

  也就是,通过上述变换,每个原始图像的像素灰度级r都会产生一个s值。变换函数T(r)应满足以下条件:

  (1) T(r)在区间中为单值且单调递增;

  (2) 当 时,即T(r)的取值范围与r相同。

  直方图均衡化:对于离散值,我们处理其概率与求和,而不是概率密度函数与积分。一幅图像中灰度级rk出现的概率近似为

                          

  其中,n是图像中像素的总和, 是灰度级 的像素个数,L为图像中可能的灰度级总数。

                            

上式中变换函数的离散形式为:

                    

  式给出的变换(映射)称为直方图均衡化或直方图线性化。

   根据上面公式推导,直方图均衡化步骤如下:

  (1) 统计原图每灰度级像素个数

  (2) 统计原图像每灰度级像素的累积个数

  (3) 建立灰度级的映射规则

  (4) 将原图每个像素点的灰度映射到新图

3 直方图均衡化优缺点

  这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。

  这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景杂讯的对比度并且降低有用信号的对比度;变换后图像的灰度级减少,某些细节消失;某些图像,如直方图有高峰,经处理后对比度不自然的过分增强。

4 直方图均衡化源码实现

 #include <windows.h>
#include <stdafx.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include<conio.h>
#pragma pack(1) typedef unsigned char BYTE;
typedef short unsigned int WORD;
typedef unsigned long DWORD; typedef struct BMP_FILEHEADER
{//定义bmp文件头 WORD bmpType;/*位图标识*/
DWORD bmpSize;/*说明文件的大小,用字节为单位*/
DWORD bmpReserved;/*保留,必须设置为0*/
DWORD bmpOffset;/*从文件头开始到实际的图象数据之间的字节的偏移量*/
DWORD bmpHeaderSize;/*说明BITMAP_INFOHEADER结构所需要的字数*/
DWORD bmpWidth;/*说明图象的宽度,以象素为单位*/
DWORD bmpHeight;/*说明图象的高度,以象素为单位.大多数的BMP文件都是倒向的位图*/
WORD bmpPlanes;/*为目标设备说明位面数,其值将总是被设为1*/ } BMP_FILEHEADER; typedef struct BMP_INFOHEADER
{//定义bmp信息头 WORD bitsPerPixel;/*说明比特数/象素*/
DWORD bmpCompression;/*说明图象数据压缩的类型*/
DWORD bmpDataSize; /*说明图象的大小,以字节为单位。当用BI_RGB格式时,可设置为0*/
DWORD bmpHResolution;/*说明水平分辨率,用象素/米表示*/
DWORD bmpVResolution;/*说明垂直分辨率,用象素/米表示*/
DWORD bmpColors;/*实际使用的颜色数,0说明使用所有调色板项*/
DWORD bmpImportantColors;/*重要影响的颜色索引的数目,如果是0,表示都重要*/ } BMP_INFOHEADER; typedef struct RGBPALETTE
{//定义8位颜色表 BYTE rgbBlue;/*指定蓝色强度*/
BYTE rgbGreen;/*指定绿色强度*/
BYTE rgbRed;/*指定红色强度*/
BYTE rgbReserved;/*保留,设为0*/ } RGBPALETTE; typedef struct RGBPALETTE_24
{//定义24位颜色表
BYTE rgbBlue;/*指定蓝色强度*/
BYTE rgbGreen;/*指定绿色强度*/
BYTE rgbRed;/*指定红色强度*/
}RGBPALETTE_24; typedef struct BMPFILEPTR
{//定义bmp文件指针类型
BMP_FILEHEADER *bmpFileHeader;//bmp文件头指针
BMP_INFOHEADER *bmpInfoHeader;//bmp信息头指针
RGBPALETTE *bmpColorTable;//颜色表指针
unsigned char *bmpDataPtr;//bmp数据指针
}BMPFILEPTR; typedef struct HE
{//定义直方图均衡化结构
float ohs[];//原始灰度级概率
float integs[];//原始灰度概率累计值
}HE; long FileLength(FILE *fp);//返回文件长度
void WriteData(unsigned char *pBmpData,FILE *fp);//写数据,将文件数据写入pBmpData所指内存单元
unsigned char* MemoryAlloc(int length);//分配length长度的内存单元
void MemoryFree(unsigned char *pBmpData);//释放内存单元
int GetPixelColor(BMPFILEPTR bmpFile,unsigned int index,int bitsperpixel);//获得颜色值
void InputPicture(BMPFILEPTR *bmpFile,unsigned char *pBmpData,FILE *fp);//输入图片,文件指针初始化
void DisplayPicture(HDC hdc,BMPFILEPTR bmpFile,POINT spoint);//显示图片,将图片显示在画板上
void ComputeOriginalProbabilty(BMPFILEPTR bmpFile,HE *hequal);//计算原始图片灰度级概率
void ComputeEqualizedProbabilty(BMPFILEPTR bmpFile,HE *hequal);//计算均衡化后的灰度级概率
void GenerateEqualizedBmpFile(BMPFILEPTR bmpFile,FILE *fp1,HE hequal);//生成均衡化之后的bmp文件 long WINAPI WndProc(HWND,UINT,UINT,LONG); //处理消息响应的函数
BOOL InitWindowsClass(HINSTANCE); //初始化窗口类
BOOL InitWindows(HINSTANCE,int); //初始化窗口函数
HWND hWndMain;//窗口句柄 long FileLength(FILE *fp)
{//返回文件长度
long curpos, length; curpos = ftell(fp);
fseek(fp, 0L, SEEK_END);
length = ftell(fp);
fseek(fp, curpos, SEEK_SET);
return length;
} unsigned char* MemoryAlloc(int length)
{//按照length长度分配内存单元,返回内存首地址
unsigned char *pBmpData; if(NULL==(pBmpData=(unsigned char*)malloc(length*sizeof(unsigned char))))
{
MessageBox(NULL,(LPCWSTR )"memory allocation failure,error!",NULL,NULL);
exit();
}
return pBmpData;
} void MemoryFree(unsigned char *pBmpData)
{//释放内存单元
free(pBmpData);
} void WriteData(unsigned char *pBmpData,FILE *fp)
{//写数据,将文件数据写入字节流中
int ind=;
fseek(fp, , SEEK_SET);
while(!feof(fp))
{
pBmpData[ind++]=fgetc(fp);
}
} int GetPixelColor(BMPFILEPTR bmpFile,unsigned int index,int bitsperpixel)
{//取像素点的颜色值,在VC++中颜色值是0x00bbggrr,返回颜色值
unsigned int pixelcolor=;
switch(bitsperpixel)
{
case : pixelcolor+=(bmpFile.bmpColorTable+*(bmpFile.bmpDataPtr+index))->rgbBlue;
pixelcolor<<=;
pixelcolor+=(bmpFile.bmpColorTable+*(bmpFile.bmpDataPtr+index))->rgbGreen;
pixelcolor<<=;
pixelcolor+=(bmpFile.bmpColorTable+*(bmpFile.bmpDataPtr+index))->rgbRed;
break;
case :
break;
case :pixelcolor+=((RGBPALETTE_24*)bmpFile.bmpDataPtr+index)->rgbBlue;
pixelcolor<<=;
pixelcolor+=((RGBPALETTE_24*)bmpFile.bmpDataPtr+index)->rgbGreen;
pixelcolor<<=;
pixelcolor+=((RGBPALETTE_24*)bmpFile.bmpDataPtr+index)->rgbRed;
break;
case :
break;
default:
;
}
return pixelcolor; }
void InputPicture(BMPFILEPTR *bmpFile,unsigned char *pBmpData,FILE *fp)
{//将bmp文件输入,存到pBmpData指针所指存储空间中,初始化bmpFile变量
WriteData(pBmpData,fp);
bmpFile->bmpFileHeader=(BMP_FILEHEADER*)(pBmpData);
bmpFile->bmpInfoHeader=(BMP_INFOHEADER*)((char*)bmpFile->bmpFileHeader+sizeof(BMP_FILEHEADER));
bmpFile->bmpColorTable=(RGBPALETTE*)((char*)bmpFile->bmpInfoHeader+sizeof(BMP_INFOHEADER));
bmpFile->bmpDataPtr=pBmpData+bmpFile->bmpFileHeader->bmpOffset; }
void DisplayPicture(HDC hdc,BMPFILEPTR bmpFile,POINT spoint)
{//显示图片,spoint为图片起始点,左上角
static int bmpHeight,bmpWidth;
int h,w;
unsigned int index=;
static int bitsperpixel;
static int pixelcolor;
bmpHeight=bmpFile.bmpFileHeader->bmpHeight;
bmpWidth=bmpFile.bmpFileHeader->bmpWidth;
bitsperpixel=bmpFile.bmpInfoHeader->bitsPerPixel;
if(==bmpFile.bmpInfoHeader->bitsPerPixel)
bmpWidth=((bmpWidth*bitsperpixel+)>>)<<;//若宽度不是4的整数倍则对齐 Rectangle(hdc,spoint.x,spoint.y,bmpWidth,bmpHeight);//画图片外框架
for(h=spoint.y+bmpHeight;h>spoint.y;h--)//从图片左下角开始逐点填充
for(w=spoint.x;w<spoint.x+bmpWidth;w++)
{
pixelcolor=GetPixelColor(bmpFile,index++,bitsperpixel);
SetPixel(hdc,w,h,pixelcolor);
}
}
void ComputeOriginalProbabilty(BMPFILEPTR bmpFile,HE *hequal)
{//计算原始灰度级概率
int i;
int pixels=(bmpFile.bmpFileHeader->bmpHeight)*(bmpFile.bmpFileHeader->bmpWidth); for(i=;i<pixels;i++)
hequal->ohs[bmpFile.bmpDataPtr[i]]++;//累计相同灰度级点个数 FILE *p1;
p1=fopen("p1.txt","w");
int p[];
for(i=;i<;i++)
{
p[i]=hequal->ohs[i]; fprintf(p1,"p[%d]=%d\n ",i,p[i]);
} for(i=;i<;i++)
hequal->ohs[i]=hequal->ohs[i]/pixels;//计算每个灰度级概率
}
void ComputeEqualizedProbabilty(BMPFILEPTR bmpFile,HE *hequal)
{// 计算原始灰度级概率的累计概率,为生成均衡化之后概率
int i;
FILE *p2;
p2=fopen("p2.txt","w");
int a[]; hequal->integs[]=hequal->ohs[];
for(i=;i<;i++)
{
hequal->integs[i]=hequal->integs[i-]+hequal->ohs[i]; a[i]=(hequal->integs[i])*;
fprintf(p2,"a[%d]=%d\n ",i,a[i]);
} }
void GenerateEqualizedBmpFile(BMPFILEPTR bmpFile,FILE *fp1,HE hequal)
{//生成均衡化后的bmp文件
unsigned long i,j;
unsigned char c;
fwrite(bmpFile.bmpFileHeader,sizeof(BMP_FILEHEADER),,fp1);//将bmp文件头结构数据赋给新文件相应部分
fwrite(bmpFile.bmpInfoHeader,sizeof(BMP_INFOHEADER),,fp1);
fwrite(bmpFile.bmpColorTable,*sizeof(RGBPALETTE),,fp1);
for(i=;i<bmpFile.bmpFileHeader->bmpSize-bmpFile.bmpFileHeader->bmpOffset;i++)
{//将灰度级数据赋给新文件数据部分
for(j=;j<;j++)
{
if(*(bmpFile.bmpDataPtr+i)==j)
{
c=hequal.integs[j]*;
break;
} }
fwrite(&c,sizeof(unsigned char),,fp1);
}
}
BMPFILEPTR bmpFile,newbmpFile;
HE hequal={,},newhequal={,};//初始化直方图结构体变量 int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{ //windows API 主函数
MSG Message; static FILE *fp = NULL,*newfp=NULL;//定义两个文件指针,分别指向两个bmp文件
static unsigned char *pBmpData,*newpBmpData;//定义两个数据指针,分别指向两处内存首地址
static int filesize=;
if(NULL==(fp=fopen("Fig4.bmp","rb+")))
{
MessageBox(NULL,(LPCWSTR )"file open failure,error!",NULL,NULL);
exit();
}
if(NULL==(newfp=fopen("newFig.bmp","wb+")))
{
MessageBox(NULL,(LPCWSTR )"file open failure,error!",NULL,NULL);
exit();
}
filesize=FileLength(fp);
pBmpData=MemoryAlloc(filesize);
newpBmpData=MemoryAlloc(filesize);
InputPicture(&bmpFile,pBmpData,fp);
ComputeOriginalProbabilty(bmpFile,&hequal);
ComputeEqualizedProbabilty(bmpFile,&hequal);
GenerateEqualizedBmpFile(bmpFile,newfp,hequal);
InputPicture(&newbmpFile,newpBmpData,newfp);
ComputeOriginalProbabilty(newbmpFile,&newhequal);
fclose(fp);
fclose(newfp); if(!InitWindowsClass(hInstance))
return FALSE;
if(!InitWindows(hInstance,nCmdShow))
return FALSE;
while(GetMessage(&Message,NULL,,))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
} int InitWindows(HINSTANCE hInstance,int nCmdShow)
{
hWndMain=CreateWindow(
(LPCWSTR )"WinFill", // registered class name
(LPCWSTR )"直方图均衡化", // window name
WS_OVERLAPPEDWINDOW, // window style
, // horizontal position of window
, // vertical position of window
, // window width
, // window height
NULL, // handle to parent or owner window
NULL, // menu handle or child identifier
hInstance, // handle to application instance
NULL // window-creation data
);
if(!hWndMain)
return FALSE;
ShowWindow(hWndMain,nCmdShow);
UpdateWindow(hWndMain);
return TRUE;
} int InitWindowsClass(HINSTANCE hInstance)
{ //初始化窗口类,对窗口类的对象赋初始值
WNDCLASS wndclass;
wndclass.style=;
wndclass.cbClsExtra=;
wndclass.cbWndExtra=;
wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.hCursor=LoadCursor(
hInstance,
IDC_ARROW
);
wndclass.hIcon=LoadIcon(
hInstance,
IDI_APPLICATION
);
wndclass.hInstance=hInstance;
wndclass.lpfnWndProc=WndProc;
wndclass.lpszClassName=(LPCWSTR )"WinFill";
wndclass.lpszMenuName=NULL;
return RegisterClass(&wndclass);
} long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam)
{
HDC hdc;
HPEN hpen;
PAINTSTRUCT ps;
POINT originpoint,pstartpoint; switch(iMessage)
{
case WM_PAINT: hdc=BeginPaint(hWnd,&ps);//绘图 hpen=CreatePen(PS_SOLID,,RGB(,,));
SelectObject(hdc,hpen);
////////////////画原始的bmp图//////////////////
pstartpoint.x=;
pstartpoint.y=;
DisplayPicture(hdc,bmpFile,pstartpoint); ///////////画均衡化后的bmp图/////////////////
pstartpoint.x=;
pstartpoint.y=;
DisplayPicture(hdc,newbmpFile,pstartpoint); return ;
case WM_DESTROY:PostQuitMessage();
return ;
default: return (DefWindowProc(hWnd,iMessage,wParam,lParam));
}
}

图像处理之直方图均衡化及C源码实现的更多相关文章

  1. Atitit Atitit 图像处理之  Oilpaint油画滤镜 水彩画 源码实现

    Atitit Atitit 图像处理之 Oilpaint油画滤镜 水彩画 源码实现 1.1. 具体原理参考1 2. 水彩画滤镜算法如下:1 2.1. 这个其实就是灰度层次降低维度的过程.2 2.2. ...

  2. OpenCV-跟我一起学数字图像处理之直方图均衡化

    从这篇博文开始,小生正式从一个毫不相干专业转投数字图像处理.废话不多说了,talk is cheap. show me the code. 直方图均衡化目的 由于一些图像灰度的分布过于集中,这样会导致 ...

  3. IPOL图像处理分析经典在线(文献+源码)

    网址: IPOL Journal · Image Processing On Line https://www.ipol.im/ 分类: 搜索: 下载文献和源码: NLM算法:IPOL Journal ...

  4. 彩色图像的直方图均衡化matlab代码

    彩色图像的直方图均衡化 - YangYudong2014的专栏 - CSDN博客 http://blog.csdn.net/yangyudong2014/article/details/4051503 ...

  5. DICOM医学图像处理:storescp.exe与storescu.exe源码剖析,学习C-STORE请求

    转载:http://blog.csdn.net/zssureqh/article/details/39213817 背景: 上一篇专栏博文中针对PACS终端(或设备终端,如CT设备)与RIS系统之间w ...

  6. matlab代码 图像处理源码

    非常不错的找图像处理源码的地方,源码搜搜. http://www.codesoso.com/Category.aspx?CategoryId=56

  7. Win8Metro(C#)数字图像处理--2.30直方图均衡化

    原文:Win8Metro(C#)数字图像处理--2.30直方图均衡化 [函数名称] 直方图均衡化函数HistogramEqualProcess(WriteableBitmap src) [算法说明] ...

  8. c#数字图像处理(六)直方图均衡化

    直方图均衡化又称直方图修平,是一种很重要的非线性点运算.使用该方法可以加强图像的局部对比度,尤其是当图像的有用数据的对比度相当接近的时候.通过这种方法,亮度可以更好的在直方图上分布. 直方图均衡化的基 ...

  9. 【16位RAW图像处理三】直方图均衡化及局部直方图均衡用于16位图像的细节增强。

    通常我们生活中遇到的图像,无论是jpg.还是png或者bmp格式,一般都是8位的(每个通道的像素值范围是0-255),但是随着一些硬件的发展,在很多行业比如医疗.红外.航拍等一些场景下,拥有更宽的量化 ...

随机推荐

  1. mac安装pkg 一直“正在验证” 卡着

    今天换了新mac, 但是之前wireshark(抓包工具) 不能用了 ,要安装Xquartz. 下载之后一直卡着, 网上找了半天没有解决方法. 最后我重启一下就好了... 重启一下. 2. 15款ma ...

  2. Java Basic&Security Tools

    JDK Tools and Utilities Basic Tools These tools are the foundation of the JDK. They are the tools yo ...

  3. NUMA 体系架构

    NUMA 体系架构 SMP 体系架构 NUMA 体系架构 NUMA 结构基本概念 Openstack flavor NUMA 策略 Nova 实现 NUMA 流程 1. SMP 体系架构 CPU 计算 ...

  4. 从零开始的Python学习Episode 10——函数

    函数 一.函数的创建 简单格式 def function_name(参数表): 函数体 return 如果没有写return,函数会默认返回一个none 二.函数的参数 必需参数: 调用函数时必需参数 ...

  5. 特征点检测--基于CNN:TILDE: A Temporally Invariant Learned DEtector

    TILDE: A Temporally Invariant Learned DEtector Yannick Verdie1,∗ Kwang Moo Yi1,∗ Pascal Fua1 Vincent ...

  6. PytorchZerotoAll学习笔记(四)--线性回归

    线性回归 # 导入 torch.torch.autograd的Variable模块import torch from torch.autograd import Variable # 生成需要回归需要 ...

  7. 使用 Sublime Text 做 Javascript 编辑器 - 集成 JSHint 问题检测工具

    JSHint(jshint.com)是 Javascritp 代码质量工具,可以帮助开发人员发现 Javascript 代码中的错误和潜在的问题.jshint.com 是一个在线编辑器,我们可以为 S ...

  8. Beta阶段中间产物

    空天猎功能说明书:https://git.coding.net/liusx0303/Plane.git 空天猎代码控制:https://coding.net/u/MR__Chen/p/SkyHunte ...

  9. 欢迎来怼第二周Scrum会议六(总第十三次)

    一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华 小组照片 二.开会信息 时间:2017/10/25  17:19~17:35(总计16min).地点:东 ...

  10. 第八次作业(课堂实战)- 项目UML设计

    本次作业博客 团队信息 队名:起床一起肝活队 原组长: 白晨曦(101) 原组员: 李麒 (123) 陈德斌(104) 何裕捷(214) 黄培鑫(217) 王焕仁(233) 林志华(128) 乐忠豪( ...