目录

1 cvui的使用

1.1 如何在您的应用程序中添加cvui

1.2 基本的“hello world”应用程序

2 更高级的应用

3 代码

4 参考


有很多很棒的GUI库,例如Qt和imgui,可以与OpenCV一起使用,允许您在运行时调整参数。但是,在某些情况下,您可能没有(或不希望)此类库的依赖关系,例如,您没有使用Qt支持编译OpenCV,或者您无法使用OpenGL。在这种情况下,您只需要一种快速,轻松的方式来创建GUI来调整算法。

这就是cvui的目的。它是一个基于OpenCV绘图基元构建的跨平台GUI库,仅需使用头文件就可以搭建。除了OpenCV本身(您可能已经在使用)之外,它没有依赖关系。Cvui在C++下通过.h文件实现全部功能,在Python下直接提供.py文件。本文仅仅讲述cvui在C++下的构建,python通常用的少。

cvui遵循一行代码就可以在屏幕上产生一个UI组件的规则。cvui具有友好的C类API,没有类/对象和多个组件,例如,跟踪栏,按钮,文字等等。cvui界面如下所示,

cvui相关使用见:

https://dovyski.github.io/cvui/

工程文件及下载见:

https://github.com/Dovyski/cvui

1 cvui 的使用

1.1 如何在您的应用程序中添加cvui

为了使用cvui,你只需要把cvui.h文件放到工程目录下,包含头文件就行了。但是对于比较新的版本,本文用的是cvui2.7版本则需要在cvui.h前加入

define CVUI_IMPLEMENTATION

具体如下所示:

#include <opencv2/opencv.hpp>
#define CVUI_IMPLEMENTATION
#include "cvui.h"

1.2 基本的“hello world”应用程序

让我们通过创建一个带有一些UI交互功能的简单hello-

world应用程序来了解cvui的功能。该应用程序包含一个按钮和一个可视界面,可视界面显示该按钮被单击的次数。代码如下:

#include <opencv2/opencv.hpp>
#define CVUI_IMPLEMENTATION
#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与您的项目正常工作:

cvui::init()在创建任何组件之前调用初始化函数。

cvui::update() 在创建所有组件后调用一次。

关于上面代码中使用的组件, 每次单击按钮时cvui::button()

函数都会返回true,因此您可以方便地在if语句中使用它。该cvui::printf()功能与标准C功能的工作方式类似printf(),%d and

%s.分别表示文字和数字。您还可以使用十六进制值选择文本的颜色0xRRGGBB,例如0xFF0000(红色),0x00FF00(绿色)和0x0000FF(蓝色)。具体看代码就知道了。

2 更高级的应用

现在让我们构建一些更复杂的东西,但就像以前一样容易。该应用程序将Canny

Edge算法应用于图像,允许用户启用/禁用该技术并调整其阈值。Canny边缘算法详细见:

https://en.wikipedia.org/wiki/Canny_edge_detector

(1) 基础

我们首先创建一个没有UI元素的应用程序。Canny

Edge算法的使用由布尔变量(use_canny)定义,而算法阈值由两个整数(low_threshold和high_threshold)定义。使用这种方法,我们必须在每次要启用/禁用canny或调整low_threshold和high_threshold时重新编译代码。

该部分代码如下:

#include <opencv2/opencv.hpp>
#define CVUI_IMPLEMENTATION
#include "cvui.h" #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>
#define CVUI_IMPLEMENTATION
#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()

用来容纳复选框的窗口来防止这个问题。代码如下:

#include <opencv2/opencv.hpp>
#define CVUI_IMPLEMENTATION
#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()用来创建一个滑动窗口栏。代码如下:

#include <opencv2/opencv.hpp>
#define CVUI_IMPLEMENTATION
#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() 函数接受指定轨迹栏允许的最小值和最大值的参数。在上面的例子中,它们分别是[5,150]

low_threshold和[80,300] high_threshold。结果是一个完全交互式的应用程序,允许用户快速,轻松地探索Canny Edge参数的调整,以及启用/禁用它的使用。效果如图所示:

3 代码

以下是此应用程序的完整代码,您不需要多行代码就可以为您的应用程序生成最小(且有用)的UI界面。该cvui并非旨在成为复杂图形应用程序开发的完整解决方案。它在很多方面都很简单并且有限。但是,它实用,易于使用,可以为您节省数小时的挫折和繁琐的工作。如果实际工程应用推荐QT而不是MFC(个人观点)。

本文所有代码和cvui头文件见:

https://github.com/luohenyueji/OpenCV-Practical-Exercise

hello world代码:

#include "pch.h"
#include <opencv2/opencv.hpp>
#define CVUI_IMPLEMENTATION
#include "cvui.h" //cvui界面名字
#define WINDOW_NAME "CVUI Hello World!" int main()
{
cv::Mat frame = cv::Mat(200, 500, CV_8UC3);
int count = 0; // Init a OpenCV window and tell cvui to use it.
//创建cvui窗口
cv::namedWindow(WINDOW_NAME);
//初始化窗口
cvui::init(WINDOW_NAME); //必须要用无限循环,每次变动cvui会生成新的一个图像,看起来界面变化了
while (true)
{
// Fill the frame with a nice color 创建程序窗口背景图像
frame = cv::Scalar(49, 52, 49); // Buttons will return true if they were clicked
//在背景图像(110,80)点添加按钮(按钮的左上角顶点坐标,所有的cvui坐标都是左上角顶点),按钮显示名字为“hello,world”
//当按钮被点击时,会返回true
if (cvui::button(frame, 110, 80, "Hello, world!"))
{
// The button was clicked, so let's increment our counter.
//统计按钮被点击次数
count++;
} // Sometimes you want to show text that is not that simple, e.g. strings + numbers.
// You can use cvui::printf for that. It accepts a variable number of parameter, pretty
// much like printf does.
// Let's show how many times the button has been clicked.
//在frame(250,90)点添加一个文本框,文本框字体大小为0.5,颜色为0xff0000
//显示的内容为"Button click count: %d", count
cvui::printf(frame, 250, 90, 0.5, 0xff0000, "Button click count: %d", count); // This function must be called *AFTER* all UI components. It does
// all the behind the scenes magic to handle mouse clicks, etc.
//更新cvui界面
cvui::update(); // Show everything on the screen
//把所有的东西显示出来
cv::imshow(WINDOW_NAME, frame);
// Check if ESC key was pressed
//ESC退出循环
if (cv::waitKey(20) == 27)
{
break;
}
} return 0;
}

canny算子代码:

#include "pch.h"
#include <opencv2/opencv.hpp>
#define CVUI_IMPLEMENTATION
#include "cvui.h" //cvui界面名字
#define WINDOW_NAME "CVUI Canny Edge" int main()
{
//读图像
cv::Mat lena = cv::imread("lena.jpg");
//背景图像
cv::Mat frame = lena.clone();
//canny阈值
int low_threshold = 50, high_threshold = 150;
//是否使用边缘检测
bool use_canny = false; // Init a OpenCV window and tell cvui to use it.
// If cv::namedWindow() is not used, mouse events will
// not be captured by cvui.
//创建cvui窗口
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);
cv::cvtColor(frame, frame, CV_GRAY2BGR);
}
else
{
// No, so just copy the original image to the displaying frame.
//直接显示图像
lena.copyTo(frame);
} // Render the settings window to house the checkbox
// and the trackbars below.
//debug下可能有bug
//主要问题在于cvui.h,void window函数问题,解决办法aOverlay = theBlock.where.clone();
//在frame(10,50)处设置一个长宽180,180的名为Settings窗口
cvui::window(frame, 10, 50, 180, 180, "Settings"); // Checkbox to enable/disable the use of Canny edge
//在frame(15,80)点添加复选框,复选框文本名"Use Canny Edge",调整参数use_canny
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
//滑动条控制最低分割阈值
//在frame(15,110)点添加滑动条,滑动条宽165,控制值low_threshold,值变化范围5到150
cvui::trackbar(frame, 15, 110, 165, &low_threshold, 5, 150);
//滑动条控制最高分割阈值
cvui::trackbar(frame, 15, 180, 165, &high_threshold, 80, 300); // This function must be called *AFTER* all UI components. It does
// all the behind the scenes magic to handle mouse clicks, etc.
//更新ui界面
cvui::update(); // Show everything on the screen
//把所有的东西显示出来
cv::imshow(WINDOW_NAME, frame); // Check if ESC was pressed
//ESC退出
if (cv::waitKey(30) == 27)
{
break;
}
} return 0;
}

4 参考

https://www.learnopencv.com/cvui-gui-lib-built-on-top-of-opencv-drawing-primitives/

[OpenCV实战]28 基于OpenCV的GUI库cvui的更多相关文章

  1. [OpenCV实战]48 基于OpenCV实现图像质量评价

    本文主要介绍基于OpenCV contrib中的quality模块实现图像质量评价.图像质量评估Image Quality Analysis简称IQA,主要通过数学度量方法来评价图像质量的好坏. 本文 ...

  2. [OpenCV实战]47 基于OpenCV实现视觉显著性检测

    人类具有一种视觉注意机制,即当面对一个场景时,会选择性地忽略不感兴趣的区域,聚焦于感兴趣的区域.这些感兴趣的区域称为显著性区域.视觉显著性检测(Visual Saliency Detection,VS ...

  3. [OpenCV实战]38 基于OpenCV的相机标定

    文章目录 1 什么是相机标定? 2 图像形成几何学 2.1 设定 2.1.1 世界坐标系 2.1.2 相机坐标系 2.1.3 图像坐标系 2.2 图像形成方法总结 3 基于OpenCV的相机标定原理 ...

  4. [OpenCV实战]45 基于OpenCV实现图像哈希算法

    目前有许多算法来衡量两幅图像的相似性,本文主要介绍在工程领域最常用的图像相似性算法评价算法:图像哈希算法(img hash).图像哈希算法通过获取图像的哈希值并比较两幅图像的哈希值的汉明距离来衡量两幅 ...

  5. [OpenCV实战]26 基于OpenCV实现选择性搜索算法

    目录 1 背景 1.1 目标检测与目标识别 1.2 滑动窗口算法 1.3 候选区域选择算法 2 选择性搜索算法 2.1 什么是选择性搜索? 2.2 选择性搜索相似性度量 2.3 结果 3 代码 4 参 ...

  6. [OpenCV实战]51 基于OpenCV实现图像极坐标变换与逆变换

    在图像处理领域中,经常通过极坐标与笛卡尔直角坐标的互转来实现图像中圆形转为方形,或者通过极坐标反变换实现方形转圆形.例如钟表的表盘,人眼虹膜,医学血管断层都需要用到极坐标变换来实现圆转方. 文章目录 ...

  7. [OpenCV实战]11 基于OpenCV的二维码扫描器

    目录 1 二维码(QRCode)扫描 2 结果 3 参考 在这篇文章中,我们将看到如何使用OpenCV扫描二维码.您将需要OpenCV3.4.4或4.0.0及更高版本来运行代码. 1 二维码(QRCo ...

  8. [OpenCV实战]15 基于深度学习的目标跟踪算法GOTURN

    目录 1 什么是对象跟踪和GOTURN 2 在OpenCV中使用GOTURN 3 GOTURN优缺点 4 参考 在这篇文章中,我们将学习一种基于深度学习的目标跟踪算法GOTURN.GOTURN在Caf ...

  9. [OpenCV实战]5 基于深度学习的文本检测

    目录 1 网络加载 2 读取图像 3 前向传播 4 处理输出 3结果和代码 3.1结果 3.2 代码 参考 在这篇文章中,我们将逐字逐句地尝试找到图片中的单词!基于最近的一篇论文进行文字检测. EAS ...

随机推荐

  1. 齐博x1会员中心如何加标签

    点击查看大图 轻松几步,你可以做会员中心的界面 这是调用文章的 代码如下:会员中心的标签跟前台使用方法是一模一样的, 关键之处就是多了一项动态参数 union="uid" 在以往, ...

  2. 配置文件yaml和ini

    前言 本文主要介绍配置文件yaml和ini的读取. 一.yaml文件 YAML是一个可读性高,易于理解,用来表达数据序列化的格式.语法与python的语法类似.文件后缀  .yaml 下面是yaml文 ...

  3. VMware Fusion配置NAT静态IP

    前言 本主机 CentOS8.2 Mac VMware Fusion 我们在使用虚拟机的时候,经常遇到这样的问题,我们会换地方,IP 会变化,如果虚拟机使用桥接的方式,那么很多与 IP 相关的服务都会 ...

  4. JS学习笔记 (四) 数组进阶

    1.基本知识 1.数组是值的有序集合.每个值叫做一个元素,而每个元素在数组中的位置称为索引,以数字表示,以0开始. 2.数组是无类型的.数组元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的 ...

  5. Codeforces Round #830 (Div. 2)D2. Balance (Hard version)(数据结构)

    题目链接 题目大意 维护一个集合的mex,每次有三种操作: '+' x:将数 x 插入集合中 '-' x:将数 x 移除集合 '?' k:询问满足mex的数是k的倍数 既集合中未出现的数中最小的数可以 ...

  6. Springboot结构梳理

    springboot各层关系梳理 1.基本流程 View层-->Controller层(响应用户请求):导入 service层,调用你service方法,controller通过接受前端传来的参 ...

  7. 云原生之旅 - 14)遵循 GitOps 实践的好工具 ArgoCD

    前言 Argo CD 是一款基于 kubernetes 的声明式的Gitops 持续部署工具. 应用程序定义.配置和环境都是声明式的,并受版本控制 应用程序部署和生命周期管理都是自动化的.可审计的,并 ...

  8. 原来用 MySQL 也可以做全文检索

    我是风筝,公众号「古时的风筝」,专注于 Java技术 及周边生态. 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面. 有朋友聊到他们的系统中要接入全 ...

  9. CSP 记

    csp 开考建好文件夹编译器不能用搞了半天换了台电脑 四道题看完一个小时过去了 第一题不会正解写了部分分还有点悬 第二题写暴力因为一个小错误调了半天 看时间不多了已经有点慌了 也没想正解直接开了下一题 ...

  10. C温故补缺(一):数据类型和基本类型占位

    数据类型 基本类型:就是算术类型,包括整型和实型 枚举类型:一组离散的整数 void类型:无可用值类型 派生类型:指针(*),数组([]),结构体(struct),共用体(union),函数(fun( ...