(学习笔记6)BMP位图照片的灰度变换之直方图

来源:互联网 发布:马来西亚海关数据 编辑:程序博客网 时间:2024/05/29 17:37

接着(学习笔记5)来写,注意注意是在(学习笔记5)上去写直方图的。每个学习笔记都是在前一个基础上去写的。
好的废话完了,直接写直方图。

step1.修改菜单栏中灰度变换下直方图的ID,如下图所示:
这里写图片描述

step2.直方图的显示,我们需要设计一个对话框来在Picture Control控件中显示,所以第二步,我们来设计对话框。
步骤如下截屏所示:
设计的最终界面如下:
这里写图片描述

接下来一步步去阐述步骤和过程。
修改对话框的ID,和对话框的Caption以及从工具箱中拉入Group Box和Picture Control控件就不用说了,请注意:Group Box中拉进去了两个Picture Control控件。
这里写图片描述

这里写图片描述

第一Picture Control的ID修改
这里写图片描述

第二个Picture Control的ID修改,以及Type,Image修改。
左上角的照片如下:添加资源命名为IDB_BITMAP1
这里写图片描述

这里写图片描述

修改“均值”下边的Edit Control的ID
这里写图片描述

修改“方差”下边的Edit Control的ID
这里写图片描述

Picture Control还有一个属性需要修改。如下截图:
这里写图片描述

step3. 响应函数。
这里写图片描述

afx_msg void OnHistogramDraw();

这里写图片描述

void Cdemo1View::OnHistogramDraw() {    // TODO: Add your command handler code here    //获取文档类中m_dib的指针,访问当前DIB数据    Cdemo1Doc *pDoc=GetDocument();    ImageDib *pDib=pDoc->m_dib;    //异常判断    if(pDib->m_nBitCount!=8&&pDib->m_nBitCount!=24){        ::MessageBox(0,L"只处理灰度和彩色图像",MB_OK,0);        return ;    }    //直方图绘制对话框    HistogramDrawDlg dlgHist;    dlgHist.m_himageDib.ReplaceDib(pDib->GetDimensions(),pDib->m_nBitCount,        pDib->m_lpColorTable, pDib->m_pImgData);    //显示直方图   dlgHist.DoModal();}

这里写图片描述

#if !defined(AFX_HISTOGRAMDRAWDLG_H__2CABD0F5_E9B6_4128_9979_64C4DAE89356__INCLUDED_)#define AFX_HISTOGRAMDRAWDLG_H__2CABD0F5_E9B6_4128_9979_64C4DAE89356__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#include "ImageDib.h"// HistogramDrawDlg.h : header file///////////////////////////////////////////////////////////////////////////////// HistogramDrawDlg dialogclass HistogramDrawDlg : public CDialog{// Constructionpublic:    //构造函数    HistogramDrawDlg(CWnd* pParent = NULL);   // standard constructor    //ImgDib类的对象m_himageDib    ImageDib m_himageDib;public:    //直方图数组    int m_histArray[256];    //直方图平均值    float m_average;    //直方图方差    float m_deviation;    //输出图像每像素位数    int m_nBitCountOut;    //输出图像位图数据指针    unsigned char * m_pImgDataOut;    //输出图像颜色表    LPRGBQUAD m_lpColorTableOut;    //输出图像的宽,像素为单位    int m_imgWidthOut;    //输出图像的高,像素为单位    int m_imgHeightOut;    //输出图像颜色表长度    int m_nColorTableLengthOut;    CEdit DEV;    CEdit AVE;public:    //以像素为单位返回输出图像的宽和高    CSize GetDimensions();    //灰度图像统计直方图    void computeHistGray();    //彩色图像亮度直方图    void computeHistBrightness();    //计算直方图均值    float computeAverage();    //计算直方图方差    float computeDeviation();    //直方图均衡    void histogramAve();    //析构函数    ~HistogramDrawDlg();// Dialog Data    //{{AFX_DATA(HistogramDrawDlg)    enum { IDD = IDD_DIALOG_Histogram };        // NOTE: the ClassWizard will add data members here    //}}AFX_DATA// Overrides    // ClassWizard generated virtual function overrides    //{{AFX_VIRTUAL(HistogramDrawDlg)    protected:    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support    //}}AFX_VIRTUAL// Implementationprotected:      // Generated message map functions    //{{AFX_MSG(HistogramDrawDlg)    virtual BOOL OnInitDialog();    afx_msg void OnPaint();    //}}AFX_MSG    DECLARE_MESSAGE_MAP()};//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif // !defined(AFX_HISTOGRAMDRAWDLG_H__2CABD0F5_E9B6_4128_9979_64C4DAE89356__INCLUDED_)

这里写图片描述

// HistogramDrawDlg.cpp : implementation file//#include "stdafx.h"#include "demo1.h"#include "HistogramDrawDlg.h"#include "ImageDib.h"#include "math.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// HistogramDrawDlg dialogHistogramDrawDlg::HistogramDrawDlg(CWnd* pParent /*=NULL*/)    : CDialog(HistogramDrawDlg::IDD, pParent){    //{{AFX_DATA_INIT(HistogramDrawDlg)        // NOTE: the ClassWizard will add member initialization here    //}}AFX_DATA_INIT    for(int i=0;i<256;i++)        m_histArray[i]=0;    m_average = 0;//均值为0    m_deviation=0;//方差为0    m_pImgDataOut=NULL;//输出图像位图数据指针为空    m_lpColorTableOut=NULL;//输出图像颜色表指针为空    m_nColorTableLengthOut=0;//输出图像颜色表长度为0    m_nBitCountOut=0;//输出图像每像素位数为0    m_imgWidthOut=0;//输出图像的宽为0    m_imgHeightOut=0;//输出图像的高为0}void HistogramDrawDlg::DoDataExchange(CDataExchange* pDX){    CDialog::DoDataExchange(pDX);    DDX_Control(pDX, IDC_STATIC_AveShow, AVE);    DDX_Control(pDX, IDC_STATIC_DevShow, DEV);    //{{AFX_DATA_MAP(HistogramDrawDlg)        // NOTE: the ClassWizard will add DDX and DDV calls here    //}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(HistogramDrawDlg, CDialog)    //{{AFX_MSG_MAP(HistogramDrawDlg)    ON_WM_PAINT()    //}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// HistogramDrawDlg message handlersBOOL HistogramDrawDlg::OnInitDialog() {    CDialog::OnInitDialog();        // TODO: Add extra initialization here    m_nBitCountOut=m_himageDib.m_nBitCount;    m_imgWidthOut=m_himageDib.m_imgWidth;    m_imgHeightOut=m_himageDib.m_imgHeight;    //将静态框1移至rect指定位置,用来画直方图    CRect rect;    rect=CRect(50,60,300,170);    GetDlgItem(IDC_STATIC_Hist)->MoveWindow(&rect);    //将颜色提示条移至指定位置    rect=CRect(50,195,300,228);    GetDlgItem(IDC_STATIC_GrayColor)->MoveWindow(&rect);    // 如果是灰度图像,则调用灰度直方图统计函数    if(m_nBitCountOut==8)        computeHistGray();    else//彩色图像则统计亮度直方图        computeHistBrightness();    //计算直方图的均值和方差    float m_ave=computeAverage();    float m_dev=computeDeviation();    //将均值信息显示在均值静态框中    char szStr[10];    sprintf(szStr, "%.2f",m_ave);     AVE.SetWindowTextW(CString(szStr));    //SetDlgItemText(IDC_STATIC_AveShow, szStr);             //将方差信息显示在方差静态框中    sprintf(szStr, "%.2f", m_dev);     //SetDlgItemText(IDC_STATIC_DevShow, szStr);     DEV.SetWindowTextW(CString(szStr));    return TRUE;  // return TRUE unless you set the focus to a control    // EXCEPTION: OCX Property Pages should return FALSE}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_histArray[i]>max)            max=m_histArray[i];    }    DWORD bufTemp[256];    double x=clientRect.Height();    for(int i=0;i<256;i++){        bufTemp[i]=(unsigned long)((float)m_histArray[i]*x/max);    }    for(int 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();    // Do not call CDialog::OnPaint() for painting messages}HistogramDrawDlg::~HistogramDrawDlg(){    //释放输出图像位图数据缓冲区    if(m_pImgDataOut!=NULL){        delete []m_pImgDataOut;        m_pImgDataOut=NULL;    }    //释放输出图像颜色表    if(m_lpColorTableOut!=NULL){        delete []m_lpColorTableOut;        m_lpColorTableOut=NULL;    }}/************************************************************************ 函数名称:* GetDimensions()**函数参数:*  无**返回值:*   图像的尺寸,用CSize类型表达**说明:返回输出图像的宽和高***********************************************************************/CSize HistogramDrawDlg::GetDimensions(){       m_imgWidthOut=m_himageDib.m_imgWidth;    m_imgHeightOut=m_himageDib.m_imgHeight;    if(m_pImgDataOut == NULL) return CSize(0, 0);    return CSize(m_imgWidthOut, m_imgHeightOut);}/************************************************************************ 函数名称:* computeHistGray()**说明:灰度图像统计直方图,m_histArray中存放了当前图像的统计数据***********************************************************************/void HistogramDrawDlg::computeHistGray(){    //只处理灰度图像    if(m_nBitCountOut!=8)        return;    //循环变量    int i,j;    //直方图数组清0    for(i=0;i<256;i++)        m_histArray[i]=0;    //每行像素所占字节数    int lineByte=(m_himageDib.m_imgWidth*m_nBitCountOut/8+3)/4*4;    //中间变量    int temp;    //统计灰度直方图    for(i=0;i<m_imgHeightOut;i++){        for(j=0;j<m_imgWidthOut;j++){            temp=*(m_himageDib.m_pImgData+i*lineByte+j);            m_histArray[temp]++;        }    }}/************************************************************************ 函数名称:* computeHistBrightness()**说明:彩色图像亮度直方图,m_histArray中存放了当前图像的亮度统计数据***********************************************************************/void HistogramDrawDlg::computeHistBrightness(){    //彩色图像有效    if(m_nBitCountOut!=24)        return;    //循环变量    int i,j;    //直方图数组清0    for(i=0;i<256;i++)        m_histArray[i]=0;    //每行像素所占字节数    int lineByte=(m_imgWidthOut*m_nBitCountOut/8+3)/4*4;    //中间变量    int temp;    //统计亮度直方图    for(i=0;i<m_imgHeightOut;i++){        for(j=0;j<m_imgWidthOut;j++){            temp=(int)(0.11**(m_himageDib.m_pImgData+i*lineByte+j*3+0)+0.59**(m_himageDib.m_pImgData+i*lineByte+j*3+1)+0.30**(m_himageDib.m_pImgData+i*lineByte+j*3+2)+0.5);            m_histArray[temp]++;        }    }}/************************************************************************ 函数名称:* computeAverage()**说明:计算直方图均值,直方图的统计特征***********************************************************************/float HistogramDrawDlg::computeAverage(){    int sum=0;    for(int i=0;i<256;i++)        sum+= i*m_histArray[i];    m_average=(float)sum/(m_himageDib.m_imgWidth*m_himageDib.m_imgHeight);    float m_aver=m_average;    return m_aver;}/************************************************************************ 函数名称:* computeDeviation()**说明:计算直方图方差,直方图的统计特征***********************************************************************/float HistogramDrawDlg::computeDeviation(){    float deviation=0;    for(int i=0;i<256;i++)        deviation += (i-m_average)*(i-m_average)*m_histArray[i];    deviation/=(m_himageDib.m_imgWidth*m_himageDib.m_imgHeight);    m_deviation=sqrt(deviation);    float m_devi=m_deviation;    return m_devi;}void HistogramDrawDlg::histogramAve(){    // 只处理灰度    if(m_himageDib.m_nBitCount!=8)        return;    //释放旧的输出图像缓冲区    if(m_pImgDataOut!=NULL){        delete []m_pImgDataOut;        m_pImgDataOut=NULL;    }    if(m_lpColorTableOut!=NULL){        delete []m_lpColorTableOut;        m_lpColorTableOut=NULL;    }    //输出图像每像素位数与输入图像相同    m_nBitCountOut=m_himageDib.m_nBitCount;    //计算颜色表长度    m_nColorTableLengthOut=m_himageDib.ComputeColorTabalLength(m_nBitCountOut);    //若有颜色表,输入图像的颜色表与输出图像颜色表相同    if(m_nColorTableLengthOut!=0)    {        m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];        memcpy(m_lpColorTableOut,m_himageDib.m_lpColorTable,            sizeof(RGBQUAD)*m_nColorTableLengthOut);    }    //输出图像的宽高,与输入图像相等    m_imgWidthOut=m_himageDib.m_imgWidth;    m_imgHeightOut=m_himageDib.m_imgHeight;    //输出图像每行像素所占的字节数    int lineByteOut=(m_himageDib.m_imgWidth*m_nBitCountOut/8+3)/4*4;    m_pImgDataOut=new unsigned char[lineByteOut*m_himageDib.m_imgHeight];    //循环变量    int i,j;    //映射表    double Map[256];    //中间变量    int Sum,temp;    //统计灰度直方图    computeHistGray();    //计算映射表    Sum=0;    for(i=0;i<256;i++){        Sum+=m_histArray[i];        Map[i]=(double)Sum*255/(m_himageDib.m_imgWidth*m_himageDib.m_imgHeight)+0.5;    }    //输出数据赋值    for(i=0;i<m_himageDib.m_imgHeight;i++)    {        for(j=0;j<m_himageDib.m_imgWidth;j++)        {                   temp = *(m_himageDib.m_pImgData+i*lineByteOut+j);            *(m_pImgDataOut+i*lineByteOut+j) = (int)Map[temp];        }    }}

运行截屏如下:
这里写图片描述

0 0