本文主要講述基于VC++6.0 MFC圖像處理的應用知識,主要結合自己大三所學課程《數字圖像處理》及課件進行回憶講解,主要通過MFC單文檔視圖實作點選彈出對話框繪制BMP圖檔的灰階直方圖,再擷取平均灰階、中指灰階和标準差等值。文章比較詳細基礎,希望該篇文章對你有所幫助~
免費資源下載下傳位址:
該篇文章主要是在上一篇文章基礎上進行的講解,其中當打開一張BMP圖像後,點選”直方圖“-》”顯示原圖直方圖“如下。
什麼是灰階直方圖?
灰階直方圖(histogram)是灰階級的函數,描述的是圖像中每種灰階級像素的個數,反映圖像中每種灰階出現的頻率。橫坐标是灰階級,縱坐标是灰階級出現的頻率。
對于連續圖像,平滑地從中心的高灰階級變化到邊緣的低灰階級。直方圖定義為:
其中A(D)為門檻值面積函數:為一幅連續圖像中被具有灰階級D的所有輪廓線所包圍的面積。對于離散函數,固定ΔD為1,則:H(D)=A(D)-A(D+1)
色彩直方圖是高維直方圖的特例,它統計色彩的出現頻率,即色彩機率分布資訊。
通常這需要一定的量化過程,将色彩分成若幹互不重疊的種類。一般不直接在RGB色彩空間中統計,而是在将亮度分離出來後,對代表色彩部分的資訊進行統計,如在HSI空間的HS子空間、YUV空間的UV子空間,以及其它反映人類視覺特點的彩色空間表示中進行。
其中直方圖的計算方法如下:
依據定義,若圖像具有L(通常L=256,即8位灰階級)級灰階,則大小為MxN的灰階圖像f(x,y)的灰階直方圖hist[0…L-1]可用如下計算獲得。
1、初始化 hist[k]=0; k=0,…,L-1
2、統計 hist[f(x,y)]++; x=0,…,M-1, y =0,…,N-1
3、歸一化 hist[f(x,y)]/=M*N
那麼說了這麼多,直方圖究竟有什麼作用呢?
在使用輪廓線确定物體邊界時,通過直方圖更好的選擇邊界門檻值,進行門檻值化處理;對物體與背景有較強對比的景物的分割特别有用;簡單物體的面積和綜合光密度IOD可以通過圖像的直方圖求得。
第一步:建立Dialog
将視圖切換到ResourceView界面,選中Dialog右鍵滑鼠建立一個Dialog,并建立一個名為IDD_DIALOG_ZFT,設定成下圖對話框。
右鍵添加屬性如下:
對話框-原始直方圖-IDD_DIALOG_ZFT
組框-RGB-IDC_STATIC_RGB
圖像-架構-IDC_STATIC_KJ-蝕刻(重點:有它才能添加直方圖在此處,注意GetDlgItem()函數中是IDC而不是IDD對話框)
添加蝕刻線(圖像蝕刻形成的直線)形如圖中的3個矩形框,并添加靜态文本:Red、Green、Blue、紅、綠、藍、像素、平均灰階、中值灰階、标準差;這些靜态文本都是IDC_STATIC且為預設屬性
添加紅色4個值(Static)、綠色4個值、藍色4個值,分别為:
IDC_STATIC_XS_RED(GREEN BLUE)對應像素XS
IDC_STATIC_PJHD_RED(GREEN BLUE)對應平均灰階PJHD
IDC_STATIC_ZZHD_RED(GREED BLUE)對應中值灰階ZZHD
IDC_STATIC_BZC_RED(GREEN BLUE)對應标準差BZC
第二步:建立類向導MFC ClassWizard
(1) 在對話框資源模闆空白區輕按兩下滑鼠(Ctrl+W),建立一個新類,命名為CImageZFTDlg會自動生成它的.h和.cpp檔案。在類向導中選中類名CImageZFTDlg,IDs為CImageZFTDlg,WM_INITDIALOG建立這個函數用于初始化。
(2) 打開類向導,選擇Member Variables頁面,添加如下變量,類型均為CString。
像素 m_redXS、m_greenXS、m_blueXS
标準差 m_redBZC、m_greeenBZC、m_blueBZC
平均灰階 m_redPJHD、m_greenPJHD、m_bluePJHD
中值灰階 m_redZZHD、m_greenZZHD、m_blueZZHD
(3) 在View.cpp中添加直方圖的頭檔案 #inlcude "ImageZFTDlg.h"
第三步:設定菜單欄調用直方圖對話框
(1) 将視圖切換到ResourceView界面,選中Menu,在IDR_MAINFRAM中添加菜單項“直方圖”,菜單屬性中選擇“彈出”,在“直方圖”中添加子菜單“顯示原圖直方圖”。
(2) 設定其屬性為ID_ZFT_YT(顯示直方圖原圖),同時建立類向導,選擇ID_ZFT_YT(IDs),通過COMMAND建立顯示直方圖函數OnZftYt()。
第四步:添加代碼及計算4個值
在ImageProcessingView.cpp中添加如下代碼,注釋中有如何求平均灰階、中值灰階和标準差的消息算法過程。
第五步:此時運作結果如下圖所示,打開圖檔可以顯示參數。
重點(極其重要*)
(1) 如何在MFC中(View中)實作對子對話框的畫圖或直方圖響應?
解決方法:在子對話框中.cpp檔案中實作畫圖響應,不要再View.cpp中實作,否則圖像會以menu背景為坐标,而在ImageZFTDlg.cpp中建立OnPaint函數實作畫圖,它預設會以子對話框為标準。
(2) 如何把View.cpp中的圖檔像素直方圖資訊傳遞給子對話框ImageZFTDlg.cpp呢?
解決方法:如果自定義ImageStruct.h中建立全局變量,每個.cpp中引用該頭檔案調用總是報錯(未知),是以我在View.h中建立一個全局變量int Red[256];再在子檔案.cpp中函數裡調用該全局變量即可extern int Red[256],這是非常重要的一個C語言知識。
(3) 畫圖函數OnPaint()參考源代碼中詳細注釋。
如何繪制坐标軸、文字、圖像,其實自己繪制而沒調用第三方庫還是挺有意思的。
第一步:建立畫直方圖函數OnPaint
打開類向導(Ctrl+W),類名選擇CImageZFTDlg,IDs選擇CImageZFTDlg,在Message函數中建立WM_PAINT映射,預設函數名為OnPaint建立函數void CImageZFTDlg::OnPaint()
第二步:繪制直方圖大緻思想如下
(1) 重點:擷取要繪制直方圖的位置和圖像資源的對應号ID(IDC_STATIC_KJ 架構),我當時認為繪制直方圖隻能繪制到”圖像“控件IDC中,不能是對話框IDD。
CWnd *pWnd = GetDlgItem(IDC_STATIC_KJ);
CDC *pDC = pWnd->GetDC();
(2) 擷取對話框矩形的長和寬
CRect rectpic;
GetDlgItem(IDC_STATIC_KJ)->GetWindowRect(&rectpic);
(3) 建立畫筆對象并對畫筆進行顔色設定
CPen *RedPen = new CPen();
RedPen->CreatePen(PS_SOLID,1RGB(255,0,0));
(4) 選中目前畫筆并儲存以前畫筆
CGdiObject *RedOlderPen = pDC->SelectObject(RedPen);
(5) 繪制直方圖(圖像坐标自己算)
矩形 pDC->Rectangle(9,327,312,468);
移動 pDC->MoveTo(15,331);
直線 pDC->LineTo(15,488);
文字 pDC->TextOut(15+48*i,450,str);
(6) 恢複以前畫筆
pDC->SelectObject(RedOlderPen);
delete RedPen;
ReleaseDC(pDC);
第三步:源代碼與詳細注釋思想
在ImageZFTDlg.cpp中修改OnPaint函數:
此時運作程式即可顯示直方圖。
最後還是希望文章對你有所幫助,如果文章有不足或錯誤之處,請海涵~文章不僅僅講述了直方圖相關的知識,同時文章也給你提供了一種繪制坐标圖像的思想和詳細注釋。有時候一直懷疑回憶這些知識會讓我停滞不前,但心安即好,何必在意!
從來沒有什麼終南捷徑和大神,真正的捷徑隻有三個:堅持、專注、認真。其他的都是細枝末節,做到這三個,其他的自然而然都會擁有。——同學CY