灰度直方图反应图像灰度的统计特性,表达了图像中取不同灰度值的面积或像素数在政府图像中所占的比例,是图像中最基本的信息。
直方图的横坐标是灰度级,一般用r表示,纵坐标是具有该灰度级的像素个数或出现这个灰度级的概率P(rk)(k为下标)。 ;式中,N为一副图像中像素的总数,nk为第k级灰度的像素数,rk表示第k个灰度级,P(rk)则表示该灰度级出现的概率.因为P(rk)给出了对rk出现概率的一个估值,所以直方图提供了原图的灰度值分布情况。
灰度直方图灰度级的分布可以提供图像信息的许多特征,为图像分析提供了一个有力的工具。例如,若直方图密集地分布在很窄的区域之内,说明图像的对比度很低;若直方图有两个峰值,则说明图像中很有可能存在两种不同亮度的区域。
class HistogramDrawDlg : public CDialog
{
DECLARE_DYNAMIC(HistogramDrawDlg)
public:
HistogramDrawDlg(CWnd* pParent = NULL); // 标准构造函数
virtual ~HistogramDrawDlg();
public:
ImageDib m_himageDib ;
int m_histArry[256] ;
float m_average ;
float m_deviation ;
int m_imgWidthOut ;
int m_imgHeightOut ;
int m_nBitCountOut ;
unsigned char * m_pImgDataOut ;
LPRGBQUAD m_lpColorTableOut ;
int m_nColorTableLengthOut ;
public:
CSize GetDimensions() ;
void ComputeHistGray() ;
float ComputeAverage() ;
float ComputeDeviation() ;
// 对话框数据
enum { IDD = IDD_DIALOG_Histogram };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
afx_msg void OnPaint() ;
DECLARE_MESSAGE_MAP()
public:
virtual BOOL OnInitDialog();
};
// HistogramDrawDlg.cpp : 实现文件
#include "stdafx.h"
#include "Pic.h"
#include "HistogramDrawDlg.h"
#include "afxdialogex.h"
#include <math.h>
// HistogramDrawDlg 对话框
IMPLEMENT_DYNAMIC(HistogramDrawDlg, CDialog)
HistogramDrawDlg::HistogramDrawDlg(CWnd* pParent /*=NULL*/)
: CDialog(HistogramDrawDlg::IDD, pParent)
{
memset(m_histArry , 0 , sizeof(m_histArry)) ;
m_average = 0.0 ;
m_deviation = 0.0 ;
m_nBitCountOut = 0 ;
m_pImgDataOut = NULL ;
m_lpColorTableOut = NULL ;
m_imgWidthOut = 0 ;
m_imgHeightOut = 0 ;
m_nColorTableLengthOut = 0 ;
}
HistogramDrawDlg::~HistogramDrawDlg()
{
if(m_pImgDataOut != NULL){
delete []m_pImgDataOut ;
m_pImgDataOut = NULL ;
}
if(m_lpColorTableOut != NULL){
delete []m_lpColorTableOut ;
m_lpColorTableOut = NULL ;
}
}
void HistogramDrawDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(HistogramDrawDlg, CDialog)
ON_WM_PAINT()
END_MESSAGE_MAP()
// HistogramDrawDlg 消息处理程序
CSize HistogramDrawDlg::GetDimensions(){
m_imgWidthOut = m_himageDib.m_imgWidth ;
m_imgHeightOut = m_himageDib.m_imgHeight ;
if(m_pImgDataOut == NULL) return CSize(0 , 0) ;
else return CSize(m_imgWidthOut , m_imgHeightOut) ;
}
void HistogramDrawDlg::ComputeHistGray(){
if(m_nBitCountOut != 8) return ;
memset(m_histArry , 0 , sizeof(m_histArry)) ;
int lineByte = (m_himageDib.m_imgWidth * m_nBitCountOut/8 + 3) / 4 * 4 ;
for(int i = 0 ; i < m_imgHeightOut ; i++){
for(int j = 0 ; j < m_imgWidthOut ; j++){
m_histArry[*(m_himageDib.m_pImgData + i * lineByte + j)]++ ;
}
}
}
float HistogramDrawDlg::ComputeAverage(){
float sum = 0 ;
for(int i = 0 ; i < 256 ; i++){
sum += i * m_histArry[i] ;
}
return m_average = sum / (m_himageDib.m_imgHeight * m_himageDib.m_imgWidth) ;
}
float HistogramDrawDlg::ComputeDeviation(){
float sum = 0 ;
for(int i = 0 ; i < 256 ; i++){
sum += (i - m_average) * (i - m_average) * m_histArry[i] ;
}
sum /= (m_himageDib.m_imgWidth * m_himageDib.m_imgHeight) ;
return m_deviation = sqrt(sum) ;
}
BOOL HistogramDrawDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_nBitCountOut = m_himageDib.m_nBitCount ;
m_imgHeightOut = m_himageDib.m_imgHeight ;
m_imgWidthOut = m_himageDib.m_imgWidth ;
CRect rect;
rect=CRect(50,60,300,170);
GetDlgItem(IDC_STATIC_hist)->MoveWindow(&rect);
if(m_nBitCountOut == 8) ComputeHistGray() ;
CString str ;
str.Format(_T("%.2lf") , ComputeAverage() ) ;
SetDlgItemText(IDC_STATIC_AveShow , str) ;
str.Format(_T("%.2lf") , ComputeDeviation() ) ;
SetDlgItemText(IDC_STATIC_DevShow , str) ;
return TRUE; // return TRUE unless you set the focus to a control
}
void HistogramDrawDlg::OnPaint(){
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
//彩色和灰度图像有效
if(m_nBitCountOut!= 8 && m_nBitCountOut!= 24)
return ;
//获取直方图绘制静态框的矩形区域
CRect clientRect;
GetDlgItem(IDC_STATIC_hist)->GetWindowRect(&clientRect);
ScreenToClient(&clientRect);
BeginWaitCursor(); // Draw Back Ground
//画背景
dc.SelectStockObject(NULL_BRUSH);
dc.Rectangle(clientRect.left, clientRect.top-5,
clientRect.right, clientRect.bottom+1);
//画直方图灰度频率与直方图绘制矩形区域比例关系,画直方图
unsigned int max=0;;
for(int i=0;i<256;i++){
if(m_histArry[i]>max)
max=m_histArry[i];
}
DWORD bufTemp[256];
double x=clientRect.Height();
int i ;
for(i=0;i<256;i++){
bufTemp[i]=(unsigned long)((float)m_histArry[i]*x/max);
}
for(i=clientRect.left;i<=clientRect.right;i++){
dc.MoveTo(i,clientRect.bottom);
dc.LineTo(i,clientRect.bottom-bufTemp[i-clientRect.left]);
}
CString str;
SetBkMode(dc,1); //字体背景设为透明
str.Format(_T("0"));
dc.TextOut(clientRect.left,clientRect.bottom+1,str);
str.Format(_T("50"));
dc.TextOut(clientRect.left+50,clientRect.bottom+1,str);
str.Format(_T("100"));
dc.TextOut(clientRect.left+100,clientRect.bottom+1,str);
str.Format(_T("150"));
dc.TextOut(clientRect.left+150,clientRect.bottom+1,str);
str.Format(_T("200"));
dc.TextOut(clientRect.left+200,clientRect.bottom+1,str);
str.Format(_T("255"));
dc.TextOut(clientRect.left+255,clientRect.bottom+1,str);
EndWaitCursor();
}