MFC对话框绘制灰度直方图重点讲义资料.docx

上传人:b****5 文档编号:27752976 上传时间:2023-07-04 格式:DOCX 页数:23 大小:1.15MB
下载 相关 举报
MFC对话框绘制灰度直方图重点讲义资料.docx_第1页
第1页 / 共23页
MFC对话框绘制灰度直方图重点讲义资料.docx_第2页
第2页 / 共23页
MFC对话框绘制灰度直方图重点讲义资料.docx_第3页
第3页 / 共23页
MFC对话框绘制灰度直方图重点讲义资料.docx_第4页
第4页 / 共23页
MFC对话框绘制灰度直方图重点讲义资料.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

MFC对话框绘制灰度直方图重点讲义资料.docx

《MFC对话框绘制灰度直方图重点讲义资料.docx》由会员分享,可在线阅读,更多相关《MFC对话框绘制灰度直方图重点讲义资料.docx(23页珍藏版)》请在冰豆网上搜索。

MFC对话框绘制灰度直方图重点讲义资料.docx

MFC对话框绘制灰度直方图重点讲义资料

MFC对话框绘制灰度直方图

一.程序运行结果

    该篇文章主要是在上一篇文章基础上进行的讲解,其中当打开一张BMP图像后,点击”直方图“-》”显示原图直方图“如下。

二.灰度直方图原理

    什么是灰度直方图?

    灰度直方图(histogram)是灰度级的函数,描述的是图像中每种灰度级像素的个数,反映图像中每种灰度出现的频率。

横坐标是灰度级,纵坐标是灰度级出现的频率。

     对于连续图像,平滑地从中心的高灰度级变化到边缘的低灰度级。

直方图定义为:

     其中A(D)为阈值面积函数:

为一幅连续图像中被具有灰度级D的所有轮廓线所包围的面积。

对于离散函数,固定ΔD为1,则:

H(D)=A(D)-A(D+1)

     色彩直方图是高维直方图的特例,它统计色彩的出现频率,即色彩概率分布信息。

     通常这需要一定的量化过程,将色彩分成若干互不重叠的种类。

一般不直接在RGB色彩空间中统计,而是在将亮度分离出来后,对代表色彩部分的信息进行统计,如在HSI空间的HS子空间、YUV空间的UV子空间,以及其它反映人类视觉特点的彩色空间表示中进行。

    其中直方图的计算方法如下:

     依据定义,若图像具有L(通常L=256,即8位灰度级)级灰度,则大小为MxN的灰度图像f(x,y)的灰度直方图hist[0…L-1]可用如下计算获得。

     1、初始化hist[k]=0;k=0,…,L-1 

    2、统计hist[f(x,y)]++;x=0,…,M-1,y=0,…,N-1 

    3、归一化hist[f(x,y)]/=M*N 

    那么说了这么多,直方图究竟有什么作用呢?

    在使用轮廓线确定物体边界时,通过直方图更好的选择边界阈值,进行阈值化处理;对物体与背景有较强对比的景物的分割特别有用;简单物体的面积和综合光密度IOD可以通过图像的直方图求得。

三.程序实现

1.建立直方图对话框

    第一步:

创建Dialog

    将视图切换到ResourceView界面,选中Dialog右键鼠标新建一个Dialog,并新建一个名为IDD_DIALOG_ZFT,设置成下图对话框。

    右键添加属性如下:

    对话框-原始直方图-IDD_DIALOG_ZFT

    组框-RGB-IDC_STATIC_RGB

     图像-框架-IDC_STATIC_KJ-蚀刻(重点:

有它才能添加直方图在此处,注意GetDlgItem()函数中是IDC而不是IDD对话框)

    添加蚀刻线(图像蚀刻形成的直线)形如图中的3个矩形框,并添加静态文本:

Red、Green、Blue、红、绿、蓝、像素、平均灰度、中值灰度、标准差;这些静态文本都是IDC_STATIC且为默认属性

    添加红色4个值(Static)、绿色4个值、蓝色4个值,分别为:

    IDC_STATIC_XS_RED(GREENBLUE)对应像素XS

    IDC_STATIC_PJHD_RED(GREENBLUE)对应平均灰度PJHD

    IDC_STATIC_ZZHD_RED(GREEDBLUE)对应中值灰度ZZHD

    IDC_STATIC_BZC_RED(GREENBLUE)对应标准差BZC

    第二步:

建立类向导MFCClassWizard

    

(1)在对话框资源模板空白区双击鼠标(Ctrl+W),创建一个新类,命名为CImageZFTDlg会自动生成它的.h和.cpp文件。

在类向导中选中类名CImageZFTDlg,IDs为CImageZFTDlg,WM_INITDIALOG建立这个函数用于初始化。

    

(2)打开类向导,选择MemberVariables页面,添加如下变量,类型均为CString。

    像素m_redXS、m_greenXS、m_blueXS

    标准差m_redBZC、m_greeenBZC、m_blueBZC

    平均灰度m_redPJHD、m_greenPJHD、m_bluePJHD

    中值灰度m_redZZHD、m_greenZZHD、m_blueZZHD

    (3)在View.cpp中添加直方图的头文件#inlcude"ImageZFTDlg.h"

     第三步:

设置菜单栏调用直方图对话框

    

(1)将视图切换到ResourceView界面,选中Menu,在IDR_MAINFRAM中添加菜单项“直方图”,菜单属性中选择“弹出”,在“直方图”中添加子菜单“显示原图直方图”。

    

(2)设置其属性为ID_ZFT_YT(显示直方图原图),同时建立类向导,选择ID_ZFT_YT(IDs),通过COMMAND建立显示直方图函数OnZftYt()。

    第四步:

添加代码及计算4个值

    在ImageProcessingView.cpp中添加如下代码,注释中有如何求平均灰度、中值灰度和标准差的消息算法过程。

[cpp] viewplain copy

1.//引用显示直方图头文件  

2.#include "ImageZFTDlg.h"  

3.#include "math.h"  

4.  

5./*全局变量在TestZFTDlg.cpp中引用 用extern*/  

6.int Red[256],Green[256],Blue[256];  

7.  

8./**************************************************/  

9./* 添加直方图显示功能,并在直方图下方显示相关信息  

10./* 如平均灰度、中值灰度、标准差和像素总数          

11./* ID_ZFT_YT:

直方图原图显示                        

12./**************************************************/  

13.void CImageProcessingView:

:

OnZftYt()   

14.{  

15.    if(numPicture==0) {  

16.        AfxMessageBox("载入图片后才能显示原图直方图!

",MB_OK,0);  

17.        return;  

18.    }  

19.    AfxMessageBox("显示原图直方图!

",MB_OK,0);  

20.    CImageZFTDlg dlg;  

21.  

22.    //打开临时的图片  

23.    FILE *fpo = fopen(BmpName,"rb");  

24.    fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  

25.    fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  

26.      

27.    int i,j;  

28.    for(j=0;j<256;j++) { //定义数组并清零  

29.        Red[j]=0;  

30.        Green[j]=0;  

31.        Blue[j]=0;  

32.    }  

33.      

34.    //计算4个数据  

35.    unsigned char red,green,blue;  

36.    int IntRed,IntGreen,IntBlue;                  //强制转换  

37.    double sumRedHD=0,sumGreenHD=0,sumBlueHD=0;   //记录像素总的灰度值和  

38.    for(i=0; i

39.    {  

40.        fread(&red,sizeof(char),1,fpo);  

41.        IntRed=int(red);  

42.        sumRedHD=sumRedHD+IntRed;  

43.        if( IntRed>=0 && IntRed<256 ) Red[IntRed]++; //像素0-255之间  

44.          

45.        fread(&green,sizeof(char),1,fpo);  

46.        IntGreen=int(green);  

47.        sumGreenHD=sumGreenHD+IntGreen;  

48.        if( IntGreen>=0 && IntGreen<256 ) Green[IntGreen]++;  

49.          

50.        fread(&blue,sizeof(char),1,fpo);  

51.        IntBlue=int(blue);  

52.        sumBlueHD=sumBlueHD+IntBlue;  

53.        if( IntBlue>=0 && IntBlue<256 ) Blue[IntBlue]++;  

54.    }  

55.    fclose(fpo);  

56.      

57.    //像素:

int型转换为CString型   

58.    dlg.m_redXS.Format("%d",m_nImage);  

59.    dlg.m_greenXS.Format("%d",m_nImage);  

60.    dlg.m_blueXS.Format("%d",m_nImage);  

61.      

62.    //平均灰度值:

计算24位bmp图片的灰度值,我是记录RGB中的所有平均值     

63.    float pinRedHD,pinGreenHD,pinBlueHD;   

64.    pinRedHD=sumRedHD*3/m_nImage;  

65.    pinGreenHD=sumGreenHD*3/m_nImage;     //平均灰度=总灰度/总像素  

66.    pinBlueHD=sumBlueHD*3/m_nImage;  

67.      

68.    dlg.m_redPJHD.Format("%.2f",pinRedHD);  

69.    dlg.m_greenPJHD.Format("%.2f",pinGreenHD);  

70.    dlg.m_bluePJHD.Format("%.2f",pinBlueHD);  

71.      

72.    /****************************************************************/  

73.    /* 中值灰度:

算法重点(黄凯大神提供)                               

74.    /* 中值灰度:

所有像素中的中位数,应该所有像素排序找到中间的灰度值  

75.    /* 算法:

num[256]记录各灰度出现次数,sum+=num[i],找到sum=总像素/2  

76.    /****************************************************************/  

77.    int sumRedZZHD=0,sumGreenZZHD=0,sumBlueZZHD=0;  

78.    int redZZHD,greenZZHD,blueZZHD;  

79.    for(i=0;i<256;i++)  

80.    {  

81.        sumRedZZHD=sumRedZZHD+Red[i];  

82.        if(sumRedZZHD>=m_nImage/6)          //m_nImage被分成3份RGB并且sum=总像素/2  

83.        {  

84.            redZZHD=i;  

85.            break;  

86.        }  

87.    }  

88.    for(i=0;i<256;i++)  

89.    {  

90.        sumGreenZZHD=sumGreenZZHD+Green[i];  

91.        if(sumGreenZZHD>=m_nImage/6)          //m_nImage被分成3份RGB并且sum=总像素/2  

92.        {  

93.            greenZZHD=i;  

94.            break;  

95.        }  

96.    }  

97.    for(i=0;i<256;i++)  

98.    {  

99.        sumBlueZZHD=sumBlueZZHD+Blue[i];  

100.        if(sumBlueZZHD>=m_nImage/6)          //m_nImage被分成3份RGB并且sum=总像素/2  

101.        {  

102.            blueZZHD=i;  

103.            break;  

104.        }  

105.    }  

106.      

107.    dlg.m_redZZHD.Format("%d",redZZHD);  

108.    dlg.m_greenZZHD.Format("%d",greenZZHD);  

109.    dlg.m_blueZZHD.Format("%d",blueZZHD);  

110.      

111.    /******************************************************************/  

112.    /*标准差:

标准差=方差的算术平方根                                    

113.    /*       方差s^2=[(x1-x)^2+(x2-x)^2+......(xn-x)^2]/n              

114.    /* 算法:

不用开m_nImage数组进行计算 用num[256]中数进行              

115.    /* 方差=(平均灰度-i)*(平均灰度-i)*Red[i]  有Red[i]个灰度值为i的数  

116.    /******************************************************************/  

117.    float redBZC,greenBZC,blueBZC;       //标准差  

118.    double redFC=0,greenFC=0,blueFC=0;    //方差  

119.    for(i=0;i<256;i++)  

120.    {  

121.        redFC=redFC+(pinRedHD-i)*(pinRedHD-i)*Red[i];   //有Red[i]个像素i  

122.        greenFC=greenFC+(pinGreenHD-i)*(pinGreenHD-i)*Green[i];  

123.        blueFC=blueFC+(pinBlueHD-i)*(pinBlueHD-i)*Blue[i];  

124.    }  

125.      

126.    redBZC=sqrt(redFC*3/m_nImage);  

127.    greenBZC=sqrt(greenFC*3/m_nImage);  

128.    blueBZC=sqrt(blueFC*3/m_nImage);  

129.      

130.    dlg.m_redBZC.Format("%.2lf",redBZC);  

131.    dlg.m_greenBZC.Format("%.2lf",greenBZC);  

132.    dlg.m_blueBZC.Format("%.2lf",blueBZC);    

133.  

134.    //重点必须添加该语句才能弹出对话框  

135.    if(dlg.DoModal()==IDOK)  

136.    {  

137.  

138.    }  

139.}  

    第五步:

此时运行结果如下图所示,打开图片可以显示参数。

2.建立对话框与View联系并绘制直方图

     重点(极其重要*)

     

(1)如何在MFC中(View中)实现对子对话框的画图或直方图响应?

    解决方法:

在子对话框中.cpp文件中实现画图响应,不要再View.cpp中实现,否则图像会以menu背景为坐标,而在ImageZFTDlg.cpp中建立OnPaint函数实现画图,它默认会以子对话框为标准。

     

(2)如何把View.cpp中的图片像素直方图信息传递给子对话框ImageZFTDlg.cpp呢?

    解决方法:

如果自定义ImageStruct.h中建立全局变量,每个.cpp中引用该头文件调用总是报错(未知),所以我在View.h中建立一个全局变量intRed[256];再在子文件.cpp中函数里调用该全局变量即可externintRed[256],这是非常重要的一个C语言知识。

     (3)画图函数OnPaint()参考源代码中详细注释。

    如何绘制坐标轴、文字、图像,其实自己绘制而没调用第三方库还是挺有意思的。

     第一步:

建立画直方图函数OnPaint

    打开类向导(Ctrl+W),类名选择CImageZFTDlg,IDs选择CImageZFTDlg,在Message函数中建立WM_PAINT映射,默认函数名为OnPaint建立函数voidCImageZFTDlg:

:

OnPaint()

     第二步:

绘制直方图大致思想如下

    

(1)重点:

获取要绘制直方图的位置和图像资源的对应号ID(IDC_STATIC_KJ框架),我当时认为绘制直方图只能绘制到”图像“控件IDC中,不能是对话框IDD。

     CWnd*pWnd=GetDlgItem(IDC_STATIC_KJ);

    CDC*pDC=pWnd->GetDC();

    

(2)获取对话框矩形的长和宽

     CRectrectpic;

    GetDlgItem(IDC_STATIC_KJ)->GetWindowRect(&rectpic);

    (3)创建画笔对象并对画笔进行颜色设置

     CPen*RedPen=newCPen();

    RedPen->CreatePen(PS_SOLID,1RGB(255,0,0));

    (4)选中当前画笔并保存以前画笔

     CGdiObject*RedOlderPen=pDC->SelectObject(RedPen);

    (5)绘制直方图(图像坐标自己算)

     矩形pDC->Rectangle(9,327,312,468);

    移动pDC->MoveTo(15,331);

    直线pDC->LineTo(15,488);

    文字pDC->TextOut(15+48*i,450,str);

    (6)恢复以前画笔

     pDC->SelectObject(RedOlderPen);

    deleteRedPen;

    ReleaseDC(pDC);

     第三步:

源代码与详细注释思想

    在ImageZFTDlg.cpp中修改OnPaint函数:

[cpp] viewplain copy

1.//****************绘制原图直方图*********************//  

2.void CImageZFTDlg:

:

OnPaint()   

3.{  

4.    CPaintDC dc(this); // device context for painting  

5.      

6.    // TODO:

 Add your message handler code here  

7.      

8.    /********************************************************************************/  

9.    /* 重点知识:

(XX)                                                               

10.    /* 如何在View.cpp中把一个变量的值传给其它对话框                                  

11.    /*                                                                               

12.    /* 错误一:

在View.h中定义的pubic变量只能在View.cpp中用                            

13.    /* 错误二:

定义一个Struct.h中存全局变量,在2个函数中分别调用#include "Struct.h"    

14.    /*                                                                          

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 语文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1