转自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 plaincopy
  1. // Implementation
  2. public:
  3. //添加成员函数
  4. void ShowBitmap(CDC* pDC,CString BmpName); //显示位图函数
  5. //添加成员变量
  6. CString EntName;     //图像文件扩展名
  7. CString BmpName;     //图像文件名称
  8. CBitmap m_bitmap;    //创建位图对象

同时采用类视图添加后,会自动在XXXView.h中添加函数定义,在XXXView.cpp中添加函数实现代码。

        第三步:编辑ImageProcessingView.cpp中ShowBitmap()函数。通过它显示BMP图片,其中代码及详细注释如下:
[cpp] view plaincopy
  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. /* 1.要装载OEM图像,则设此参数值为0  OBM_ OEM位图 OIC_OEM图标 OCR_OEM光标
  10. /* 2.BmpName要装载图片的文件名
  11. /* 3.装载图像类型:
  12. /*   IMAGE_BITMAP-装载位图 IMAGE_CURSOR-装载光标 IMAGE_ICON-装载图标
  13. /* 4.指定图标或光标的像素宽度和长度 以像素为单位
  14. /* 5.加载选项:
  15. /*   IR_LOADFROMFILE-指明由lpszName指定文件中加载图像
  16. /*   IR_DEFAULTSIZE-指明使用图像默认大小
  17. /*   LR_CREATEDIBSECTION-当uType参数为IMAGE_BITMAP时,创建一个DIB项
  18. /**************************************************************************/
  19. if( m_bitmap.m_hObject )
  20. {
  21. m_bitmap.Detach();           //切断CWnd和窗口联系
  22. }
  23. m_bitmap.Attach(m_hBitmap);      //将句柄HBITMAP m_hBitmap与CBitmap m_bitmap关联
  24. //边界
  25. CRect rect;
  26. GetClientRect(&rect);
  27. //图片显示(x,y)起始坐标
  28. int m_showX=0;
  29. int m_showY=0;
  30. int m_nWindowWidth = rect.right - rect.left;   //计算客户区宽度
  31. int m_nWindowHeight = rect.bottom - rect.top;  //计算客户区高度
  32. //定义并创建一个内存设备环境DC
  33. CDC dcBmp;
  34. if( !dcBmp.CreateCompatibleDC(pDC) )   //创建兼容性的DC
  35. return;
  36. BITMAP m_bmp;                          //临时bmp图片变量
  37. m_bitmap.GetBitmap(&m_bmp);            //将图片载入位图中
  38. CBitmap *pbmpOld = NULL;
  39. dcBmp.SelectObject(&m_bitmap);         //将位图选入临时内存设备环境
  40. //图片显示调用函数stretchBlt
  41. pDC->StretchBlt(0,0,m_bmp.bmWidth,m_bmp.bmHeight,&dcBmp,0,0,
  42. m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY);
  43. /*******************************************************************************/
  44. /* BOOL StretchBlt(int x,int y,int nWidth,int nHeight,CDC* pSrcDC,
  45. /*                 int xSrc,int ySrc,int nSrcWidth,int nSrcHeight,DWORD dwRop );
  46. /* 1.参数x、y位图目标矩形左上角x、y的坐标值
  47. /* 2.nWidth、nHeigth位图目标矩形的逻辑宽度和高度
  48. /* 3.pSrcDC表示源设备CDC指针
  49. /* 4.xSrc、ySrc表示位图源矩形的左上角的x、y逻辑坐标值
  50. /* 5.dwRop表示显示位图的光栅操作方式 SRCCOPY用于直接将位图复制到目标环境中
  51. /*******************************************************************************/
  52. dcBmp.SelectObject(pbmpOld);           //恢复临时DC的位图
  53. DeleteObject(&m_bitmap);               //删除内存中的位图
  54. dcBmp.DeleteDC();                      //删除CreateCompatibleDC得到的图片DC
  55. /**
  56. * 面代码为后面显示第二张图片
  57. */
  58. }

第四步:设置打开BMP图片函数。"查看"->"建立类向导"(Ctrl+W)->选择"类名"CImageProcessing->在命令对象ID中双击"ID_FILE_OPEN"->自动生成默认成员函数OnFileOpen,消息为COMMAND。双击成员函数(Member Functions)进入函数编辑。

编辑ImageProcessingView.cpp函数实现打开图片,代码如下:

[cpp] view plaincopy
  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. //按下确定按钮 dlg.DoModal() 函数显示对话框
  9. if( dlg.DoModal() == IDOK )
  10. {
  11. BmpName = dlg.GetPathName();     //获取文件路径名   如D:\pic\abc.bmp
  12. EntName = dlg.GetFileExt();      //获取文件扩展名
  13. EntName.MakeLower();             //将文件扩展名转换为一个小写字符
  14. Invalidate();                    //调用该函数就会调用OnDraw重绘画图
  15. }
  16. }

第五步:在ImageProcessingView.cpp中找到OnDraw()函数,通过OnDraw()函数调用ShowBitmap()函数显示图片。代码如下:

[cpp] view plaincopy
  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 plaincopy
  1. // Implementation
  2. public:
  3. //添加成员函数
  4. void ShowBitmap(CDC* pDC,CString BmpName); //显示位图函数
  5. bool ReadBmp();                            //用来读取bmp个手机图片
  6. bool SaveBmp(LPCSTR lpFileName);           //用来保存bmp格式图片
  7. //添加成员变量
  8. CString EntName;     //图像文件扩展名
  9. CString BmpName;     //图像文件名称
  10. CBitmap m_bitmap;    //创建位图对象
  11. int m_nWidth;       //图像实际宽度
  12. int m_nHeight;      //图像实际高度
  13. int m_nDrawWidth;   //图像显示宽度
  14. int m_nDrawHeight;  //图像显示高度
  15. DWORD m_nImage;     //图像数据的字节数 只含位图
  16. DWORD m_nSize;      //图像文件大小
  17. int m_nLineByte;    //图像一行所占字节数
  18. int m_nBitCount;    //图像每个像素所占位数
  19. int m_nPalette;     //位图实际使用的颜色表中的颜色数
  20. BYTE *m_pImage;         //读入图片数据后的指针
  21. BITMAPFILEHEADER bfh;   //全局变量文件头
  22. BITMAPINFOHEADER bih;   //全局变量信息头
  23. RGBQUAD m_pPal;         //颜色表指针

第二步:在ImageProcessingView.cpp中实现ReadBmp函数和SaveBmp函数。

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

[cpp] view plaincopy
  1. // Implementation
  2. public:
  3. //添加成员函数
  4. void ShowBitmap(CDC* pDC,CString BmpName); //显示位图函数
  5. bool ReadBmp();                       //用来读取bmp个手机图片
  6. bool SaveBmp(LPCSTR lpFileName);           //用来保存bmp格式图片
  7. //添加成员变量
  8. CString EntName;     //图像文件扩展名
  9. CString BmpName;     //图像文件名称
  10. CBitmap m_bitmap;    //创建位图对象
  11. CBitmap m_bitmaplin;   //创建临时位图对象进行处理
  12. CString BmpNameLin;    //保存图像副本文件

第二步:在ImageProcessingView.cpp中ShowBitmap()函数前添加变量numPicture和level。

[cpp] view plaincopy
  1. /*************************************************************/
  2. /* numPicture变量显示图片数量
  3. /* 0-提示错误或未打开图片 1-显示一张图片 2-显示两张图片和处理
  4. /*************************************************************/
  5. int numPicture = 0;
  6. /*************************************************************/
  7. /* level变量显示具体的处理操作,每个处理函数中赋值该变量
  8. /* 0-显示2张图片 1-显示灰度图片 3-显示图片采样
  9. /* 2 4 8 16 32 64-不同量化等级量化图片
  10. /*************************************************************/
  11. int level = 0;
  12. //****************显示BMP格式图片****************//
  13. void CImageProcessingView::ShowBitmap(CDC *pDC, CString BmpName)
  14. {
  15. ....
  16. }

第三步:修改ImageProcessingView.cpp中OnFileOpen()函数,添加临时变量名和显示一张图片标志变量。代码如下:

[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  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. //**灰度图像就是 R=G=B且为三者的1/3 level=1时灰度图像**//
  11. void CImageProcessingView::OnShowHd()
  12. {
  13. if(numPicture==0)
  14. {
  15. AfxMessageBox("载入图片后才能灰度图片!",MB_OK,0);
  16. return;
  17. }
  18. AfxMessageBox("灰度图像!",MB_OK,0);
  19. //打开临时的图片
  20. FILE *fpo = fopen(BmpName,"rb");
  21. FILE *fpw = fopen(BmpNameLin,"wb+");
  22. //读取文件
  23. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
  24. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
  25. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
  26. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
  27. //灰度图像
  28. unsigned char color;
  29. unsigned char red,green,blue;
  30. /********************************************************************/
  31. /* 注意:原来下面所有操作都是for( i=0; i<m_nWidth*m_nHeight; i++ )
  32. /* 后发现如果图片最后一行没有完整的一行数据,会出现图像变多或变少
  33. /* 但图像的总像素为m_nImage,如果是m_nImage/3就可以保证所有像素都有
  34. /********************************************************************/
  35. for(int i=0; i < m_nImage/3; i++ )
  36. {
  37. fread(&red,sizeof(char),1,fpo);
  38. fread(&green,sizeof(char),1,fpo);
  39. fread(&blue,sizeof(char),1,fpo);
  40. color=(red+green+blue)/3;
  41. red=color;
  42. green=color;
  43. blue=color;
  44. fwrite(&red,sizeof(char),1,fpw);
  45. fwrite(&green,sizeof(char),1,fpw);
  46. fwrite(&blue,sizeof(char),1,fpw);
  47. }
  48. fclose(fpo);
  49. fclose(fpw);
  50. numPicture = 2;
  51. level=1;
  52. Invalidate();
  53. }

第七步:修改ShowBitmap()函数中双显部分,添加如下代码:

[cpp] view plaincopy
  1. //****************显示BMP格式图片****************//
  2. void CImageProcessingView::ShowBitmap(CDC *pDC, CString BmpName)
  3. {
  4. ....
  5. /**
  6. * 面代码为后面显示第二张图片
  7. */
  8. if(numPicture==2) {
  9. //显示图片函数LoadImage
  10. HBITMAP m_hBitmapChange;
  11. if(level==0) //显示2张图 BmpNameLin原图
  12. {
  13. m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpName,IMAGE_BITMAP,0,0,
  14. LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
  15. }
  16. else
  17. if(level==1) //灰度图片 BmpNameLin临时图片
  18. {
  19. m_hBitmapChange = (HBITMAP) LoadImage(NULL,BmpNameLin,IMAGE_BITMAP,0,0,
  20. LR_LOADFROMFILE|LR_DEFAULTSIZE|LR_CREATEDIBSECTION);
  21. }
  22. if( m_bitmap.m_hObject ) {
  23. m_bitmap.Detach();            //m_bitmap为创建的位图对象
  24. }
  25. m_bitmap.Attach(m_hBitmapChange);
  26. //定义并创建一个内存设备环境
  27. CDC dcBmp;
  28. if( !dcBmp.CreateCompatibleDC(pDC) )   //创建兼容性的DC
  29. return;
  30. BITMAP m_bmp;                          //临时bmp图片变量
  31. m_bitmap.GetBitmap(&m_bmp);            //将图片载入位图中
  32. CBitmap *pbmpOld = NULL;
  33. dcBmp.SelectObject(&m_bitmap);         //将位图选入临时内存设备环境
  34. //如果图片太大显示大小为固定640*640 否则显示原图大小
  35. if(m_nDrawWidth<650 && m_nDrawHeight<650)
  36. pDC->StretchBlt(m_nWindowWidth-m_nDrawWidth,0,
  37. m_nDrawWidth,m_nDrawHeight,&dcBmp,0,0,m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY);
  38. else
  39. pDC->StretchBlt(m_nWindowWidth-640,0,640,640,&dcBmp,0,0,
  40. m_bmp.bmWidth,m_bmp.bmHeight,SRCCOPY);
  41. //恢复临时DC的位图
  42. dcBmp.SelectObject(pbmpOld);
  43. }
  44. }

双显和灰度运行效果如下图所示:

四. 图片量化处理

(参考我的文库: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 plaincopy
  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. //****************量化 量化等级为4****************//
  39. void CImageProcessingView::OnLh4()
  40. {
  41. if(numPicture==0) {
  42. AfxMessageBox("载入图片后才能量化!",MB_OK,0);
  43. return;
  44. }
  45. AfxMessageBox("量化等级Level=4!",MB_OK,0);
  46. //打开临时的图片
  47. FILE *fpo = fopen(BmpName,"rb");
  48. FILE *fpw = fopen(BmpNameLin,"wb+");
  49. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
  50. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
  51. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
  52. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
  53. m_pImage=(BYTE*)malloc(m_nImage);
  54. fread(m_pImage,m_nImage,1,fpo);
  55. //等级4量化
  56. for(int i=0; i<m_nImage; i++ ) {
  57. if(m_pImage[i]<64) {
  58. m_pImage[i]=0;
  59. }
  60. else if( (m_pImage[i]>=64) && (m_pImage[i]<128) ) {
  61. m_pImage[i]=64;
  62. }
  63. else if( (m_pImage[i]>=128) && (m_pImage[i]<192) ) {
  64. m_pImage[i]=128;
  65. }
  66. else if(m_pImage[i]>=192) {
  67. m_pImage[i]=192;
  68. }
  69. }
  70. fwrite(m_pImage,m_nImage,1,fpw);
  71. fclose(fpo);
  72. fclose(fpw);
  73. numPicture = 2;
  74. level=4;
  75. Invalidate();
  76. }
  77. //****************量化 量化等级为8****************//
  78. void CImageProcessingView::OnLh8()
  79. {
  80. if(numPicture==0) {
  81. AfxMessageBox("载入图片后才能量化!",MB_OK,0);
  82. return;
  83. }
  84. AfxMessageBox("量化等级Level=8!",MB_OK,0);
  85. //打开临时的图片 读取文件
  86. FILE *fpo = fopen(BmpName,"rb");
  87. FILE *fpw = fopen(BmpNameLin,"wb+");
  88. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
  89. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
  90. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
  91. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
  92. //malloc只能申请4字节的空间 (未知)
  93. m_pImage=(BYTE*)malloc(m_nImage);
  94. fread(m_pImage,m_nImage,1,fpo);
  95. //等级8量化
  96. for(int i=0; i<m_nImage; i++ ) {
  97. if(m_pImage[i]<32) {
  98. m_pImage[i]=0;
  99. }
  100. else if( (m_pImage[i]>=32) && (m_pImage[i]<64) ) {
  101. m_pImage[i]=32;
  102. }
  103. else if( (m_pImage[i]>=64) && (m_pImage[i]<96) ) {
  104. m_pImage[i]=64;
  105. }
  106. else if( (m_pImage[i]>=96) && (m_pImage[i]<128) ) {
  107. m_pImage[i]=96;
  108. }
  109. else if( (m_pImage[i]>=128) && (m_pImage[i]<160) ) {
  110. m_pImage[i]=128;
  111. }
  112. else if( (m_pImage[i]>=160) && (m_pImage[i]<192) ) {
  113. m_pImage[i]=160;
  114. }
  115. else if( (m_pImage[i]>=192) && (m_pImage[i]<224) ) {
  116. m_pImage[i]=192;
  117. }
  118. else if(m_pImage[i]>=224) {
  119. m_pImage[i]=224;
  120. }
  121. }
  122. fwrite(m_pImage,m_nImage,1,fpw);
  123. fclose(fpo);
  124. fclose(fpw);
  125. numPicture = 2;
  126. level=8;
  127. Invalidate();
  128. }
  129. //****************量化 量化等级为16****************//
  130. void CImageProcessingView::OnLh16()
  131. {
  132. if(numPicture==0) {
  133. AfxMessageBox("载入图片后才能量化!",MB_OK,0);
  134. return;
  135. }
  136. AfxMessageBox("量化等级Level=16!",MB_OK,0);
  137. int i,j;
  138. //打开临时的图片
  139. FILE *fpo = fopen(BmpName,"rb");
  140. FILE *fpw = fopen(BmpNameLin,"wb+");
  141. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
  142. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
  143. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
  144. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
  145. m_pImage=(BYTE*)malloc(m_nImage);
  146. fread(m_pImage,m_nImage,1,fpo);
  147. for( i=0; i<m_nImage; i++ ) {
  148. j=16;
  149. while(j<=256)
  150. {
  151. if(m_pImage[i]<j)
  152. {
  153. if(m_pImage[i]<16)
  154. m_pImage[i]=0;
  155. else
  156. m_pImage[i]=j-16;
  157. break;
  158. }
  159. else j+=16;
  160. }
  161. }
  162. fwrite(m_pImage,m_nImage,1,fpw);
  163. fclose(fpo);
  164. fclose(fpw);
  165. numPicture = 2;
  166. level=16;
  167. Invalidate();
  168. }
  169. //****************量化 量化等级为32****************//
  170. void CImageProcessingView::OnLh32()
  171. {
  172. if(numPicture==0) {
  173. AfxMessageBox("载入图片后才能量化!",MB_OK,0);
  174. return;
  175. }
  176. AfxMessageBox("量化等级Level=32!",MB_OK,0);
  177. int i,j;
  178. //打开临时的图片
  179. FILE *fpo = fopen(BmpName,"rb");
  180. FILE *fpw = fopen(BmpNameLin,"wb+");
  181. //读取文件
  182. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
  183. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
  184. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
  185. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
  186. m_pImage=(BYTE*)malloc(m_nImage);
  187. fread(m_pImage,m_nImage,1,fpo);
  188. //等级32化
  189. for( i=0; i<m_nImage; i++ )
  190. {
  191. j=8;
  192. while(j<=256)
  193. {
  194. if(m_pImage[i]<j)
  195. {
  196. if(m_pImage[i]<8)
  197. m_pImage[i]=0;
  198. else
  199. m_pImage[i]=j-8;
  200. break;
  201. }
  202. else j+=8;
  203. }
  204. }
  205. fwrite(m_pImage,m_nImage,1,fpw);
  206. fclose(fpo);
  207. fclose(fpw);
  208. numPicture = 2;
  209. level=32;
  210. Invalidate();
  211. }
  212. //****************量化 量化等级为64****************//
  213. void CImageProcessingView::OnLh64()
  214. {
  215. if(numPicture==0) {
  216. AfxMessageBox("载入图片后才能量化!",MB_OK,0);
  217. return;
  218. }
  219. AfxMessageBox("量化等级Level=64!",MB_OK,0);
  220. int i,j;
  221. //打开临时的图片
  222. FILE *fpo = fopen(BmpName,"rb");
  223. FILE *fpw = fopen(BmpNameLin,"wb+");
  224. //读取文件
  225. fread(&bfh,sizeof(BITMAPFILEHEADER),1,fpo);
  226. fread(&bih,sizeof(BITMAPINFOHEADER),1,fpo);
  227. fwrite(&bfh,sizeof(BITMAPFILEHEADER),1,fpw);
  228. fwrite(&bih,sizeof(BITMAPINFOHEADER),1,fpw);
  229. m_pImage=(BYTE*)malloc(m_nImage);
  230. fread(m_pImage,m_nImage,1,fpo);
  231. //等级64量化
  232. for( i=0; i<m_nImage; i++ )
  233. {
  234. j=4;
  235. while(j<=256)
  236. {
  237. if(m_pImage[i]<j)
  238. {
  239. if(m_pImage[i]<16)
  240. m_pImage[i]=0;
  241. else
  242. m_pImage[i]=j-4;
  243. break;
  244. }
  245. else j+=4;
  246. }
  247. }
  248. fwrite(m_pImage,m_nImage,1,fpw);
  249. fclose(fpo);
  250. fclose(fpw);
  251. numPicture = 2;
  252. level=64;
  253. Invalidate();
  254. }

第四步:修改ShowBitmap()函数,显示量化处理。添加如下代码:

[cpp] view plaincopy
  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 plaincopy
  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. int numWidth,numHeight;     //图片此区间取相同的像素点
  31. int numSYWidth,numSYHeight; //剩余期间区域
  32. /*********************************************************/
  33. /* 表示numWidth*numHeight为一个区域 该区域颜色相同
  34. /* 如 512/512=1 512/512=1 1*1为一个区域
  35. /* dlg.m_xPlace*dlg.m_yPlace 表示新的(x,y)坐标
  36. /* numSYWidth表示剩余空间 该区域统一为一个颜色
  37. /*********************************************************/
  38. numWidth=m_nWidth/dlg.m_xPlace;
  39. numHeight=m_nHeight/dlg.m_yPlace;
  40. numSYWidth=m_nWidth%dlg.m_xPlace;
  41. numSYHeight=m_nHeight%dlg.m_yPlace;
  42. int Y,X;
  43. int i,j,m,n;
  44. unsigned char red,green,blue;  //存储三种颜色
  45. /* 有((m_xPlace * m_yPlace)+ 剩余区域 )个小区域 */
  46. for( i=0; i<dlg.m_yPlace; i++ )       //高度
  47. {
  48. Y=numHeight*i;                    //获取Y坐标
  49. for( j=0; j<dlg.m_yPlace; j++ )   //宽度
  50. {
  51. X=numWidth*j;                 //获取X坐标
  52. /*获取填充颜色*/
  53. red=m_pImage[(X+Y*m_nWidth)*3];
  54. green=m_pImage[(X+Y*m_nWidth)*3+1];
  55. blue=m_pImage[(X+Y*m_nWidth)*3+2];
  56. /*填出图像循环 小区域中的长宽循环*/
  57. for( n=0; n<numHeight; n++ )
  58. {
  59. for( m=0; m<numWidth*3; )
  60. {
  61. m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=red;
  62. m++;
  63. m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=green;
  64. m++;
  65. m_pImage[(X+Y*m_nWidth)*3+m+n*m_nWidth*3]=blue;
  66. m++;
  67. }
  68. }
  69. }
  70. }
  71. fwrite(m_pImage,m_nImage,1,fpw);
  72. fclose(fpo);
  73. fclose(fpw);
  74. numPicture = 2;
  75. level=3;
  76. Invalidate();
  77. }
  78. }
        第四步:修改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/)

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

  1. 数字图像处理二维码识别 python+opencv实现二维码实时识别

    数字图像处理二维码识别 python+opencv实现二维码实时识别 特点: (1)可以实现普通二维码,条形码: (2)解决了opencv输出中文乱码的问题 (3)增加网页自动跳转功能 (4)实现二维 ...

  2. 数字图像处理——二值、灰度和彩色图像,位图切割

    二值.灰度和彩色图像处理 1. 二值.灰度图像的转换 2. 彩色图像的表示 3. 位图切割 -------------------------- -------------------------- ...

  3. 数字图像处理(15): 灰度直方图(matplotlib 和OpenCV 绘制直方图)

    目录 1 灰度直方图简介 1.1 灰度直方图概念 1.2 灰度直方图作用 1.3 绘制的直方图 1.4 归一化直方图 2 matplotlib库 绘制直方图-hist() 3 OpenCV库 绘制直方 ...

  4. 灰度共生矩阵特征提取步骤_【数字图像处理】 灰度共生矩阵特征分析法

    灰度共生矩阵特征分析法 相邻某一间隔长度的两个像素,它们之间要么具有相同的灰度级,要么具有不同的灰度级,若能找出这样两个像素的联合分布的统计形式,对于图像的纹理分析很有意义. 灰度共生矩阵(GLDM) ...

  5. 数字图像处理之灰度化

    囧,ADK还要更新一大截.所以我还是接着写吧,接下来是数字图像的相关文章,全部使用Python实现. 首先讲的是灰度化. 开始,我们先讲讲什么是灰度. 大家都知道,一幅图片有很多个像素点,对于RGB图 ...

  6. Matlab数字图像处理 02 灰度变化(图像直方图、直方图均衡化、直方图匹配)

    第二章 灰度变化 2.1 图像的亮度.对比度和动态范围 2.1.1 亮度 2.1.2 对比度 2.1.3 动态范围 2.2 线性灰度变换 2.2.1 具有饱和处理的线性灰度变换 2.2.2 分段线性灰 ...

  7. java 灰度直方图_【数字图像处理】灰度直方图、直方图均衡化、直方图规定化...

    灰度直方图 一幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的一个重要特征.图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少. 图像的灰度直方图是灰 ...

  8. 【数字图像处理】灰度变换函数(对数变换、反对数变换、幂次变换)

    // 对比度增强.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h" #include <opencv2/opencv.hpp> #i ...

  9. 数字图像处理(二)——BMP图像的统计

      最近正在准备考研,其余的几篇文章及代码在考研结束之后再更新,敬请期待.关注一下不迷路

  10. 数字图像处理二:图像空域运算

    (1)选择两幅图像,一幅是物体图像,一幅是背景图像,采用正确的图像代数运算方法,分别实现图像叠加.混合图像的分离和图像的局部显示效果. 原理: 叠加:将两幅图像进行加法运算. 分离:将混合图像与背景图 ...

最新文章

  1. 正确设置语言,加速WP应用提交
  2. 2009年中国贫富标准线
  3. 【转】 LINQ TO SQL中的selectMany
  4. Apache防DDOS模块mod_evasive的安装配置和使用
  5. 下列哪个适合做链栈_很多朋友在问:多层实木生态板和颗粒板哪个更适合做衣柜呢?...
  6. 监督学习、半监督学习、无监督学习定义
  7. Win7性能信息和工具在哪打开
  8. 崇尚个人当前状态的社会
  9. eureka集群基于DNS配置方式
  10. redis 如何查看某个库的key_如何发现 Redis 热点 Key ,解决方案有哪些?
  11. 单线程多线程_理解线程,就会由单线程向多线程进军
  12. 微软Win11 商店各个应用可单独下载
  13. 2020软考论文想要拿高分,要避开这些坑!
  14. 直播平台怎么搭建直播特效,实现原理与难点是什么
  15. 想学python网课哪个好-推荐书单(网课)-人生/编程/Python/机器学习-191本
  16. vue实现文件下载功能
  17. OC 需求 检测手机是否安装某个App,app是否安装(删除)appmusic
  18. python 打开网页方法_python打开网页的方法
  19. 益阳安化高考2021成绩查询,2021年安化县高考状元名单资料,今年安化县高考状元多少分...
  20. 格调高又小众的EPUB 阅读器(转载)

热门文章

  1. 易语言封装调用乐玩多线程插件模块
  2. [linux]shell中单引号和双引号区别
  3. Excel编辑很慢,上下滚动很慢解决方法
  4. 用纯CSS画出蓝天白云(详细版)
  5. 剑网三账号无法连接服务器,剑网三百家争鸣无法获取服务器列表解决方法 登不上游戏怎么办...
  6. Scanner常用方法
  7. JavaWeb商城订单模型+分页模型(JavaWeb+jsp+Ajax)
  8. 【office考试】MS_office考试试题汇总
  9. 关于用DELPHI开发服务器软件中的一些经验
  10. Android包体积过大,真的会影响绩效