第四章 图像的灰度变换
Posted 和优秀的人一起成长
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第四章 图像的灰度变换相关的知识,希望对你有一定的参考价值。
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以上是关于第四章 图像的灰度变换的主要内容,如果未能解决你的问题,请参考以下文章
《数字图像处理》第三章学习总结感悟1:灰度变换与空间滤波概念及常用灰度变换方法介绍