摘要:

我学习openCV3看的是《学习openCV3》这本书,很厚的一本,不知道是不是因为自己看的还不是很多,个人觉得里面的有些重要函数讲的不是很详细,比如createTrackbar()这个函数,这个函数出现在这本书的第三个实例程序,书中只是说明了这是一个创建滚动条的程序,然而对里面的参数讲解以及与他相对应的回调函数讲解都不是很完美,因此我就打开了它的定义以及到网上找了一些博主的文章来学习,但是感觉讲的都不是很全,下面我结合自己的实验加上自己的理解,讲解一下我对这个函数的看法。

函数说明:

createTrackbar()函数的函数原型为:

CV_EXPORTS int createTrackbar(const String& trackbarname, const String& winname,int* value, int count,TrackbarCallback onChange = 0, void* userdata = 0);

trackbarname:这个参数用来给这个滚动条取一个名字;

winname:这个参数用来指定你要吧这个滚动条用到那个窗口上;

value:这个参数用来设置滑块初始值位置,同时记录滑块以后的位置;

count:这个参数用来指定滚动条可以滚动的最大值;

onChange:这个参数可以理解为一个函数类型的变量(当然这样说感觉有点怪),用来接收回调函数函数名的,默认值为0;

userdata:这个变量这个参数是用户传给回调函数的数据,用来处理轨迹条事件,默认值为0。

这里面一共有6个参数,其中value这个参数容易理解有偏差,onchange,userdata这俩参数可能难以理解;

下面先说我对value这个参数的看法:

value这个参数首先要知道它是用来给滑块位置一个初始值的,也就是告诉我们滑块最初位置在哪,而不是滑块可以滑动范围的最小值,滑块可以滑动的范围永远都是[0, count],count即为第四个参数,然后还要理解一个概念,代码运行过程中,不是value的值影响滑块的位置,而是由于用户对滑块的移动改变了value的值,也就是说value是被动的。

然后在说对onChange该参数的理解:

首先我们看一下回调函数的函数原型:

void (*TrackbarCallback)(int pos, void* userdata);

当我们没看回调函数原型时可能很难理解有些代码中定义回调函数时为什么必须要有那俩参数,当看了回调函数原型后我相信有C++基础的人也都能明白了,那么我来说说回调函数和createTrackbar()函数的关系;首先,我们看到回调函数和createTrackbar函数都有一个形参名为userdata,那这是不是巧合呢?答案当然不是,你可以这样理解,回调函数是一个必须依托于createTrackbar()函数而使用的函数,他不能单独拿来使用,那他的两个形参是怎么用的呢?首先第一个形参pos,它表示的是当前滑块所在的位置,它的值是createTrackbar()传给他的,也就是createTrackbar()形参value的值,这个传输过程是在createTrackbar()内部实现的,无需深究,然后回调函数形参userdata的值就是通过createTrackbar()的形参userdata直接得到的,所以createTrackbar()的形参userdata其实就是专门给回调函数准备的。

函数的使用上的问题:

createTrackbar()在使用上可能也会比较神奇,比如说你可能看到如下程序:

  1. #include <iostream>
  2. #include <opencv2/core/core.hpp>
  3. #include <opencv2/highgui/highgui.hpp>
  4. #include <imgproc.hpp>
  5.  
  6. using namespace std;
  7. using namespace cv;
  8.  
  9. //TrackBar发生改变的回调函数
  10. void onChangeTrackBar(int pos, void* userdata);
  11.  
  12. //主函数
  13. int main()
  14. {
  15. //trackbar的值
  16. int posTrackBar = ;
  17. //trackbar的最大值
  18. int maxValue = ;
  19.  
  20. //读入图像,以灰度图形式读入
  21. Mat img = imread("F:\\图片\\timg.jpg", );
  22.  
  23. //新建窗口
  24. namedWindow("二值化");
  25. imshow("二值化", img);
  26.  
  27. //创建trackbar,我们把img作为数据传进回调函数中
  28. createTrackbar("pos", "二值化", &posTrackBar, maxValue, onChangeTrackBar, &img);
  29.  
  30. waitKey();
  31.  
  32. return ;
  33. }
  34.  
  35. // 回调函数
  36. void onChangeTrackBar(int pos, void* usrdata)
  37. {
  38. // 强制类型转换
  39. Mat src = *(Mat*)(usrdata);
  40. Mat dst;
  41.  
  42. // 二值化
  43. threshold(src, dst, pos, , );
  44. imshow("二值化", dst);
  45. }

上面这个是一个很简单的用于图像二值化处理的代码,当你运行它时你会神奇的发现,这里面没有一个循环,但是你却可以一直滑动滚动条的滑块,而且图像会出现相应的变化,如图滑块到不同位置的效果:

这里其实是靠createTrackbar事件处理得到的,学过一点计算机的人就可以理解为该函数其实一直运行在后台检测是否有滑块移动这种中断产生,然后当你移动滑块时就会触发中断,这时回调函数就相当于中断服务函数来处理中断(不完全准确但是可以这么理解,就像牛顿的经典定律,不是完全准确的描述这个世界,但是在宏观层面来说,用来理解世界是很好的定律)。

结语:

以上全是我个人通过实验验证过的,如果有什么不对的地方,欢迎大家评论区指出。最后附上一些测试用代码:

视频的连续播放,进度可调:

  1. #include <opencv.hpp>
  2. #include<iostream>
  3.  
  4. using namespace std;
  5.  
  6. int g_slider_position = ;
  7. int g_run = , g_dontset = ;
  8. cv::VideoCapture g_cap;
  9.  
  10. void onTrackbarSlide(int pos, void *) {
  11. g_cap.set(cv::CAP_PROP_POS_FRAMES, pos);
  12. if (!g_dontset) {
  13. g_run = ;
  14. }
  15.  
  16. g_dontset = ;
  17. }
  18.  
  19. int main() {
  20. cv::namedWindow("show_video", );
  21. g_cap.open("F:\\图片\\123.mp4");
  22. int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);
  23. int tmpw = (int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH);
  24. int tmph = (int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT);
  25. cout << "Video has" << frames << "frames of dimensions(" << tmpw << "," << tmph << ")." << endl;
  26. cv::createTrackbar("Position", "show_video", &g_slider_position, frames, onTrackbarSlide);
  27. cv::Mat frame;
  28. while () {
  29. if (g_run != ) {
  30. g_cap >> frame;
  31. if (frame.empty()) {
  32. break;
  33. }
  34. int current_pos = (int)g_cap.get(cv::CAP_PROP_POS_FRAMES);
  35. g_dontset = ;
  36.  
  37. cv::setTrackbarPos("Position", "show_video", current_pos);
  38. cv::imshow("show_video", frame);
  39.  
  40. g_run = -;
  41. }
  42. char c = (char)cv::waitKey();
  43. if (c == 's') {
  44. g_run = ;
  45. cout << "Single step,run = " << g_run << endl;
  46. }
  47. if (c == 'r') {
  48. g_run = -;
  49. cout << "Run mode,run" << g_run << endl;
  50. }
  51. if (c == ) {
  52. cv::destroyWindow("show_video");
  53. break;
  54. }
  55. }
  56. cv::destroyWindow("show_video");
  57. return ;
  58. }

计算机视觉(二)-opencv之createTrackbar()详解的更多相关文章

  1. Hadoop Mapreduce分区、分组、二次排序过程详解[转]

    原文地址:Hadoop Mapreduce分区.分组.二次排序过程详解[转]作者: 徐海蛟 教学用途 1.MapReduce中数据流动   (1)最简单的过程:  map - reduce   (2) ...

  2. (原创)LAMP搭建之二:apache配置文件详解(中英文对照版)

    LAMP搭建之二:apache配置文件详解(中英文对照版) # This is the main Apache server configuration file. It contains the # ...

  3. Velocity魔法堂系列二:VTL语法详解

    一.前言 Velocity作为历史悠久的模板引擎不单单可以替代JSP作为Java Web的服务端网页模板引擎,而且可以作为普通文本的模板引擎来增强服务端程序文本处理能力.而且Velocity被移植到不 ...

  4. Python学习二:词典基础详解

    作者:NiceCui 本文谢绝转载,如需转载需征得作者本人同意,谢谢. 本文链接:http://www.cnblogs.com/NiceCui/p/7862377.html 邮箱:moyi@moyib ...

  5. Zookeeper系列二:分布式架构详解、分布式技术详解、分布式事务

    一.分布式架构详解 1.分布式发展历程 1.1 单点集中式 特点:App.DB.FileServer都部署在一台机器上.并且访问请求量较少 1.2  应用服务和数据服务拆分  特点:App.DB.Fi ...

  6. Java8初体验(二)Stream语法详解(转)

    本文转自http://ifeve.com/stream/ Java8初体验(二)Stream语法详解 感谢同事[天锦]的投稿.投稿请联系 tengfei@ifeve.com上篇文章Java8初体验(一 ...

  7. Java8初体验(二)Stream语法详解---符合人的思维模式,数据源--》stream-->干什么事(具体怎么做,就交给Stream)--》聚合

    Function.identity()是什么? // 将Stream转换成容器或Map Stream<String> stream = Stream.of("I", & ...

  8. RocketMQ详解(二)安装使用详解

    专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...

  9. Hadoop集群搭建安装过程(二)(图文详解---尽情点击!!!)

    Hadoop集群搭建安装过程(二)(配置SSH免密登录)(图文详解---尽情点击!!!) 一.配置ssh无密码访问 ®生成公钥密钥对 1.在每个节点上分别执行: ssh-keygen -t rsa(一 ...

随机推荐

  1. lightoj 1036 - A Refining Company(简单dp)

    题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1036 题解:设dp[i][j]表示处理到(i,j)点时的最大值然后转移显然是 ...

  2. HDU 4565 So Easy! 广义斐波拉数 数论 (a+sqrt(b))^n%mod 模板

    So Easy! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  3. Symmetric Matrix 牛客网暑期ACM多校训练营(第一场) B dp 组合数学

    Count the number of n x n matrices A satisfying the following condition modulo m. * Ai, j ∈ {0, 1, 2 ...

  4. [Swoole入门到进阶] [精选公开课] Swoole服务器-Server的四层生命周期

    PHP 完整生命周期 执行PHP文件 PHP扩展模块初始化(MINIT) PHP扩展请求初始化(RINIT) 执行 PHP 逻辑 PHP扩展请求结束(RSHUTDOWN) PHP脚本清理 PHP扩展模 ...

  5. 微信小程序 select 下拉框组件

    一.源码地址 https://github.com/imxiaoer/WeChatMiniSelect 二.效果图 录屏图片质量较差,所以大家会看到残影(捂脸) 三.组件源码 1. select.wx ...

  6. 【Nginx】简介以及安装、启动、关闭

    一.概述 二.Nginx基本安装 2.1 Windows安装Nginx Nginx目录结构 2.2 Linux安装Nginx 2.3 Mac利用homebrew安装 三.nginx启动关闭 3.1 重 ...

  7. 060 Python必备库-从数据处理到人工智能

    目录 一.概述 1.1 从数据处理到人工智能 二.Python库之数据分析 2.1 numpy 2.2 pandas 2.3 scipy 三.Python库之数据可视化 3.1 matplotlib ...

  8. linux 常用压缩、解压命令

    .tar.gz     解压为          tar   -zxvf   xx.tar.gz    压缩为 tar -zcvf  target.tar.gz ./src_dir zip 解压为   ...

  9. spring aop 之链式调用

    关关雎鸠,在河之洲.窈窕淑女,君子好逑. 概述 AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横 ...

  10. airflow使用SimpleHttpOperator实现http调用任务

    使用SimpleHttpOperator作为处理器的时候,会发现默认访问的地址www.google.com端口为443 例如下面这样定义的任务 task = SimpleHttpOperator( t ...