第四章 圖像的灰度變換


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、運行:

結束~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM