【图形学】MFC画统计图,直方图

 

我封装了一个类,可以直接用来画图像处理的直方图,也可用于画各种统计图,话不多说~直接上代码供大家使用吧

对了,这篇文章我改编自zhenxiaohui这个作者的文章,做的修改如下:

1.改编了类,可以用于所有的柱形统计图,不仅仅是直方图

2.修改了里面的一个计算错误,原文的:NowPos.y = 500 - 500.0f * 20.0f * ImagData[i] / (max * 21);
应该改为:NowPos.y = 500 - ((float)Ystep*21)* 20.0f * ImagData[i] / (max * 21);

当然,我这里对他的程序作了很大改进,所以上面这句话会以不同的形式出现:

 

/*函数说明:画柱形统计图或直方图
By:ZXX
参数说明:
count:保存要输出的数据的数组
control:要显示在那个控件的ID
num:数组的维数
比如直方图的调用:DrawHistogram(count,IDC_OLDHISTOGRAM,256);
*/
void CImhistDlg::DrawHistogram(int count[],int control,int num)
{
	CClientDC dc(this);
	//得到控件的大小
	CRect rect;
	GetDlgItem(control)->GetWindowRect(&rect);//获取控件相对于屏幕的位置
	ScreenToClient(rect);//转化为对话框上的相对位置
	CPen* pPenBlue = new CPen;                                  //创建画笔对象
	pPenBlue->CreatePen(PS_SOLID, 2, RGB(0,0,0));     //黑色画笔
	CPen* pPenBlack = new CPen;                                 //创建画笔对象
	pPenBlack->CreatePen(PS_SOLID, 1, RGB(0,0,0)); //黑色画笔
	//选中黑色画笔,并保存当前画笔
	CGdiObject* pOldPen = dc.SelectObject(pPenBlack);
	int i = 0;
	CString str;
	//绘制坐标系
	int OriX=rect.left+40,OriY=rect.bottom-20;//坐标系原点OriX,OriY
	CPoint OPos(OriX,OriY),NowPos;	//OPos是原点坐标
	//绘制x坐标轴
	dc.MoveTo(OPos);
	int flag=0;//flag=0,原比例坐标,flag=1,扩大比例坐标
	int temp=40 + (num-1)*2 + 5;
	//str.Format("%d",temp);
	//AfxMessageBox(str);
	if(rect.right-rect.left>temp)
	{
		flag=1;
		NowPos.x = OriX + temp;
	}
	else
	{
		flag=0;
		NowPos.x = OriX + (num-1) + 5;
	}
	NowPos.y = OriY;
	dc.LineTo(NowPos);
	//绘制箭头
	dc.LineTo(NowPos.x-5,NowPos.y-5);
	dc.MoveTo(NowPos);
	dc.LineTo(NowPos.x-5,NowPos.y+5);
	//绘制x轴坐标系数
	
	for (i = 0;i < num;i = i+5)
	{
		if (i % 10 == 0)
		{
			if(flag==1)
			{
				dc.MoveTo(OPos.x + 2 * i,OPos.y);
				dc.LineTo(CPoint(OPos.x + 2 * i,OPos.y - 5));
			}
			else
			{
				dc.MoveTo(OPos.x + i,OPos.y);
				dc.LineTo(CPoint(OPos.x + i,OPos.y - 5));
			}
		}
		if (i % 20 == 0)
		{
			str.Format("%d",i);
			if(flag==1)
			{
				dc.TextOut(OPos.x + 2 * i,OPos.y + 1,str);
			}
			else
			{
				dc.TextOut(OPos.x + i,OPos.y + 1,str);
			}
		}
	}
	
	//绘制最大的255
	str.Format("%d",(num-1));
	if(flag==1)
	{
		dc.MoveTo(OPos.x + 2 * (num-1),OPos.y);
		dc.LineTo(CPoint(OPos.x + 2 * (num-1),OPos.y - 5));
		dc.TextOut(OPos.x + 2 * (num-1),OPos.y + 1,str);
	}
	else
	{
		dc.MoveTo(OPos.x + (num-1),OPos.y);
		dc.LineTo(CPoint(OPos.x + (num-1),OPos.y - 5));
		dc.TextOut(OPos.x + (num-1),OPos.y + 1,str);
	}
	//AfxMessageBox("a");
	//绘制y轴坐标系数
	dc.MoveTo(OPos);
	NowPos.x = OPos.x;
	NowPos.y = rect.top;
	dc.LineTo(NowPos);
	//绘制箭头
	dc.LineTo(NowPos.x - 5,NowPos.y + 5);
	dc.MoveTo(NowPos);
	dc.LineTo(NowPos.x + 5,NowPos.y + 5);
	
	//寻找数据数组最大的数据
	int max = 0;
	for (i = 0;i < num;i++)
	{
		if (max < count[i])
		{
			max = count[i];
		}
	}
	//y轴坐标系数的数据步长
	int Tstep = max / 10;	//10个数据
	//y轴坐标系数的刻度步长
	int Ystep = (OriY-rect.top) / 21;//除以21的原因是,有20是因为上面的数据步长是10,现在20就是2格显示一个步长,还有一个1是多出来的好看
	//显示y坐标的刻度和数据
	for (i = 1;i != 22;i++)//显示21个刻度
	{
		dc.MoveTo(OPos.x,OPos.y - Ystep * i );
		dc.LineTo(CPoint(OPos.x + 5,OPos.y - Ystep * i));
		if (i % 2 == 0)
		{
			str.Format("%d",Tstep * i / 2);
			dc.TextOut(rect.left,OPos.y - Ystep * i - 10,str);
		}
	}
	
	//绘制灰度图像的直方图
	int RealStep = OPos.y-rect.top-(OriY-rect.top-Ystep*21);
	dc.SelectObject(pPenBlue); //选择蓝色画笔
	for (i = 0;i < num;i++)
	{
		if(flag==1)
		{
			NowPos.x = OPos.x + (2 * i);
		}
		else
		{
			NowPos.x = OPos.x + i;
		}
		NowPos.y = OPos.y;
		dc.MoveTo(NowPos);
		NowPos.y = OPos.y - (float)(((float)(RealStep*20))/(21*max))*count[i];
		//说明:上面这个大家可能不懂为什么,先注意一下上面的y轴坐标系数的数据步长,y轴坐标系数的刻度步长
		//比例这样计算的:(RealStep/21):(max/10)=X:1,然后要求X,X表示1个数据用多少格表示
		dc.LineTo(NowPos);
	}
	//恢复以前的画笔
	dc.SelectObject(pOldPen);
	delete pPenBlue;
	delete pPenBlack;
}


截图如下:

 

 

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值