本文共 13272 字,大约阅读时间需要 44 分钟。
什么是灰度直方图? 灰度直方图(histogram)是灰度级的函数,描述的是图像中每种灰度级像素的个数,反映图像中每种灰度出现的频率。横坐标是灰度级,纵坐标是灰度级出现的频率。
//引用显示直方图头文件#include "ImageZFTDlg.h"#include "math.h"/*全局变量在TestZFTDlg.cpp中引用 用extern*/int Red[256],Green[256],Blue[256];/**************************************************//* 添加直方图显示功能,并在直方图下方显示相关信息 /* 如平均灰度、中值灰度、标准差和像素总数 /* ID_ZFT_YT:直方图原图显示 /**************************************************/void CImageProcessingView::OnZftYt() { if(numPicture==0) { AfxMessageBox("载入图片后才能显示原图直方图!",MB_OK,0); return; } AfxMessageBox("显示原图直方图!",MB_OK,0); CImageZFTDlg dlg; //打开临时的图片 FILE *fpo = fopen(BmpName,"rb"); fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo); fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo); int i,j; for(j=0;j<256;j++) { //定义数组并清零 Red[j]=0; Green[j]=0; Blue[j]=0; } //计算4个数据 unsigned char red,green,blue; int IntRed,IntGreen,IntBlue; //强制转换 double sumRedHD=0,sumGreenHD=0,sumBlueHD=0; //记录像素总的灰度值和 for(i=0; i第五步:此时运行结果如下图所示,打开图片可以显示参数。=0 && IntRed<256 ) Red[IntRed]++; //像素0-255之间 fread(&green,sizeof(char),1,fpo); IntGreen=int(green); sumGreenHD=sumGreenHD+IntGreen; if( IntGreen>=0 && IntGreen<256 ) Green[IntGreen]++; fread(&blue,sizeof(char),1,fpo); IntBlue=int(blue); sumBlueHD=sumBlueHD+IntBlue; if( IntBlue>=0 && IntBlue<256 ) Blue[IntBlue]++; } fclose(fpo); //像素:int型转换为CString型 dlg.m_redXS.Format("%d",m_nImage); dlg.m_greenXS.Format("%d",m_nImage); dlg.m_blueXS.Format("%d",m_nImage); //平均灰度值:计算24位bmp图片的灰度值,我是记录RGB中的所有平均值 float pinRedHD,pinGreenHD,pinBlueHD; pinRedHD=sumRedHD*3/m_nImage; pinGreenHD=sumGreenHD*3/m_nImage; //平均灰度=总灰度/总像素 pinBlueHD=sumBlueHD*3/m_nImage; dlg.m_redPJHD.Format("%.2f",pinRedHD); dlg.m_greenPJHD.Format("%.2f",pinGreenHD); dlg.m_bluePJHD.Format("%.2f",pinBlueHD); /****************************************************************/ /* 中值灰度:算法重点(黄凯大神提供) /* 中值灰度:所有像素中的中位数,应该所有像素排序找到中间的灰度值 /* 算法:num[256]记录各灰度出现次数,sum+=num[i],找到sum=总像素/2 /****************************************************************/ int sumRedZZHD=0,sumGreenZZHD=0,sumBlueZZHD=0; int redZZHD,greenZZHD,blueZZHD; for(i=0;i<256;i++) { sumRedZZHD=sumRedZZHD+Red[i]; if(sumRedZZHD>=m_nImage/6) //m_nImage被分成3份RGB并且sum=总像素/2 { redZZHD=i; break; } } for(i=0;i<256;i++) { sumGreenZZHD=sumGreenZZHD+Green[i]; if(sumGreenZZHD>=m_nImage/6) //m_nImage被分成3份RGB并且sum=总像素/2 { greenZZHD=i; break; } } for(i=0;i<256;i++) { sumBlueZZHD=sumBlueZZHD+Blue[i]; if(sumBlueZZHD>=m_nImage/6) //m_nImage被分成3份RGB并且sum=总像素/2 { blueZZHD=i; break; } } dlg.m_redZZHD.Format("%d",redZZHD); dlg.m_greenZZHD.Format("%d",greenZZHD); dlg.m_blueZZHD.Format("%d",blueZZHD); /******************************************************************/ /*标准差:标准差=方差的算术平方根 /* 方差s^2=[(x1-x)^2+(x2-x)^2+......(xn-x)^2]/n /* 算法:不用开m_nImage数组进行计算 用num[256]中数进行 /* 方差=(平均灰度-i)*(平均灰度-i)*Red[i] 有Red[i]个灰度值为i的数 /******************************************************************/ float redBZC,greenBZC,blueBZC; //标准差 double redFC=0,greenFC=0,blueFC=0; //方差 for(i=0;i<256;i++) { redFC=redFC+(pinRedHD-i)*(pinRedHD-i)*Red[i]; //有Red[i]个像素i greenFC=greenFC+(pinGreenHD-i)*(pinGreenHD-i)*Green[i]; blueFC=blueFC+(pinBlueHD-i)*(pinBlueHD-i)*Blue[i]; } redBZC=sqrt(redFC*3/m_nImage); greenBZC=sqrt(greenFC*3/m_nImage); blueBZC=sqrt(blueFC*3/m_nImage); dlg.m_redBZC.Format("%.2lf",redBZC); dlg.m_greenBZC.Format("%.2lf",greenBZC); dlg.m_blueBZC.Format("%.2lf",blueBZC); //重点必须添加该语句才能弹出对话框 if(dlg.DoModal()==IDOK) { }}
//****************绘制原图直方图*********************//void CImageZFTDlg::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here /********************************************************************************/ /* 重点知识:(百度) /* 如何在View.cpp中把一个变量的值传给其它对话框 /* /* 错误一:在View.h中定义的pubic变量只能在View.cpp中用 /* 错误二:定义一个Struct.h中存全局变量,在2个函数中分别调用#include "Struct.h" /* /* 解决方法一: (CSDN 不会)参数用 A& a 两个对话框里都可以访问a /* 解决方法二: (CSDN 不会)重载 /* /* 解决:在View.cpp中定义全局变量 void CBmpDrawView::OnZftYt() 前面 并函数中操作 /* 在dialog的cpp中即void CTestZFTDlg::OnPaint()中在定义一个extern int a /********************************************************************************/ extern int Red[256],Green[256],Blue[256]; /*写在该空间中可以省略Invalidate()语句*/ /*获取控件的CDC指针*/ CRect rectpic; GetDlgItem(IDC_STATIC_KJ)->GetWindowRect(&rectpic); int x,y; x=rectpic.Width(); y=rectpic.Height(); CWnd *pWnd=GetDlgItem(IDC_STATIC_KJ); CDC *pDC=pWnd->GetDC(); /***********************/ /*重点:画直方图 红色 /**********************/ CPen *RedPen=new CPen(); //创建画笔对象 RedPen->CreatePen(PS_SOLID,1,RGB(255,0,0)); //红色画笔 CGdiObject *RedOlderPen=pDC->SelectObject(RedPen); //选中当前红色画笔并保存以前的画笔 /*画图*/ pDC->Rectangle(9,16,312,147); //画一个矩形框 pDC->MoveTo(15,20); //绘制坐标轴 pDC->LineTo(15,128); //Y竖轴 pDC->LineTo(305,128); //X横轴 pDC->MoveTo(305,128); //绘制X箭头 pDC->LineTo(300,123); //绘制上边箭头 pDC->MoveTo(305,128); pDC->LineTo(300,133); //绘制下边箭头 pDC->MoveTo(15,20); //绘制Y箭头 pDC->LineTo(10,25); //绘制左边箭头 pDC->MoveTo(15,20); pDC->LineTo(20,25); //绘制右边箭头 /**********************************************************************/ /* TextOut函数功能: /* 该函数用当前选择的字体、背景颜色和正文颜色将一个字符串写到指定位置 /* BOOL TextOut(HDC hdc,int x,int y,LPCTSTR str,int numStr) /* 表示:x起始坐标,y起始坐标,字符串,字符串中字符个数 /* /* SetTextColor函数功能: /* 设置指定设备环境(HDC)的字体颜色 /* SetTextColor (HDC, COLORREF) 如:SetTextColor(HDC,RGB(255,0,0)); /**********************************************************************/ CString str; int i; for(i=0;i<=5;i++) //写X轴刻度线 { str.Format("%d",i*50); //0-255之间添加6个刻度值 pDC->SetTextColor(RGB(255,0,255)); //设置字体颜色 pDC->TextOut(15+48*i,130,str); //输出字体 pDC->MoveTo(15+48*i,128); //绘制X轴刻度 pDC->LineTo(15+48*i,125); } for(i=0;i<=5;i++) //写Y轴刻度线 { pDC->MoveTo(15,128-20*i); //绘制Y轴刻度 pDC->LineTo(18,128-20*i); } /*绘制直方图主要的代码*/ for(i=1;i<256;i++) { pDC->MoveTo(15+i,128); if( (128-16) > (Red[i]/40) ) pDC->LineTo(15+i,128-(Red[i]/40)); else pDC->LineTo(15+i,16); //超过矩形的画矩形高 } /**********************/ /*重点:画直方图 绿色 /**********************/ CPen *GreenPen=new CPen(); //创建画笔对象 GreenPen->CreatePen(PS_SOLID,1,RGB(0,255,0)); //绿色画笔 CGdiObject *GreenOlderPen=pDC->SelectObject(GreenPen); pDC->Rectangle(9,167,312,308); //画一个矩形框 pDC->MoveTo(15,171); //绘制坐标轴 pDC->LineTo(15,288); //Y竖轴 pDC->LineTo(305,288); //X横轴 pDC->MoveTo(305,288); //绘制X箭头 pDC->LineTo(300,283); //绘制上边箭头 pDC->MoveTo(305,288); pDC->LineTo(300,293); //绘制下边箭头 pDC->MoveTo(15,171); //绘制Y箭头 pDC->LineTo(10,176); //绘制左边箭头 pDC->MoveTo(15,171); pDC->LineTo(20,176); //绘制右边箭头 for(i=0;i<=5;i++) //写X轴刻度线 { str.Format("%d",i*50); //0-255之间添加6个刻度值 pDC->SetTextColor(RGB(255,0,255)); //设置字体颜色 pDC->TextOut(15+48*i,290,str); //输出字体 pDC->MoveTo(15+48*i,288); //绘制X轴刻度 pDC->LineTo(15+48*i,285); } for(i=0;i<=5;i++) //写Y轴刻度线 { pDC->MoveTo(15,288-20*i); //绘制Y轴刻度 pDC->LineTo(18,288-20*i); } /*绘制直方图主要的代码*/ for(i=1;i<256;i++) { pDC->MoveTo(15+i,288); if( (288-167) > (Green[i]/40) ) pDC->LineTo(15+i,288-(Green[i]/40)); else pDC->LineTo(15+i,167); //超过矩形的画矩形高 } /**********************/ /*重点:画直方图 蓝色 /***************((*****/ CPen *BluePen=new CPen(); //创建画笔对象 BluePen->CreatePen(PS_SOLID,1,RGB(0,0,255)); //蓝色画笔 CGdiObject *BlueOlderPen=pDC->SelectObject(BluePen); pDC->Rectangle(9,327,312,468); //画一个矩形框 pDC->MoveTo(15,331); //绘制坐标轴 pDC->LineTo(15,448); //Y竖轴 pDC->LineTo(305,448); //X横轴 pDC->MoveTo(305,448); //绘制X箭头 pDC->LineTo(300,443); //绘制上边箭头 pDC->MoveTo(305,448); pDC->LineTo(300,453); //绘制下边箭头 pDC->MoveTo(15,331); //绘制Y箭头 pDC->LineTo(10,336); //绘制左边箭头 pDC->MoveTo(15,331); pDC->LineTo(20,336); //绘制右边箭头 for(i=0;i<=5;i++) //写X轴刻度线 { str.Format("%d",i*50); //0-255之间添加6个刻度值 pDC->SetTextColor(RGB(255,0,255)); //设置字体颜色 pDC->TextOut(15+48*i,450,str); //输出字体 pDC->MoveTo(15+48*i,448); //绘制X轴刻度 pDC->LineTo(15+48*i,445); } for(i=0;i<=5;i++) //写Y轴刻度线 { pDC->MoveTo(15,448-20*i); //绘制Y轴刻度 pDC->LineTo(18,448-20*i); } /*绘制直方图主要的代码*/ for(i=1;i<256;i++) { pDC->MoveTo(15+i,448); if( (448-327) > (Blue[i]/40) ) pDC->LineTo(15+i,448-(Blue[i]/40)); else pDC->LineTo(15+i,327); //超过矩形的画矩形高 } //恢复以前的画笔 pDC->SelectObject(RedOlderPen); pDC->SelectObject(GreenOlderPen); pDC->SelectObject(BlueOlderPen); delete RedPen; delete GreenPen; delete BluePen; ReleaseDC(pDC); return; // Do not call CDialog::OnPaint() for painting messages}此时运行程序即可显示直方图。 最后还是希望文章对你有所帮助,如果文章有不足或错误之处,请海涵~文章不仅仅讲述了直方图相关的知识,同时文章也给你提供了一种绘制坐标图像的思想和详细注释。有时候一直怀疑回忆这些知识会让我停滞不前,但心安即好,何必在意! 从来没有什么终南捷径和大神,真正的捷径只有三个:坚持、专注、认真。其他的都是细枝末节,做到这三个,其他的自然而然都会拥有。——同学CY