关于VC绘制图像的直方图

 

直方图显示应该是图像处理程序必须有的一个功能吧。我的设想是这样,在MFC单文档的菜单上点击【显示直方图】图标,会弹出对话框,显示256色BMP图像的直方图。效果如下:

下面就开始实现这一功能

1、设计对话框

新插入一个资源对话框之后,只在其上添加一个picture控件。picture控件ID为IDC_HIST_PAINT,类型为Rectangle,color改为白色(可以任意)。其实后来才知道,不一定非得在picture控件上画图,其实在对话框上也能直接画图,这就是VC的强大之处的体现!

2、为对话框控件关联类,双击对话框控件会弹出类向导,提示你新建的对话框控件还没有类与之关联,新建类还是。。。在此选择新建类,类名为CHistDialog。在CHistDialog类中新建两个变量      分别用于存储最大灰度值像素数和每个灰度值像素数。重载CHistDialog类的OnPaint函数。重载方法如下图:

我想让直方图显示对话框只负责显示,至于maxcount和 count[256]的统计仍然让CDib类完成,那么,暂时将OnPaint放在一边,处理其他函数。

3、在菜单资源上做如下图所示事情


用类向导建立【查看直方图】菜单的响应函数OnHistLook,具体实现如下


void CReadBMPView::OnHistLook()

{

       // TODO: Add your command handler code here

       CReadBMPDoc* pDoc = GetDocument();

       ASSERT_VALID(pDoc);

       if(pDoc->statedoc)

       {

              if (!pDoc->bmp_file.Is24Bit())

              {

                     if (pDoc->bmp_file.PiexlCount())

                     {

                            CHistDialog Histdlg;

                            Histdlg.DoModal();

                     }            

 

              }

              else

              {

                     AfxMessageBox("直方图不支持24位!");

              }

 

       }

       else

              AfxMessageBox("未载入图像!");

}

从上面的代码我们可以知道,要在CDib类中实现完成maxcount和count[256]的统计函数.PiexlCount(),没错!

4、首先为CDib类添加成员int maxcount和int count[256],并在构造函数中初始化为0,注意,VC中数组的初始化与C++中有些不同,最简单的是用memset函数代码如下:

CDib::CDib()

{

。。。。。。

 memset(count, 0, sizeof(count));

 maxcount=0;

}

为CDib类添加函数.PiexlCount(),代码如下:

BOOL CDib::PiexlCount()

{

       if (!Is24Bit())

       {     for (UINT h=0;h<Bmphight;h++)

              {

                            for (UINT w=0;w<Bmpbytewidth;w++)

                            {

                                   count[*(m_pDataCopy+h*Bmphight+w)]++;

                            }

              }

              for (int i=0;i<256;i++)

              {

                     if (maxcount<count[i])

                     {

                            maxcount=count[i];

                     }

              }

              m_valid = TRUE;

              return TRUE;

       }

       else

              return FALSE;

}

5,幕后工作完成以后回到CHistDialog的OnPaint函数

为了显示载入图像的直方图,首先应该得到这个对象的指针,而这个对象是在CReadBMPDoc类中生成的,如何在CHistDialog中得到CReadBMPDoc类的指针成了一个关键问题,以上问题也就是:如何从弹出的对话框类中得到文档类的指针。

解决这一问题方法如下:

为CReadBMPDoc类添加成员函数GetDoc(),代码如下:

CReadBMPDoc* CReadBMPDoc::GetDoc()

{

       CFrameWnd* pFrame = (CFrameWnd*)(AfxGetApp()->m_pMainWnd);   

      return (CReadBMPDoc*)pFrame->GetActiveDocument();   

}

 

这样从CHistDialog得到CReadBMPDoc指针就可以用

CReadBMPDoc* pDoc=CReadBMPDoc::GetDoc();

其他已经没有什么大的难点了,OnPaint代码如下:

void CHistDialog::OnPaint()

{

       //定义变量

       CString str;

       CRect rect;

       CWnd *pWnd=GetDlgItem(IDC_HIST_PAINT);

       CPaintDC dc(pWnd);//

       pWnd->GetClientRect(&rect);

       CReadBMPDoc* pDoc=CReadBMPDoc::GetDoc();

       for (int i=0;i<256;i++)

       {

              m_count[i]=pDoc->bmp_file.count[i];

       }

       m_maxcount=pDoc->bmp_file.maxcount;

 

       //创建黑色画笔用于绘制坐标

       CPen* pPenblack=new CPen;

       pPenblack->CreatePen(PS_SOLID,2,RGB(0,0,0));

       CPen* pPengary=new CPen;

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

       CGdiObject* pOldPen=dc.SelectObject(pPenblack);

 

       //绘制坐标轴

       dc.MoveTo(10,rect.Height()-10);//绘图区左下角定义的原点。

       dc.LineTo(10,0);//绘制X轴

       dc.MoveTo(10,rect.Height()-10);

       dc.LineTo(rect.Width(),rect.Height()-10);//绘制Y轴坐标

       //绘制X轴箭头

       dc.MoveTo(10,0);

       dc.LineTo(4,6);

       dc.MoveTo(10,0);

       dc.LineTo(16,6);

       //绘制Y轴箭头

       dc.MoveTo(rect.Width(),rect.Height()-10);

       dc.LineTo(rect.Width()-6,rect.Height()-4);

       dc.MoveTo(rect.Width(),rect.Height()-10);

       dc.LineTo(rect.Width()-6,rect.Height()-16);

       //删除画笔

       dc.SelectObject(pPengary);

       for (int j=1;j<=5;j++)

       {

              int m=(rect.Height()-20)/5.0*j;

              int n=m_maxcount/5.0*j;

              str.Format("%d",n);

              dc.TextOut(12,rect.Height()-10-m,str);

              dc.MoveTo(12,rect.Height()-10-m);

              dc.LineTo(rect.Width(),rect.Height()-10-m);

       }

       dc.SelectObject(pOldPen);

       delete pPenblack;

       delete pPengary;

       CPen* pPenblue=new CPen;

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

       CGdiObject* pOldPen2=dc.SelectObject(pPenblue);

 

       for (int k=0;k<256;k++)

       {

              int a=(rect.Width()-20)/256.0*k;

              int b=(rect.Height()-20)/(m_maxcount+0.0)*m_count[k];

              dc.MoveTo(a+15,rect.Height()-10);

              dc.LineTo(a+15,rect.Height()-10-b);

       }

       dc.SelectObject(pOldPen2);

       delete pPenblue;     

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值