简介:
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();
}
网友评论