本博客参考了这篇博客,其实可以说是对该篇博客的补充和改进
一、鼠标截图
其中用到的方法有
imread("arnold_schwarzenegger.jpg") //读取图片的函数,用法参考imread六种姿势
setMouseCallback("inWindows", onMouse, 0);
void setMousecallback(const string& winname, MouseCallback onMouse, void* userdata=0)
winname:窗口的名字
onMouse:鼠标响应函数,回调函数。指定窗口里每次鼠标时间发生的时候,被调用的函数指针。 这个函数的原型应该为void on_Mouse(int event, int x, int y, int flags, void* param);
userdate:传给回调函数的参数
onMouse(int event, int x, int y, int flag, void *param)
void on_Mouse(int event, int x, int y, int flags, void* param);
event是 CV_EVENT_*变量之一
x和y是鼠标指针在图像坐标系的坐标(不是窗口坐标系)
flags是CV_EVENT_FLAG的组合, param是用户定义的传递到setMouseCallback函数调用的参数。
cvRectangle( CvArr* img, CvPoint pt1, CvPoint pt2, CvScalar color,
int thickness=1, int line_type=8, int shift=0 );
img:图像.pt1:矩形的一个顶点。pt2:矩形对角线上的另一个顶点
color:线条颜色 (RGB) 或亮度(灰度图像 )(grayscale image)
thickness:组成矩形的线条的粗细程度。取负值时(如 CV_FILLED)函数绘制填充了色彩的矩形
line_type :线条的类型。见cvLine的描述 shift :坐标点的小数点位数
具体代码如下,修改了ROI = inImage(Rect(pt.x, pt.y, x - pt.x, y - pt.y));这里
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
Mat inImage = imread("arnold_schwarzenegger.jpg");//施瓦辛格,放在项目同一文件夹里
Mat outImage = inImage.clone();
bool flag = false;
Point pt;
Mat ROI;
void onMouse(int event, int x, int y, int flag, void *param)
{
switch (event)
{
case CV_EVENT_LBUTTONDOWN: //鼠标左键按下
printf("鼠标左键按下\n");
flag = true;
pt.x = x;
pt.y = y;
break;
case CV_EVENT_MOUSEMOVE:
printf("鼠标移动\n");
if (flag)
{
inImage.copyTo(outImage); //将原图像赋值给temp,以便永远只有一个矩形(否则许多矩形会重叠在一起)
rectangle(outImage, pt, Point(x, y), Scalar(0, 255, 0), 2, 8);
//这里的Scalar是控制矩形颜色的,分别是R,G,B三色道,(0,255,0)是绿色,(255,0,0)是红色,(0,0,255)是蓝色
}
break;
case CV_EVENT_LBUTTONUP:
printf("鼠标左键抬起\n");
flag = false;
//ROI = outImage(Rect(pt.x, pt.y, x - pt.x, y - pt.y)); //确定ROI区域,有矩形边框
//ROI = inImage(Rect(pt.x, pt.y, x - pt.x, y - pt.y));//无矩形边框,这样写只能鼠标右下复制,其他方式会出现error
//做一个简单的数学变换
ROI = inImage(Rect(min(pt.x,x),min(pt.y,y),abs(x-pt.x),abs(y-pt.y)));//使用min函数可以省去不必要的判断
imshow("Out", ROI);
imwrite("ROI.jpg", ROI);
break;
default:
break;
}
}
int main()
{
namedWindow("inWindows", CV_WINDOW_AUTOSIZE);
setMouseCallback("inWindows", onMouse, 0);//我理解是开了线程,检测“inWindows”里面的鼠标动作
while (1)//不加while(1),闪一下就没了
{
imshow("inWindows", outImage);//窗口显示outImage,施瓦辛格图片
if (27 == waitKey(30)) //按esc键退出循环
{
break;
}
}
destroyAllWindows();
return 0;
}
二、滑动条播放视频
createTrackbar(const string& trackbarname, const string& winname, int* value, int count, TrackbarCallback onChange=0, void*userdata=0)
Parameters:
- trackbarname:创建的滑动条名。
- winname:滑动条的父窗体名。
- value:滑动条当前值。
- count:允许的最大值,最小值为0。
- onChange:回调函数,当滑动条位置发生变化时,调用此函数。函数形如void Foo(int,void*);,第一个是位置值,第二个是userdata
- userdata:可以被传递给回调函数,可以在没有全局位置变量时起作用。
void setTrackbarPos(const String& trackbarname, const String& winname, int pos)
Parameters:
- trackbarname:滑动条名称。
- winname:窗口名称。
- pos:新位置。
/*
滑动条视频播放
*/
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int value;
void onChange(int pos, void *param)//进度条拖动要做的事情
{
VideoCapture cap = *(VideoCapture *)param;
cap.set(CV_CAP_PROP_POS_FRAMES, value); //设置视频帧位置
}
int main()
{
Mat frame;
VideoCapture capture;
capture.open("test.MP4");
if (!capture.isOpened())
{
printf("can't open video file\n");
return -1;
}
int fps = (int)capture.get(CV_CAP_PROP_FPS); //获取视频帧率
int frameCount = (int)capture.get(CV_CAP_PROP_FRAME_COUNT); //获取视频总帧数
namedWindow("video", CV_WINDOW_AUTOSIZE);
createTrackbar("frame", "video", &value, frameCount, onChange, (void *)&capture);
while (true)
{
int framePos = (int)capture.get(CV_CAP_PROP_POS_FRAMES);
setTrackbarPos("frame", "video", framePos);
capture.read(frame);
if(!frame.empty()) //添加这一句之后不会出现error
imshow("video", frame);
if (27 == waitKey(1000 / fps))
{
break;
}
}
capture.release();
destroyAllWindows();
return 0;
}