MFC实现图像灰度、采样和量化功能详解

本文主要讲述基于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成员变量和成员函数。添加代码如下:

 
  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图片,其中代码及详细注释如下:

 
  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函数实现打开图片,代码如下:

 
  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()函数显示图片。代码如下:

 
  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中直接复制。

 
  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函数。

 
  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()函数代码如下:

 
  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(成员函数)中双击该函数进入函数并编辑。添加如下代码:

 
  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获取一些重要参数。


 

 

三. 图像灰度处理


(参考我的百度文库:http://wenku.baidu.com/view/3b869230f111f18583d05a43)
 

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,因为后面处理操作是处理备份文件与原图进行比较。

 
  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。

 
  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()函数,添加临时变量名和显示一张图片标志变量。代码如下:

 
  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()函数,代码如下:

 
  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添加代码如下:

 
  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()函数中双显部分,添加如下代码:

 
  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()重绘图像即可。

 
  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()函数,显示量化处理。添加如下代码:

 
  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中添加代码

 
  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);

        }
        运行效果如下图所示,其中彩色图片应该先灰度处理再进行其他操作。





 

     

//

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/492337.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

97页PPT,读懂自动驾驶全产业链发展!

来源&#xff1a;兴业证券近年来&#xff0c;汽车电子正在朝着电动化、网联化、智能化、共享化方向发展&#xff0c;尤其是大幅精进的自动驾驶技术备受关注。本文汇总了自动驾驶相机、雷达、高精地图等产业链情况&#xff0c;从中可以看出汽车无人驾驶行业蓝图。如今&#xff0…

MFC对话框绘制灰度直方图

本文主要讲述基于VC6.0 MFC图像处理的应用知识&#xff0c;主要结合自己大三所学课程《数字图像处理》及课件进行回忆讲解&#xff0c;主要通过MFC单文档视图实现点击弹出对话框绘制BMP图片的灰度直方图&#xff0c;再获取平均灰度、中指灰度和标准差等值。文章比较详细基础&am…

一张图看懂华为2018年年报

来源&#xff1a;华为摘要&#xff1a;3 月 29 日&#xff0c;华为发布了 2018 年年度报告。报告显示&#xff0c;华为在 2018 的营收为 7212.02 亿元&#xff08;约合 1051.91亿美元&#xff09;&#xff0c;同比增长 19.5%&#xff0c;净利润 593 亿元人民币&#xff0c;同比…

MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理

本文主要讲述基于VC6.0 MFC图像处理的应用知识&#xff0c;主要结合自己大三所学课程《数字图像处理》及课件进行讲解&#xff0c;主要通过MFC单文档视图实现显示BMP图片点运算处理&#xff0c;包括图像灰度线性变换、灰度非线性变换、图像阈值化处理、图像均衡化处理等知识&am…

马化腾:5G和AI双核驱动产业互联网进入“快车道”

来源&#xff1a;腾讯科技腾讯科技讯 3月30至31日&#xff0c;2019中国&#xff08;深圳&#xff09;IT领袖峰会以“IT新未来&#xff1a;5G与人工智能”为主题&#xff0c;汇聚了众多科技领袖和各界精英&#xff0c;聚焦未来通信、工业互联网、数字城市、金融科技等热门话题。…

MFC空间几何变换之图像平移、镜像、旋转、缩放

本文主要讲述基于VC6.0 MFC图像处理的应用知识&#xff0c;主要结合自己大三所学课程《数字图像处理》及课件进行讲解&#xff0c;主要通过MFC单文档视图实现显示BMP图片空间几何变换&#xff0c;包括图像平移、图形旋转、图像反转倒置镜像和图像缩放的知识。同时文章比较详细基…

超级干货:一文看懂5G产业链及投资机会

来源&#xff1a;新材料在线摘要&#xff1a;本文将讲述5G行业概况、产业链结构、上游关键原材料、本行业竞争格局及材料重点应用领域。报告合集涵盖5G关键材料、5G天线、氮化镓半导体、导热材料、电磁屏蔽材料、高频覆铜板基材、微波介质陶瓷、先进封装、手机外壳等九大市场研…

MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化

本文主要讲述基于VC6.0 MFC图像处理的应用知识&#xff0c;主要结合自己大三所学课程《数字图像处理》及课件进行讲解&#xff0c;主要通过MFC单文档视图实现显示BMP图像增强处理&#xff0c;包括图像普通平滑、高斯平滑、不同算子的图像锐化知识。希望该篇文章对你有所帮助&am…

南京大学教授施斌及其团队—— 光纤变“神经” 大地能感知

来源&#xff1a;人民日报你能相信吗&#xff1f;一根头发丝粗细的光纤&#xff0c;根据不同地质环境和多场监测要求&#xff0c;穿上各种“定制”的外衣&#xff0c;就能变身敏感强健的“大地感知神经”&#xff0c;使得大地一有灾害异动&#xff0c;远在千里之外的监测系统就…

MFC详解显示BMP格式图片

本文主要是讲述《数字图像处理》系列栏目中的第一篇文章.主要详细介绍了BMP图片格式,同时使用C和MFC显示BMP格式,主要结合自己的《数字图像处理》课程和以前的项目叙述讲解. 一.BMP图片格式定义 BMP文件格式是Windows操作系统推荐和支持的标准图像文件格式,是一种将内存或显示…

0pencv——图像腐蚀

1、代码如下&#xff1a; #include "stdafx.h" #include <opencv2/opencv.hpp>using namespace cv;int main() {Mat srcImage imread("小狗1.jpg");imshow("显示图像", srcImage);Mat element getStructuringElement(MORPH_RECT, Size(…

腾讯研究院发布:《人工智能+制造产业发展研究》报告

来源&#xff1a;腾讯研究院摘要&#xff1a;工业革命以后的“自动化”概念追求的是机器自动生产&#xff0c;本质是“机器替人”&#xff0c;强调在完全不需要人的情况下进行不间断的大规模机器生产&#xff1b;而“智能化”追求的是机器的柔性生产&#xff0c;本质是“人机协…

Opencv——图像模糊

1、代码如下&#xff1a; #include "stdafx.h" #include <opencv2/opencv.hpp>using namespace cv;int main() {Mat srcImage imread("小狗1.jpg");imshow("原图像", srcImage);Mat dstImage;blur(srcImage, dstImage, Size(5, 5));imsh…

Android开发中依赖注入的应用

什么是依赖注入&#xff1f; 依赖是指一个对象持有其他对象的引用。依赖注入则是将这些依赖对象传递给被依赖对象&#xff0c;而不是被依赖对象自己创建这些对象。 public class MyClass{private AnotherClass mAnotherObject;public MyClass(){mAnotherObject new AnotherCla…

工业富联2018年报来了!上市后首张成绩单大起底

未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。未来智能实验室的主要工作包括&#xff1a;建立AI智能系统智商评测体系&#xff0c;开展世界人工智能智商评测&#xff1b;开展互联网&#xff08;城市&#xff09;云…

Opencv——图像膨胀

1、代码如下&#xff1a; #include "stdafx.h" #include <opencv2/opencv.hpp>using namespace cv;int main() {Mat srcImage imread("小狗1.jpg");imshow("原图像", srcImage);Mat dstImage;Mat element getStructuringElement(MORPH_…

深度学习背后的基础-神经网络揭秘

来源&#xff1a;混沌巡洋舰摘要&#xff1a;最近&#xff0c; 深度学习三杰获得了计算机界最重要的图灵奖&#xff0c; 它们的贡献都集中在对深度学习的根据神经网络的理论突破。 今天我们看到的所有和人工智能有关的伟大成就&#xff0c; 从阿法狗到自动驾驶&#xff0c; 从海…

Opencv——灰度变换、直方图均衡化

1、代码如下&#xff1a; #include "stdafx.h" #include <opencv2/opencv.hpp>using namespace cv;int main() {Mat srcImage imread("lena.bmp");Mat grayImage;cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);Mat dstImage;equalizeHist(grayIm…

并发模型之——共享内存模型(线程与锁)理论篇

这里我们使用Java的线程与锁来解析共享内存模型&#xff1b;做过java开发并且了解线程安全问题的知道&#xff0c;要使某段代码是线程安全的那必须要满足两个条件&#xff1a;内存可见性、原子性&#xff1b; 内存可见性 在JVM规定多个线程进行通讯是通过共享变量进行的&a…

谷歌员工怒了 900人联名抗议 刚成立的AI道德委员会处境尴尬

来源&#xff1a;网易智能谷歌员工又怒了。3月26日&#xff0c;谷歌宣布成立人工智能项目外部顾问委员会&#xff0c;该委员会将与谷歌就面部识别和公平性等人工智能的主要问题进行磋商。争议的焦点在于&#xff0c;谷歌将保守派传统基金会(Heritage Foundation)主席凯科尔斯詹…