learn opencv-cvui:一個構建在OpenCV繪圖基元之上的GUI庫
cvui:一個構建在OpenCV繪圖基元之上的GUI庫
通常計算機視覺專案的開發涉及調整技術的引數以實現期望的結果。例如,這些引數可以是邊緣檢測演算法的閾值或影象的亮度。如果您不使用任何圖形使用者介面(GUI)來調整這些引數,則需要停止您的應用程式,調整您的程式碼,再次執行應用程式,評估並重復,直到它為好。這是乏味和耗時的。
有很多很棒的GUI庫,例如Qt和imgui,可以和OpenCV一起使用,以便在執行時調整引數。在Mac上使用OpenCV的Qt,看看這個帖子。但是,可能有些情況下,您沒有(或不想)這些庫的依賴關係,例如,你還沒有用Qt支援編譯OpenCV,或者你不能使用OpenGL。在這種情況下,所有你需要的是建立一個GUI來調整你的演算法的快速和無憂無慮的方式。
這就是cvui的目的。它是建立在OpenCV繪圖基元之上的C ++,僅標題和跨平臺(Windows,Linux和OSX)UI庫。除OpenCV之外,它沒有任何依賴性(您可能已經在使用它)。
遵循規則
一行程式碼應該在螢幕上產生一個UI元件。
結果,lib具有友好的C類API,沒有類/物件和多個元件,例如, 跟蹤欄,按鈕,文字等等:
一些在cvui中可用的UI元件。
如何在你的應用程式中使用cvui
為了使用cvui,你只需在你的專案中包含cvui.h,給它一個影象(即cv :: Mat)來渲染元件,你就完成了!
基本的“hello world”應用程式
讓我們看看cvui的功能,通過建立一個簡單的hello-world應用程式與一些UI互動。 該應用程式包含一個按鈕和一個可視指示器,顯示該按鈕被點選的次數。 這裡是程式碼:
#include <opencv2/opencv.hpp>
#include "cvui.h"
#define WINDOW_NAME "CVUI Hello World!"
int main(void)
{
cv::Mat frame = cv::Mat(200, 500, CV_8UC3);
int count = 0;
// Init a OpenCV window and tell cvui to use it.
cv::namedWindow(WINDOW_NAME);
cvui::init(WINDOW_NAME);
while (true) {
// Fill the frame with a nice color
frame = cv::Scalar(49, 52, 49);
// Show a button at position (110, 80)
if (cvui::button(frame, 110, 80, "Hello, world!")) {
// The button was clicked, so let's increment our counter.
count++;
}
// Show how many times the button has been clicked.
// Text at position (250, 90), sized 0.4, in red.
cvui::printf(frame, 250, 90, 0.4, 0xff0000, "Button click count: %d", count);
// Update cvui internal stuff
cvui::update();
// Show everything on the screen
cv::imshow(WINDOW_NAME, frame);
// Check if ESC key was pressed
if (cv::waitKey(20) == 27) {
break;
}
}
return 0;
}
確保cvui與您的專案正常工作
1、在渲染任何元件之前呼叫初始化函式cvui :: init()。
2、所有元件都被渲染後呼叫cvui :: update()一次。
關於上面程式碼中使用的元件,cvui :: button()函式每次點選按鈕都會返回true,所以你可以方便的在if語句中使用它。 cvui :: printf()函式與標準C printf()函式的工作方式類似,所以您可以使用符號%d和%s輕鬆地在螢幕上呈現文字和數字。 您還可以使用十六進位制值作為0xRRGGBB來選擇文字的顏色,例如 0xFF0000(紅色),0x00FF00(綠色)和0x0000FF(藍色)。
更高階的應用程式
現在讓我們來構建一些更復雜的東西,但是和以前一樣容易。 應用程式將Canny Edge演算法應用於影象,允許使用者啟用/禁用該技術並調整其閾值。
步驟1:基礎
我們首先建立一個沒有UI元素的應用程式。 Canny Edge演算法的使用由布林變數(use_canny)定義,而演算法閾值由兩個整數(low_threshold和high_threshold)定義。 使用這種方法,我們必須重新編譯程式碼,每次我們要啟用/禁用該技術或調整其閾值。
該應用程式的程式碼如下:
#include <opencv2/opencv.hpp>
#define WINDOW_NAME "CVUI Canny Edge"
int main(int argc, const char *argv[])
{
cv::Mat lena = cv::imread("lena.jpg");
cv::Mat frame = lena.clone();
int low_threshold = 50, high_threshold = 150;
bool use_canny = false;
cv::namedWindow(WINDOW_NAME);
while (true) {
// Should we apply Canny edge?
if (use_canny) {
// Yes, we should apply it.
cv::cvtColor(lena, frame, CV_BGR2GRAY);
cv::Canny(frame, frame, low_threshold, high_threshold, 3);
} else {
// No, so just copy the original image to the displaying frame.
lena.copyTo(frame);
}
// Show everything on the screen
cv::imshow(WINDOW_NAME, frame);
// Check if ESC was pressed
if (cv::waitKey(30) == 27) {
break;
}
}
return 0;
}
結果是顯示原始影象(use_canny為false)或顯示檢測到的邊緣(use_canny為true)的應用程式:
步驟2:動態啟用/禁用邊緣檢測
我們通過使用cvui並新增一個複選框來控制use_canny的值來改進工作流程。 使用該方法,使用者可以在應用程式仍在執行時啟用/禁用Canny Edge。 我們新增所需的cvui程式碼並使用cvui :: checkbox函式:
#include <opencv2/opencv.hpp>
#include "cvui.h"
#define WINDOW_NAME "CVUI Canny Edge"
int main(void)
{
cv::Mat lena = cv::imread("lena.jpg");
cv::Mat frame = lena.clone();
int low_threshold = 50, high_threshold = 150;
bool use_canny = false;
// Init a OpenCV window and tell cvui to use it.
cv::namedWindow(WINDOW_NAME);
cvui::init(WINDOW_NAME);
while (true) {
// Should we apply Canny edge?
if (use_canny) {
// Yes, we should apply it.
cv::cvtColor(lena, frame, CV_BGR2GRAY);
cv::Canny(frame, frame, low_threshold, high_threshold, 3);
} else {
// No, so just copy the original image to the displaying frame.
lena.copyTo(frame);
}
// Checkbox to enable/disable the use of Canny edge
cvui::checkbox(frame, 15, 80, "Use Canny Edge", &use_canny);
// Update cvui internal stuff
cvui::update();
// Show everything on the screen
cv::imshow(WINDOW_NAME, frame);
// Check if ESC was pressed
if (cv::waitKey(30) == 27) {
break;
}
}
return 0;
}
單獨這個小的修改已經是測試應用程式而不重新編譯所有內容的時間保護程式了:
根據正在使用的影象可能難以看到呈現的複選框及其標籤。 有白色背景的圖象。 我們可以通過使用cvui :: window()來建立一個視窗來防止這個問題。
cvui在呼叫元件函式時呈現每個元件,因此我們必須在cvui :: checkbox()之前呼叫cvui :: window(),否則視窗將顯示在複選框前面:
#include <opencv2/opencv.hpp>
#include "cvui.h"
#define WINDOW_NAME "CVUI Canny Edge"
int main(void)
{
cv::Mat lena = cv::imread("lena.jpg");
cv::Mat frame = lena.clone();
int low_threshold = 50, high_threshold = 150;
bool use_canny = false;
// Init a OpenCV window and tell cvui to use it.
cv::namedWindow(WINDOW_NAME);
cvui::init(WINDOW_NAME);
while (true) {
// Should we apply Canny edge?
if (use_canny) {
// Yes, we should apply it.
cv::cvtColor(lena, frame, CV_BGR2GRAY);
cv::Canny(frame, frame, low_threshold, high_threshold, 3);
} else {
// No, so just copy the original image to the displaying frame.
lena.copyTo(frame);
}
// Render the settings window to house the UI
cvui::window(frame, 10, 50, 180, 180, "Settings");
// Checkbox to enable/disable the use of Canny edge
cvui::checkbox(frame, 15, 80, "Use Canny Edge", &use_canny);
// Update cvui internal stuff
cvui::update();
// Show everything on the screen
cv::imshow(WINDOW_NAME, frame);
// Check if ESC was pressed
if (cv::waitKey(30) == 27) {
break;
}
}
return 0;
}
第3步:調整閾值
現在是時候允許使用者在執行時選擇low_threashold和high_threashold的值了。 由於這些引數可以在一個時間間隔內變化,我們可以使用cvui :: trackbar()來建立一個trackbar:
#include <opencv2/opencv.hpp>
#include "cvui.h"
#define WINDOW_NAME "CVUI Canny Edge"
int main(void)
{
cv::Mat lena = cv::imread("lena.jpg");
cv::Mat frame = lena.clone();
int low_threshold = 50, high_threshold = 150;
bool use_canny = false;
// Init a OpenCV window and tell cvui to use it.
cv::namedWindow(WINDOW_NAME);
cvui::init(WINDOW_NAME);
while (true) {
// Should we apply Canny edge?
if (use_canny) {
// Yes, we should apply it.
cv::cvtColor(lena, frame, CV_BGR2GRAY);
cv::Canny(frame, frame, low_threshold, high_threshold, 3);
} else {
// No, so just copy the original image to the displaying frame.
lena.copyTo(frame);
}
// Render the settings window to house the UI
cvui::window(frame, 10, 50, 180, 180, "Settings");
// Checkbox to enable/disable the use of Canny edge
cvui::checkbox(frame, 15, 80, "Use Canny Edge", &use_canny);
// Two trackbars to control the low and high threshold values
// for the Canny edge algorithm.
cvui::trackbar(frame, 15, 110, 165, &low_threshold, 5, 150);
cvui::trackbar(frame, 15, 180, 165, &high_threshold, 80, 300);
// Update cvui internal stuff
cvui::update();
// Show everything on the screen
cv::imshow(WINDOW_NAME, frame);
// Check if ESC was pressed
if (cv::waitKey(30) == 27) {
break;
}
}
return 0;
}
cvui :: trackbar()函式接受指定trackbar允許的最小值和最大值的引數。 在上例中,low_threshold分別為[5,150],high_threshold分別為[80,130]。
其結果是一個完全互動式的應用程式,允許使用者快速輕鬆地探索Canny Edge引數的調整,以及啟用/禁用它的使用:
下面是這個應用程式的完整程式碼,沒有評論。 它顯示你不需要許多程式碼行來為你的應用程式生成一個最小的(和有用的)UI:
#include <opencv2/opencv.hpp>
#include "cvui.h"
#define WINDOW_NAME "CVUI Canny Edge"
int main(void)
{
cv::Mat lena = cv::imread("lena.jpg");
cv::Mat frame = lena.clone();
int low_threshold = 50, high_threshold = 150;
bool use_canny = false;
cv::namedWindow(WINDOW_NAME);
cvui::init(WINDOW_NAME);
while (true) {
if (use_canny) {
cv::cvtColor(lena, frame, CV_BGR2GRAY);
cv::Canny(frame, frame, low_threshold, high_threshold, 3);
} else {
lena.copyTo(frame);
}
cvui::window(frame, 10, 50, 180, 180, "Settings");
cvui::checkbox(frame, 15, 80, "Use Canny Edge", &use_canny);
cvui::trackbar(frame, 15, 110, 165, &low_threshold, 5, 150);
cvui::trackbar(frame, 15, 180, 165, &high_threshold, 80, 300);
cvui::update();
cv::imshow(WINDOW_NAME, frame);
if (cv::waitKey(30) == 27) {
break;
}
}
return 0;
}
結論
cvui lib是根據需要建立的。 這並不是為了開發複雜的圖形應用程式而成為一個全面的解決方案。 這很簡單,有很多方面的限制。 然而,它是實用的,易於使用,可以節省你幾個小時的挫折和繁瑣的工作。
如果你喜歡cvui,不要忘記在Github上檢視它的儲存庫,它的文件和所有示例應用程式(可以用cmake構建)。