人機交互量測同名點程序--雙像三維建模小軟件開發實例(四)

一個量測同名點的程序是圖像幾何定向的必要準備,爲此我們開發了ImageMeasuringApparatus(圖1),它是一款用來進行雙像立體量測的程序,其功能有:

1、  影像對的顯示和漫遊;

2、  顯示縮略圖,進行手動粗定位;

3、  載入已量測點、手動亞像素級刺點。

該程序源代碼(VC++)和詳細的開發說明文檔(.doc)已經添加在了本人的資源裏,可以下載查閱。

圖 1. ImageMeasuringApparatus運行界面

下面我們闡述改程序的開發方法,通過學習本方法或許有助於加強對於MFC多視圖圖形界面程序開發的掌握:

本程序是基於MFC的單文檔應用程序,佈局上採用分割窗口形式。其中涉及的主要的類有CMainFrame,CImageMeasuringApparatusDoc,CMeasuringView,CPhotoView以及CPhotoView2,另外還有一些對話框用來接收參數,原理簡單此處不予介紹。

CMainFrame類主要實現了主框架窗口的分割,分割方式如圖2所示。

CImageMeasuringApparatusDoc 類用來存儲影像和量測點數據。

CMeasuringView類用以顯示縮略圖,微調視圖,並響應用戶微調操作。

CPhotoViewCPhotoView2類用以顯示原始影像,相應用戶漫遊刺點等操作。

圖 2 窗口分割示意圖

下面通過操作實例來分析各類的關係:

1、 打開影像,顯示,漫遊及粗定位。

①點擊菜單或工具欄打開按鈕,CImageMeasuringApparatusDoc類響應該消息,打開文件對話框接收用戶輸入的文件路徑,利用OpenCV讀取左右影像數據保存於m_img_l和m_img_r,並分別轉換備份一個三通道影像m_l和m_r,以便後續處理。刷新視圖。

②在CPhotoView和CPhotoView2的Ondraw函數中顯示CImageMeasuringApparatusDoc保存的影像,注意轉換座標將其顯示到視圖中心。

③點擊,就轉換CMainFrame中保存的布爾型變量flag_drag的值爲true,在CPhotoView和CPhotoView2中添加鼠標按下,拖放和釋放的消息響應函數,在CMainFrame的flag_drag爲true的情況下處理用戶的漫遊影像操作。

④在CMeasuringView的縮略圖上按下左鍵,要將原始影像粗定位到相應位置。爲此,在其LButtonDown中將按下點位置座標轉到原始影像,設置CPhotoView或CPhotoView2的offset變量,刷新視圖,實現定位。

2、 載入像點,顯示像點。

①點擊菜單或工具欄載入像點按鈕,CImageMeasuringApparatusDoc類響應該消息,打開文件對話框接收用戶輸入的文件路徑,讀取左右影像像點數據保存在m_pt_l,m_pt_r,同時保存點數m_ptl_num和m_ptr_num。

②在CPhotoView ,CPhotoView2和CMeasuringView的m_overview_l和m_overview_r控件上實現顯示像點的功能。首先像點座標轉換到這三個視圖的座標,然後在該座標處畫十字絲即可。

3、 手動刺點,微調,保存所刺像點。

①點擊刺點按鈕,就轉換CMainFrame中保存的布爾型變量flag_cross的值爲true,在CPhotoView和CPhotoView2中添加鼠標按下,拖放和釋放的消息響應函數,在CMainFrame的flag_drag爲true的情況下處理用戶的刺點操作。

②一旦觸發刺點操作,就從原始影像上汲取觸發點處爲中心31*31範圍的像素值保存在CMeasuringView的m_ptl_lpBits和m_ptr_lpBits中。

③CMeasuringView將m_ptl_lpBits和m_ptr_lpBits像素塊顯示在微調視圖上,當用戶點擊微調按鈕時調整offset_l和offset_r值,重繪微調視圖上的圖像。

④量點完畢,按下空格鍵時彈出輸入點號對話框,輸入點號後保存該點對於CImageMeasuringApparatusDoc的m_pt_l和m_pt_r.

⑤點擊保存按鈕,將保存CImageMeasuringApparatusDoc的m_pt_l和m_pt_r與當前文件夾下。

圖 3. 類視圖

以下是上述幾個類的詳細說明:

1 CMainFrame

成員變量:

   CSplitterWnd m_wndSplitter1;//窗口分割器1

   CSplitterWnd m_wndSplitter2;//窗口分割器2

   bool m_flag_drag;//是否按下拖動工具

   bool m_flag_cross;//是否按下刺點工具

成員函數:

virtual BOOL OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext);

//分割窗口,分別是CPhotoView,CphotoView2,CMeasuringView類型窗口。

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

//設置窗口大小,取消最大化按鈕

afx_msg void OnBtnDrag();

//按下拖動按鈕的響應函數,設置變量m_flag_dragtrue

afx_msg void OnUpdateBtnDrag(CCmdUI* pCmdUI);

//設置工具按鈕激活顯示狀態

afx_msg void OnBtnCross();

//按下刺點按鈕的響應函數,設置變量m_flag_crosstrue

afx_msg void OnUpdateBtnCross(CCmdUI* pCmdUI);

//設置工具按鈕激活顯示狀態

2 CImageMeasuringApparatusDoc

成員變量:

CvvImage m_img_l;//原始左影像

CvvImage m_img_r; //原始右影像

IplImage *m_l; //3波段左影像

IplImage *m_r; //3波段右影像

IMAPOINT m_pt_l[5000]; //左影像量測點

IMAPOINT m_pt_r[5000]; //右影像量測點

int m_ptl_num;//左影像量測點數

int m_ptr_num; //右影像量測點數

成員函數:

afx_msg void OnFileOpen();

//打開影像得到m_img_l與m_img_r,然後將其轉換爲三波段的m_l與m_r,方便實現像點量測時精細調節視圖顯示。

afx_msg void OnOpenPoints();

//打開已量測點文件,保存左右影像量測點數以及像點座標

afx_msg void OnBtnSavept();

//保存量測的點至當前文件

typedef struct

{

int no;

float x;

float y;

}IMAPOINT;

3 CMeasuringView

成員變量:

       CStatic   m_point_r; //右影像微調視圖控件

       CStatic   m_point_l; //左影像微調視圖控件

       CStatic   m_overview_r; //右影像縮略視圖控件

       CStatic   m_overview_l; //左影像縮略視圖控件

    double zoom_l,zoom_r; //縮略圖放縮比例

       unsigned char *m_ptl_lpBits;//當前所刺點塊像素值

       unsigned char *m_ptr_lpBits;//當前所刺點塊像素值

       CPoint offset_l;//微調偏移量

       CPoint offset_r;//微調偏移量

成員函數:

virtual void OnDraw(CDC* pDC);

//從Doc中讀取影像數據,計算並保存縮略圖放縮比例,在縮略圖中畫出左右影像縮略圖,

//從Doc中讀取像點數據,根據縮略圖顯示方式及放縮比例換算到縮略圖並畫出十字絲顯示

//在微調視圖中畫出十字絲

void AddPoints();

//向Doc中保存量測點的數組m_pt_l以及m_pt_r加入新量測的點

//m_pt_l以及m_pt_r由CPhotoView和CPhotoView2中m_pt以及CMeasuringView中的//offset_l核offset_r求和而得到。

void DrawPoints(CDC *pDC, int flag);

//在左右縮略圖上畫出所有像點,爲pDC傳入m_overview_l以及m_overview_r對應的DC,

//flag相應爲LEFT及RIGHT

void DrawRedCross();

//畫出像點微調視圖的中心十字絲

void DrawPointView(int flag);

//在微調視圖中畫出所刺的像點塊,參數flag爲LEFT或RIGHT. 利用API函數//StretchDIBits實現該功能,圖像數據塊爲成員變量m_ptl_lpBits和m_ptr_lpBits。爲了實//現微調功能,不能直接在m_point_l和m_point_r控件的pDC上畫小影像塊,而要先利用//兼容DC畫出放大的影像並根據微調量移動到合適的位置,最後將其利用BitBlt直接複製//到原來的控件DC中即可。

//要注意的是圖像數據塊的行寬必需爲4的整數倍。

virtual BOOL PreTranslateMessage(MSG* pMsg);

//爲了響應空格鍵按下時的消息,以便輸入點號,重載該函數,在其中調用AddPoints()

afx_msg void OnBtnLl();

afx_msg void OnBtnLd();

afx_msg void OnBtnLr();

afx_msg void OnBtnLu();

afx_msg void OnBtnRd();

afx_msg void OnBtnRl();

afx_msg void OnBtnRr();

afx_msg void OnBtnRu();

//響應微調按鈕操作,微調小影像快並重繪

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

//在縮略視圖中點擊圖像上某點,就把CPhotoView和CPhotoView2移動到相應的位置

4 CPhotoView

成員變量:

CPoint offset;//大影像偏移量

CPoint m_pt;//當前所刺的點

CPoint oriPoint;//開始拖動影像時鼠標座標

bool m_flag_draging;//是否正在拖動影像

成員函數:

virtual BOOL PreTranslateMessage(MSG* pMsg);

//爲了響應空格鍵按下時的消息,以便輸入點號,重載該函數,在其中調用CMeasuring類//的成員函數AddPoints()

virtual void OnDraw(CDC* pDC);

//將打開的左影像顯示在窗口中心,採用雙緩存方式:先用兼容DC顯示然後直接複製

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

//左鍵按下時如果當前激活工具爲拖動,則記錄初始移動點位座標,並捕獲鼠標

//左鍵按下時如果當前激活工具爲刺點,則利用GetPtBits(CPoint point, unsigned char *lpBits)

//獲取當前點爲中心31*31範圍中的影像塊像素值

afx_msg void OnMouseMove(UINT nFlags, CPoint point);

//鼠標移動時根據激活工具狀態設置光標類型,如果狀態爲拖動則還要實時更新影像偏移量//同時重置拖動初始點位

afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

//如果激活工具狀態爲拖動,則釋放鼠標並設置m_flag_dragingfalse

//如果激活工具狀態爲刺點,則在當前點畫出十字絲,同時把當前點保存到m_pt

CImageMeasuringApparatusDoc* GetDocument();

//自添加的函數,用以獲取文檔類指針

void GetPtBits(CPoint point, unsigned char *lpBits);

//point換算到影像上然後取以相應點爲中心31*31範圍的像素值保存在lpBits

void DrawPoints(CDC *pDC);

//Doc中的點位數據顯示在影像上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章