第四章 图像的灰度变换

VC++图像处理程序设计(第1版)    杨淑莹 编著     边奠英 主审
第四章 图像的灰度变换
Joanna-In-Hdu&Hust 手工打,印象更深刻
使用工具 VS2010 mfc
整本书的代码文件、测试图片和程序运行exe请在这里下载https://github.com/CaptainLYN/VCPictureProcessing

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 #include<WindowsX.h>
  5 #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<height;j++)
 16         for(int i=0;i<width;i++)
 17         {
 18             t=p_data+j*linebytes+i;//书上的写的比较辣鸡
 19             if(*t>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<height;j++)
 35         for(int i=0;i<width;i++)
 36         {
 37             p=p_data+j*linebytes+i;
 38             if(*p<YuZhi)
 39                 *p=0;
 40             else
 41                 *p=255;
 42         }
 43 }
 44 void HuiDuDib::ShuangYu(int low,int high,int mode)
 45 {
 46     LPBYTE p_data=dib->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<height;j++)
 55         for(int i=0;i<width;i++)
 56         {
 57             t=p_data+j*linebytes+i;
 58             if(*t<=low||*t>=high)
 59                 *t=0;
 60             else
 61                 *t=255;
 62         }
 63         break;
 64         case 1://255-0-255
 65     for(int j=0;j<height;j++)
 66         for(int i=0;i<width;i++)
 67         {
 68             t=p_data+j*linebytes+i;
 69             if(*t<=low||*t>=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<height;j++)
 86         for(int i=0;i<width;i++)
 87         {
 88             t=p_data+linebytes*j+i;
 89             *t=255-*t;
 90         }
 91 }
 92 void HuiDuDib::ChuangKou(BYTE low,BYTE high)
 93 {
 94     LPBYTE p_data=dib->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<height;j++)
100         for(int i=0;i<width;i++)
101         {
102             t=p_data+j*linebytes+i;
103             if(*t<low)
104                 *t=0;
105             else if(*t>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<height;j++)
117         for(int i=0;i<width;i++)
118         {
119             t=p_data+linebytes*j+i;
120             if(*t>0&&*t<=X1)
121             {
122                 *t=*t*(Y1/X1);
123             }
124             else if(*t<X1&&*t<X2)
125             {
126                 *t=Y1+(Y2-Y1)/(X2-X1)*(*t-X1);
127             }
128             else if(X2!=255)
129             {
130                 *t=Y2+(255-Y2)/(255-X2)*(*t-X2);
131             }
132         }
133 }
134 float* HuiDuDib::ZhiFangTu(bool moshi)
135 {
136     float *tongji=new float[256];//要记得销毁
137     
138     memset(tongji,0,sizeof(float)*256);
139     BYTE* p_data=dib->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<height;j++)
146     {
147         for(i=0;i<width;i++)
148         {
149             temp=p_data+j*linebytes+i;
150             tongji[*temp]++;
151         }
152     }
153     if(moshi==true)
154     {
155     for(i=0;i<256;i++)
156         tongji[i]=tongji[i]/(height*width);
157     }
158     return tongji;
159 }
160 void HuiDuDib::FenBuJunHengHua()
161 {
162     int i,j;
163     //灰度分布密度
164     float *fPs_R;
165     //中间变量
166     float temp_r[256];//就是S[]累计函数
167     int nNs_R[256];//就是L[],r对应的新像素值
168     //初始化
169     memset(temp_r,0,sizeof(temp_r));
170     LPBYTE p_data=dib->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         else
178             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<height;j++)
187         for(i=0;i<width;i++)
188         {
189             temp=*((unsigned char*)p_data+linebytes*j+i);//8位数据
190             *((unsigned char*)p_data+linebytes*j+i)=nNs_R[temp];
191         }
192     delete []fPs_R;
193 }
194 void HuiDuDib::PiPeiBianHuan(BYTE jishu,int* huidu,float *shuju)
195 {
196     long i,j;
197     int daiti[256];//记录每个像素被代替为哪一个像素
198     float *gailv;//灰度分布概率
199     float temp[256];
200     LPBYTE p_data=dib->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         else
210             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         else
219             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<jishu;j++)
230         {
231             //当前差值
232             float now_value=0;
233             //计算差值
234             if(gailv[i]-shuju[j]>=0)
235                 now_value=gailv[i]-shuju[j];
236             else
237                 now_value=shuju[j]-gailv[i];
238             //寻找最接近的规定直方图灰度级
239             if(now_value<min_value_r)
240             {
241                 m_r=j;
242                 min_value_r=now_value;
243             }
244         }
245         //建立灰度映射表,即用规定直方图的哪一个值代替当前灰度值
246         daiti[i]=huidu[m_r];
247     }
248     //对各像素进行处理
249     int linebytes=dib->GetDibWidthBytes();
250     unsigned char t;
251     for(j=0;j<height;j++)
252     {
253         for(i=0;i<width;i++)
254         {
255             t=*((unsigned char*)p_data+linebytes*j+i);
256             *((unsigned char*)p_data+linebytes*j+i)=daiti[t];
257         }
258     }
259 }
260 int HuiDuDib::PingJunHuiDu()
261 {
262     float* data=ZhiFangTu(true);
263     float shu=0;
264     for(int i=0;i<256;i++)
265         shu+=data[i]*i;
266     return (int)(shu+0.5);
267 }

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 constructor
12     virtual ~ZhiFangDlg();
13     void OnPaint();
14     void SetData(float* data);
15 
16 // Dialog Data
17     enum { IDD = 139 };//这里总是出问题,所以直接写成数字了
18 
19 protected:
20     virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
21     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<data[i])
 94             max=data[i];
 95     }
 96     //y轴坐标系数的数据步长
 97     //float Tstep=max/10;
 98     //y轴坐标系数的刻度步长
 99     float Ystep=174/20;
100     //显示y坐标的刻度和数据
101     i=20;
102     dc->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、运行:

结束~

 

posted @ 2017-11-19 21:29  Joanna-In-Hdu&Hust  阅读(1529)  评论(0编辑  收藏  举报