官网文档链接:https://dovyski.github.io/cvui/advanced-multiple-windows/
多 OpenCV 窗口 (Multiple OpenCV windows)
如果项目使用了多个 OpenCV 窗口,例如,显示中间结果,而且那些窗口有 cvui 组件,用户需要执行一些额外的步骤来确保 UI 组件正常工作。以下部分展示了如何在多个窗口中使用 cvui 组件。
1. 创建窗口 (Create the windows)
cvui 使用 OpenCV 中的 cv::setMouseCallback() 来监视每个窗口上的交互,因此在调用 cvui::init() 之前,应用程序使用的窗口必须存在。这样,cvui 就可以对它们中的每一个设置回调。
最简单的方法是让 cvui 在 cvui::init() 中创建窗口。下面是一个使用窗口名数组调用 cvui::init() 的示例,这样 cvui 将自动创建窗口:
#define WINDOW1_NAME "Window 1"
#define WINDOW2_NAME "Windows 2"
#define WINDOW3_NAME "Windows 3"
#define WINDOW4_NAME "Windows 4"
#include <opencv2/opencv.hpp>
#define CVUI_IMPLEMENTATION
#include "cvui.h"
int main() {
// Tell cvui to init and create 4 windows.
const cv::String windows[] = { WINDOW1_NAME, WINDOW2_NAME, WINDOW3_NAME, WINDOW4_NAME };
cvui::init(windows, 4);
while(true) {
// your logic here
}
}
1.1 创建自己的窗口 ( (Optional) Create your own windows)
如果要创建自己的窗口,请确保在调用 cvui::init() 之前使用 cv::namedWindow() 来创建它们。
当使用 cvui::init() 初始化 cvui 时,仍然需要指定窗口的名称(这将是默认的窗口),然后为 cvui 要监视的每个后续窗口调用 cvui::watch()。
#define CVUI_IMPLEMENTATION
#define CVUI_DISABLE_COMPILATION_NOTICES
#include "cvui.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#define WINDOW1_NAME "Windows 1"
#define WINDOW2_NAME "Windows 2"
#define WINDOW3_NAME "Windows 3"
#define WINDOW4_NAME "Windows 4"
int main(int argc, char** argv)
{
// Create OpenCV windows
cv::namedWindow(WINDOW1_NAME);
cv::namedWindow(WINDOW2_NAME);
cv::namedWindow(WINDOW3_NAME);
cv::namedWindow(WINDOW4_NAME);
// Init cvui, using WINDOW1_NAME as the default window.
// The last parameter is false, informing cvui to not
// create any new window.
cvui::init(WINDOW1_NAME, -1, false);
// Tell cvui to monitor the windows,
// otherwise UI interactions will not work on them.
cvui::watch(WINDOW2_NAME);
cvui::watch(WINDOW3_NAME);
cvui::watch(WINDOW4_NAME);
while (true)
{
// your logic here
}
return 0;
}
2. 指定并渲染 cvui 窗口 (Tell cvui about the window, then render it)
当在多个窗口中使用 cvui 组件时,需要通知 cvui 这些组件属于哪个窗口。这样做的方法是将 cvui::context(NAME) 和 cvui::imshow(NAME, frame) 对之间的所有 cvui 组件调用封装起来,其中 NAME 是正在处理的窗口的名称。
下面的示例演示了如何在两个不同的窗口(例如:“window1” 和 “window2”)中渲染一些组件,假设这些窗口之前已经创建并正确初始化了:
// Create a frame for the windows
cv::Mat frame = cv::Mat(200, 500, CV_8UC3);
cvui::context("window1"); // Inform cvui that the components to be rendered from now one belong to "window1"
cvui::text(frame, 10, 50, "Hello, window1");
cvui::imshow("window1", frame); // update cvui interactions on window "window1" and show it
cvui::context("window1"); // Inform cvui that the components to be rendered from now one belong to "window2"
cvui::text(frame, 5, 5, "Hey, window2");
cvui::imshow("window1", frame); // update cvui interactions on window "window2"
问题
完整代码
#define CVUI_IMPLEMENTATION
#define CVUI_DISABLE_COMPILATION_NOTICES
#include "cvui.h"
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#define WINDOW1_NAME "Windows 1"
#define WINDOW2_NAME "Windows 2"
#define WINDOW3_NAME "Windows 3"
#define WINDOW4_NAME "Windows 4"
int main(int argc, char** argv)
{
cv::namedWindow("window1");
cv::namedWindow("window2");
cvui::init("window1", -1, false);
// Create a frame for the windows
cv::Mat frame = cv::Mat(200, 500, CV_8UC3);
frame = cv::Scalar(100, 100, 100);
cvui::context("window1"); // Inform cvui that the components to be rendered from now one belong to "window1"
cvui::text(frame, 10, 50, "Hello, window1");
cvui::imshow("window1", frame); // update cvui interactions on window "window1" and show it
cvui::context("window2"); // Inform cvui that the components to be rendered from now one belong to "window2"
cvui::text(frame, 5, 5, "Hey, window2");
cvui::imshow("window2", frame); // update cvui interactions on window "window2" and show it
cv::waitKey(500);
cvui::watch("window1");
cv::waitKey(0);
cvui::watch("window2");
cv::waitKey(0);
return 0;
}
运行结果
如图所示,window2 中也包含了 window1 的组件,不知所以。
2.1 精细控制更新和显示 ((Optional) Fine control update and show)
用户可以忽略 cvui::imshow(),这是 cvui 增强版的 cv::imshow(),但用户需要控制每个窗口的更新和显示,例如,通过自己调用 cv::imshow(),可以实现
在这种情况下,可以将所有 cvui 组件调用封装在一对 cvui::context(NAME) 和 cvui::update(NAME) 之间,其中 NAME 是正在处理的窗口的名称。
注意:实际上,cvui::imshow() 所做的就是调用 cvui::update(),然后调用 cv::imshow(),免去用户自己调用这一步。
下面的示例中演示了如何在两个不同的窗口(例如 “window1” 和 “window2”)中分别更新和呈现一些组件,前提是这些窗口之间已经创建并正确初始化了:
// Create a frame for this window and fill it with a nice color
cv::Mat frame = cv::Mat(200, 500, CV_8UC3);
cvui::context("window1"); // Inform cvui that the components to be rendered from now one belong to "window1"
cvui::text(frame, 10, 50, "Hello, window1");
cvui::update("window1"); // update cvui interactions on window "window1"
// Show the content of window "window1" on the screen
cvui::imshow("window1", frame);
cvui::context("window1"); // Inform cvui that the components to be rendered from now one belong to "window2"
cvui::text(frame, 5, 5, "Hey, window2");
cvui::update("window1"); // update cvui interactions on window "window2"
// Show the content of window "window2" on the screen
cvui::imshow("window2", frame);