遙感圖像處理時少不了ENVI,用過ENVI的人都知道,打開圖像時或圖像處理完後,在縮略圖上移動鼠標時,鼠標周圍的圖像信息會在大的視圖中實時的顯示,即大圖會跟着小圖中的鼠標移動,這便是圖像的連動效果。以下圖是ENVI的示意圖:html
在軟件設計中,要實現相似ENVI中連動的效果,確實要費一番腦筋。web
要求:有兩幅圖,一個是縮略圖,一個是原圖或處理後的圖,使用兩個對話框,鼠標在小的縮略圖中移動或點擊時,大圖中的圖像實時顯示出鼠標所在位置的圖像。函數
結果展現:首先給出結果展現,這樣讀者也好明白實現這樣的功能入手點和重點在那些地方。ui
從上圖中能夠看出:1.大圖在移動時其實只須要控制滑動杆的位置便可,控制滑動杆的位置即設置水平和垂直兩個滑動軸的值大小;spa
2.須要檢測出鼠標在縮略圖中的滑動和點擊事件.net
再聯繫到使用QT實現時,可使用信號與槽將這二者聯繫起來,兩幅圖對應兩個對話框,使用兩個類分別實現對話框的功能。鼠標在縮略圖中點擊或移動時,實時記錄鼠標所在位置,並觸發信號,大圖的槽函數響應縮略圖對話框發過來的信號,設置滑動軸的值。設計
座標值與滑動軸值之間的聯繫:須要肯定鼠標在縮略圖中的位置,x長度佔縮略圖寬度的百分比,y長度佔縮略圖長度的百分比,而後這兩個值傳遞給大圖對話框的類對象,根據這兩個百分比和大圖圖像的寬和高設置滑動杆的值。code
縮略圖對話框類爲SmallImage,大圖對話框類爲ImgShoworm
首先是在SmallImage類中重寫鼠標事件,縮略圖圖像顯示區大小固定爲300*300htm
1 //smallimage.h 2 #ifndef SMALLIMAGE_H 3 #define SMALLIMAGE_H 4 5 #include <QWidget> 6 #include <QMouseEvent> 7 #include "ui_smallimage.h" 8 9 class SmallImage : public QWidget 10 { 11 Q_OBJECT 12 13 public: 14 SmallImage(QWidget *parent = 0); 15 ~SmallImage(); 16 17 void show_small_img(float *data,int width,int height);//顯示縮略圖圖像 18 19 float x_value;//鼠標點所在位置佔x軸的百分比 20 float y_value;//鼠標點所在位置佔y軸的百分比 21 22 signals: 23 void press(float x,float y); 24 25 private: 26 Ui::SmallImage ui; 27 28 void mousePressEvent(QMouseEvent *ev);//重寫鼠標按下事件 29 void mouseMoveEvent(QMouseEvent *ev);//重寫鼠標移動事件 30 31 int img_width_;//縮略圖寬 32 int img_height_;//縮略圖高 33 34 }; 35 36 #endif // SMALLIMAGE_H 37 38 39 //smallimage.cpp 40 //重寫鼠標按下事件 41 void SmallImage::mousePressEvent(QMouseEvent *ev) 42 { 43 int x1=ui.label->x();//x座標 44 int y1=ui.label->y();//y座標 45 int x_left=x1+(300-img_width_)/2;//縮略圖左起x座標 46 int x_right=x1+img_width_+(300-img_width_)/2;//縮略圖右邊的x座標 47 int y_top=y1+(300-img_height_)/2;//縮略圖上起y座標 48 int y_bottom=y1+img_height_+(300-img_height_)/2;//縮略圖底部y座標 49 int x0=ev->x(); 50 int y0=ev->y(); 51 if ( (x0>=x_left) && (x0<=x_right) && (y0>=y_top) && (y0<=y_bottom)) 52 { 53 x_value=(float)(x0-x_left)/(float)img_width_; 54 y_value=(float)(y0-y_top)/(float)img_height_; 55 //觸發鼠標按下信號 56 emit press(x_value,y_value); 57 } 58 } 59 60 //鼠標移動操做 61 void SmallImage::mouseMoveEvent(QMouseEvent *ev) 62 { 63 int x1=ui.label->x();//x座標 64 int y1=ui.label->y();//y座標 65 int x_left=x1+(300-img_width_)/2;//縮略圖左起x座標 66 int x_right=x1+img_width_+(300-img_width_)/2;//縮略圖右邊的x座標 67 int y_top=y1+(300-img_height_)/2;//縮略圖上起y座標 68 int y_bottom=y1+img_height_+(300-img_height_)/2;//縮略圖底部y座標 69 int x0=ev->x(); 70 int y0=ev->y(); 71 if ( (x0>=x_left) && (x0<=x_right) && (y0>=y_top) && (y0<=y_bottom)) 72 { 73 x_value=(float)(x0-x_left)/(float)img_width_; 74 y_value=(float)(y0-y_top)/(float)img_height_; 75 emit press(x_value,y_value); 76 } 77 }
而後是在ImgShow類中定義槽函數
1 //imgshow.h 2 public slots: 3 void set_scroll_value(float x0,float y0);//設置滑動杆的值 4 5 //imgshow.cpp 6 //設置滑動杆的值 7 void ImgShow::set_scroll_value(float x0, float y0) 8 { 9 ui.scrollArea->horizontalScrollBar()->setValue(x0*img_width_- 10 11 (ui.scrollArea->width())/2); 12 ui.scrollArea->verticalScrollBar()->setValue(y0*img_height_- 13 14 (ui.scrollArea->height())/2); 15 }
最後是當着兩個對話框均顯示出來以後將他們的信號與槽鏈接起來。
connect(small_img,SIGNAL(press(float,float)),img_show,SLOT(set_scroll_value(float,float)))
還有至關重要的一點就是,兩個對話框必須都是非模態,關於非模態的內容請見:http://blog.csdn.net/luo_klt/article/details/8826975
本文中忽略了圖像讀取及顯示等操做,在本人博客中的其餘文章中有詳細敘述,詳見:
http://www.cnblogs.com/Romi/archive/2012/03/14/2396627.html
http://www.cnblogs.com/Romi/archive/2012/03/14/2396533.html
http://www.cnblogs.com/Romi/archive/2012/03/29/2424073.html
最後說一下,此文論述的方法是經過移動滑動杆(即改變滑動杆的值)來實現圖像連動的,該文中的大圖是顯示的所有圖像而非區域圖像。
當只須要對區域進行處理而非所有圖像時,這時上述方法便不起做用了,這時有一個簡單的方法是固定選取鼠標在縮略圖中周圍的一小塊數據,將它所有處理而後顯示在大圖上,每當鼠標移動或點擊時都進行選取區域處理而後顯示的執行過程。由於固定選取的是一小塊區域所以處理起來速度也快。
假若不是上面說的兩種狀況而是選取一塊感興趣區域時,這時就更加麻煩了,但回頭一想,選擇感興趣區域區域大還好區域小的話,連動還有什麼意義呢,何況選擇的都不會是大的區域。有一個辦法是先把選擇的區域經過第三方軟件截下來,而後使用文中的方法對截下來保存的圖像數據進行處理並顯示。