在opencv膨胀的代码案例中,使用到了createTrackbar这个函数,先看一下API接口定义:
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该参数的理解:
首先我们看一下回调函数的函数原型:
typedef void (CV_CDECL *TrackbarCallback)(int pos, void* userdata);
当我们没看回调函数原型时可能很难理解有些代码中定义回调函数时为什么必须要有那俩参数,当看了回调函数原型后我相信有C++基础的人也都能明白了,那么我来说说回调函数和createTrackbar()函数的关系;我们看到回调函数和createTrackbar函数都有一个形参名为userdata,那这是不是巧合呢?答案当然不是,你可以这样理解,回调函数是一个必须依托于createTrackbar()函数而使用的函数,他不能单独拿来使用,那他的两个形参是怎么用的呢?首先第一个形参pos,它表示的是当前滑块所在的位置,它的值是createTrackbar()传给他的,也就是createTrackbar()形参value的值,这个传输过程是在createTrackbar()内部实现的,无需深究,然后回调函数形参userdata的值就是通过createTrackbar()的形参userdata直接得到的,所以createTrackbar()的形参userdata其实就是专门给回调函数准备的。
下面看示例:
#include
#include
using namespace std;
using namespace cv;
void dilateOnchange(int pos,void* src)
{
Mat dst;
int s = pos*2 +1;
Mat kernel = getStructuringElement(MORPH_RECT,Size(s,s),Point(-1,-1));
dilate(*(Mat *)src,dst,kernel);
imshow("dst",dst);
}
int main(int argc,char** argv)
{
Mat src = imread("../photo/test.jpg");
if(src.empty()){
cout<<"could not load inage.."<<endl;
return -1;
}
Mat src1;
cvtColor(src,src1,CV_RGB2GRAY);
imshow("src",src1);
int value = 1;
createTrackbar("dilate","src",&value,20,dilateOnchange,&src1);
waitKey(0);
destroyAllWindows();
return 0;
}