OpenCV C++滑动条插件
这个就是Opecv3中文版的例程,做了些注释,以及排坑指南。
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\imgproc\imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int g_slider_position = 0;
//储存滑动条的位置,用g_表全局变量,增加代码可读性
int g_run = 1;
//在新的跳转之后置0,若为正,则表示,在下一次停止前要播放多少帧。
int g_dontset = 0;
//用来避免在自动运行进度条位置时触发单步模式。
VideoCapture g_cap;
void onTrackbarSlide(int pos,void *)//回调函数,作为之后创建滑动条的参数实时返回滑动条实时位置,在下面的createTrackbar函数中会使用。
{
g_cap.set(CAP_PROP_POS_FRAMES, pos);
if (!g_dontset)g_run = 1;//如果g_dontset!=0(用户调整滑动条时)则进入单步模式
g_dontset = 0;//使creatTrackbar里调用回调函数时不进入单步模式
}//只有在用户鼠标移动滑动条时才进如单步模式,而自动移动滑动条时,不进入单步模式
int main()
{
namedWindow("Example", WINDOW_AUTOSIZE);
g_cap.open("C:\\Users\\hl\\Desktop\\led.mp4");
int frames = (int)g_cap.get(CAP_PROP_FRAME_COUNT);//得到视频的总帧数
int tmpw = (int)g_cap.get(CAP_PROP_FRAME_WIDTH);//得到视频的宽
int tmph = (int)g_cap.get(CAP_PROP_FRAME_HEIGHT);//得到视频的高
cout << "Video has" << frames << "frames of dimension(" << tmpw << "," << tmph << ")." << endl;
//创建一个滑动条(滑动条名称/窗口名称/引用滑动条当前位置/总帧数(最大值)/回调函数不要可以NULL)
createTrackbar("Position", "Example", &g_slider_position, frames,onTrackbarSlide);
//这个滑动条的名称千万别打错了,就因为我打成一次position,并不报错,但是运行的时候滑动条始终不动!!!因为动的是另一个看不见的滑动条....
//像这种P和p的错误,找起来太费劲了,我服了。
Mat frame;
while (1)
{
if (g_run != 0)
{
g_cap >> frame;//VideoCapture重载了>>运算符,得到帧。
if (frame.empty())break;
int current_pos = (int)g_cap.get(CAP_PROP_POS_FRAMES);
g_dontset = 1;
//g_donset不为0时,回调函数内部会设置g_run=1进入单步模式
setTrackbarPos("Position", "Example", current_pos);
imshow("Example", frame);
if(g_run>0) g_run -= 1;
//只有在g_run大于0时才-1,不然在播放视频的时候,每帧都要多做一次减法,减少一些运算量嘛,能节约一点是一点。
}
char c = (char)waitKey(10);
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)break;//点击ESC退出程序
}
waitKey(0);
destroyWindow("Example");//销毁窗口习惯,减少内存泄漏的机会
return 0;
}
效果成功后
点击r即为播放
点击s为播放一帧
当然如果你像点击s后播放十帧,那就将if(c==‘s’)下面的g_run=1改成=10即可。
核心问题就是这个集成好的createTrackbar()函数的回调过程不太理解,既然他集成过了,我们直接记一下常用的用法,会用就行。
此外,对于一般的调参数改变图像的例子。
#include<opencv2/opencv.hpp>
using namespace cv;
Mat img;//输入图片
Mat out;//输出图片
int g_slide_position = 0;//滑动条当前位置
const int g_max_position = 8;//滑动条最大位置
void onTrackbarSlide(int, void*)
{
out = img.clone();//将原图复制一份到输出图里
//******************************************************************
//*内的内容可替换成需要的参数以及函数,这边为降采样的次数
for (int i = 0; i < g_slide_position; i++)
{
pyrDown(out, out);//降采样一次
}
//******************************************************************
imshow("输出图像", out);
}
int main()
{
img = imread("C:\\Users\\hl\\Desktop\\lena1.jpg");
namedWindow("输出图像", WINDOW_NORMAL);
createTrackbar("降采样次数", "输出图像", &g_slide_position, g_max_position, onTrackbarSlide);
onTrackbarSlide(0,0);
waitKey();
return 0;
}
另外一个好玩的例子,受第4章练习第一题的启发,做了个滑动条。
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
Mat screen = Mat(10, 10, CV_8UC1, Scalar(0));
int g_slide_position = 0;
Mat code(int num)//数字编码
{
Mat_<uchar> num_code;
switch (num)
{
case 0:
num_code = Mat(10, 10, CV_8UC1,Scalar(0));
for(int i=2;i<8;i++)
{
num_code(1, i) = 255;
num_code(7, i) = 255;
num_code(i, 2) = 255;
num_code(i, 7) = 255;
}
return num_code;
case 1:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 1; i < 9; i++)
{
num_code(i,7) = 255;
}
return num_code;
case 2:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i < 8; i++)
{
num_code(1, i) = 255;
num_code(4, i) = 255;
num_code(7, i) = 255;
}
num_code(2, 7) = 255;
num_code(3, 7) = 255;
num_code(5, 2) = 255;
num_code(6, 2) = 255;
return num_code;
case 3:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i < 8; i++)
{
num_code(1, i) = 255;
num_code(4, i) = 255;
num_code(7, i) = 255;
}
num_code(2, 7) = 255;
num_code(3, 7) = 255;
num_code(5, 7) = 255;
num_code(6, 7) = 255;
return num_code;
case 4:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 1; i < 8; i++)
{
num_code(i, 7) = 255;
}
for (int i = 1; i < 5; i++)
{
num_code(i, 2) = 255;
}
num_code(4, 3) = 255;
num_code(4, 4) = 255;
num_code(4, 5) = 255;
num_code(4, 6) = 255;
return num_code;
case 5:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i < 8; i++)
{
num_code(1, i) = 255;
num_code(4, i) = 255;
num_code(7, i) = 255;
}
num_code(2, 2) = 255;
num_code(3, 2) = 255;
num_code(5, 7) = 255;
num_code(6, 7) = 255;
return num_code;
case 6:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i < 8; i++)
{
num_code(1, i) = 255;
num_code(4, i) = 255;
num_code(7, i) = 255;
}
num_code(2, 2) = 255;
num_code(3, 2) = 255;
num_code(5, 2) = 255;
num_code(6, 2) = 255;
num_code(5, 7) = 255;
num_code(6, 7) = 255;
return num_code;
case 7:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 3; i < 8; i++)
{
num_code(1, i) = 255;
}
for (int i = 2; i < 9; i++)
{
num_code(i, 7) = 255;
}
return num_code;
case 8:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i < 8; i++)
{
num_code(1, i) = 255;
num_code(4, i) = 255;
num_code(7, i) = 255;
}
num_code(2, 2) = 255;
num_code(3, 2) = 255;
num_code(5, 2) = 255;
num_code(6, 2) = 255;
num_code(5, 7) = 255;
num_code(6, 7) = 255;
num_code(2, 7) = 255;
num_code(3, 7) = 255;
return num_code;
case 9:
num_code = Mat(10, 10, CV_8UC1, Scalar(0));
for (int i = 2; i < 8; i++)
{
num_code(1, i) = 255;
num_code(4, i) = 255;
num_code(7, i) = 255;
}
num_code(2, 2) = 255;
num_code(3, 2) = 255;
num_code(2, 7) = 255;
num_code(3, 7) = 255;
num_code(5, 7) = 255;
num_code(6, 7) = 255;
}
return num_code;
}
void screen_initial()//展示初始化
{
for (int i = 1; i < 9; i++)
{
screen.at<uchar>(i, 1) = 255;
screen.at<uchar>(i, 4) = 255;
screen.at<uchar>(i, 6) = 255;
}
for (int i = 7; i < 9; i++)
{
screen.at<uchar>(8, i) = 255;
}
screen.at<uchar>(4, 2) = 255;
screen.at<uchar>(4, 3) = 255;
}
void onTrackbarSlide(int, void*)//滑动条回调函数
{
screen = code(g_slide_position);
imshow("out", screen);
}
int main()
{
screen_initial();//初始化展示 我的名字啊HL
namedWindow("out", WINDOW_NORMAL);
imshow("out", screen);
createTrackbar("num", "out", &g_slide_position, 9, onTrackbarSlide);
waitKey(0);
return 0;
}
运行程序显示初始化界面:我的名字哈哈。
然后滑动滑动条即可,这边数字编码是自己编的,还凑合。