数字图像处理(二)灰度、量化、采样

 转自https://blog.csdn.net/eastmount/article/details/46010637

本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程《数字图像处理》及课件进行讲解,主要通过MFC单文档视图实现显示BMP格式图片,并通过Bitmap进行灰度处理、图片采样和量化功能。

        个人认为对初学者VC++6.0可能还是很值得学习的工具,所以采用它来讲解,而不是VS或C#。同时文章比较详细基础,希望该篇文章对你有所帮助~
       【数字图像处理】一.MFC详解显示BMP格式图片
       【数字图像处理】二.MFC单文档分割窗口显示图片
        
免费资源下载地址:
        http://download.csdn.net/detail/eastmount/8748403


一. 单文档显示BMP图片

        第一步:新建项目"MFC AppWizard(exe)",项目名为ImageProcessing,在应用程序类型中选择"单个文档",点击"确定"。在左栏的"资源视图"中,点击"Menu->IDR_MAINFRAM"可以查看并修改菜单视图。


        第二步:向CImageProcessingView类添加成员变量和成员函数。在右栏的"类视图"右键ImageProcessingView添加函数或直接在ImageProcessingView.h中直接添加public成员变量和成员函数。添加代码如下:
[cpp]  view plain  copy
  1. // Implementation  
  2. public:  
  3.     //添加成员函数  
  4.     void ShowBitmap(CDC* pDC,CString BmpName); //显示位图函数  
  5.   
  6.     //添加成员变量  
  7.     CString EntName;     //图像文件扩展名  
  8.     CString BmpName;     //图像文件名称  
  9.     CBitmap m_bitmap;    //创建位图对象  
        同时采用类视图添加后,会自动在XXXView.h中添加函数定义,在XXXView.cpp中添加函数实现代码。



        第三步:编辑ImageProcessingView.cpp中ShowBitmap()函数。通过它显示BMP图片,其中代码及详细注释如下:
[cpp]  view plain  copy
  1. //****************显示BMP格式图片****************//  
  2. void CImageProcessingView::ShowBitmap(CDC *pDC, CString BmpName)  
  3. {  
  4.     //定义bitmap指针 调用函数LoadImage装载位图  
  5.     HBITMAP m_hBitmap;  
  6.     m_hBitmap = (HBITMAP) LoadImage(NULL,BmpName,IMAGE_BITMAP,0,0,  
  7.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  8.           
  9.     /*************************************************************************/  
  10.     /* 1.要装载OEM图像,则设此参数值为0  OBM_ OEM位图 OIC_OEM图标 OCR_OEM光标 
  11.     /* 2.BmpName要装载图片的文件名                   
  12.     /* 3.装载图像类型:  
  13.     /*   IMAGE_BITMAP-装载位图 IMAGE_CURSOR-装载光标 IMAGE_ICON-装载图标     
  14.     /* 4.指定图标或光标的像素宽度和长度 以像素为单位     
  15.     /* 5.加载选项: 
  16.     /*   IR_LOADFROMFILE-指明由lpszName指定文件中加载图像 
  17.     /*   IR_DEFAULTSIZE-指明使用图像默认大小 
  18.     /*   LR_CREATEDIBSECTION-当uType参数为IMAGE_BITMAP时,创建一个DIB项 
  19.     /**************************************************************************/  
  20.   
  21.     if( m_bitmap.m_hObject )  
  22.     {  
  23.         m_bitmap.Detach();           //切断CWnd和窗口联系  
  24.     }  
  25.     m_bitmap.Attach(m_hBitmap);      //将句柄HBITMAP m_hBitmap与CBitmap m_bitmap关联  
  26.       
  27.     //边界  
  28.     CRect rect;  
  29.     GetClientRect(&rect);  
  30.   
  31.     //图片显示(x,y)起始坐标  
  32.     int m_showX=0;  
  33.     int m_showY=0;  
  34.     int m_nWindowWidth = rect.right - rect.left;   //计算客户区宽度  
  35.     int m_nWindowHeight = rect.bottom - rect.top;  //计算客户区高度  
  36.           
  37.     //定义并创建一个内存设备环境DC  
  38.     CDC dcBmp;  
  39.     if( !dcBmp.CreateCompatibleDC(pDC) )   //创建兼容性的DC  
  40.         return;  
  41.     BITMAP m_bmp;                          //临时bmp图片变量  
  42.     m_bitmap.GetBitmap(&m_bmp);            //将图片载入位图中  
  43.     CBitmap *pbmpOld = NULL;        
  44.     dcBmp.SelectObject(&m_bitmap);         //将位图选入临时内存设备环境  
  45.       
  46.     //图片显示调用函数stretchBlt  
  47.     pDC->StretchBlt(0,0,m_bmp.bmWidth,m_bmp.bmHeight,&dcBmp,0,0,  
  48.         m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY);  
  49.       
  50.     /*******************************************************************************/  
  51.     /* BOOL StretchBlt(int x,int y,int nWidth,int nHeight,CDC* pSrcDC,  
  52.     /*                 int xSrc,int ySrc,int nSrcWidth,int nSrcHeight,DWORD dwRop ); 
  53.     /* 1.参数x、y位图目标矩形左上角x、y的坐标值       
  54.     /* 2.nWidth、nHeigth位图目标矩形的逻辑宽度和高度       
  55.     /* 3.pSrcDC表示源设备CDC指针                           
  56.     /* 4.xSrc、ySrc表示位图源矩形的左上角的x、y逻辑坐标值  
  57.     /* 5.dwRop表示显示位图的光栅操作方式 SRCCOPY用于直接将位图复制到目标环境中             
  58.     /*******************************************************************************/  
  59.       
  60.     dcBmp.SelectObject(pbmpOld);           //恢复临时DC的位图  
  61.     DeleteObject(&m_bitmap);               //删除内存中的位图  
  62.     dcBmp.DeleteDC();                      //删除CreateCompatibleDC得到的图片DC  
  63.   
  64.   
  65.     /** 
  66.      * 面代码为后面显示第二张图片 
  67.      */  
  68.   
  69. }  
        第四步:设置打开BMP图片函数。"查看"->"建立类向导"(Ctrl+W)->选择"类名"CImageProcessing->在命令对象ID中双击"ID_FILE_OPEN"->自动生成默认成员函数OnFileOpen,消息为COMMAND。双击成员函数(Member Functions)进入函数编辑。
        编辑ImageProcessingView.cpp函数实现打开图片,代码如下:
[cpp]  view plain  copy
  1. //****************打开文件****************//  
  2. void CImageProcessingView::OnFileOpen()   
  3. {  
  4.     //两种格式的文件:bmp gif  
  5.     CString filter;    
  6.     filter="所有文件(*.bmp,*.jpg,*.gif)|*.bmp;*.jpg| BMP(*.bmp)|*.bmp| JPG(*.jpg)|*.jpg||";    
  7.     CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY,filter,NULL);              
  8.     
  9.     //按下确定按钮 dlg.DoModal() 函数显示对话框    
  10.     if( dlg.DoModal() == IDOK )    
  11.     {    
  12.         BmpName = dlg.GetPathName();     //获取文件路径名   如D:\pic\abc.bmp    
  13.         EntName = dlg.GetFileExt();      //获取文件扩展名    
  14.         EntName.MakeLower();             //将文件扩展名转换为一个小写字符    
  15.         Invalidate();                    //调用该函数就会调用OnDraw重绘画图    
  16.     }     
  17. }  
        第五步:在ImageProcessingView.cpp中找到OnDraw()函数,通过OnDraw()函数调用ShowBitmap()函数显示图片。代码如下:
[cpp]  view plain  copy
  1. void CImageProcessingView::OnDraw(CDC* pDC)  
  2. {  
  3.     CImageProcessingDoc* pDoc = GetDocument();  
  4.     ASSERT_VALID(pDoc);  
  5.     // TODO: add draw code for native data here  
  6.     if (!pDoc) return;    
  7.     if( EntName.Compare(_T("bmp")) == 0 )      //bmp格式    
  8.     {    
  9.         ShowBitmap(pDC,BmpName);               //显示图片    
  10.     }    
  11. }  
        第六步:此时点击运行,同时点击文件-打开,即可显示图片如下图所示:

        PS:这是非常著名的一张图片莱娜图(Lenna),全图是一张花花公子封面的裸图,后成为数字图像处理的标志图片。哈哈~至于BMP图片格式参照第一篇文章


二. 读取BMP图片和保存图片

        BMP图片格式如下图所示:(参考自己文库)

        在很多处理中,都需要获取BMP图像的一些数据,如图像宽度、高度、像素大小等,后面的处理与之相关,主要的是ReadBmp函数。
       第一步:在XXXView.h中添加BMP格式图像相关的成员变量和成员函数,其中成员函数通过类视图右键添加,成员变量可以在XXXView.h中直接复制。
[cpp]  view plain  copy
  1. // Implementation  
  2. public:  
  3.     //添加成员函数  
  4.     void ShowBitmap(CDC* pDC,CString BmpName); //显示位图函数  
  5.     bool ReadBmp();                            //用来读取bmp个手机图片  
  6.     bool SaveBmp(LPCSTR lpFileName);           //用来保存bmp格式图片  
  7.   
  8.     //添加成员变量  
  9.     CString EntName;     //图像文件扩展名  
  10.     CString BmpName;     //图像文件名称  
  11.     CBitmap m_bitmap;    //创建位图对象  
  12.   
  13.     int m_nWidth;       //图像实际宽度  
  14.     int m_nHeight;      //图像实际高度  
  15.     int m_nDrawWidth;   //图像显示宽度  
  16.     int m_nDrawHeight;  //图像显示高度  
  17.     DWORD m_nImage;     //图像数据的字节数 只含位图  
  18.     DWORD m_nSize;      //图像文件大小  
  19.     int m_nLineByte;    //图像一行所占字节数  
  20.     int m_nBitCount;    //图像每个像素所占位数  
  21.     int m_nPalette;     //位图实际使用的颜色表中的颜色数  
  22.       
  23.     BYTE *m_pImage;         //读入图片数据后的指针  
  24.     BITMAPFILEHEADER bfh;   //全局变量文件头  
  25.     BITMAPINFOHEADER bih;   //全局变量信息头  
  26.     RGBQUAD m_pPal;         //颜色表指针  
        第二步:在ImageProcessingView.cpp中实现ReadBmp函数和SaveBmp函数。
[cpp]  view plain  copy
  1. //***************读取图片数据*************//  
  2. bool CImageProcessingView::ReadBmp()  
  3. {  
  4.     //图片读出存储其中的东西  
  5.     FILE *fp = fopen(BmpName,"rb");  
  6.     if(fp==0)  
  7.     {         
  8.         AfxMessageBox("无法打开文件!",MB_OK,0);  
  9.         return 0;   
  10.     }  
  11.     //读取文件头 解决BMP格式倒置的方法  
  12.     fread(&bfh.bfType,sizeof(WORD),1,fp);  
  13.     fread(&bfh.bfSize,sizeof(DWORD),1,fp);  
  14.     fread(&bfh.bfReserved1,sizeof(WORD),1,fp);  
  15.     fread(&bfh.bfReserved2,sizeof(WORD),1,fp);  
  16.     fread(&bfh.bfOffBits,sizeof(DWORD),1,fp);  
  17.     //图像文件的总字节数  
  18.     m_nSize = bfh.bfSize;  
  19.     //判断是否是bmp格式图片  
  20.     if(bfh.bfType!=0x4d42)   //'BM'  
  21.     {  
  22.         AfxMessageBox("不是BMP格式图片!",MB_OK,0);  
  23.         return 0;  
  24.     }  
  25.     //读取信息头  
  26.     fread(&bih.biSize,sizeof(DWORD),1,fp);  
  27.     fread(&bih.biWidth,sizeof(LONG),1,fp);  
  28.     fread(&bih.biHeight,sizeof(LONG),1,fp);  
  29.     fread(&bih.biPlanes,sizeof(WORD),1,fp);  
  30.     fread(&bih.biBitCount,sizeof(WORD),1,fp);  
  31.     fread(&bih.biCompression,sizeof(DWORD),1,fp);  
  32.     fread(&bih.biSizeImage,sizeof(DWORD),1,fp);  
  33.     fread(&bih.biXPelsPerMeter,sizeof(LONG),1,fp);  
  34.     fread(&bih.biYPelsPerMeter,sizeof(LONG),1,fp);  
  35.     fread(&bih.biClrUsed,sizeof(DWORD),1,fp);  
  36.     fread(&bih.biClrImportant,sizeof(DWORD),1,fp);  
  37.     if(bih.biSize!=sizeof(bih))  
  38.     {  
  39.         AfxMessageBox("本结构所占用字节数出现错误");  
  40.         return 0;  
  41.     }  
  42.     //位图压缩类型,必须是 0(不压缩) 1(BI_RLE8压缩类型)或2(BI_RLE压缩类型)之一  
  43.     if(bih.biCompression == BI_RLE8 || bih.biCompression == BI_RLE4)  
  44.     {  
  45.         AfxMessageBox("位图被压缩!");  
  46.         return 0;  
  47.     }  
  48.     //获取图像高宽和每个像素所占位数  
  49.     m_nHeight = bih.biHeight;  
  50.     m_nWidth = bih.biWidth;  
  51.     m_nDrawHeight = bih.biHeight;  
  52.     m_nDrawWidth = bih.biWidth;  
  53.     m_nBitCount = bih.biBitCount;   //每个像素所占位数  
  54.     //计算图像每行像素所占的字节数(必须是32的倍数)  
  55.     m_nLineByte = (m_nWidth*m_nBitCount+31)/32*4;  
  56.     //图片大小 调用系统自带的文件头 BITMAPFILEHEADER bfh; BITMAPINFOHEADER bih;   
  57.     //否则用 BITMAPFILEHEADER_ bfh; BITMAPINFOHEADER_ bih;要 m_nImage = m_nLineByte * m_nHeight - 2;  
  58.     m_nImage = m_nLineByte * m_nHeight;  
  59.     //位图实际使用的颜色表中的颜色数 biClrUsed  
  60.     m_nPalette = 0;                       //初始化  
  61.     if(bih.biClrUsed)  
  62.         m_nPalette = bih.biClrUsed;  
  63.     //申请位图空间 大小为位图大小 m_nImage  
  64.     //malloc只能申请4字节的空间 (未知)  
  65.     m_pImage=(BYTE*)malloc(m_nImage);  
  66.     fread(m_pImage,m_nImage,1,fp);  
  67.     fclose(fp);  
  68.     return true;  
  69. }  
       其中SaveBmp()函数代码如下:
[cpp]  view plain  copy
  1. //****************保存文件****************//  
  2. bool CImageProcessingView::SaveBmp(LPCSTR lpFileName) //lpFileName为位图文件名  
  3. {  
  4.     //保存bmp格式图片 写图片过程 只处理24像素的图片 该图片无调色板  
  5.     FILE *fpo = fopen(BmpName,"rb");  
  6.     FILE *fpw = fopen(lpFileName,"wb");  
  7.     fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  8.     fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  9.     fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  10.     fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  11.     //malloc只能申请4字节的空间 (未知)  
  12.     m_pImage=(BYTE*)malloc(m_nImage);  
  13.     fread(m_pImage,m_nImage,1,fpo);  
  14.     fwrite(m_pImage,m_nImage,1,fpw);  
  15.     fclose(fpo);  
  16.     fclose(fpw);  
  17.     return true;  
  18. }  
        第三步:添加保存menu控件和函数。点击”查看-建立类向导“,在ID列表中找到ID_FILE_SAVE,点击COMMAND(Message列表),双击添加默认成员函数OnFileSave,同时在Member Functions(成员函数)中双击该函数进入函数并编辑。添加如下代码:
[cpp]  view plain  copy
  1. //******************文件保存*****************//  
  2. void CImageProcessingView::OnFileSave()   
  3. {  
  4.     // TODO: Add your command handler code here  
  5.     CString filter;  
  6.     filter="所有文件(*.bmp,*.jpg)|*.bmp;*.jpg| BMP(*.bmp)|*.bmp| JPG(*.jpg)|*.jpg||";  
  7.     //重点: 1-文件打开 0-文件保存  
  8.     CFileDialog dlg(0,NULL,NULL,OFN_HIDEREADONLY,filter,NULL);     
  9.     //按下确定按钮  
  10.     if( dlg.DoModal() == IDOK ) {  
  11.         CString str;  
  12.         CString strName;  
  13.         CString filename;  
  14.         str = dlg.GetPathName();           //获取文件的路径  
  15.         filename = dlg.GetFileTitle();     //获取文件名  
  16.         int nFilterIndex=dlg.m_ofn.nFilterIndex;  
  17.         if( nFilterIndex == 2 )            //当用户选择文件过滤器为".BMP"时  
  18.         {  
  19.             str = str + ".bmp";            //自动加扩展名.bmp  
  20.             SaveBmp(str);                  //保存bmp图片 就是一个写出图片的过程   
  21.             AfxMessageBox("图片保存成功",MB_OK,0);  
  22.         }  
  23.     }  
  24. }  
        第四步:在XXXView.cpp中OnDraw()函数中调用读取图片函数。
        if( EntName.Compare(_T("bmp")) == 0 )      //bmp格式  
        {  

                ReadBmp();
                ShowBitmap(pDC,BmpName);               //显示图片  
        }  

        运行程序,打开图片点击保存即可实现。重点是ReadBmp获取一些重要参数。


三. 图像灰度处理

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)就是灰度图了。
        改变象素矩阵的RGB值,来达到彩色图转变为灰度图
        加权平均值算法:根据光的亮度特性,其实正确的灰度公式应当是:
                                                R=G=B=R*0.299+G*0.587+B0.144
        为了提高速度我们做一个完全可以接受的近似,公式变形如下:R=G=B=(R*3+G*6+B)/10 
        真正的24位真彩图与8位的灰度图的区别就在于,真彩图文件中没有调色板,灰度图有调色板,真彩图中的象素矩阵是RGB值,灰度图中的象素矩阵是调色板索引值。源代码只简单的改变象素矩阵的RGB值,来达到彩色图转为灰度图,并没有添加调色板;该程序未实现添加了调色板。

2.灰度处理源码

        第一步:在前面的代码基础上继续,先在ImageProcessingView.h中添加成员变量m_bitmaplin和BmpNameLin,因为后面处理操作是处理备份文件与原图进行比较。
[cpp]  view plain  copy
  1. // Implementation  
  2. public:  
  3.     //添加成员函数  
  4.     void ShowBitmap(CDC* pDC,CString BmpName); //显示位图函数  
  5.     bool ReadBmp();                       //用来读取bmp个手机图片  
  6.     bool SaveBmp(LPCSTR lpFileName);           //用来保存bmp格式图片  
  7.   
  8.     //添加成员变量  
  9.     CString EntName;     //图像文件扩展名  
  10.     CString BmpName;     //图像文件名称  
  11.     CBitmap m_bitmap;    //创建位图对象  
  12.   
  13.     CBitmap m_bitmaplin;   //创建临时位图对象进行处理  
  14.     CString BmpNameLin;    //保存图像副本文件  
        第二步:在ImageProcessingView.cpp中ShowBitmap()函数前添加变量numPicture和level。
[cpp]  view plain  copy
  1. /*************************************************************/  
  2. /* numPicture变量显示图片数量 
  3. /* 0-提示错误或未打开图片 1-显示一张图片 2-显示两张图片和处理 
  4. /*************************************************************/  
  5. int numPicture = 0;  
  6.   
  7. /*************************************************************/  
  8. /* level变量显示具体的处理操作,每个处理函数中赋值该变量 
  9. /* 0-显示2张图片 1-显示灰度图片 3-显示图片采样 
  10. /* 2 4 8 16 32 64-不同量化等级量化图片 
  11. /*************************************************************/   
  12. int level = 0;      
  13.   
  14. //****************显示BMP格式图片****************//  
  15. void CImageProcessingView::ShowBitmap(CDC *pDC, CString BmpName)  
  16. {  
  17.     ....  
  18. }  
        第三步:修改ImageProcessingView.cpp中OnFileOpen()函数,添加临时变量名和显示一张图片标志变量。代码如下:
[cpp]  view plain  copy
  1. //****************打开文件****************//  
  2. void CImageProcessingView::OnFileOpen()   
  3. {  
  4.     CString filter;    
  5.     filter="所有文件(*.bmp,*.jpg,*.gif)|*.bmp;*.jpg| BMP(*.bmp)|*.bmp| JPG(*.jpg)|*.jpg||";    
  6.     CFileDialog dlg(TRUE,NULL,NULL,OFN_HIDEREADONLY,filter,NULL);               
  7.     if( dlg.DoModal() == IDOK )    
  8.     {    
  9.         BmpName = dlg.GetPathName();       
  10.         BmpNameLin = "picture.bmp";      //临时变量名  
  11.         numPicture=1;                    //显示一张图片  
  12.         EntName = dlg.GetFileExt();         
  13.         EntName.MakeLower();                
  14.         Invalidate();                       
  15.     }     
  16. }  
        第四步:将视图切换到ResourceView界面,选中Menu->在IDR_MAINFRAME中添加菜单”显示“,双击它在菜单属性中选择”弹出“。在”显示“的子菜单中添加:
        双图显示--ID_SHOW_TWO(ID)--默认属性
        灰度图片--ID_SHOW_HD(ID)--默认属性


        第五步:点击"查看"->"建立类向导"(Ctrl+W),选择CImageProcessing类,然后ID_SHOW_TWO,双击COMMAND(Message),生成默认成员函数。

        在XXXView.cpp中实现OnShowTwo()函数,代码如下:
[cpp]  view plain  copy
  1. //****************显示两张图片****************//  
  2. void CImageProcessingView::OnShowTwo()   
  3. {  
  4.     //如果没有导入图片直接点击双显 提示错误  
  5.     if(numPicture==0)  
  6.     {  
  7.         AfxMessageBox("载入图片后才能显示2张图片!");  
  8.         return;  
  9.     }  
  10.     AfxMessageBox("显示两张图片!",MB_OK,0);  
  11.     numPicture = 2;    //全局变量 显示两图  
  12.     level =0;          //level=0双显  
  13.     Invalidate();      //调用Invalidate 每秒调用一次OnDraw画图  
  14. }  
        第六步:同上面相同的方法,"查看"->”建立类向导“->ID_SHOW_HD(ID)->COMMAND(Message),默认成员函数名。在XXXView.cpp添加代码如下:
[cpp]  view plain  copy
  1. /********************************************************************************************/  
  2. /* 祥见http://blog.csdn.net/xiakq/article/details/2956902有详细的灰度算法                    
  3. /* 其中24位的图片灰度时,采用如下算法:                                                        
  4. /* 1.平均值算法 R=G=B=(R+G+B)/3                                                               
  5. /* 2.快速算法 R=G=B=(R+G+B+128)/4>>2                                                           
  6. /* 3.加权平均值算法 根据光的亮度特性,其实正确的灰度公式应当是R=G=B=R*0.299+G*0.587+B0.144    
  7. /*   为了提高速度我们做一个完全可以接受的近似,公式变形如下 R=G=B=(R*3+G*6+B)/10             
  8. /* 4.精确加权平均值算法 R=G=B=R*0.299+G*0.587+B0.144                                         
  9. /********************************************************************************************/  
  10.   
  11. //**灰度图像就是 R=G=B且为三者的1/3 level=1时灰度图像**//  
  12. void CImageProcessingView::OnShowHd()   
  13. {  
  14.     if(numPicture==0)  
  15.     {  
  16.         AfxMessageBox("载入图片后才能灰度图片!",MB_OK,0);  
  17.         return;  
  18.     }  
  19.     AfxMessageBox("灰度图像!",MB_OK,0);  
  20.     //打开临时的图片  
  21.     FILE *fpo = fopen(BmpName,"rb");  
  22.     FILE *fpw = fopen(BmpNameLin,"wb+");  
  23.     //读取文件  
  24.     fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  25.     fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  26.     fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  27.     fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  28.     //灰度图像  
  29.     unsigned char color;  
  30.     unsigned char red,green,blue;  
  31.   
  32.     /********************************************************************/  
  33.     /* 注意:原来下面所有操作都是for( i=0; i<m_nWidth*m_nHeight; i++ )   
  34.     /* 后发现如果图片最后一行没有完整的一行数据,会出现图像变多或变少    
  35.     /* 但图像的总像素为m_nImage,如果是m_nImage/3就可以保证所有像素都有  
  36.     /********************************************************************/  
  37.   
  38.     for(int i=0; i < m_nImage/3; i++ )  
  39.     {  
  40.         fread(&red,sizeof(char),1,fpo);  
  41.         fread(&green,sizeof(char),1,fpo);  
  42.         fread(&blue,sizeof(char),1,fpo);  
  43.   
  44.         color=(red+green+blue)/3;  
  45.         red=color;  
  46.         green=color;    
  47.         blue=color;  
  48.   
  49.         fwrite(&red,sizeof(char),1,fpw);  
  50.         fwrite(&green,sizeof(char),1,fpw);  
  51.         fwrite(&blue,sizeof(char),1,fpw);  
  52.     }  
  53.     fclose(fpo);  
  54.     fclose(fpw);  
  55.     numPicture = 2;  
  56.     level=1;  
  57.     Invalidate();  
  58. }  
        第七步:修改ShowBitmap()函数中双显部分,添加如下代码:
[cpp]  view plain  copy
  1. //****************显示BMP格式图片****************//  
  2. void CImageProcessingView::ShowBitmap(CDC *pDC, CString BmpName)  
  3. {  
  4.         ....  
  5.   
  6.     /** 
  7.      * 面代码为后面显示第二张图片 
  8.      */  
  9.   
  10.     if(numPicture==2) {  
  11.         //显示图片函数LoadImage  
  12.         HBITMAP m_hBitmapChange;  
  13.         if(level==0) //显示2张图 BmpNameLin原图  
  14.         {  
  15.             m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpName,IMAGE_BITMAP,0,0,  
  16.                 LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  17.         }  
  18.         else  
  19.         if(level==1) //灰度图片 BmpNameLin临时图片  
  20.         {  
  21.             m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,  
  22.                 LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  23.         }  
  24.         if( m_bitmap.m_hObject ) {  
  25.             m_bitmap.Detach();            //m_bitmap为创建的位图对象  
  26.         }  
  27.         m_bitmap.Attach(m_hBitmapChange);  
  28.         //定义并创建一个内存设备环境  
  29.         CDC dcBmp;  
  30.         if( !dcBmp.CreateCompatibleDC(pDC) )   //创建兼容性的DC  
  31.             return;  
  32.         BITMAP m_bmp;                          //临时bmp图片变量  
  33.         m_bitmap.GetBitmap(&m_bmp);            //将图片载入位图中  
  34.         CBitmap *pbmpOld = NULL;  
  35.         dcBmp.SelectObject(&m_bitmap);         //将位图选入临时内存设备环境  
  36.   
  37.         //如果图片太大显示大小为固定640*640 否则显示原图大小  
  38.         if(m_nDrawWidth<650 && m_nDrawHeight<650)  
  39.             pDC->StretchBlt(m_nWindowWidth-m_nDrawWidth,0,  
  40.                 m_nDrawWidth,m_nDrawHeight,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY);  
  41.         else  
  42.             pDC->StretchBlt(m_nWindowWidth-640,0,640,640,&dcBmp,0,0,  
  43.                 m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY);   
  44.         //恢复临时DC的位图  
  45.         dcBmp.SelectObject(pbmpOld);             
  46.     }  
  47.   
  48. }  
        双显和灰度运行效果如下图所示:



四. 图片量化处理

(参考我的文库:http://wenku.baidu.com/view/80b18961f5335a8102d220a0

1.量化基本概念

        图像数字化包括量化和取样两个过程,其中:
        量化:幅值f(x,y)的离散化,f(x,y)表示静止灰度图像的空间坐标
        取样:对空间连续坐标(x,y)的离散化

        
一幅行数为M、列数为N图像大小为M×N的矩阵形式为:(其中矩阵中每个元素代表一个像素)

        该工程所有的处理都基于24位的bmp格式图片的处理,24为表示biBitCount=24,1个像素占3个字节(red、green、blue)。

        如图量化级不同产生的灰度也不同,量化是使连续信号的幅度用有限级的数码表示的过程。
        量化等级=2:使用2种灰度级(0~255)表示图片,小于128的取0,大于等于128的取128。把位图数据块所有数据在临时图片中取值,在显示即可。
        量化等级=4:使用4种灰度级显示图片,就会发现图片分层为4种颜色。同时,0-64区间取0,64-128区间取64,128-192区间取128,192-255区间取192。
        量化的取值各不相同,我采用的是最简单的取值。其它方法可自己去查阅资料。





2.量化处理源码

        第一步:设置菜单栏。将试图切换到ResourceView界面--选中Menu--IDR_MAINFRAME中添加菜单“量化”--双击它在菜单属性中选择“弹出”。在“显示”的子菜单中添加:属性为默认属性。
        量化 Level 2--ID_LH_2       量化 Level 4--ID_LH_4
        量化 Level 8--ID_LH_8       量化 Level 16--ID_LH_16
        量化 Level 32--ID_LH_32   量化 Level 64--ID_LH_64


        第二步:建立类向导。查看->建立类导向(Ctrl+W)->CXXXView(类名)->ID_LH_2->COMMAND(Messages)->默认成员函数名。 相同方法分别为量化等级2、4、8、16、32、64建立类导向。

        第三步:在ImageProcessingView.cpp中编辑灰度函数。代码如下:
        核心流程是打开两张图片原图(BmpName)和临时图片(BmpNameLin),然后读取原图信息头赋值给临时处理图片,在读取原图m_nImage整个像素矩阵,量化处理每个像素(即分等级量化),最后文件写量化后的像素矩阵给BmpNameLin,在赋值全局变量level\numPicture和调用Invalidate()重绘图像即可。
[cpp]  view plain  copy
  1. //****************量化 量化等级为2****************//  
  2. void CImageProcessingView::OnLh2()   
  3. {  
  4.     if(numPicture==0) {  
  5.         AfxMessageBox("载入图片后才能量化!",MB_OK,0);  
  6.         return;  
  7.     }  
  8.     AfxMessageBox("量化等级Level=2!",MB_OK,0);  
  9.     //打开临时的图片  
  10.     FILE *fpo = fopen(BmpName,"rb");  
  11.     FILE *fpw = fopen(BmpNameLin,"wb+");  
  12.     //读取文件  
  13.     fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  14.     fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  15.     fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  16.     fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  17.     //malloc只能申请4字节的空间  
  18.     m_pImage=(BYTE*)malloc(m_nImage);  
  19.     fread(m_pImage,m_nImage,1,fpo);  
  20.     //等级2量化  
  21.     for(int i=0; i<m_nImage; i++ ) {  
  22.         //24位的为调色板为真彩图 Red Green Blue 为3字节   
  23.         //量化等级为2取中间值为 64 和 192  
  24.         if(m_pImage[i]<128) {   
  25.             m_pImage[i]=0;  
  26.         }  
  27.         else if(m_pImage[i]>=128) {  
  28.             m_pImage[i]=128;  
  29.         }  
  30.     }  
  31.     fwrite(m_pImage,m_nImage,1,fpw);  
  32.     fclose(fpo);  
  33.     fclose(fpw);  
  34.     numPicture = 2;  
  35.     level=2;  
  36.     Invalidate();  
  37. }  
  38.   
  39. //****************量化 量化等级为4****************//  
  40. void CImageProcessingView::OnLh4()   
  41. {  
  42.     if(numPicture==0) {  
  43.         AfxMessageBox("载入图片后才能量化!",MB_OK,0);  
  44.         return;  
  45.     }  
  46.     AfxMessageBox("量化等级Level=4!",MB_OK,0);  
  47.     //打开临时的图片  
  48.     FILE *fpo = fopen(BmpName,"rb");  
  49.     FILE *fpw = fopen(BmpNameLin,"wb+");  
  50.     fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  51.     fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  52.     fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  53.     fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  54.     m_pImage=(BYTE*)malloc(m_nImage);  
  55.     fread(m_pImage,m_nImage,1,fpo);  
  56.     //等级4量化  
  57.     for(int i=0; i<m_nImage; i++ ) {  
  58.         if(m_pImage[i]<64) {  
  59.             m_pImage[i]=0;  
  60.         }  
  61.         else if( (m_pImage[i]>=64) && (m_pImage[i]<128) ) {  
  62.             m_pImage[i]=64;  
  63.         }  
  64.         else if( (m_pImage[i]>=128) && (m_pImage[i]<192) ) {  
  65.             m_pImage[i]=128;  
  66.         }  
  67.         else if(m_pImage[i]>=192) {  
  68.             m_pImage[i]=192;  
  69.         }  
  70.     }  
  71.     fwrite(m_pImage,m_nImage,1,fpw);  
  72.     fclose(fpo);  
  73.     fclose(fpw);  
  74.     numPicture = 2;  
  75.     level=4;  
  76.     Invalidate();  
  77. }  
  78.   
  79. //****************量化 量化等级为8****************//  
  80. void CImageProcessingView::OnLh8()   
  81. {  
  82.     if(numPicture==0) {  
  83.         AfxMessageBox("载入图片后才能量化!",MB_OK,0);  
  84.         return;  
  85.     }  
  86.     AfxMessageBox("量化等级Level=8!",MB_OK,0);  
  87.     //打开临时的图片 读取文件  
  88.     FILE *fpo = fopen(BmpName,"rb");  
  89.     FILE *fpw = fopen(BmpNameLin,"wb+");  
  90.     fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  91.     fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  92.     fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  93.     fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  94.     //malloc只能申请4字节的空间 (未知)  
  95.     m_pImage=(BYTE*)malloc(m_nImage);  
  96.     fread(m_pImage,m_nImage,1,fpo);  
  97.     //等级8量化  
  98.     for(int i=0; i<m_nImage; i++ ) {  
  99.         if(m_pImage[i]<32) {  
  100.             m_pImage[i]=0;  
  101.         }  
  102.         else if( (m_pImage[i]>=32) && (m_pImage[i]<64) ) {  
  103.             m_pImage[i]=32;  
  104.         }  
  105.         else if( (m_pImage[i]>=64) && (m_pImage[i]<96) ) {  
  106.             m_pImage[i]=64;  
  107.         }  
  108.         else if( (m_pImage[i]>=96) && (m_pImage[i]<128) ) {  
  109.             m_pImage[i]=96;  
  110.         }  
  111.         else if( (m_pImage[i]>=128) && (m_pImage[i]<160) ) {  
  112.             m_pImage[i]=128;  
  113.         }  
  114.         else if( (m_pImage[i]>=160) && (m_pImage[i]<192) ) {  
  115.             m_pImage[i]=160;  
  116.         }  
  117.         else if( (m_pImage[i]>=192) && (m_pImage[i]<224) ) {  
  118.             m_pImage[i]=192;  
  119.         }  
  120.         else if(m_pImage[i]>=224) {  
  121.             m_pImage[i]=224;  
  122.         }  
  123.     }  
  124.     fwrite(m_pImage,m_nImage,1,fpw);  
  125.     fclose(fpo);  
  126.     fclose(fpw);  
  127.     numPicture = 2;  
  128.     level=8;  
  129.     Invalidate();  
  130. }  
  131.   
  132. //****************量化 量化等级为16****************//  
  133. void CImageProcessingView::OnLh16()   
  134. {  
  135.     if(numPicture==0) {  
  136.         AfxMessageBox("载入图片后才能量化!",MB_OK,0);  
  137.         return;  
  138.     }  
  139.     AfxMessageBox("量化等级Level=16!",MB_OK,0);  
  140.     int i,j;  
  141.     //打开临时的图片  
  142.     FILE *fpo = fopen(BmpName,"rb");  
  143.     FILE *fpw = fopen(BmpNameLin,"wb+");  
  144.     fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  145.     fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  146.     fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  147.     fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  148.     m_pImage=(BYTE*)malloc(m_nImage);  
  149.     fread(m_pImage,m_nImage,1,fpo);  
  150.     for( i=0; i<m_nImage; i++ ) {  
  151.         j=16;  
  152.         while(j<=256)  
  153.         {  
  154.             if(m_pImage[i]<j)   
  155.             {  
  156.                 if(m_pImage[i]<16)   
  157.                     m_pImage[i]=0;  
  158.                 else   
  159.                     m_pImage[i]=j-16;  
  160.                 break;  
  161.             }  
  162.             else j+=16;  
  163.         }  
  164.     }  
  165.     fwrite(m_pImage,m_nImage,1,fpw);  
  166.     fclose(fpo);  
  167.     fclose(fpw);  
  168.     numPicture = 2;  
  169.     level=16;  
  170.     Invalidate();  
  171. }  
  172.   
  173. //****************量化 量化等级为32****************//  
  174. void CImageProcessingView::OnLh32()   
  175. {  
  176.     if(numPicture==0) {  
  177.         AfxMessageBox("载入图片后才能量化!",MB_OK,0);  
  178.         return;  
  179.     }  
  180.     AfxMessageBox("量化等级Level=32!",MB_OK,0);  
  181.     int i,j;  
  182.     //打开临时的图片  
  183.     FILE *fpo = fopen(BmpName,"rb");  
  184.     FILE *fpw = fopen(BmpNameLin,"wb+");  
  185.     //读取文件  
  186.     fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  187.     fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  188.     fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  189.     fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  190.     m_pImage=(BYTE*)malloc(m_nImage);  
  191.     fread(m_pImage,m_nImage,1,fpo);  
  192.     //等级32化  
  193.     for( i=0; i<m_nImage; i++ )  
  194.     {  
  195.         j=8;  
  196.         while(j<=256)  
  197.         {  
  198.             if(m_pImage[i]<j)   
  199.             {  
  200.                 if(m_pImage[i]<8)   
  201.                     m_pImage[i]=0;  
  202.                 else   
  203.                     m_pImage[i]=j-8;  
  204.                 break;  
  205.             }  
  206.             else j+=8;  
  207.         }  
  208.     }  
  209.     fwrite(m_pImage,m_nImage,1,fpw);  
  210.     fclose(fpo);  
  211.     fclose(fpw);  
  212.     numPicture = 2;  
  213.     level=32;  
  214.     Invalidate();  
  215. }  
  216.   
  217. //****************量化 量化等级为64****************//  
  218. void CImageProcessingView::OnLh64()   
  219. {  
  220.     if(numPicture==0) {  
  221.         AfxMessageBox("载入图片后才能量化!",MB_OK,0);  
  222.         return;  
  223.     }  
  224.     AfxMessageBox("量化等级Level=64!",MB_OK,0);  
  225.     int i,j;  
  226.     //打开临时的图片  
  227.     FILE *fpo = fopen(BmpName,"rb");  
  228.     FILE *fpw = fopen(BmpNameLin,"wb+");  
  229.     //读取文件  
  230.     fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  231.     fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  232.     fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  233.     fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  234.     m_pImage=(BYTE*)malloc(m_nImage);  
  235.     fread(m_pImage,m_nImage,1,fpo);  
  236.     //等级64量化  
  237.     for( i=0; i<m_nImage; i++ )  
  238.     {  
  239.         j=4;  
  240.         while(j<=256)  
  241.         {  
  242.             if(m_pImage[i]<j)   
  243.             {  
  244.                 if(m_pImage[i]<16)   
  245.                     m_pImage[i]=0;  
  246.                 else   
  247.                     m_pImage[i]=j-4;  
  248.                 break;  
  249.             }  
  250.             else j+=4;  
  251.         }  
  252.     }  
  253.     fwrite(m_pImage,m_nImage,1,fpw);  
  254.     fclose(fpo);  
  255.     fclose(fpw);  
  256.     numPicture = 2;  
  257.     level=64;  
  258.     Invalidate();  
  259. }  
        第四步:修改ShowBitmap()函数,显示量化处理。添加如下代码:
[cpp]  view plain  copy
  1. if(level==0) //显示2张图 BmpNameLin原图  
  2. {  
  3.     m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpName,IMAGE_BITMAP,0,0,  
  4.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  5. }  
  6. else  
  7. if(level==1) //灰度图片 BmpNameLin临时图片  
  8. {  
  9.     m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,  
  10.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  11. }  
  12. else         //量化2  
  13. if(level==2)  
  14. {  
  15.     m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,  
  16.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  17. }  
  18. else         //量化4  
  19. if(level==4)    
  20. {  
  21.     m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,  
  22.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  23. }  
  24. else         //量化8  
  25. if(level==8)  
  26. {  
  27.     m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,  
  28.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  29. }  
  30. else         //量化16  
  31. if(level==16)  
  32. {  
  33.     m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,  
  34.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  35. }  
  36. else         //量化32  
  37. if(level==32)  
  38. {  
  39.     m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,  
  40.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  41. }  
  42. else         //量化64  
  43. if(level==64)  
  44. {  
  45.     m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,  
  46.         LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);  
  47. }  
        运行效果如下图,当量化Level=2时很明显的两种灰度颜色,Level=4有4种颜色。


五. 图像采样功能

(参考我的文库:http://wenku.baidu.com/view/b3ef4e1f964bcf84b9d57baf)

1.图像采样概念

        该工程所有的处理都基于24位的bmp格式图片的处理,24为表示biBitCount=24,1个像素占3个字节(red、green、blue)。如图一张512*512的原图,保持灰度级256不变后的各种采样。输入采样坐标:如16*16,它的含义是原图512*512像素,现在组成一个新的图片为16*16像素,(512/16=32,512/16=32)则每32*32组成一个新的区域。共有这种区域16*16个,采样的方法有2种:
        a.把这个32*32区域全部赋值成左上角那个像素,这样图片的大小不变,困难在于赋值要4层循环。(项目中采用的就是这种方法)
        b.把这个32*32区域的左上角取出来,组成一个新的图片,共有16*16个像素,这张图片的大小要变小,只有16*16个像素。但难点在于同时要把bmp文件头中的图片大小、信息头中的长宽像素改变、偏移量等信息更新。


        又如下图所示:
        原图8*8的矩阵要处理成3*3的矩阵,则循环先处理第一二行,①②④⑤为3*3处理,去左上角的RGB,③⑥为2*3的处理;重点是原图读取一维数组需要转成二维数组赋值处理;最后再处理最后一行数据。采样中公式为:
        //获取填充颜色 相当于一次读取一个像素的RGB值再乘3跳3个字节
        red=m_pImage[(X+Y*m_nWidth)*3];
        green=m_pImage[(X+Y*m_nWidth)*3+1];
        blue=m_pImage[(X+Y*m_nWidth)*3+2];
        //填出图像循环 小区域中的长宽循环
        //(X+Y*m_nWidth)*3跳到该小区域 再赋值3*3小区域的RGB 同一区域RGB相同
        m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=red; m++;
        m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=green; m++;
        m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=blue; m++;


        PS:难点是还未处理剩余部分的采样。

2.图像采样代码

        第一步:设置菜单栏
        a.将视图切换到ResourceView界面--选中Menu--IDR_MAINFRAME中添加菜单“采样”--双击它在菜单属性中选择“弹出
        b.在“采样”的子菜单中添加:属性为默认属性。ID_CY--图片采样。
        c.建立类导向:查看--建立类导向(Ctrl+W)--CImageProcessingView(类名)--ID_CY--COMMAND(Messages)--默认成员函数名。生成void CImageProcessingView::OnCy()采样函数。
        第二步:设置采样对话框
        a.将试图切换到ResourceView界面--选中Dialog,右键鼠标新建一个Dialog,并新建一个名为IDD_DIALOG_CY。编辑框(X)IDC_EDIT_CYX 和 (Y)IDC_EDIT_CYY,确定为默认按钮。设置成下图对话框:

        b.在对话框资源模板空白区域双击鼠标—Create a new class创建一个新类--命名为CImageCYDlg。会自动生成它的.h和.cpp文件。类向导Ctrl W--类名:CImageCYDlg--CImageCYDlg(IDs)—WM_INITDLAOG建立这个函数可以用于初始化。

 
        c.打开类向导Ctrl+W--选择MemberVariables页面, 类名:CImageCYDlg--Add Variables--设置成:
                IDC_EDIT_CYX--int--m_xPlace
                IDC_EDIT_CYY--int--m_yPlace
        d.在View.cpp中添加采样的头文件#include "ImageCYDlg.h"

        第三步:在ImageProcessingView.cpp中添加代码

[cpp]  view plain  copy
  1. //****************图片采样****************//  
  2. void CImageProcessingView::OnCy()   
  3. {  
  4.     if(numPicture==0) {  
  5.         AfxMessageBox("载入图片后才能采样!",MB_OK,0);  
  6.         return;  
  7.     }  
  8.     CImageCYDlg dlg;     //定义采样对话框  
  9.     //显示对话框  
  10.     if( dlg.DoModal()==IDOK ) {  
  11.         //采样坐标最初为图片的自身像素  
  12.         if( dlg.m_xPlace==0 || dlg.m_yPlace==0 ) {  
  13.             AfxMessageBox("输入图片像素不能为0!",MB_OK,0);  
  14.             return;  
  15.         }  
  16.         if( dlg.m_xPlace>m_nWidth || dlg.m_yPlace>m_nHeight ) {  
  17.             AfxMessageBox("图片像素不能为超过原图长宽!",MB_OK,0);  
  18.             return;  
  19.         }  
  20.         AfxMessageBox("图片采样!",MB_OK,0);  
  21.         //打开临时的图片 读取文件  
  22.         FILE *fpo = fopen(BmpName,"rb");  
  23.         FILE *fpw = fopen(BmpNameLin,"wb+");  
  24.         fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);  
  25.         fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);  
  26.         fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);  
  27.         fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);  
  28.         fread(m_pImage,m_nImage,1,fpo);  
  29.       
  30.         /*图片采样*/  
  31.         int numWidth,numHeight;     //图片此区间取相同的像素点  
  32.         int numSYWidth,numSYHeight; //剩余期间区域   
  33.   
  34.         /*********************************************************/  
  35.         /* 表示numWidth*numHeight为一个区域 该区域颜色相同        
  36.         /* 如 512/512=1 512/512=1 1*1为一个区域                   
  37.         /* dlg.m_xPlace*dlg.m_yPlace 表示新的(x,y)坐标          
  38.         /* numSYWidth表示剩余空间 该区域统一为一个颜色            
  39.         /*********************************************************/  
  40.   
  41.         numWidth=m_nWidth/dlg.m_xPlace;          
  42.         numHeight=m_nHeight/dlg.m_yPlace;        
  43.         numSYWidth=m_nWidth%dlg.m_xPlace;       
  44.         numSYHeight=m_nHeight%dlg.m_yPlace;     
  45.         int Y,X;  
  46.         int i,j,m,n;  
  47.         unsigned char red,green,blue;  //存储三种颜色  
  48.       
  49.         /* 有((m_xPlace * m_yPlace)+ 剩余区域 )个小区域 */  
  50.         for( i=0; i<dlg.m_yPlace; i++ )       //高度  
  51.         {  
  52.             Y=numHeight*i;                    //获取Y坐标  
  53.             for( j=0; j<dlg.m_yPlace; j++ )   //宽度  
  54.             {  
  55.                 X=numWidth*j;                 //获取X坐标  
  56.                 /*获取填充颜色*/  
  57.                 red=m_pImage[(X+Y*m_nWidth)*3];  
  58.                 green=m_pImage[(X+Y*m_nWidth)*3+1];  
  59.                 blue=m_pImage[(X+Y*m_nWidth)*3+2];  
  60.                 /*填出图像循环 小区域中的长宽循环*/  
  61.                 for( n=0; n<numHeight; n++ )  
  62.                 {  
  63.                     for( m=0; m<numWidth*3; )  
  64.                     {  
  65.                         m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=red;  
  66.                         m++;  
  67.                         m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=green;  
  68.                         m++;  
  69.                         m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=blue;  
  70.                         m++;  
  71.                     }  
  72.                 }  
  73.             }  
  74.         }  
  75.         fwrite(m_pImage,m_nImage,1,fpw);  
  76.         fclose(fpo);  
  77.         fclose(fpw);  
  78.         numPicture = 2;  
  79.         level=3;  
  80.         Invalidate();  
  81.     }  
  82. }  
        第四步:修改ShowBitmap(CDC* pDC,CString BmpName)中的代码:
        else if(level==3) //图片采样
        {
          m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,
                 LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
        }
        运行效果如下图所示,其中彩色图片应该先灰度处理再进行其他操作。








        总结:后悔当初还没有写博客,通过回忆几年前的代码,很多当时的体会和思想都已不复存在了!可能你在百度文库中看到类似的文章,因为那些都是我在2012年上传的,最初是通过它进行分享编程知识的,后来发现了更好的CSDN而取代之。这篇文章感觉太详细,有时候一直怀疑是不是失去了算法的本质,不应该写这么详细的文章,而更加精简一点,但可能和从小记笔记有关,很难改过来了,慢慢改吧!
        最后还是希望文章对你有所帮助,如果文章有不足或错误之处,请海涵~
      (By:Eastmount 2015-5-28 下午点   http://blog.csdn.net/eastmount/
        

猜你喜欢

转载自blog.csdn.net/hjxu2016/article/details/80385236
今日推荐