首页 > 代码库 > MFC中BMP图片双显和灰度
MFC中BMP图片双显和灰度
<一>. Bmp图片双显和灰度原理
为了方便后续的量化采样处理,这里首先要实现bmp图片双显的功能,即在menu的左边显示原图,把原图的文件头数据和信息头数据保存在全局变量数组中;同时建立一个临时的”picture.bmp”图片(默认保存路径在打开原图的位置),以后的操作对临时的图片进行处理。
1 什么叫灰度图?任何颜色都有红、绿、蓝三原色组成,假如原来某点的颜色为RGB(R,G,B),那么,我们可以通过下面几种方法,将其转换为灰度:
浮点算法:Gray=R*0.3+G*0.59+B*0.11;
整数方法:Gray=(R*30+G*59+B*11)/100;
移位方法:Gray =(R*28+G*151+B*77)>>8;
平均值法:Gray=(R+G+B)/3;(此程序采用算法);
仅取绿色:Gray=G;
通过上述任一种方法求得Gray后,将原来的RGB(R,G,B)中的R,G,B统一用Gray替换,形成新的颜色RGB(Gray,Gray,Gray),用它替换原来的RGB(R,G,B)就是灰度图了。
2 改变象素矩阵的RGB值,来达到彩色图转变为灰度图
加权平均值算法:根据光的亮度特性,其实正确的灰度公式应当是
R=G=B=R*0.299+G*0.587+B0.144;
为了提高速度我们做一个完全可以接受的近似,公式变形如下:R=G=B=(R*3+G*6+B)/10 ;
<二>.MFC实现双显和灰度
第一步:建立标记位
1.在View.cpp文件中显示函数前建立标记位,即:
void CBmpDrawView::ShowBitmap(CDC *pDC,CString BmpName)前添加:/*****************************************************//* numPicture=0时显示提示错误信息 *//* numPicture=1时显示1张图片在OnFileOpen中定义 *//* numPicture=2时显示2张图片和处理在处理函数中定义 */ /*****************************************************//*****************************************************//* level=0时显示2张图片 *//* level=1时显示灰度图片 *//* level=3时显示图片采样 *//* level=2 4 8 16 32 63时不同量化级量化图片 */ /*****************************************************/int numPicture=0; //显示图片数 int level=0; //显示量化等级
2.在View.h中建立处理图像的副本文件和默认路径:
CBitmap m_bitmaplin;//创建临时位图对象进行处理CString BmpNameLin; //保存图像的副本文件 原工程中
3.在View.cpp的OnFileOpen文件打开函数中初始化标记变量:
void CBmpDrawView::OnFileOpen()中添加:if( dlg.DoModal() == IDOK ) { //获取路径 文件名 扩展文件名 BmpName = dlg.GetPathName(); BmpNameLin = "picture.bmp"; AfxMessageBox("图片打开成功",MB_OK,0); numPicture=1; EntName = dlg.GetFileExt(); EntName.MakeLower(); //小写字符串 Invalidate(); }
第二步:报错处理
指的是在没有载入图片(numPicture=0)时就按保存按钮,或双显、灰度、量化、采样按钮,就会提示相应的错误提示。因为在打卡图片OnFileOpen函数中令numPicture=1初始化才能显示图片及处理。
在View.cpp中的函数void CBmpDrawView::OnFileSave()中最前面增加代码如下:
//如果没有导入图片直接点击保存 提示信息 if(numPicture==0){ AfxMessageBox("载入图片后才能保存图片!",MB_OK,0); return; }
第三步:增加双显菜单
a.将试图切换到ResourceView界面--选中Menu--在IDR_MAINFRAME中添加菜单“显示”--双击它在菜单属性中选择“弹出”
b.在“显示”的子菜单中添加:
双图显示--ID_SHOW_TWO(ID)--默认属性
灰度图片--ID_SHOW_HD(ID)--默认属性
第四步:实现双显
查看--建立类导向(Ctrl+W)--CBmpDrawView(类名)--ID_SHOW_TWO-- COMMAND(Messages)--默认成员函数名。
添加代码:
/*显示2张图片*/void CBmpDrawView::OnShowTwo() { // TODO: Add your command handler code here //如果没有导入图片直接点击显示2张图片 提示信息 if(numPicture==0) { AfxMessageBox("载入图片后才能显示2张图片!"); return; } AfxMessageBox("显示两张图片!",MB_OK,0); numPicture = 2; //全局变量=2显示双图、=1显示一图 、=0无图显示 level=0; //level=0双图显示 Invalidate(); //调用Invalidata()每秒调用一次OnDraw画图}
第五步:实现灰度图片
查看--建立类导向(Ctrl+W)--CBmpDrawView(类名)--ID_SHOW_HD(ID)-- COMMAND(Messages)--默认成员函数名。
添加代码:
/*灰度图像就是 R=G=B且为三者的1/3 level=1时灰度图像*/void CBmpDrawView::OnShowHd() { //如果没有导入图片直接点击灰度 提示信息 if(numPicture==0){ AfxMessageBox("载入图片后才能灰度图片!",MB_OK,0); return; } AfxMessageBox("灰度图像!",MB_OK,0);FILE *fpo = fopen(BmpName,"rb"); FILE *fpw = fopen(BmpNameLin,"wb+"); fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo); fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo); fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw); fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw); /*灰度图像处理r=g=b=(r+g+b)/3*/ int color,red,green,blue; for( int i=0; i<m_nWidth*m_nHeight; i++ ) { fread(&red,sizeof(char),1,fpo); fread(&green,sizeof(char),1,fpo); fread(&blue,sizeof(char),1,fpo); color=(red+green+blue)/3; red=color; green=color; blue=color; fwrite(&red,sizeof(char),1,fpw); fwrite(&green,sizeof(char),1,fpw); fwrite(&blue,sizeof(char),1,fpw); } fclose(fpo); fclose(fpw); numPicture = 2; level=1; Invalidate();}
第六步:添加代码在ShowBitmap显示处理修改
/*显示BMP格式图片 双显灰度功能*/void CBmpDrawView::ShowBitmap(CDC *pDC, CString BmpName){ HBITMAP m_hBitmap; m_hBitmap = (HBITMAP) LoadImage(NULL,BmpName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION); if( m_bitmap.m_hObject ){ m_bitmap.Detach();} m_bitmap.Attach(m_hBitmap); CRect rect; GetClientRect(&rect); int m_nWindowWidth = rect.right - rect.left; //计算客户区宽度 int m_nWindowHeight = rect.bottom - rect.top; //计算客户区高度 CDC dcBmp; if( !dcBmp.CreateCompatibleDC(pDC) ) return; BITMAP m_bmp; m_bitmap.GetBitmap(&m_bmp); CBitmap *pbmpOld = NULL; dcBmp.SelectObject(&m_bitmap); if(m_nDrawWidth<650 && m_nDrawHeight<650)pDC->StretchBlt(0,0,m_nDrawWidth,m_nDrawHeight,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY); elsepDC->StretchBlt(0,0,640,640,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY); dcBmp.SelectObject(pbmpOld); DeleteObject(&m_bitmap); dcBmp.DeleteDC(); /*显示第2张图片*/ if( numPicture == 2 ) { HBITMAP m_hBitmapChange; if(level==0) //显示2张图 { m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION); } else if(level==1) //灰度图片 { m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION); } if( m_bitmap.m_hObject ){ m_bitmap.Detach(); } m_bitmap.Attach(m_hBitmapChange); CDC dcBmp; if( !dcBmp.CreateCompatibleDC(pDC) ) return; BITMAP m_bmp; m_bitmap.GetBitmap(&m_bmp); CBitmap *pbmpOld = NULL; dcBmp.SelectObject(&m_bitmap); /*图片显示调用函数StretchBlt */ if(m_nDrawWidth<650 && m_nDrawHeight<650)pDC->StretchBlt(m_nWindowWidth-m_nDrawWidth,0,m_nDrawWidth,m_nDrawHeight,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY); elsepDC->StretchBlt(m_nWindowWidth-640,0,640,640,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY); //显示大小为640*640 dcBmp.SelectObject(pbmpOld); //恢复临时DC的位图 }}
MFC中BMP图片双显和灰度