1. 程式人生 > 實用技巧 >OpenCV-Utils學習日誌:GUI模組要點總結

OpenCV-Utils學習日誌:GUI模組要點總結

1.主窗體管理

(1)namedWindow(win, flag=1)=void●destroyWindow(win)=void●destroyAllWindows()=void

1)flag=WINDOW_NORMAL:尺寸可任意縮放且可全屏的窗體

2)flag=WINDOW_AUTOSIZE:尺寸固定為影象大小且不可全屏的窗體

3)flag=WINDOW_KEEPRATIO:尺寸可任意縮放且可全屏但長寬比例固定的窗體

4)flag=WINDOW_OPENGL:支援OpenGL的窗體

(2)moveWindow(win, x, y)=void●resizeWindow(win, w, h)=void●resizeWindow(win, size)=void

(3)getWindowImageRect(win)=rect●setWindowTitle(win, title)=void

1)x和y是窗體左上角在螢幕座標系中的座標,w和h是窗體的寬高

2)rect是窗體工作區(即影象)左上角在螢幕座標系中的座標和寬高

(4)setWindowProperty(win, key, val)=void●getWindowProperty(win, key)=val

1)key=WND_PROP_FULLSCREEN:取WINDOW_NORMAL或WINDOW_FULLSCREEN

2)key=WND_PROP_AUTOSIZE:取WINDOW_NORMAL或WINDOW_AUTOSIZE

3)key=WND_PROP_ASPECT_RATION:WINDOW_FREERATIO或WINDOW_KEEPRATIO

4)key=WND_PROP_OPENGL:未知

5)key=WND_PROP_VISIBLE:未知

2.事件迴圈

(1)imshow(win, ima)=void●imshow(win, texture2D)=void:顯示影象或二維紋理

(2)waitKey(delay=0)=int●waitKeyEx(delay=0)=int:後者返回完整鍵碼(值與系統相關)

(3)loadWindowParameters()=void:載入備份的主窗體屬性及其所有子窗體屬性

(4)saveWindowParameters()=void:備份主窗體屬性及其所有子窗體屬性到記憶體

(5)startWindowThread()=int:功能未知

(6)startLoop(Fun, argc, argv)=int●stopLop()=void:對QtConcurrent::run的封裝

3.工作區管理

(1)displayStatusBar(win, str, delay=0)=void:在狀態列左側顯示指定毫秒(0無限)

(2)displayOverlay(win, str, delay=0)=void:在工作區頂部顯示指定毫秒(0無限)當滑鼠靠近

(3)fontQt(fontName, pointSize=-1, color=Scalar::all(0), weight=~, style=~, spacing=0)=font

1)weight=QT_FONT_LIGHT、~NORMAL、~DEMIBOLD、~BOLD、~BLACK

2)style=QT_STYLE_NORMAL、~ITALIC、~OBLIQUE

(4)selectROI(ima, showCrosschair=true, formCenter=false)=rect

(5)selectROI(win, ima, showCrosschair=true, fromCenter=false)=rect

(6)selectROIs(win, ima, rects, ~)=void●addText(ima, str, pt, font)=void

1)繪製ima到窗體並等待滑鼠操作,滑鼠右鍵按下與釋放可繪製矩形

2)showCrosschair為真繪製田字矩形,fromCenter為真繪製起點是矩形中心

3)selectROI按enter/space/esc返回繪製的矩形,按c退出並返回空矩形

4)selectROIs按enter/space進行下一次繪製,按esc退出繪製

4.事件互動

(1)setMouseCallback(win, cbMouse, usrdata=0)=void●getMouseWheelDelta(wheelFlag)=int

1)回撥函式形式:void cbMouse(eventType, x, y, eventFlag, usrdata){}

2)eventType取值:event_mousemove/event_mousewheel/event_mousehwheel

3)eventType取值:event_lbuttondown/event_lbuttonup/event_lbuttondblclk

4)eventType取值:event_rbuttondown/event_rbuttonup/event_rbuttondblclk

5)eventType取值:event_mbuttondown/event_mbuttonup/event_mbuttondblclk

6)eventFlag取值:event_flag_lbutton/event_flag_rbutton/event_flag_mbutton

7)eventFlag取值:event_flag_ctrlkey/event_flag_shiftkey/event_flag_altkey

8)wheelFlag取值:僅響應event_mousewheel和event_mousehwheel事件

(2)createTrackbar(bar, win, bindVar, maxVal, cbTracker=0, usrdata=0)=int

(3)setTrackbarMin(bar, win,val)=void●setTrackbarMax(bar, win, val)=void

(4)setTrackbarPos(bar, win, val)=void●getTrackbarPos(bar, win)=int

1)回撥函式形式:void cbTracker(val, usrdata) {}

2)最簡使用方式:繫結變數是隨跟蹤條實時更新的,若無複雜操作則不用提供回撥函式

3)按需使用方式:在需要時再由getTrackbarPos獲取跟蹤條的當前值

(5)createButton(bar, cbButton, usrdata=0, btnType=QT_PUSH_BUTTON, state=false)

1)回撥函式形式:void cbButton(state, usrdata)

2)btnType取值:qt_push_button/qt_checkbox/qt_radiobox + qt_new_buttonbar

3)單選按分組:同一行的單選按鈕歸為同一組,即同一行的單選按鍵互斥

(6)回撥函式的lambda問題:用lambda似乎捕獲引數只能為空,但可直接訪問外部靜態變數

5.立體顯示

(1)setOpenGlContext(win)=void●updateWindow(win)=void

(2)setOpenGlDrawCallback(win, cbGlDraw, usrdata)=void

1)回撥函式形式:void cbGlDraw(usrdata)=void

2)使用注意事項:首先要設定窗體支援OpenGL,否則setOpenGLContext會異常。

3)使用基本流程:參見對應樣例程式碼。這幾個函式難以完成立體互動,需用viz模組。

6.使用樣例

以下提供OpenCV GUI模組的使用樣例,封裝在類AboutOpenCVGUI,實現功能如下:

(1)模擬使用selectROI和selectROIs,在影象上選擇感知興趣的區域並按相應的鍵退出後,終端將顯示選擇的區域。

(2)模擬使用setWindowTitle、displayStatusBar及displayOverlay,可在視窗相應處觀察到相應的文字且在動態變化,按q退出。

(3)模擬使用setMouseCallback、createTracker、createButton,可單擊右上角的掃帚開啟子視窗檢視建立的控制。

以下是詳細程式碼,依賴於C++14、OpenCV4.x和Spdlog。

  1 #include <opencv2/opencv.hpp>
  2 #include <spdlog/spdlog.h>
  3 using namespace std;
  4 using namespace cv;
  5 
  6 #ifndef StrPairKey
  7 #define StrPairKey(key) make_pair(#key, key)
  8 #define StrPairVal(val) make_pair(val, #val)
  9 #endif
 10 
 11 class AboutOpenCVGUI
 12 {
 13 public:
 14     struct MouseInfo
 15     {
 16         int rowsUser;//GivenByUser
 17         int colsUser;//GivenByUser
 18         MouseInfo(int rows = INT_MAX, int cols = INT_MAX) : rowsUser(rows), colsUser(cols) {}
 19         int xMouse;//UpdatedByCbMouse
 20         int yMouse;//UpdatedByCbMouse
 21         int eventMouse;//UpdatedByCbMouse
 22         int flagMouse;//UpdatedByCbMouse
 23         const map<int, string> mouseEvents =
 24         {
 25             StrPairVal(EVENT_MOUSEMOVE),
 26             StrPairVal(EVENT_LBUTTONDOWN),
 27             StrPairVal(EVENT_RBUTTONDOWN),
 28             StrPairVal(EVENT_MBUTTONDOWN),
 29             StrPairVal(EVENT_LBUTTONUP),
 30             StrPairVal(EVENT_RBUTTONUP),
 31             StrPairVal(EVENT_MBUTTONUP),
 32             StrPairVal(EVENT_LBUTTONDBLCLK),
 33             StrPairVal(EVENT_RBUTTONDBLCLK),
 34             StrPairVal(EVENT_MBUTTONDBLCLK),
 35             StrPairVal(EVENT_MOUSEWHEEL),
 36             StrPairVal(EVENT_MOUSEHWHEEL)
 37         };
 38         const map<int, string> mouseFlags =
 39         {
 40             StrPairVal(EVENT_FLAG_LBUTTON),
 41             StrPairVal(EVENT_FLAG_RBUTTON),
 42             StrPairVal(EVENT_FLAG_MBUTTON),
 43             StrPairVal(EVENT_FLAG_CTRLKEY),
 44             StrPairVal(EVENT_FLAG_SHIFTKEY),
 45             StrPairVal(EVENT_FLAG_ALTKEY)
 46         };
 47     };
 48 
 49     static void callbackMouse(int event, int x, int y, int flag, void* pMouseInfo)
 50     {    //common case. could be replaced by lambda based on actual requirement
 51         MouseInfo* mouseInfo = (MouseInfo*)pMouseInfo;
 52 
 53         if (x >= mouseInfo->colsUser * 3) x -= mouseInfo->colsUser * 3;
 54         else if (x >= mouseInfo->colsUser * 2) x -= mouseInfo->colsUser * 2;
 55         else if (x >= mouseInfo->colsUser) x -= mouseInfo->colsUser;
 56 
 57         if (y >= mouseInfo->rowsUser * 3) y -= mouseInfo->rowsUser * 3;
 58         else if (y >= mouseInfo->rowsUser * 2) y -= mouseInfo->rowsUser * 2;
 59         else if (y >= mouseInfo->rowsUser) y -= mouseInfo->rowsUser;
 60 
 61         mouseInfo->xMouse = x;
 62         mouseInfo->yMouse = y;
 63         mouseInfo->eventMouse = event;
 64         mouseInfo->flagMouse = flag;
 65     }
 66 
 67 public:
 68     static void testBasicGUI(int argc = 0, char** argv = 0)
 69     {
 70         Mat_<Vec3b> ima(720, 1280, Vec3b(128, 128, 128));
 71 
 72         //1.AboutSelectROI
 73         string tips1 = "cv::selectROI: press enter/space/esc to return selected rect, press c to return invalid rect.";
 74         string tips2 = "cv::selectROIs: press enter/space to select next rect, press esc to return all selected rects.";
 75         string tips3 = "current mode: cv::selectROIs";
 76         auto exitFunction = [](Mat ima, string str)->void { putText(ima, "Current Test: " + str, Point(ima.cols >> 2, ima.rows - 100), FONT_HERSHEY_PLAIN, 3, Scalar(255, 0, 0), 3, LINE_8, false); };
 77         putText(ima, tips1, Point(10, 100), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
 78         putText(ima, tips2, Point(10, 200), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
 79         putText(ima, tips3, Point(10, 300), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
 80         exitFunction(ima, "selectROI"); Rect rect = cv::selectROI(__FUNCTION__, ima, true, false); 
 81         spdlog::info(fmt::format("selectROI results: {} {} {} {}", rect.x, rect.y, rect.width, rect.height));
 82         exitFunction(ima, "selectROIs"); vector<Rect> rects; cv::selectROIs(__FUNCTION__, ima, rects, true, false);
 83         for(size_t k = 0; k < rects.size(); ++k) spdlog::info(fmt::format("selectROIs results{}: {} {} {} {}", k, rects[k].x, rects[k].y, rects[k].width, rects[k].height));
 84 
 85         //2.AboutTipFunctions
 86         cv::setWindowProperty(__FUNCTION__, 1, 0);//__FUNCTION__ window has created but fixed size. 
 87         for (int k = 0; ; ++k)
 88         {
 89             ima = Vec3b(128, 128, 128);
 90 
 91             tips1 = std::to_string(k) + string(" cv::setWindowTitle: show tips in the title bar until next tip is reached");
 92             tips2 = std::to_string(k) + string(" cv::displayStatusBar: show tips in the status bar until given time or next tip is reached");
 93             tips3 = std::to_string(k) + string(" cv::displayOverlay: show tips at the top of the workarea until given time or next tip is reached when mouse hovers");
 94             putText(ima, tips1, Point(10, 100), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
 95             putText(ima, tips2, Point(10, 200), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
 96             putText(ima, tips3, Point(10, 300), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
 97             exitFunction(ima, "TipsFunction");
 98 
 99             cv::imshow(__FUNCTION__, ima);
100             cv::setWindowTitle(__FUNCTION__, tips1);
101             cv::displayStatusBar(__FUNCTION__, tips2, 2000);
102             cv::displayOverlay(__FUNCTION__, tips3, 2000);
103             if (cv::waitKey(4000) == 'q') break;
104         }
105 
106         //3.AboutControls
107         ima = Vec3b(128, 128, 128);
108         MouseInfo mouseInfo(ima.rows, ima.cols); cv::setMouseCallback(__FUNCTION__, callbackMouse, &mouseInfo);
109         int value = 128; cv::createTrackbar("tracker", __FUNCTION__, &value, 255, 0, 0);
110         auto cbButton = [](int state, void* usrdata)->void
111         {
112             string* str = (string*)usrdata;
113             if (str->find_first_of(':') == string::npos) *str += string(": ") + std::to_string(state);
114             else *str = str->substr(0, str->find_first_of(':')) + string(": ") + std::to_string(state);
115         };
116         string radioNames[8]; for (int k = 0; k < 8; ++k) cv::createButton(radioNames[k] = string("RadioBox") + std::to_string(k + 1), cbButton, radioNames + k, QT_RADIOBOX | (k == 0 || k == 4 ? QT_NEW_BUTTONBAR : 0));
117         string checkNames[8]; for (int k = 0; k < 8; ++k) cv::createButton(checkNames[k] = string("CheckBox") + std::to_string(k + 1), cbButton, checkNames + k, QT_CHECKBOX | (k == 0 || k == 4 ? QT_NEW_BUTTONBAR : 0));
118         string pushNames[8]; for (int k = 0; k < 8; ++k) cv::createButton(pushNames[k] = string("PushButton") + std::to_string(k + 1), cbButton, pushNames + k, QT_PUSH_BUTTON | (k == 0 || k == 4 ? QT_NEW_BUTTONBAR : 0));
119         string winName = __FUNCTION__;
120         cv::createButton("PushButtonAccept", [](int state, void* usrdata)->void {cv::setWindowTitle(*((string*)usrdata), "PushButtonAccept"); }, &winName, QT_PUSH_BUTTON | QT_NEW_BUTTONBAR);
121         cv::createButton("PushButtonCancel", [](int state, void* usrdata)->void {cv::setWindowTitle(*((string*)usrdata), "PushButtonCancel"); }, &winName, QT_PUSH_BUTTON | QT_NEW_BUTTONBAR);
122         while (1)
123         {
124             ima = Vec3b(value, value, value);
125             for (int k = 0; k < 8; ++k) putText(ima, radioNames[k], Point(100 + k % 4 * 250, 100 + k / 4 * 100), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
126             for (int k = 0; k < 8; ++k) putText(ima, checkNames[k], Point(100 + k % 4 * 250, 300 + k / 4 * 100), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
127             for (int k = 0; k < 8; ++k) putText(ima, pushNames[k], Point(100 + k % 4 * 250, 500 + k / 4 * 100), FONT_HERSHEY_PLAIN, 1.5, Scalar(255, 255, 255), 2, LINE_8, false);
128 
129             cv::displayOverlay(__FUNCTION__, string("x: ") + std::to_string(mouseInfo.xMouse) + "   y: " + std::to_string(mouseInfo.yMouse), 0);
130             exitFunction(ima, "Controls");
131             cv::imshow(__FUNCTION__, ima);
132             if (cv::waitKey(40) == 'q') break;
133         }
134     }
135 
136 };
137 
138 int main(int argc, char** argv) { AboutOpenCVGUI::testBasicGUI(argc, argv); return 0; }
View Code