Visual C++實現數字圖像增強處理

發表于:2007-05-25來源:作者:點擊數: 標簽:增強C++數字visual圖像
前言 對于一個圖像處理系統來說,可以將流程分為三個階段,在獲取原始圖像后,首先是圖像預處理階段、第二是特征抽取階段、第三是識別分析階段。圖像預處理階段尤為重要,如果這階段處理不好,后面的工作根本無法展開。 在實際應用中,我們的系統獲取的原始


  前言

  對于一個圖像處理系統來說,可以將流程分為三個階段,在獲取原始圖像后,首先是圖像預處理階段、第二是特征抽取階段、第三是識別分析階段。圖像預處理階段尤為重要,如果這階段處理不好,后面的工作根本無法展開。
  
  在實際應用中,我們的系統獲取的原始圖像不是完美的,例如對于系統獲取的原始圖像,由于噪聲、光照等原因,圖像的質量不高,所以需要進行預處理,以有利于提取我們感興趣的信息。圖像的預處理包括圖像增強、平滑濾波、銳化等內容。圖像的預處理既可以在空間域實現,也可以在頻域內實現,我們主要介紹在空間域內對圖像進行點運算,它是一種既簡單又重要的圖像處理技術,它能讓用戶改變圖像上像素點的灰度值,這樣通過點運算處理將產生一幅新圖像。下面我們開始介紹與圖像點運算的相關知識。

  一、圖像的直方圖

  圖像直方圖是圖像處理中一種十分重要的圖像分析工具,它描述了一幅圖像的灰度級內容,任何一幅圖像的直方圖都包含了豐富的信息,它主要用在圖象分割,圖像灰度變換等處理過程中。從數學上來說圖像直方圖是圖像各灰度值統計特性與圖像灰度值的函數,它統計一幅圖像中各個灰度級出現的次數或概率;從圖形上來說,它是一個二維圖,橫坐標表示圖像中各個像素點的灰度級,縱坐標為各個灰度級上圖像各個像素點出現的次數或概率。如果不特別說明,本講座中的直方圖的縱坐標都對應著該灰度級在圖像中出現的概率。我們的例子是在一個對話框中顯示一個圖像的直方圖,為實現該目的,我們定義了一個名為"ZFT"的對話框類用來顯示圖像的直方圖,具體實現代碼和效果圖如下(關于代碼實現部分可以參考筆者2001年在天極網上發表的一篇VC實現數字圖像處理的文章):


//////////////////////////////////直方圖對話框構造函數;
ZFT::ZFT(CWnd* pParent /*=NULL*/)
: CDialog(ZFT::IDD, pParent)//ZFT為定義的用來顯示直方圖的對話框類;
{
 Width=Height=0;//對話框初始化階段設置圖像的寬和高為"0";
}
////////////////////////對話框重畫函數;
void ZFT::OnPaint()
{
 CRect rect;//矩形區域對象;
 CWnd *pWnd;//得到圖片框的窗口指針;
 pWnd=GetDlgItem(IDC_Graphic);//得到ZFT對話框內的"Frame"控件的指針;
 file://(IDC_Graphic為放置在對話框上的一個"Picture"控件,并講類型設置為"Frame")。
 pWnd->GetClientRect(&rect);//得到"Frame"控件窗口的"視"區域;
 int i;
 CPaintDC dc(pWnd);//得到"Frame"控件的設備上下文;
 file://畫直方圖的x、y軸;
 dc.MoveTo(0,rect.Height());
 dc.LineTo(rect.Width(),rect.Height());
 dc.MoveTo(0,rect.Height());
 dc.LineTo(0,0);
 file://畫直方圖,num[]是"ZFT"的內部數組變量,存放的是圖像各個灰度級出現的概率;該數組的各個分量在  顯示具體圖像的直方圖時設置;
 for(i=0;i<256;i++)//根據圖像上的各個灰度級出現的概率,在坐標上對應的畫出一根直線,從而各個表示各灰度級出現概率的直線構成了圖像的直方圖;
 {
  dc.MoveTo(i+1,rect.Height());
  dc.LineTo (i+1,(rect.Height()-rect.Height()*num[i]*30));
  file://此處num分量乘以"30"是為了放大個灰度級上對應的出現概率直線,增強顯示效果;
 }
}
////////////////////////////////////////////////////////
void ZFT::OnMouseMove(UINT nFlags, CPoint point)
{//OnMouseMove函數處理鼠標消息,顯示當前鼠標所在直方圖上的灰度值等信息;
 CWnd *pWnd,*pWndText;//定義兩個窗口對象;
 CPoint point1;//定義個一個點對象;
 point1=point;//存放當前鼠標的位置信息;
 CRect rect;//矩形對象;
 CString string ;//字符串對象;
 pWnd=GetDlgItem(IDC_Graphic);//得到顯示直方圖的框架窗口對象指針;
 pWndText=GetDlgItem(IDC_NUM);//得到指向文本框對象(IDC_NUM)窗口的指針;
 pWnd->GetWindowRect(&rect);//獲取pWnd窗口對象窗口區域位置;
 file://屏幕坐標轉換為客戶區坐標;
 ScreenToClient(&rect);
 file://判斷當前鼠標是否指在直方圖內;
 if(rect.PtInRect (point))
 {
  int x=point1.x-rect.left;
  file://當前鼠標位置減去區域的起始位置恰好為當前鼠標所指位置所表示的灰度級;
  string.Format("%d",x);
  file://顯示當前位置對應的圖像的灰度級;
  pWndText->SetWindowText((LPCTSTR)string);
 }
 CDialog::OnMouseMove(nFlags, point);
}
////////////////////////////////////////
void CDibView::OnImagehorgm()
file://在程序的"視"類對象內處理顯示圖像直方圖的函數;
{
 CDibDoc *pDoc=GetDocument();
 HDIB hdib;
 hdib=pDoc->GetHDIB();
 BITMAPINFOHEADER *lpDIBHdr;//位圖信息頭結構指針;
 BYTE *lpDIBBits;//指向位圖像素灰度值的指針;
 lpDIBHdr=( BITMAPINFOHEADER *)GlobalLock(hdib);//得到圖像的位圖頭信息
 lpDIBBits=(BYTE*)lpDIBHdr+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
 file://獲取圖像像素值
 ZFT dialog;//直方圖對話框模板對象;
 int i,j;
 int wImgWidth=lpDIBHdr->biWidth;
 int wImgHeight=lpDIBHdr->biHeight;
 file://a[]數組用來存放各個灰度級出現的概率;
 float a[256];
 for(i=0;i<256;i++)//初始化數組;
 {  
  a[i]=0;
 }
 file://統計各個灰度級出現的次數;
 for(i=0;i  {
  for(j=0;j   {
   a[*(lpDIBBits+WIDTHBYTES(wImgWidth*8)*i+j)]++;
  }
  file://統計各個灰度級出現的概率;
  for(i=0;i<256;i++)
  {
   a[i]=a[i]/(wImgHeight*wImgWidth);//得到每個灰度級的出現概率;
   memcpy(dialog.num,a,256*sizeof(float));
  }
 }
  dialog.DoModal();//顯示直方圖對話框;
 }
 return;
}


(a)LENA圖像

(b)直方圖
                     圖一

  上圖為LENA的原始圖像和其對應的直方圖,在(b)圖中的135表示當前鼠標在直方圖中所指的位置對應的灰度級為135。從該直方圖可以看出,LENA圖像的灰度主要分布在中高灰度級上,在低灰度級上圖像的像素數幾乎為零。



  二、圖像增強

  影響系統圖像清晰程度的因素很多,例如室外光照度不夠均勻就會造成圖像灰度過于集中;由CCD(攝像頭)獲得的圖像經過A/D(數/模轉換,該功能在圖像系統中由數字采集卡來實現)轉換、線路傳送都會產生噪聲污染等等。因此圖像質量不可避免的降低了,輕者表現為圖像不干凈,難于看清細節;重者表現為圖像模糊不清,連概貌也看不出來。因此,在對圖像進行分析之前,必須要對圖像質量進行改善,一般情況下改善的方法有兩類:圖像增強和圖像復原。圖像增強不考慮圖像質量下降的原因,只將圖像中感興趣的特征有選擇的突出,而衰減不需要的特征,它的目的主要是提高圖像的可懂度。圖像增強的方法分為空域法和頻域法兩類,空域法主要是對圖像中的各個像素點進行操作;而頻域法是在圖像的某個變換域內,對圖像進行操作,修改變換后的系數,例如付立葉變換、DCT變換等的系數,然后再進行反變換得到處理后的圖像。圖像復原技術與增強技術不同,它需要了解圖像質量下降的原因,首先要建立"降質模型",再利用該模型,恢復原始圖像。本期講座我們主要介紹各種增強技術在圖象處理系統中的實際應用。

  1.灰度變換

  簡單的說,灰度變換就是指對圖像上各個像素點的灰度值x按某個函數T()變換到y。例如為了提高圖像的清晰度,需要將圖像的灰度級整個范圍或其中某一段(A,B)擴展或壓縮到(A,B);需要顯示出圖像的細節部分等都要求采用灰度變換方法?;叶茸儞Q有時又被稱為圖像的對比度增強或對比度拉伸。假定輸入圖像中的一個像素的灰度級為Z,經過T(Z)函數變換后輸出圖像對應的灰度級為Z ,其中要求Z和Z 都要在圖像的灰度范圍之內。根據T()形式,可以將灰度變換分為線性變換和非線性變換。具體應用中采用何種T(),需要根據變換的要求而定。

  對于圖像的灰度變換,我們這里介紹一種稍微復雜一點的方法,既直方圖均衡化。直方圖均衡化是灰度變換的一個重要應用,廣泛應用在圖像增強處理中,它是以累計分布函數變換為基礎的直方圖修正法,可以產生一幅灰度級分布具有均勻概率密度的圖像,擴展了像素的取值動態范圍。若像素點的原灰度為R,變換后的灰度為S,需要注意的是R、S是歸一化后的灰度值,其灰度變換函數T()為:

S=T (R); k=0,1…, ;

  式中, 是第j級灰度值的概率, 是圖像中j級灰度的像素總數, 是圖像中灰度級的總數目, 是圖象中像素的總數。對變換后的S值取最靠近的一個灰度級的值,建立灰度級變換表,將原圖像變換為直方圖均衡的圖像。下面是實現圖像直方圖均衡化函數的源代碼和效果圖:

void CDibView::OnZftJh()
{
 CClientDC pDC(this);
 HDC hDC=pDC.GetSafeHdc();//獲取當前設備上下文的句柄;
 SetStretchBltMode(hDC,COLORONCOLOR);
 CDibDoc *pDoc=GetDocument();
 HDIB hdib;
 hdib=pDoc->GetHDIB();
 BITMAPINFOHEADER *lpDIBHdr;//位圖信息頭結構指針;
 BYTE *lpDIBBits;//指向位圖像素灰度值的指針;
 lpDIBHdr=( BITMAPINFOHEADER *)GlobalLock(hdib);//得到圖像的位圖頭信息
 lpDIBBits=(BYTE*)lpDIBHdr+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
 file://獲取圖像像素值
 float p[256],p1[256],num[256];
 int i,j,k;
 for(i=0;i<256;i++)//清空三個數組;
 { num[i]=0.0f;
  p[i]=0.0f;
  p1[i]=0.0f;
 }
 file://num[]存放圖象各個灰度級出現的次數;
 int Height=lpDIBHdr->biHeight;
 int Width=lpDIBHdr->biWidth;
 for(i=0;i   for(j=30;j   {
   num[*(lpDIBBits+WIDTHBYTES(Width*8)*i+j)]++;
  }
  file://p[]存放圖像各個灰度級的出現概率;
  for(i=0;i<256;i++)
  {
   p[i]=num[i]/(Width*Height);
  }
  file://p1[]存放各個灰度級之前的概率和,用于直方圖變換;
  for(i=0;i<256;i++)
  {
   for(k=0;k<=i;k++)
   p1[i]+=p[k];
  }
  file://直方圖變換;
  for(i=0;i   for(j=30;j   {   *(lpDIBBits+WIDTHBYTES(Width*8)*i+j)=(BYTE)(p1[*(lpDIBBits+WIDTHBYTES(Width*8)*i+j)]*255+0.5);
  }
  StretchDIBits (hDC,0,0,lpDIBHdr->biWidth,lpDIBHdr->biHeight,0,0,
         lpDIBHdr->biWidth,lpDIBHdr->biHeight,
         lpDIBBits,(LPBITMAPINFO)lpDIBHdr,
         DIB_RGB_COLORS,
         SRCCOPY);//顯示圖像;
}


(a)LENA原圖
  
(b)直方圖均衡化后的效果圖


(c)原始圖象的直方圖
 
(d)均衡化后的直方他圖

                      圖 二

  從上述效果圖可以看出,經過直方圖均衡化處理后,圖像變的清晰了,從直方圖來看,處理后的LENA的圖像直方圖分布更均勻了,在每個灰度級上圖像都有像素點。但是直方圖均衡化存在著兩個缺點:

  1)變換后圖像的灰度級減少,某些細節消失;

  2)某些圖像,如直方圖有高峰,經處理后對比度不自然的過分增強。

  為此M.Kamel和Lian Guan等人從圖像相鄰像素一般高度相關這一事實出發,將灰度概率分布和空間相關性聯系在一起,提出了用二維條件概率密度函數取代一維概率密度函數作為均衡化條件,很好的解決了這個問題,有興趣的朋友可以參閱一些圖像處理書籍和資料。


  2.圖像平滑

  圖像平滑主要是為了消除噪聲。噪聲并不限于人眼所能看的見的失真和變形,有些噪聲只有在進行圖像處理時才可以發現。圖像的常見噪聲主要有加性噪聲、乘性噪聲和量化噪聲等。圖像中的噪聲往往和信號交織在一起,尤其是乘性噪聲,如果平滑不當,就會使圖像本身的細節如邊界輪廓、線條等變的模糊不清,如何既平滑掉噪聲有盡量保持圖像細節,是圖像平滑主要研究的任務。

  一般來說,圖像的能量主要集中在其低頻部分,噪聲所在的頻段主要在高頻段,同時系統中所要提取的汽車邊緣信息也主要集中在其高頻部分,因此,如何去掉高頻干擾又同時保持邊緣信息,是我們研究的內容。為了去除噪聲,有必要對圖像進行平滑,可以采用低通濾波的方法去除高頻干擾。圖像平滑包括空域法和頻域法兩大類,在空域法中,圖像平滑的常用方法是采用均值濾波或中值濾波,對于均值濾波,它是用一個有奇數點的滑動窗口在圖像上滑動,將窗口中心點對應的圖像像素點的灰度值用窗口內的各個點的灰度值的平均值代替,如果滑動窗口規定了在取均值過程中窗口各個像素點所占的權重,也就是各個像素點的系數,這時候就稱為加權均值濾波;對于中值濾波,對應的像素點的灰度值用窗口內的中間值代替。實現均值或中值濾波時,為了簡便編程工作,可以定義一個n*n的模板數組。另外,讀者需要注意一點,在用窗口掃描圖像過程中,對于圖像的四個邊緣的像素點,可以不處理;也可以用灰度值為"0"的像素點擴展圖像的邊緣。下面給出了采用加權均值濾波的圖像平滑函數代碼和效果圖:

void CDibView::OnImagePh()
{
 CClientDC pDC(this);
 HDC hDC=pDC.GetSafeHdc();//獲取當前設備上下文的句柄;
 SetStretchBltMode(hDC,COLORONCOLOR);
 HANDLE data1handle;
 LPBITMAPINFOHEADER lpBi;
 CDibDoc *pDoc=GetDocument();
 HDIB hdib;
 unsigned char *hData;
 unsigned char *data;
 hdib=pDoc->GetHDIB();
 BeginWaitCursor();
 lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib);
 hData=(unsigned char*)FindDIBBits((LPSTR)lpBi);
 pDoc->SetModifiedFlag(TRUE);
 data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight);
 data=(unsigned char*)GlobalLock((HGLOBAL)data1handle);
 AfxGetApp()->BeginWaitCursor();
 int i,j,s,t,ms=1;
 int sum=0,sumw=0;
 int mask[3][3]={{1,1,1},{1,2,1},{1,1,1}};//定義的3x3加權平滑模板;
 for(i=0; ibiHeight; i++)
 for(j=0; jbiWidth; j++)
 {
  sumw=0; sum=0;
  for(s=(-ms); s<=ms; s++)
  for(t=(-ms); t<=ms; t++)     if(((i+s)>=0)&&((j+t)>=0)&&((i+s)biHeight)&&((j+t)biWidth))
 {
  sumw += mask[1+s][1+t];   
  sum+=*(hData+(i+s)*WIDTHBYTES(lpBi->biWidth*8)+(j+t))*mask[1+s][1+t];
  }
  if(sumw==0) sumw=1;
   sum/=sumw;
  if(sum>255)sum=255;
  if(sum<0)sum=0;
  *(data+i*WIDTHBYTES(lpBi->biWidth*8)+j)=sum;
 }
 for( j=0; jbiHeight; j++)
 for(i=0;ibiWidth;i++)  *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j);
  StretchDIBits (hDC,0,0,lpBi->biWidth,lpBi->biHeight,0,0,
         lpBi->biWidth,lpBi->biHeight,
         hData,(LPBITMAPINFO)lpBi,
         DIB_RGB_COLORS,
         SRCCOPY);//顯示圖像;
}


(a)LENA原圖

(b)平滑后的效果圖

                     圖三

  中值或均值平滑有時處理圖像的效果并不是很好,它雖然去除了一定的噪聲,但同時使圖像中的邊緣變的模糊,這主要和所選取的窗口大小有關,為此下面介紹了一種既能保持邊緣清晰又能消除噪聲的方法,其算法如圖四所示:


(a)

(b)

(c)

                 圖 四 圖像平滑模板

  上圖的含義是在圖像中取5*5的區域,包含點(i,j)的五邊形和六邊形各四個,3*3的區域一個,計算這九個區域的標準差和灰度的平均值,取標準差最小區域的灰度平均值作為點(i,j)的灰度。由于該算法的實現代碼和上述代碼大同小異,所以代碼部分就不再贅述。


  3.圖像銳化

  圖像平滑往往使圖像中的邊界、輪廓變的模糊,為了減少這類不利效果的影響,這就需要利用圖像鋭化技術,使圖像的邊緣變的清晰。圖像銳化處理的目的是為了使圖像的邊緣、輪廓線以及圖像的細節變的清晰,經過平滑的圖像變得模糊的根本原因是因為圖像受到了平均或積分運算,因此可以對其進行逆運算(如微分運算)就可以使圖像變的清晰。從頻率域來考慮,圖像模糊的實質是因為其高頻分量被衰減,因此可以用高通濾波器來使圖像清晰。

  為了要把圖像中間任何方向伸展的的邊緣和輪廓線變得清晰,我們希望對圖像的某種運算是各向同性的??梢宰C明偏導平方和的運算是各向同性的,既:


  式中( )是圖像旋轉前的坐標,( )是圖像旋轉后的坐標。梯度運算就是在這個式子的基礎上開方得到的。圖像(x,y)點的梯度值:


  為了突出物體的邊緣,常常采用梯度值的改進算法,將圖像各個點的梯度值與某一閾值作比較,如果大于閾值,該像素點的灰度用梯度值表示,否則用一個固定的灰度值表示。

  我們在對圖像增強的過程中,采用的是一種簡單的高頻濾波增強方法:


  式中f,g分別為銳化前后的圖像, 是與擴散效應有關的系數。 表示對圖像f進行二次微分的拉普拉斯算子。這表明不模糊的圖像可以由模糊的圖像減去乘上系數的模糊圖像拉普拉斯算子來得到。 可以用下面的模板H={{1,4,1},{4,-20,4},{1,4,1}}來近似。在具體實現時,上述模板H中的各個系數可以改變, 這個系數的選擇也很重要,太大了會使圖像的輪廓過沖,太小了則圖像銳化不明顯。實驗表明, 選取2-8之間往往可以達到比較滿意的效果。下面給出 等于4的情況下的實現代碼和效果圖:

void CDibView::OnMenuitem32785()
{
CClientDC pDC(this);
HDC hDC=pDC.GetSafeHdc();//獲取當前設備上下文的句柄;
SetStretchBltMode(hDC,COLORONCOLOR);
CDibDoc *pDoc=GetDocument();
HDIB hdib;
hdib=pDoc->GetHDIB();
BITMAPINFOHEADER *lpDIBHdr;//位圖信息頭結構指針;
BYTE *lpDIBBits;//指向位圖像素灰度值的指針;
lpDIBHdr=( BITMAPINFOHEADER *)GlobalLock(hdib);//得到圖像的位圖頭信息 lpDIBBits=(BYTE*)lpDIBHdr+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);//獲取圖像像素值
BYTE* pData1;
static int a[3][3]={{1,4,1},{4,-20,4},{1,4,1}};//拉普拉斯算子模板;
int m,n,i,j,sum;
int Width=lpDIBHdr->biWidth;
int Height=lpDIBHdr->biHeight;
pData1=(BYTE*)new char[WIDTHBYTES(Width*8)*Height];
file://進行拉普拉斯濾波運算;
for(i=1;i for(j=1;j {
sum=0;
for(m=-1;m<2;m++)
for(n=-1;n<2;n++) sum+=*(lpDIBBits+WIDTHBYTES(Width*8)*(i+m)+j+n)*a[1+m][1+n];
if(sum<0) sum=0;
if(sum>255) sum=255;
*(pData1+WIDTHBYTES(Width*8)*i+j)=sum;
}
file://原始圖像pData減去拉普拉斯濾波處理后的圖像pData1
for(i=0;i for(j=0;j { sum=(int)(*(lpDIBBits+WIDTHBYTES(Width*8)*i+j)-4*(*(pData1+WIDTHBYTES(Width*8)*i+j)));
if(sum<0) sum=0;
if(sum>255) sum=255;
*(lpDIBBits+WIDTHBYTES(Width*8)*i+j)=sum;
}
StretchDIBits (hDC,0,0,lpDIBHdr->biWidth,lpDIBHdr->biHeight,0,0,
lpDIBHdr->biWidth,lpDIBHdr->biHeight,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr,
DIB_RGB_COLORS,
SRCCOPY);
}


(a)LENA原圖

(b)拉普拉斯銳化圖

                    圖 五

  本文主要講解了圖像直方圖的基本概念和圖像點處理運算中的增強、平滑、銳化概念和實現算法,并給處理實現代碼和處理效果圖和廣大讀者朋友們交流,希望達到拋磚引玉的作用。



 

原文轉自:http://www.anti-gravitydesign.com

評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97