第四章 图像的灰度变换

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:灰度变换与空间滤波概念及常用灰度变换方法介绍

matlab 灰度变换函数

对视频剪辑应用灰度图像变换+Moviepy生成灰度视频处理遇到几个有意思的问题

图像的点运算----底层代码与Halcon库函数

OpenCV——图像灰度变换