绘制灰度直方图
晚上帮信息院的高中同学做图像处理的实验,里面有一项是编写一个绘制灰度直方图的程序。感觉信息院的实验还是比较接地气。不想咱院的实验…呵呵呵呵呵。看起来都挺高大上的,就是有点假大空。
###绘制灰度直方图の第一步 打开位图文件
// TODO: 在此添加控件通知处理程序代码
static char szFilter[]="位图文件(*.bmp)|*.bmp;*.dib|All Files(*.*)|*.*||";
CFileDialog pickfile(true,"*.bmp",NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,szFilter);
if(pickfile.DoModal()==IDOK)
{
UpdateData(1);
myfilename=pickfile.GetPathName();
}else
{
myfilename.Empty();
}
CBitmap bitmap;
/*
CRect myrc;
mypic.GetWindowRect(&myrc);
*/
hbitmap=(HBITMAP)LoadImage(AfxGetInstanceHandle(),
myfilename,
IMAGE_BITMAP,
512,
300,
LR_LOADFROMFILE);
mypic.SetBitmap(hbitmap);
getresult();
DrawResult();
首先用构造一个CFileDialog类对象获取文件位置。
这里还顺便把它贴到一个图片控件上预览图片了。
然后计算灰度。
##绘制灰度直方图の第二步 计算灰度
所谓灰度就是指亮度。一个白色的点,RGB值0xFFFFFF。那么他的灰度就是0xFF。黑的像素点就是0。 对于RGB分量相同的颜色灰度就是R,G,B的值。这很显然。 那么对于彩色的点,其实并不是想象中的R,G,B分量乘以1/3累加。 人眼对于各种颜色的感觉并不一致,同样强度绿光在人眼看来就比同样强度的蓝光要亮。因此RGB加权值不一样。
具体的东西可以看维基:Gray Scale 。
这里给出windows下用的公式:
Y=0.299R+0.587G+0.114*B
CFile myfile;
if(!myfile.Open(myfilename,CFile::modeRead))
{
MessageBox("打开文件错误!");
return;
}
BITMAPFILEHEADER bmpH;
if (myfile.Read((LPSTR)&bmpH, sizeof(bmpH)) != sizeof(bmpH))
{
MessageBox("读取文件头错误!");
return;
}
BITMAPINFOHEADER bmpIH;
if(myfile.Read((LPSTR)&bmpIH,sizeof(bmpIH))!=sizeof(bmpIH))
{
MessageBox("读取文件头错误!");
return;
}
myfile.Close();
CString str;
str.Format(" %d*%d",bmpIH.biWidth,bmpIH.biHeight);
T_path.SetWindowTextA(myfilename+str);
CDC memDC;
memDC.CreateCompatibleDC(NULL);
HBITMAP hbmp;
hbmp=(HBITMAP)LoadImage(AfxGetInstanceHandle(),
myfilename,
IMAGE_BITMAP,
bmpIH.biWidth,
bmpIH.biHeight,
LR_LOADFROMFILE);
SelectObject(memDC,hbmp);
for(int i=0;i<256;i++)
result[i]=0;
COLORREF cr;
int gray;
for(int y=0;y<bmpIH.biHeight;y++)
for(int x=0;x<bmpIH.biWidth;x++)
{
cr=memDC.GetPixel(x,y);
gray=(0.299*GetRValue(cr)+0.587*GetGValue(cr)+0.114*GetBValue(cr));
result[gray]++;
}
这里面用CFile打开文件,为的是读取位图文件的文件头。在BITMAPINFOHEADER里有图片的大小信息。
然后为省事我就不自己解析bitmap文件了,直接用MFC的工具把它画到内存里。然后直接memDC.GetPixel()获取像素信息了,省事。 不知道她们实验与不允许。
计算灰度,统计灰度分布。
然后绘图:
##绘制灰度直方图の第二步 计算灰度
CDC* pDC=((CStatic*)GetDlgItem(IDC_STATIC_DRAW))->GetWindowDC();
CRect mc;
GetDlgItem(IDC_STATIC_DRAW)->GetWindowRect(&mc);
pDC->FillSolidRect(0,0,mc.Width(),mc.Height(),RGB(00,00,00));
//CString str;
//str.Format("H:%d W:%d",mc.Height(),mc.Width());
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(250,250,0));
pDC->TextOutA(0,0,"灰度直方图");
CPen myPen(PS_SOLID,1,RGB(0,200,0));
int max=0;
for(int i=0;i<256;i++)
{
if(result[i]>max)
max=result[i];
}
pDC->SelectObject(&myPen);
int h;
for(int i=0;i<256;i++)
{
if(result[i])
h=256-(result[i]*256/max);
else
h=256;
pDC->MoveTo(i*2,256);
pDC->LineTo(i*2,h);
pDC->MoveTo(i*2+1,256);
pDC->LineTo(i*2+1,h);
}
恩,就是画几根线而已。