天天看点

【数字图像处理】四.MFC对话框绘制灰度直方图

        本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程《数字图像处理》及课件进行回忆讲解,主要通过MFC单文档视图实现点击弹出对话框绘制BMP图片的灰度直方图,再获取平均灰度、中指灰度和标准差等值。文章比较详细基础,希望该篇文章对你有所帮助~

        免费资源下载地址:

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

【数字图像处理】四.MFC对话框绘制灰度直方图
【数字图像处理】四.MFC对话框绘制灰度直方图

        什么是灰度直方图?

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

【数字图像处理】四.MFC对话框绘制灰度直方图

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

【数字图像处理】四.MFC对话框绘制灰度直方图

        其中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可以通过图像的直方图求得。

       第一步:创建Dialog

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

【数字图像处理】四.MFC对话框绘制灰度直方图

        右键添加属性如下:

        对话框-原始直方图-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(GREEN BLUE)对应像素XS

        IDC_STATIC_PJHD_RED(GREEN BLUE)对应平均灰度PJHD

        IDC_STATIC_ZZHD_RED(GREED BLUE)对应中值灰度ZZHD

        IDC_STATIC_BZC_RED(GREEN BLUE)对应标准差BZC

       第二步:建立类向导MFC ClassWizard

        (1) 在对话框资源模板空白区双击鼠标(Ctrl+W),创建一个新类,命名为CImageZFTDlg会自动生成它的.h和.cpp文件。在类向导中选中类名CImageZFTDlg,IDs为CImageZFTDlg,WM_INITDIALOG建立这个函数用于初始化。

        (2) 打开类向导,选择Member Variables页面,添加如下变量,类型均为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

【数字图像处理】四.MFC对话框绘制灰度直方图

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

        第三步:设置菜单栏调用直方图对话框

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

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

【数字图像处理】四.MFC对话框绘制灰度直方图

       第四步:添加代码及计算4个值

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

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

【数字图像处理】四.MFC对话框绘制灰度直方图

        重点(极其重要*)

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

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

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

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

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

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

        第一步:建立画直方图函数OnPaint

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

        第二步:绘制直方图大致思想如下

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

        CWnd *pWnd = GetDlgItem(IDC_STATIC_KJ);

        CDC *pDC = pWnd->GetDC();

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

        CRect rectpic;

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

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

        CPen *RedPen = new CPen();

        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);

        delete RedPen;

        ReleaseDC(pDC);

        第三步:源代码与详细注释思想

        在ImageZFTDlg.cpp中修改OnPaint函数:

        此时运行程序即可显示直方图。

        最后还是希望文章对你有所帮助,如果文章有不足或错误之处,请海涵~文章不仅仅讲述了直方图相关的知识,同时文章也给你提供了一种绘制坐标图像的思想和详细注释。有时候一直怀疑回忆这些知识会让我停滞不前,但心安即好,何必在意!

        从来没有什么终南捷径和大神,真正的捷径只有三个:坚持、专注、认真。其他的都是细枝末节,做到这三个,其他的自然而然都会拥有。——同学CY

继续阅读