美文网首页AI人工智能与数学之美
opencv C++ trackbar回调函数的参数传递

opencv C++ trackbar回调函数的参数传递

作者: 1037号森林里一段干木头 | 来源:发表于2020-12-03 10:45 被阅读0次

    简介:

    opencv的highgui里有一个trackbar控件,可以动态改变参数,让图片实现实时变化。opencv官网的例子并没有用参数传递,而是用的是全局变量,这样会导致程序结构混乱,所以研究了下变成函数参数传递的方式。

    • 原图


      church01.jpg
    • 效果


      image.png
      • 创建trackbar控件的函数原型
    int cv::createTrackbar  (   
    const String &  trackbarname,
    const String &  winname,
    int *   value,
    int     count,
    TrackbarCallback    onChange = 0,
    void *  userdata = 0 
    )   
    

    参数详解:

    • trackbarname 滑动条的名称
    • winname 滑动条附着的窗口的名称
    • value 滑动条的位置表示的值
    • TrackbarCallback 回调函数名
    • userdata 用户参数传递指针,只能是一个void *类型的
      • trackbar回调函数原型
    typedef void(* cv::TrackbarCallback) (int pos, void *userdata)
    

    参数详解:

    • pos 滑动条当前位置表示的值
    • void *userdata 用户传递的参数
      注:此函数只能有两个参数,而且第二个参数必须是void * 类型的数据,自己添加参数的话就会提示没有写回调函数。
      • 实例
        写一个阈值分割的小程序,滑动条控制分割阈值,参数传递时用结构体。
        完整代码如下:
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgproc.hpp"
    #include <iostream>
    struct mydata{
        cv::Mat img;//原图
        cv::Mat dst;//阈值分割后的图
        int th ;//阈值
    };
    
    void thresh_callback(int pos, void *p)
    {
        mydata cfg = *(mydata *)p;//
        cv::threshold(cfg.img,cfg.dst,pos,255,cv::THRESH_TOZERO);
        cv::namedWindow("winname",0);
        cv::imshow("winname",cfg.dst);
    }
    
    int main()
    {
        mydata cfg;
        std::string img_path = "C:\\Users\\bxzyz\\Desktop\\book\\opencv-cookbook\\images\\church01.jpg";
        cv::Mat img  = cv::imread(img_path);
        cv::Mat dst = img.clone();
        cfg.img = img;
        cfg.dst = dst;
        //cfg.ksize = cv::Size(5,5);
        int th = 127;//初始默认值
        int th_max = 255;
        
        while (1)
        {
            cv::createTrackbar("th", "winname", &th, th_max, thresh_callback, (void*)(&cfg));
            thresh_callback(th,&cfg);
            //按Esc键退出程序
            if (cv::waitKey(3)==27)
            {
                break;
            }
        }
        cv::destroyAllWindows();
    }
    
    

    核心在mydata cfg = *(mydata *)p;
    把main函数里的mydata 的实例cfg的地址传递给void *p指针,然后把P强制类型转换,变成我们定义的结构体的类型。用这种方法就可以传递任何我们想要的数据了。

    补充:

    三个通道分开做阈值分割再合并的
    效果


    image.png

    代码:

    
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgproc.hpp"
    #include <iostream>
    struct mydata{
        cv::Mat img;
        cv::Mat dst;
        int th ;
        int thr;
        int thg;
        int thb;
        
    };
    // void thresh_callback(int pos, void *p)
    // {
    //  mydata cfg = *(mydata *)p;
    //  cv::threshold(cfg.img,cfg.dst,pos,255,cv::THRESH_TOZERO);
    //  cv::namedWindow("winname",0);
    //  cv::imshow("winname",cfg.dst);
        
    // }
    
    void thresh_callback_r(int posr, void *p)
    {
        mydata cfg = *(mydata *)p;
        cfg.thr = posr;
        std::vector<cv::Mat> channels(3);
        cv::split(cfg.img, channels);
        cv::threshold(channels[0],channels[0],cfg.thb,255,cv::THRESH_TOZERO);
        cv::threshold(channels[1],channels[1],cfg.thg,255,cv::THRESH_TOZERO);
        cv::threshold(channels[2],channels[2],cfg.thr,255,cv::THRESH_TOZERO);
        cv::merge(channels, cfg.dst);
        cv::namedWindow("winname",0);
        cv::imshow("winname", cfg.dst);
    }
    
    void thresh_callback_g(int posg, void *p)
    {
        mydata cfg = *(mydata *)p;
        cfg.thg = posg;
        std::vector<cv::Mat> channels(3);
        cv::split(cfg.img, channels);
        cv::threshold(channels[0],channels[0],cfg.thb,255,cv::THRESH_TOZERO);
        cv::threshold(channels[1],channels[1],cfg.thg,255,cv::THRESH_TOZERO);
        cv::threshold(channels[2],channels[2],cfg.thr,255,cv::THRESH_TOZERO);
        cv::merge(channels, cfg.dst);
        cv::namedWindow("winname",0);
        cv::imshow("winname", cfg.dst);
    }
    
    void thresh_callback_b(int posb, void *p)
    {
        mydata cfg = *(mydata *)p;
        cfg.thb = posb;
        std::vector<cv::Mat> channels(3);
        cv::split(cfg.img, channels);
        cv::threshold(channels[0],channels[0],cfg.thb,255,cv::THRESH_TOZERO);
        cv::threshold(channels[1],channels[1],cfg.thg,255,cv::THRESH_TOZERO);
        cv::threshold(channels[2],channels[2],cfg.thr,255,cv::THRESH_TOZERO);
        cv::merge(channels, cfg.dst);
        cv::namedWindow("winname",0);
        cv::imshow("winname", cfg.dst);
    }
    
    int main()
    {
        mydata cfg;
        std::string img_path = "C:\\Users\\bxzyz\\Desktop\\book\\opencv-cookbook\\images\\church01.jpg";
        cv::Mat img  = cv::imread(img_path);
        cv::Mat dst = img.clone();
        cfg.img = img;
        cfg.dst = dst;
        //cfg.ksize = cv::Size(5,5);
        int th = 127;//初始默认值
        cfg.thr=0;
        cfg.thg=0;
        cfg.thb=0;
        int th_max = 255;
        
        while (1)
        {
            cv::createTrackbar("thr", "winname", &cfg.thr, th_max, thresh_callback_r, (void*)(&cfg));
            thresh_callback_r(cfg.thr,&cfg);
    
            cv::createTrackbar("thg", "winname", &cfg.thg, th_max, thresh_callback_g, (void*)(&cfg));
            thresh_callback_g(cfg.thg,&cfg);
    
            cv::createTrackbar("thb", "winname", &cfg.thb, th_max, thresh_callback_b, (void*)(&cfg));
            thresh_callback_b(cfg.thb,&cfg);
            
            if (cv::waitKey(1)==27)
            {
                break;
            }
        }
        
        cv::destroyAllWindows();
    }
    
    
    
    

    相关文章

      网友评论

        本文标题:opencv C++ trackbar回调函数的参数传递

        本文链接:https://www.haomeiwen.com/subject/xdxmwktx.html