我处理的是24位的真彩色图,所以会先将非灰度的24位图变换为灰度的24位图,然后进行。在直方图绘制的时候用到了从父窗口获得成员数据或调用父窗口中的函数。这部分也是我参考网络上的程序写的,而建立非模态对话框也是。
获得父对话框窗口中的成员变量的值或调用父窗口中的函数的代码:
CWnd* hParent=GetParent();
CDIPDlg* dlg=(CDIPDlg*)hParent;
char* m_dib=dlg->GetDibDataPoint();
int m_nHeight=dlg->GetDibDataHeight();
int m_nWidth=dlg->GetDibDataWidth();
int m_nBitCount=dlg->GetDibDataBitCount();
通过上面的dlg就可以引用到父对话框窗口中的成员变量或成员函数。
建立非模态对话框的程序如下:
CGrayHistPlotDlg* dlg=new CGrayHistPlotDlg();
dlg->Create(IDD_DLG_GRAYHISTPLOT);
dlg->ShowWindow(SW_SHOW);
其中IDD_DLG_GRAYHISTPLOT是非模态对话框的资源表示,而在调用ShowWIndow的时候要用表示SW_SHOW。既然是非模态对话框,那么我的程序中的画直方图的代码都是在非模态对话框的OnPaint()函数中写的,全部程序如下:
void CGrayHistPlotDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
//画坐标轴,横轴大小为270像素,纵轴大小为300像素
//原点的坐标为(50,50+300),Y轴顶点坐标(50,50),X轴定点坐标(50+270,350)
CPoint oPt;
oPt.x=50;
oPt.y=350;
CPoint xPt;
xPt.x=50+270;
xPt.y=350;
CPoint yPt;
yPt.x=50;
yPt.y=50;
//画X轴和Y轴的直线
dc.MoveTo(oPt);
dc.LineTo(xPt);
dc.MoveTo(oPt);
dc.LineTo(yPt);
//画X轴和Y轴的箭头
//X轴的两个箭头坐标为x1(50+270-9,350+5),x2(50+270-9,350-5)
//Y轴的两个箭头坐标为y1(50-5,50+9),y2(50+5,50+9)
CPoint x1,x2;
x1.x=50+270-9;
x1.y=350+5;
x2.x=50+270-9;
x2.y=350-5;
dc.MoveTo(xPt);
dc.LineTo(x1);
dc.MoveTo(xPt);
dc.LineTo(x2);
CPoint y1,y2;
y1.x=50-5;
y1.y=50+9;
y2.x=50+5;
y2.y=50+9;
dc.MoveTo(yPt);
dc.LineTo(y1);
dc.MoveTo(yPt);
dc.LineTo(y2);
//标记原点,X轴和Y轴
CRect oRect;
oRect.top=oPt.y+2;
oRect.left=oPt.x;
oRect.right=oRect.left+10;
oRect.bottom=oRect.top+15;
dc.DrawText("O",oRect,DT_WORDBREAK|DT_CENTER);
CRect xRect;
xRect.left=x1.x;
xRect.top=x1.y+2;
xRect.right=xRect.left+10;
xRect.bottom=xRect.top+15;
dc.DrawText("X",xRect,DT_CENTER);
CRect yRect;
yRect.top=y1.y;
yRect.left=y1.x-10;
yRect.right=yRect.left+10;
yRect.bottom=yRect.top+15;
dc.DrawText("Y",yRect,DT_CENTER);
//获得绘制直方图所需要的数据
CWnd* hParent=GetParent();
CDIPDlg* dlg=(CDIPDlg*)hParent;
char* m_dib=dlg->GetDibDataPoint();
int m_nHeight=dlg->GetDibDataHeight();
int m_nWidth=dlg->GetDibDataWidth();
int m_nBitCount=dlg->GetDibDataBitCount();
int nCount[256];
for(int i=0;i<256;i++) nCount[i]=0;
long LineBytes=((m_nWidth*m_nBitCount)+31)/32*4;
for(i=0;i<m_nHeight;i++)
{
for(int j=0;j<LineBytes;j++)
{
BYTE B=*(m_dib+LineBytes*i+j);
j++;
j++;
nCount[B]++;
}
}
//处理直方图的数据,使其在一定的范围内
int max=0;
for(i=0;i<256;i++)
{
if(nCount[i]>max) max=nCount[i];
}
for(i=0;i<256;i++)
{
if(max==0)
{
AfxMessageBox("error");
return;
}
nCount[i]=static_cast<int>((nCount[i]*300)/max);
}
//绘制直方图
BYTE w=2;
for(i=0;i<256;i++)
{
//每条直线用两个像素的宽度来画,即为一个宽为2的矩形条
for(int j=0;j<w;j++)
{
dc.MoveTo(CPoint(50+i+j,350));
dc.LineTo(CPoint(50+i+j,350-nCount[i]));
}
}
//X轴的一些刻度
//刻度“50”
CRect r50;
r50.left=oPt.x+50;
r50.top=oPt.y+20;
r50.right=r50.left+20;
r50.bottom=r50.top+15;
dc.DrawText("50",r50,DT_CENTER);
//画刻度50处的向上箭头
//pt501为箭头的下面的点,pt502为箭头的上面的点
//pt503为箭头的左边的点,pt504为箭头的右边的点
CPoint pt501,pt502,pt503,pt504;
pt501.x=r50.left;
pt501.y=r50.top-2;
pt502.x=pt501.x;
pt502.y=pt501.y-15;
pt503.x=pt502.x-3;
pt503.y=pt502.y+3;
pt504.y=pt503.y;
pt504.x=pt502.x+3;
dc.MoveTo(pt501);
dc.LineTo(pt502);
dc.MoveTo(pt502);
dc.LineTo(pt503);
dc.MoveTo(pt502);
dc.LineTo(pt504);
//刻度“100”
CRect r100;
r100.left=oPt.x+100;
r100.top=oPt.y+20;
r100.right=r100.left+30;
r100.bottom=r100.top+15;
dc.DrawText("100",r100,DT_CENTER);
//画刻度100处向上箭头
//pt1001为箭头的下面的点,pt1002为箭头的上面的点
//pt1003为箭头的左边的点,pt1004为箭头的右边的点
CPoint pt1001,pt1002,pt1003,pt1004;
pt1001.x=r100.left;
pt1001.y=r100.top-2;
pt1002.x=pt1001.x;
pt1002.y=pt1001.y-15;
pt1003.x=pt1002.x-3;
pt1003.y=pt1002.y+3;
pt1004.y=pt1003.y;
pt1004.x=pt1002.x+3;
dc.MoveTo(pt1001);
dc.LineTo(pt1002);
dc.MoveTo(pt1002);
dc.LineTo(pt1003);
dc.MoveTo(pt1002);
dc.LineTo(pt1004);
//刻度“150”
CRect r150;
r150.left=oPt.x+150;
r150.top=oPt.y+20;
r150.right=r150.left+30;
r150.bottom=r150.top+15;
dc.DrawText("150",r150,DT_CENTER);
//画刻度150处向上箭头
//pt1501为箭头的下面的点,pt1502为箭头的上面的点
//pt1503为箭头的左边的点,pt1504为箭头的右边的点
CPoint pt1501,pt1502,pt1503,pt1504;
pt1501.x=r150.left;
pt1501.y=r150.top-2;
pt1502.x=pt1501.x;
pt1502.y=pt1501.y-15;
pt1503.x=pt1502.x-3;
pt1503.y=pt1502.y+3;
pt1504.y=pt1503.y;
pt1504.x=pt1502.x+3;
dc.MoveTo(pt1501);
dc.LineTo(pt1502);
dc.MoveTo(pt1502);
dc.LineTo(pt1503);
dc.MoveTo(pt1502);
dc.LineTo(pt1504);
//刻度“200”
CRect r200;
r200.left=oPt.x+200;
r200.top=oPt.y+20;
r200.right=r200.left+30;
r200.bottom=r200.top+15;
dc.DrawText("200",r200,DT_CENTER);
//画刻度200处向上箭头
//pt2001为箭头的下面的点,pt2002为箭头的上面的点
//pt2003为箭头的左边的点,pt2004为箭头的右边的点
CPoint pt2001,pt2002,pt2003,pt2004;
pt2001.x=r200.left;
pt2001.y=r200.top-2;
pt2002.x=pt2001.x;
pt2002.y=pt2001.y-15;
pt2003.x=pt2002.x-3;
pt2003.y=pt2002.y+3;
pt2004.y=pt2003.y;
pt2004.x=pt2002.x+3;
dc.MoveTo(pt2001);
dc.LineTo(pt2002);
dc.MoveTo(pt2002);
dc.LineTo(pt2003);
dc.MoveTo(pt2002);
dc.LineTo(pt2004);
//刻度“255”
CRect r255;
r255.left=oPt.x+255;
r255.top=oPt.y+20;
r255.right=r255.left+30;
r255.bottom=r255.top+15;
dc.DrawText("255",r255,DT_CENTER);
//画刻度255处向上箭头
//pt2551为箭头的下面的点,pt2552为箭头的上面的点
//pt2553为箭头的左边的点,pt2554为箭头的右边的点
CPoint pt2551,pt2552,pt2553,pt2554;
pt2551.x=r255.left;
pt2551.y=r255.top-2;
pt2552.x=pt2551.x;
pt2552.y=pt2551.y-15;
pt2553.x=pt2552.x-3;
pt2553.y=pt2552.y+3;
pt2554.y=pt2553.y;
pt2554.x=pt2552.x+3;
dc.MoveTo(pt2551);
dc.LineTo(pt2552);
dc.MoveTo(pt2552);
dc.LineTo(pt2553);
dc.MoveTo(pt2552);
dc.LineTo(pt2554);
// Do not call CDialog::OnPaint() for painting messages
}
运行时的效果图片如下:
界面如下:
点击“直方图曲线”后的绘制的直方图如下:
点“直方图均衡”之后,得到直方图如下:
另外,如果你的绘图程序在最小化之后不能显示了,或者是被别的窗口挡住之后,图片都显示的不完整了,那么你可以在对话框的onPaint()函数总写上重画图形的代码,这样就不会再窗口最小化之后就没有图片了。像我的主程序中的OnPaint()函数中就有重画的代码:
void CDIPDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
CDC* pDC=GetDC();
BYTE* lpdib=(BYTE*)::GlobalLock((HGLOBAL)m_hDIB);
BITMAPINFO* m_pBitmapInfo=(BITMAPINFO*)lpdib;
::StretchDIBits(pDC->m_hDC,10,10,m_nWidth,m_nHeight,0,0,m_nWidth,m_nHeight,m_pDibData,m_pBitmapInfo,DIB_RGB_COLORS,SRCCOPY);
::GlobalUnlock((HGLOBAL)m_hDIB);
}
}