[OpenCV实战]28 基于OpenCV的GUI库cvui
目录
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的更多相关文章
- [OpenCV实战]48 基于OpenCV实现图像质量评价
本文主要介绍基于OpenCV contrib中的quality模块实现图像质量评价.图像质量评估Image Quality Analysis简称IQA,主要通过数学度量方法来评价图像质量的好坏. 本文 ...
- [OpenCV实战]47 基于OpenCV实现视觉显著性检测
人类具有一种视觉注意机制,即当面对一个场景时,会选择性地忽略不感兴趣的区域,聚焦于感兴趣的区域.这些感兴趣的区域称为显著性区域.视觉显著性检测(Visual Saliency Detection,VS ...
- [OpenCV实战]38 基于OpenCV的相机标定
文章目录 1 什么是相机标定? 2 图像形成几何学 2.1 设定 2.1.1 世界坐标系 2.1.2 相机坐标系 2.1.3 图像坐标系 2.2 图像形成方法总结 3 基于OpenCV的相机标定原理 ...
- [OpenCV实战]45 基于OpenCV实现图像哈希算法
目前有许多算法来衡量两幅图像的相似性,本文主要介绍在工程领域最常用的图像相似性算法评价算法:图像哈希算法(img hash).图像哈希算法通过获取图像的哈希值并比较两幅图像的哈希值的汉明距离来衡量两幅 ...
- [OpenCV实战]26 基于OpenCV实现选择性搜索算法
目录 1 背景 1.1 目标检测与目标识别 1.2 滑动窗口算法 1.3 候选区域选择算法 2 选择性搜索算法 2.1 什么是选择性搜索? 2.2 选择性搜索相似性度量 2.3 结果 3 代码 4 参 ...
- [OpenCV实战]51 基于OpenCV实现图像极坐标变换与逆变换
在图像处理领域中,经常通过极坐标与笛卡尔直角坐标的互转来实现图像中圆形转为方形,或者通过极坐标反变换实现方形转圆形.例如钟表的表盘,人眼虹膜,医学血管断层都需要用到极坐标变换来实现圆转方. 文章目录 ...
- [OpenCV实战]11 基于OpenCV的二维码扫描器
目录 1 二维码(QRCode)扫描 2 结果 3 参考 在这篇文章中,我们将看到如何使用OpenCV扫描二维码.您将需要OpenCV3.4.4或4.0.0及更高版本来运行代码. 1 二维码(QRCo ...
- [OpenCV实战]15 基于深度学习的目标跟踪算法GOTURN
目录 1 什么是对象跟踪和GOTURN 2 在OpenCV中使用GOTURN 3 GOTURN优缺点 4 参考 在这篇文章中,我们将学习一种基于深度学习的目标跟踪算法GOTURN.GOTURN在Caf ...
- [OpenCV实战]5 基于深度学习的文本检测
目录 1 网络加载 2 读取图像 3 前向传播 4 处理输出 3结果和代码 3.1结果 3.2 代码 参考 在这篇文章中,我们将逐字逐句地尝试找到图片中的单词!基于最近的一篇论文进行文字检测. EAS ...
随机推荐
- Windows Socket 接口简介
Windows Socket接口是Windows下网络编程的接口,在介绍Windows Socket接口之前,首先要简单介绍一下TCP/IP协议和描述网络系统架构的 OSI模型,以及TCP/IP模型 ...
- Lombok好用是好用,就是容易踩坑,这份避坑指南请查收
序言 各位好啊,我是会编程的蜗牛,作为java开发者,我们平常在开发过程中,总是希望能够尽量少敲代码.这一方面,当然是为了偷懒,另一方面,当然也是为了代码看起来更加简洁一点,不断往编程规范上靠.然后其 ...
- centos7搭建安装loki、promtail、Grafana日志系统
loki.promtail.Grafana安装包 链接:https://pan.baidu.com/s/1vkSa_KYrXM0UEI8i42KdaA 提取码:4d4q 如果安装失败或者下载速度慢可以 ...
- HTML元素大全(2)-表单
01.<form>表单 <form> 表单是比较重要的HTML元素,块元素,主要作用是向服务端提交数据.结合表单元素input使用,通过内部的button按钮提交(type=& ...
- SQL的表的连接Left Join / Right Join /inner join相关
Left Join / Right Join /inner join相关关于左连接和右连接总结性的一句话:左连接where只影向右表,右连接where只影响左表.Left Joinselect * f ...
- 小菜鸡的学习笔记---<正则表达式(1)>
正则表达式学习笔记(1) (纯新手学习笔记,大佬绕路 QAQ) 一.简介 正则表达式就是一种文本模式用来匹配一系列满足特定条件的字符串,可以对比一下数学里面的表达式,比如我们要用一个表达式表示一串数字 ...
- Django开发汇总
基本配置 # 设置数据库为使用的mysql DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'libr ...
- (译)TDD(测试驱动开发)的5个步骤
原文:5 steps of test-driven development https://developer.ibm.com/articles/5-steps-of-test-driven-deve ...
- C#通过unsafe来操作指针
这里不介绍unsafe的理论,这里单单介绍它的用法.如果要了解的更具体,可以看这篇大神的博文:C#通过指针操作图像 先从一个很简单的例子介绍: private void TestInptr() { u ...
- go get 报错:dial tcp 142.251.43.17:443: i/o timeout
自动下载 go env -w GO111MODULE=on 设置环境为国内代理 go env -w GOPROXY=https://goproxy.cn,direct 注:go 版本需要支持 mod