c++ 回调函数_计算机视觉之OpenCV的creatTrackbar()函数

最近在学习OpenCV,对creatTrackbar()这个函数,产生了一点疑问,于是就是网上寻找一些文章来学习。本文转载于https://www.cnblogs.com/geek-hao/p/11668248.html

函数说明

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()在使用上可能也会比较神奇,比如说你可能看到如下程序:

#include

#include

#include

#include

using namespace std;

using namespace cv;

//TrackBar发生改变的回调函数

void onChangeTrackBar(int pos, void* userdata);

//主函数

int main()

{

//trackbar的值

int posTrackBar = 0;

//trackbar的最大值

int maxValue = 255;

//读入图像,以灰度图形式读入

Mat img = imread("F:图片img.jpg", 0);

//新建窗口

namedWindow("二值化");

imshow("二值化", img);

//创建trackbar,我们把img作为数据传进回调函数中

createTrackbar("pos", "二值化", &posTrackBar, maxValue, onChangeTrackBar, &img);

waitKey();

return 0;

}

// 回调函数

void onChangeTrackBar(int pos, void* usrdata)

{

// 强制类型转换

Mat src = *(Mat*)(usrdata);

Mat dst;

// 二值化

threshold(src, dst, pos, 255, 0);

imshow("二值化", dst);

}

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

91db7f629fd500d1704aeaff3b14100d.png

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

结语:

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

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

#include

#include

using namespace std;

int g_slider_position = 0;

int g_run = 1, g_dontset = 0;

cv::VideoCapture g_cap;

void onTrackbarSlide(int pos, void *) {

g_cap.set(cv::CAP_PROP_POS_FRAMES, pos);

if (!g_dontset) {

g_run = 1;

}

g_dontset = 0;

}

int main() {

cv::namedWindow("show_video", 0);

g_cap.open("F:图片123.mp4");

int frames = (int)g_cap.get(cv::CAP_PROP_FRAME_COUNT);

int tmpw = (int)g_cap.get(cv::CAP_PROP_FRAME_WIDTH);

int tmph = (int)g_cap.get(cv::CAP_PROP_FRAME_HEIGHT);

cout << "Video has" << frames << "frames of dimensions(" << tmpw << "," << tmph << ")." << endl;

cv::createTrackbar("Position", "show_video", &g_slider_position, frames, onTrackbarSlide);

cv::Mat frame;

while (1) {

if (g_run != 0) {

g_cap >> frame;

if (frame.empty()) {

break;

}

int current_pos = (int)g_cap.get(cv::CAP_PROP_POS_FRAMES);

g_dontset = 1;

cv::setTrackbarPos("Position", "show_video", current_pos);

cv::imshow("show_video", frame);

g_run = -1;

}

char c = (char)cv::waitKey(33);

if (c == 's') {

g_run = 1;

cout << "Single step,run = " << g_run << endl;

}

if (c == 'r') {

g_run = -1;

cout << "Run mode,run" << g_run << endl;

}

if (c == 27) {

cv::destroyWindow("show_video");

break;

}

}

cv::destroyWindow("show_video");

return 0;

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在海康相机中,函数 `mv_cc_registerimagecallbackforbgr` 用于注册回调函数,用以实时获取相机捕获的图像数据,并将其中的 RGB 数据以 OpenCV 格式返回。 OpenCV 是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。在回调函数中使用 OpenCV 格式返回图像数据,以便使用 OpenCV 库中的函数进行图像处理和分析。回调函数的定义如下: ```c++ void __stdcall ImageCallbackForBGR(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser) { cv::Mat image; // 根据相机的输出格式,将 pData 数据转换成 OpenCV 支持的 BGR 格式图像 if (pFrameInfo->enPixelType == PixelType_Gvsp_BGR8_Packed) { image = cv::Mat(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3, pData).clone(); } else if (pFrameInfo->enPixelType == PixelType_Gvsp_RGBA8_Packed) { // 如果相机输出为 RGBA 格式,则需要先将其转换成 BGR 格式 cv::Mat rgbaImage(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC4, pData); cv::cvtColor(rgbaImage, image, CV_RGBA2BGR); } // 在此可对图像进行 OpenCV 相关操作,例如显示图像、保存图像等 cv::imshow("Image", image); cv::waitKey(1); } ``` 回调函数接收到相机捕获的图像数据后,首先根据相机的输出格式确定图像的编码方式,如果为 BGR 格式,则可以直接构造出 OpenCV 的 `cv::Mat` 对象;如果为 RGBA 格式,则需要先将其转换为 BGR 格式。接下来,可以在回调函数中通过 OpenCV 提供的函数对图像进行操作,例如显示图像、保存图像等。 以上就是在 `mv_cc_registerimagecallbackforbgr` 回调函数中使用 OpenCV 格式的解答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值