VC++图像处理程序设计(第1版) 杨淑莹 编著 边奠英 主审
第四章 图像的灰度变换
Joanna-In-Hdu&Hust 手工打,印象更深刻
使用工具 VS2010 mfc
整本书的代码文件、测试图片和程序运行exe请在这里下载:
1、此章的灰度代码的头文件:HuiDuDib.h:
1 #pragma once 2 class HuiDuDib:public CObject 3 { 4 protected: 5 CDib* dib; 6 public: 7 void Fei0(); 8 void GetDib(CDib *d); 9 void GuDing(int YuZhi);10 void ShuangYu(int low,int high,int mode);11 void FanSe();12 void ChuangKou(BYTE low,BYTE high);13 void ZheXian(BYTE X1,BYTE y1,BYTE X2,BYTE Y2);//优点是根据用户需要,拉伸感兴趣的物体细节,相对抑制不感兴趣的灰度级14 float* ZhiFangTu(bool i);//相比原书,改变了接口,为true返回小数的,为false返回整数的15 void FenBuJunHengHua();//减少像素个数少的灰度级,展宽灰度级个数多的,从而达到清晰图像的目的16 void PiPeiBianHuan(BYTE jishu,int* huidu,float *shuju);//jishu表示要匹配的灰度图有多少级,huidu中依次记录了从小到大每一个灰度值,shuju记录了每一个灰度值的gailv;对原图和目标灰度直方图进行灰度直方图均衡化,然后对于原图的每一个灰度级找到在目标灰度图中的灰度概率最相近的灰度,进行单映射变换,然后对原图进行灰度替换17 int PingJunHuiDu();//返回图像的平均灰度18 };
2、HuiDuDib.cpp:
1 #include"stdafx.h" 2 #include"CViewImage.h" 3 #include"CDib.h" 4 #include5 #include"ZhiFangDlg.h" 6 #include"HuiDuDib.h" 7 8 void HuiDuDib::Fei0()//Luna的图片全是白色 9 { 10 LPBYTE p_data=dib->GetData(); 11 LPBYTE t; 12 int width=dib->GetWidth(); 13 int height=dib->GetHeight(); 14 int linebytes=dib->GetDibWidthBytes();//其实早已经写好了每行字节的获取方法,一直没用 15 for(int j=0;j 0) 20 *t=255; 21 } 22 } 23 void HuiDuDib::GetDib(CDib *d) 24 { 25 dib=d; 26 } 27 void HuiDuDib::GuDing(int YuZhi) 28 { 29 LPBYTE p_data,p; 30 p_data=dib->GetData(); 31 int width=dib->GetWidth(); 32 int height=dib->GetHeight(); 33 int linebytes=dib->GetDibWidthBytes(); 34 for(int j=0;j GetData(); 47 LPBYTE t; 48 int width=dib->GetWidth(); 49 int height=dib->GetHeight(); 50 int linebytes=dib->GetDibWidthBytes(); 51 switch(mode) 52 { 53 case 0://0-255-0 54 for(int j=0;j =high) 59 *t=0; 60 else 61 *t=255; 62 } 63 break; 64 case 1://255-0-255 65 for(int j=0;j =high) 70 *t=255; 71 else 72 *t=0; 73 } 74 break; 75 } 76 77 } 78 void HuiDuDib::FanSe() 79 { 80 LPBYTE p_data=dib->GetData(); 81 LPBYTE t; 82 int width=dib->GetWidth(); 83 int height=dib->GetHeight(); 84 int linebytes=dib->GetDibWidthBytes(); 85 for(int j=0;j GetData(); 95 LPBYTE t; 96 int width=dib->GetWidth(); 97 int height=dib->GetHeight(); 98 int linebytes=dib->GetDibWidthBytes(); 99 for(int j=0;j high)106 *t=255;107 }108 }109 void HuiDuDib::ZheXian(BYTE X1,BYTE Y1,BYTE X2,BYTE Y2)110 {111 LPBYTE p_data=dib->GetData();112 LPBYTE t;113 int width=dib->GetWidth();114 int height=dib->GetHeight();115 int linebytes=dib->GetDibWidthBytes();116 for(int j=0;j 0&&*t<=X1)121 {122 *t=*t*(Y1/X1);123 }124 else if(*t GetData();140 BYTE *temp;141 int width=dib->GetWidth();142 int height=dib->GetHeight();143 int linebytes=dib->GetDibWidthBytes();144 int i,j;145 for(j=0;j GetData();171 fPs_R=ZhiFangTu(true);//这里是跟书处理不一样的172 //进行均衡化处理173 for(i=0;i<256;i++)174 {175 if(i==0)176 temp_r[0]=fPs_R[0];177 else178 temp_r[i]=temp_r[i-1]+fPs_R[i];179 nNs_R[i]=(int)(255.0f*temp_r[i]+0.5f);//+0.5f为了减少精度的缺失,满足四舍五入180 }181 int width=dib->GetWidth();182 int height=dib->GetHeight();183 unsigned char temp;184 int linebytes=dib->GetDibWidthBytes();185 //对各像素进行灰度转换186 for(j=0;j GetData();201 long width=dib->GetWidth();202 long height=dib->GetHeight();203 gailv=ZhiFangTu(true);204 //计算原始累计直方图205 for(i=0;i<256;i++)206 {207 if(i==0)208 temp[0]=gailv[0];209 else210 temp[i]=temp[i-1]+gailv[i];211 gailv[i]=temp[i];212 }213 //计算规定的累积直方图214 for(i=0;i<256;i++)215 {216 if(i==0)217 temp[0]=shuju[0];218 else219 temp[i]=temp[i-1]+shuju[i];220 shuju[i]=temp[i];221 }222 for(i=0;i<256;i++)223 {224 //最接近的规定直方图灰度等级,用规定的直方图等级代替概率差不多的等级225 //让原来的直方图的形状大体接近规定的直方图226 int m_r=0;227 //最小差值228 float min_value_r=1;229 for(j=0;j =0)235 now_value=gailv[i]-shuju[j];236 else237 now_value=shuju[j]-gailv[i];238 //寻找最接近的规定直方图灰度级239 if(now_value GetDibWidthBytes();250 unsigned char t;251 for(j=0;j
3、其中用于显示直方图的文件:
头文件ZhiFangDlg.h:
1 #pragma once 2 3 4 // ZhiFangDlg dialog 5 6 class ZhiFangDlg : public CDialogEx 7 { 8 DECLARE_DYNAMIC(ZhiFangDlg) 9 10 public:11 ZhiFangDlg(CWnd* pParent = NULL); // standard constructor12 virtual ~ZhiFangDlg();13 void OnPaint();14 void SetData(float* data);15 16 // Dialog Data17 enum { IDD = 139 };//这里总是出问题,所以直接写成数字了18 19 protected:20 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support21 float *data;22 DECLARE_MESSAGE_MAP()23 public:24 afx_msg void OnBnClickedButton1();25 };
ZhiFangDlg.cpp:
1 // ZhiFangDlg.cpp : implementation file 2 // 3 4 #include "stdafx.h" 5 #include "MfcPictureProcessing.h" 6 #include "ZhiFangDlg.h" 7 #include "afxdialogex.h" 8 9 10 // ZhiFangDlg dialog 11 12 IMPLEMENT_DYNAMIC(ZhiFangDlg, CDialogEx) 13 14 ZhiFangDlg::ZhiFangDlg(CWnd* pParent /*=NULL*/) 15 : CDialogEx(ZhiFangDlg::IDD, pParent) 16 { 17 data=NULL; 18 } 19 20 ZhiFangDlg::~ZhiFangDlg() 21 { 22 } 23 24 void ZhiFangDlg::DoDataExchange(CDataExchange* pDX) 25 { 26 CDialogEx::DoDataExchange(pDX); 27 } 28 29 30 BEGIN_MESSAGE_MAP(ZhiFangDlg, CDialogEx) 31 ON_BN_CLICKED(IDC_BUTTON1, &ZhiFangDlg::OnBnClickedButton1) 32 END_MESSAGE_MAP() 33 34 35 // ZhiFangDlg message handlers 36 void ZhiFangDlg::SetData(float *d) 37 { 38 data=d; 39 } 40 void ZhiFangDlg::OnPaint() 41 { 42 // 43 //CPaintDC dc(this);//用这个画不出来 44 CDC *dc=GetDC(); 45 CPen* pPen=new CPen;//创建画笔 46 pPen->CreatePen(PS_SOLID,1,RGB(0,0,0));//创建一支黑笔 47 CGdiObject *pOldPen=dc->SelectObject(pPen);//选中新画笔,保存旧画笔 48 int i=0; 49 CString str; 50 CPoint OPos(14,188),NowPos;//绘制坐标系 51 //绘制X坐标轴 52 dc->MoveTo(OPos); 53 NowPos.x=284; 54 NowPos.y=188; 55 dc->LineTo(NowPos); 56 //绘制箭头 57 dc->LineTo(279,183); 58 dc->MoveTo(NowPos); 59 dc->LineTo(279,193); 60 //绘制x轴坐标系数 61 //下面单独挑出来是为了好看 62 i=0; 63 dc->MoveTo(OPos.x+i,OPos.y); 64 dc->LineTo(CPoint(OPos.x+i,OPos.y+5)); 65 str.Format(_T("%d"),i); 66 dc->TextOutW(OPos.x+i-5,OPos.y+7,str); 67 for(i=10;i<256;i+=10)//这里有修改 68 { 69 if(i%10==0)//绘制竖杠 70 { 71 dc->MoveTo(OPos.x+i,OPos.y); 72 dc->LineTo(CPoint(OPos.x+i,OPos.y+5)); 73 } 74 if(i%40==0)//绘制字 75 { 76 str.Format(_T("%d"),i); 77 dc->TextOutW(OPos.x+i-10,OPos.y+7,str); 78 } 79 } 80 //绘制y轴坐标系数 81 dc->MoveTo(OPos); 82 NowPos.x=OPos.x; 83 NowPos.y=4; 84 dc->LineTo(NowPos); 85 //绘制箭头 86 dc->LineTo(NowPos.x-5,NowPos.y+5);//画笔最后停在哪里,绘制的中心就在哪里 87 dc->MoveTo(NowPos); 88 dc->LineTo(NowPos.x+5,NowPos.y+5); 89 //寻找数组最大的数据 90 float max=0; 91 for(i=0;i<256;i++) 92 { 93 if(max MoveTo(OPos.x,OPos.y-Ystep*i);103 dc->LineTo(OPos.x+5,OPos.y-Ystep*i);104 str.Format(_T("%f"),max);//这里修改了105 dc->TextOutW(20,OPos.y-Ystep*i-20,str); 106 107 //绘制灰度直方图108 for(i=0;i<256;i++)109 {110 NowPos.x=OPos.x+i;111 NowPos.y=OPos.y;112 dc->MoveTo(NowPos);113 NowPos.y=187-20*Ystep*data[i]/max;//计算比例,用20*Ystep,不能用175,因为中间精度缺失了太多114 dc->LineTo(NowPos);115 }116 dc->SelectObject(pOldPen);117 118 delete pPen;119 //Invalidate();120 }121 122 void ZhiFangDlg::OnBnClickedButton1()123 {124 if(data!=NULL)125 OnPaint();126 }
4、用于调用上面文件的运行函数:
1 void CMfcPictureProcessingDlg::On32797()//灰度非零取一 2 { 3 if(filePath.Compare(_T(""))!=0) 4 { 5 CDib dib; 6 dib.LoadFile(filePath); 7 if(dib.m_valid) 8 { 9 HuiDuDib d; 10 d.GetDib(&dib); 11 d.Fei0(); 12 CViewImage i; 13 i.GetDib(&dib); 14 CDC *pDC=GetDC(); 15 i.OnDraw2(pDC,dib.GetWidth()+5,0); 16 } 17 } 18 else{ 19 MessageBox(_T("请先选择文件!"),_T("提示"),MB_OK); 20 } 21 } 22 23 24 void CMfcPictureProcessingDlg::On32798()//灰度固定阈值 25 { 26 if(filePath.Compare(_T(""))!=0) 27 { 28 CDib dib; 29 dib.LoadFile(filePath); 30 if(dib.m_valid) 31 { 32 HuiDuDib hui; 33 hui.GetDib(&dib); 34 GuDingDlg gd; 35 gd.DoModal(); 36 if(gd.ifok) 37 { 38 hui.GuDing(gd.GetYuZhi()); 39 CViewImage i; 40 i.GetDib(&dib); 41 CDC *pDC=GetDC(); 42 i.OnDraw2(pDC,dib.GetWidth()+5,0); 43 } 44 } 45 } 46 else{ 47 MessageBox(_T("请先选择文件!"),_T("提示"),MB_OK); 48 } 49 } 50 51 void CMfcPictureProcessingDlg::On32800()//灰度双阈值 52 { 53 if(filePath.Compare(_T(""))!=0) 54 { 55 CDib dib; 56 dib.LoadFile(filePath); 57 if(dib.m_valid) 58 { 59 HuiDuDib hd; 60 hd.GetDib(&dib); 61 ShuangYuZhiDlg s; 62 s.DoModal(); 63 if(s.ifok) 64 { 65 hd.ShuangYu(s.GetLow(),s.GetHigh(),s.GetMode()); 66 CViewImage imageview; 67 imageview.GetDib(&dib); 68 CDC *pDC=GetDC(); 69 imageview.OnDraw2(pDC,dib.GetWidth()+5,0); 70 } 71 } 72 } 73 else{ 74 MessageBox(_T("请先选择文件!"),_T("提示"),MB_OK); 75 } 76 } 77 78 79 void CMfcPictureProcessingDlg::On32801()//灰度反色变换 80 { 81 if(filePath.Compare(_T(""))!=0) 82 { 83 CDib dib; 84 dib.LoadFile(filePath); 85 if(dib.m_valid) 86 { 87 CDC *pDC=GetDC(); 88 HuiDuDib h; 89 h.GetDib(&dib); 90 h.FanSe(); 91 CViewImage imageview; 92 imageview.GetDib(&dib); 93 imageview.OnDraw2(pDC,dib.GetWidth()+5,0); 94 } 95 } 96 else{ 97 MessageBox(_T("请先选择文件!"),_T("提示"),MB_OK); 98 } 99 }100 101 102 void CMfcPictureProcessingDlg::On32802()//灰度窗口变换103 {104 if(filePath.Compare(_T(""))!=0)105 {106 CDib dib;107 dib.LoadFile(filePath);108 if(dib.m_valid)109 {110 ChuangkouDlg k;111 k.DoModal();112 if(k.ifok)113 {114 HuiDuDib h;115 h.GetDib(&dib);116 h.ChuangKou(k.GetLow(),k.GetHigh());117 CDC *pDC=GetDC();118 CViewImage imageview;119 imageview.GetDib(&dib);120 imageview.OnDraw2(pDC,dib.GetWidth()+5,0);121 }122 } 123 }124 else{125 MessageBox(_T("请先选择文件!"),_T("提示"),MB_OK);126 }127 }128 129 130 void CMfcPictureProcessingDlg::On32803()//折线变换131 {132 if(filePath.Compare(_T(""))!=0)133 {134 CDib dib;135 dib.LoadFile(filePath);136 if(dib.m_valid)137 {138 ZheXianDlg z;139 z.DoModal();140 if(z.ifok)141 {142 CDC *pDC=GetDC();143 HuiDuDib hdib;144 hdib.GetDib(&dib);145 hdib.ZheXian(z.GetX1(),z.GetY1(),z.GetX2(),z.GetY2());146 CViewImage imageview;147 imageview.GetDib(&dib);148 imageview.OnDraw2(pDC,dib.GetWidth()+5,0);149 }150 }151 }152 else{153 MessageBox(_T("请先选择文件!"),_T("提示"),MB_OK);154 }155 }156 157 158 void CMfcPictureProcessingDlg::On32804()//灰度直方图159 {160 if(filePath.Compare(_T(""))!=0)161 {162 CDib dib;163 dib.LoadFile(filePath);//这里为了练习效果,只显示原图的164 if(dib.m_valid)165 {166 HuiDuDib hdib;167 hdib.GetDib(&dib);168 float *p=hdib.ZhiFangTu(true);169 //开始画直方图170 ZhiFangDlg d;171 d.SetData(p);172 d.DoModal();173 delete []p;174 }175 }176 else{177 MessageBox(_T("请先选择文件!"),_T("提示"),MB_OK);178 }179 }180 181 182 void CMfcPictureProcessingDlg::On32805()//灰度分布均衡化183 {184 if(filePath.Compare(_T(""))!=0)185 {186 CDib dib;187 dib.LoadFile(filePath);188 if(dib.m_valid)189 {190 HuiDuDib hdib;191 hdib.GetDib(&dib);192 hdib.FenBuJunHengHua();193 CViewImage imageview;194 imageview.GetDib(&dib);195 CDC* pDC=GetDC();196 imageview.OnDraw2(pDC,dib.GetWidth()+5,0);197 float* p=hdib.ZhiFangTu(true);198 ZhiFangDlg d;199 d.SetData(p);200 d.DoModal();201 delete []p;202 }203 }204 else{205 MessageBox(_T("请先选择文件!"),_T("提示"),MB_OK);206 }207 }
5、运行:
结束~