一、鼠标交互
1.鼠标事件响应
void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);
/*******************************************************************
* winname: 监听窗口名称
* onMouse: 鼠标事件回调函数
* userdata: 递给回调函数的可选参数
*********************************************************************/
2.鼠标事件回调函数
typedef void (*MouseCallback)(int event, int x, int y, int flags, void* userdata);
//MouseCallback onMouse
void onMouse(int event,int x,int y,int flag,void *param)
/*******************************************************************
* event: 事件类型
* x: 鼠标所在图像的坐标
* y:
* flags: 代表拖拽事件
* param: 自己定义的onMouse事件的ID
*********************************************************************/
3.鼠标事件类型
enum MouseEventTypes {
EVENT_MOUSEMOVE = 0, //鼠标移动
EVENT_LBUTTONDOWN = 1, //鼠标左键按下
EVENT_RBUTTONDOWN = 2, //鼠标右键按下
EVENT_MBUTTONDOWN = 3, //鼠标中键按下
EVENT_LBUTTONUP = 4, //鼠标左键弹起
EVENT_RBUTTONUP = 5, //鼠标右键弹起
EVENT_MBUTTONUP = 6, //鼠标中键弹起
EVENT_LBUTTONDBLCLK = 7, //鼠标左键双击
EVENT_RBUTTONDBLCLK = 8, //鼠标右键双击
EVENT_MBUTTONDBLCLK = 9, //鼠标中间双击
EVENT_MOUSEWHEEL = 10, //鼠标滚轮 正数和负数分别表示向前和向后滚动
EVENT_MOUSEHWHEEL = 11 //鼠标滚轮 正数和负数分别表示向右和向左滚动
};
4.鼠标拖拽类型
enum MouseEventFlags {
EVENT_FLAG_LBUTTON = 1, //左键拖动
EVENT_FLAG_RBUTTON = 2, //右键拖动
EVENT_FLAG_MBUTTON = 4, //中键拖动
EVENT_FLAG_CTRLKEY = 8, //ctr拖动
EVENT_FLAG_SHIFTKEY = 16, //shift拖动
EVENT_FLAG_ALTKEY = 32 //alt拖动
};
5.☆综合代码
注意点:
①将onMouse函数(回调函数)设置为类中的静态函数--->不用创建对象直接调用。
②onMouse(回调函数)的参数是固定的,最后一个参数是void* param,此处是通过DrawShape这个类生成的对象来进行绘制操作的,所以param传入的是其生成的对象。最后在onMouse函数中第一步,就必须得强制类型转换才行。
③namedWindow函数是用来生成一个窗口的,参数对应setMouseCallback函数的第一个参数const String& winname(窗口的名称)
④无需写鼠标事件响应函数的函数体(直接调用),setMouseCallback,直接传参即可,注意第二个参数就是回调函数,第三个参数是param
⑤Rect类实例化后是一个存储矩形基本信息的对象。x,y,width,height
//Opencv鼠标左键画圆,右键画方
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class DrawShape
{
public:
DrawShape() :mat(imread("mm.jpg")) {}
void Show(string wName = "drawShape")
{
imshow(wName, mat);
}
void DrawCircle(int x = 300, int y = 300, int r = 10)
{
circle(mat, Point(x, y), r, Scalar(0, 255, 0));
}
void DrawRecagnle(int x = 200, int y = 200, int w = 40, int h = 40)
{
rectangle(mat, Rect(x, y, w, h), Scalar(255, 0, 0));
}
static void OnMouse(int event, int x, int y, int flag, void* param);
protected:
Mat mat;
};
void DrawShape::OnMouse(int event, int x, int y, int flag, void* param)
{
DrawShape* pshape = (DrawShape*)param;
switch(event)
{
case EVENT_LBUTTONDOWN:
cout << "左键按下......." << endl;
pshape->DrawCircle(x,y,10);
break;
case EVENT_RBUTTONDOWN:
cout << "右键按下......." << endl;
pshape->DrawRecagnle(x-5,y-5,10,10);
break;
}
}
int main()
{
DrawShape* pshape = new DrawShape;
namedWindow("drawShape");
setMouseCallback("drawShape", &DrawShape::OnMouse, pshape);
//主循环
while (1)
{
pshape->Show();
if (waitKey(10) == 27)
{
break;
}
}
delete pshape;
pshape = nullptr;
return 0;
}
二、opencv视频操作
opencv里对视频的编码解码等支持并不是很良好,所以不要希望用opencv 做多媒体开发,opencv是一个强大的计算机视觉库,而不是视频流编码器或者解码器。希望大家不要走入这个误区,可以把这部分简单单独看待。而且生成的视频文件不能大于2GB,而且不能添加音频。如果想搞音视频处理可以使用FFmpeg
库。
1.视频读取
opencv中通过VideoCaptrue
类对视频进行读取操作以及调用摄像头,类如下
class VideoCapture
{
public:
VideoCapture();
explicit VideoCapture(const String& filename, int apiPreference = CAP_ANY);
explicit VideoCapture(const String& filename, int apiPreference, const std::vector<int>& params);
explicit VideoCapture(int index, int apiPreference = CAP_ANY);
explicit VideoCapture(int index, int apiPreference, const std::vector<int>& params);
virtual ~VideoCapture();
virtual bool open(const String& filename, int apiPreference = CAP_ANY);
virtual bool open(const String& filename, int apiPreference, const std::vector<int>& params);
virtual bool open(int index, int apiPreference = CAP_ANY);
virtual bool open(int index, int apiPreference, const std::vector<int>& params);
virtual bool isOpened() const;
virtual void release();
virtual bool grab();
virtual bool retrieve(OutputArray image, int flag = 0);
virtual VideoCapture& operator >> (CV_OUT Mat& image);
virtual VideoCapture& operator >> (CV_OUT UMat& image);
virtual bool read(OutputArray image);
virtual bool set(int propId, double value);
virtual double get(int propId) const;
String getBackendName() const;
void setExceptionMode(bool enable) { throwOnFail = enable; }
bool getExceptionMode() { return throwOnFail; }
bool waitAny(const std::vector<VideoCapture>& streams,CV_OUT std::vector<int>& readyIndex,int64 timeoutNs = 0);
protected:
Ptr<CvCapture> cap;
Ptr<IVideoCapture> icap;
bool throwOnFail;
friend class internal::VideoCapturePrivateAccessor;
};
打开视频与捕获设备
①创建对象除了下面代码创建的方式(构造函数)以外,还可以使用内部的成员函数open函数。
②参数是一个路径--->对应视频 参数若是0--->对应摄像头
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap = VideoCapture("test.mp4");
if(!cap.isOpened())
{
cout << "打开失败!" << endl;
return 0;
}
VideoCapture camera = VideoCapture(0);
if (!camera.isOpened())
{
cout << "摄像头打开失败!" << endl;
return 0;
}
return 0;
}
获取视频属性
获得视频有诸多属性,比如:帧率、总帧数、尺寸、格式等
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap = VideoCapture("test.mp4");
if(!cap.isOpened())
{
cout << "打开失败!" << endl;
return 0;
}
cout << "宽度:" << cap.get(CAP_PROP_FRAME_WIDTH) << endl;
cout << "高度:" << cap.get(CAP_PROP_FRAME_HEIGHT) << endl;
cout << "帧数:" << cap.get(CAP_PROP_FRAME_COUNT) << endl;
cout << "帧率:" << cap.get(CAP_PROP_FPS) << endl;
//VideoCapture camera = VideoCapture(0);
//if (!camera.isOpened())
//{
// cout << "摄像头打开失败!" << endl;
// return 0;
//}
return 0;
}
其他属性获取
enum VideoCaptureProperties {
CAP_PROP_POS_MSEC =0, //视频文件的当前位置,单位为毫秒
CAP_PROP_POS_FRAMES =1, //解码/捕获的帧的基于0的索引
CAP_PROP_POS_AVI_RATIO =2, //视频文件的相对位置:0=影片开始,1=影片结束
CAP_PROP_FRAME_WIDTH =3, //视频宽度
CAP_PROP_FRAME_HEIGHT =4, //视频高度
CAP_PROP_FPS =5, //帧率
CAP_PROP_FOURCC =6, //4个字符的编解码器代码
CAP_PROP_FRAME_COUNT =7, //视频文件中的帧数
CAP_PROP_FORMAT =8, //视频格式
CAP_PROP_MODE =9,
CAP_PROP_BRIGHTNESS =10, //图像亮度(摄像模式)
CAP_PROP_CONTRAST =11, //图像对比度(摄像模式)
CAP_PROP_SATURATION =12, //图像饱和度(摄像模式)
CAP_PROP_HUE =13, //图像的色调(摄像模式)
CAP_PROP_GAIN =14, //图像增益(摄像模式)
CAP_PROP_EXPOSURE =15, //曝光(摄像模式)
CAP_PROP_CONVERT_RGB =16, //图像是否应该转换为RGB的布尔标记
CAP_PROP_WHITE_BALANCE_BLUE_U =17,
CAP_PROP_RECTIFICATION =18,
CAP_PROP_MONOCHROME =19,
CAP_PROP_SHARPNESS =20,
CAP_PROP_AUTO_EXPOSURE =21,
CAP_PROP_GAMMA =22,
CAP_PROP_TEMPERATURE =23,
CAP_PROP_TRIGGER =24,
CAP_PROP_TRIGGER_DELAY =25,
CAP_PROP_WHITE_BALANCE_RED_V =26,
CAP_PROP_ZOOM =27,
CAP_PROP_FOCUS =28,
CAP_PROP_GUID =29,
CAP_PROP_ISO_SPEED =30,
CAP_PROP_BACKLIGHT =32,
CAP_PROP_PAN =33,
CAP_PROP_TILT =34,
CAP_PROP_ROLL =35,
CAP_PROP_IRIS =36,
CAP_PROP_SETTINGS =37,
CAP_PROP_BUFFERSIZE =38,
CAP_PROP_AUTOFOCUS =39,
CAP_PROP_SAR_NUM =40,
CAP_PROP_SAR_DEN =41,
CAP_PROP_BACKEND =42,
CAP_PROP_CHANNEL =43,
CAP_PROP_AUTO_WB =44,
CAP_PROP_WB_TEMPERATURE=45,
CAP_PROP_CODEC_PIXEL_FORMAT =46,
CAP_PROP_BITRATE =47,
CAP_PROP_ORIENTATION_META=48,
CAP_PROP_ORIENTATION_AUTO=49,
CAP_PROP_HW_ACCELERATION=50,
CAP_PROP_HW_DEVICE =51,
CAP_PROP_HW_ACCELERATION_USE_OPENCL=52,
CAP_PROP_OPEN_TIMEOUT_MSEC=53,
CAP_PROP_READ_TIMEOUT_MSEC=54,
CAP_PROP_STREAM_OPEN_TIME_USEC =55,
CAP_PROP_VIDEO_TOTAL_CHANNELS = 56,
CAP_PROP_VIDEO_STREAM = 57,
CAP_PROP_AUDIO_STREAM = 58,
CAP_PROP_AUDIO_POS = 59,
CAP_PROP_AUDIO_SHIFT_NSEC = 60,
CAP_PROP_AUDIO_DATA_DEPTH = 61,
CAP_PROP_AUDIO_SAMPLES_PER_SECOND = 62,
CAP_PROP_AUDIO_BASE_INDEX = 63,
CAP_PROP_AUDIO_TOTAL_CHANNELS = 64,
CAP_PROP_AUDIO_TOTAL_STREAMS = 65,
CAP_PROP_AUDIO_SYNCHRONIZE = 66,
CAP_PROP_LRF_HAS_KEY_FRAME = 67,
CAP_PROP_CODEC_EXTRADATA_INDEX = 68,
#ifndef CV_DOXYGEN
CV__CAP_PROP_LATEST
#endif
};
视频转图像
视频转图像显示
方法:一帧一帧的流操作(已重载)即可。
(注意:流操作结束之后,原对象的相关信息都会丢失,若还要继续使用,需要重新获取。)
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap = VideoCapture("test.mp4");
if(!cap.isOpened())
{
cout << "打开失败!" << endl;
return 0;
}
Mat img;
while (true)
{
cap >> img; //flip
if (img.empty())
{
break;
}
imshow("图像", img);
waitKey(30);
}
cap.release();
return 0;
}
视频转图像保存(每一帧图像的保存)
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap = VideoCapture("test.mp4");
if(!cap.isOpened())
{
cout << "打开失败!" << endl;
return 0;
}
Mat img;
int index = 1;
while (true)
{
cap >> img; //flip
if (img.empty())
{
break;
}
//imshow("图像", img);
string name = "mm/img" + to_string(index++) + ".jpg";
imwrite(name, img);
waitKey(30);
}
cap.release();
return 0;
}
摄像头转图像(构造函数的参数传入0即可)
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap = VideoCapture(0);
if(!cap.isOpened())
{
cout << "打开失败!" << endl;
return 0;
}
Mat img;
int index = 1;
while (true)
{
cap >> img;
if (img.empty())
{
break;
}
imshow("图像", img);
waitKey(30);
}
cap.release();
return 0;
}
视频保存
opencv中通过VideoWriter
类对视频进行读取操作以及调用摄像头,该类的API与VideoCapture类似,该类的主要API除了构造函数外,提供了open、isOpened、release、write和重载操作符<<
class CV_EXPORTS_W VideoWriter
{
public:
CV_WRAP VideoWriter();
CV_WRAP VideoWriter(const String& filename, int fourcc, double fps,
Size frameSize, bool isColor = true);
CV_WRAP VideoWriter(const String& filename, int apiPreference, int fourcc, double fps,
Size frameSize, bool isColor = true);
CV_WRAP VideoWriter(const String& filename, int fourcc, double fps, const Size& frameSize,
const std::vector<int>& params);
CV_WRAP VideoWriter(const String& filename, int apiPreference, int fourcc, double fps,
const Size& frameSize, const std::vector<int>& params);
virtual ~VideoWriter();
CV_WRAP virtual bool open(const String& filename, int fourcc, double fps,
Size frameSize, bool isColor = true);
CV_WRAP bool open(const String& filename, int apiPreference, int fourcc, double fps,
Size frameSize, bool isColor = true);
CV_WRAP bool open(const String& filename, int fourcc, double fps, const Size& frameSize,
const std::vector<int>& params);
CV_WRAP bool open(const String& filename, int apiPreference, int fourcc, double fps,
const Size& frameSize, const std::vector<int>& params);
CV_WRAP virtual bool isOpened() const;
CV_WRAP virtual void release();
virtual VideoWriter& operator << (const Mat& image);
virtual VideoWriter& operator << (const UMat& image);
CV_WRAP virtual void write(InputArray image);
CV_WRAP virtual bool set(int propId, double value);
CV_WRAP virtual double get(int propId) const;
CV_WRAP static int fourcc(char c1, char c2, char c3, char c4);
CV_WRAP String getBackendName() const;
protected:
Ptr<CvVideoWriter> writer;
Ptr<IVideoWriter> iwriter;
static Ptr<IVideoWriter> create(const String& filename, int fourcc, double fps,
Size frameSize, bool isColor = true);
};
针对静态函数 fourcc函数,四个参数如何传入,见下面的网站,挑一个格式,分解成四个字符传入即可。--->常作为open的第二个参数。
视频其他格式http://mp4ra.org/#/codecs
摄像头转视频保存.
①VideoWriter的open需要四个参数:
1)保存的路径名
2)int fourcc--->解编码格式
3)fps帧率
4)Size对象(宽度和高度来构造)--->常通过get方法来获取。
②将在cap中 流出每一帧的图片img
再流入save对象即可实现。
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
VideoCapture cap = VideoCapture(0);
if(!cap.isOpened())
{
cout << "打开失败!" << endl;
return 0;
}
int width = cap.get(CAP_PROP_FRAME_WIDTH);
int height = cap.get(CAP_PROP_FRAME_HEIGHT);
VideoWriter save;
save.open("save.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), 30, Size(width, height), true);
Mat img;
while (true)
{
cap >> img;
imshow("摄像头", img);
save << img;
//按ESC退出
if (waitKey(10) == 27)
{
break;
}
}
cap.release();
save.release();
return 0;
}
综合代码(封装成一个Video类)
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
class Video
{
public:
Video();
~Video();
void GetVideo(string fileName = "test.mp4");//初始化cap
void SaveToVideo(string fileName = "out.avi");
void SaveToImg(string preName = "mm/img");
void Camera(string fileName = "录像.avi");
protected:
VideoCapture cap;
VideoWriter save;
};
Video::Video()
{
}
Video::~Video()
{
cap.release();
save.release();
}
void Video::GetVideo(string fileName)
{
cap = VideoCapture(fileName);
if (!cap.isOpened())
{
cout << "视频获取失败!" << endl;
}
}
void Video::SaveToVideo(string fileName)
{
int w = cap.get(CAP_PROP_FRAME_WIDTH);
int h = cap.get(CAP_PROP_FRAME_HEIGHT);
int fps = cap.get(CAP_PROP_FPS);
save.open(fileName, VideoWriter::fourcc('M', 'J', 'P', 'G'), fps, Size(w, h), true);
Mat img;
while (true)
{
cap >> img;
if (img.empty())
break;
save << img;
}
}
void Video::SaveToImg(string preName)
{
Mat img;
int index = 0;
string name;
while (true)
{
cap >> img;
if (img.empty())
{
break;
}
name = preName + to_string(index++) + ".jpg";
imwrite(name, img);
}
}
void Video::Camera(string fileName)
{
cap = VideoCapture(0);
if (!cap.isOpened())
{
cout << "摄像头打开失败!" << endl;
return;
}
int w = cap.get(CAP_PROP_FRAME_WIDTH);
int h = cap.get(CAP_PROP_FRAME_HEIGHT);
save.open(fileName, VideoWriter::fourcc('M', 'J', 'P', 'G'), 30, Size(w, h), true);
Mat img;
while (true)
{
cap >> img;
imshow("摄像头", img);
save << img;
if (waitKey(10) == 27)
{
break;
}
}
}
int main()
{
Video* pvideo = new Video;
pvideo->GetVideo();
pvideo->SaveToImg();
//刚才读到的video已经全部流出去了。
pvideo->GetVideo();
pvideo->SaveToVideo();
pvideo->Camera();
delete pvideo;
return 0;
}
三、opencv滑块交互操作
opencv滑块交互操作
滑动条(Trackbar)是opencv动态调节参数特别好用的一种工具,虽然看起来着实有点丑
滑动条创建函数
int createTrackbar(const String& trackbarname, const String& winname,int* value, int count,TrackbarCallback onChange = 0,void* userdata = 0);
/*******************************************************************
* trackbarname: 滑动条名字
* winname: 依附窗口名
* value: 滑块位置
* count: 滑块最大值(最小值是0)
* onChange: 滑块回调函数
* userdata: 用户回传给回调函数的数据
*********************************************************************/
滑动条回调函数
typedef void (*TrackbarCallback)(int pos, void* userdata);
void On_Trackbar(int pos, void* userdata);
/*******************************************************************
* pos: 位置
* userdata: 用户回传给回调函数的数据
*********************************************************************/
① 主要实现滑动条回调函数,然后直接调用createTrackerbar函数即可。
②下面主要实现,亮度条的调节滑动条---->本质上通过at函数提高每个像素点的像素值即可.
综合代码
//滑块 去操作一张图片的像素点,改变图片的连读即可
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
class TrackBar
{
public:
TrackBar() :img(imread("mm.jpg")), curBright(6), maxBright(30)
{
}
void Show(string wName = "trackBar")
{
imshow(wName, img);
}
int* GetData()
{
return &curBright;
}
int GetMaxBright()
{
return maxBright;
}
static void On_Trackbar(int pos, void* userdata);
private:
Mat img;
int curBright;
int maxBright;
};
void TrackBar::On_Trackbar(int pos, void* userdata)
{
TrackBar* pBar = (TrackBar*)userdata;
if (!pBar->img.data)
{
return;
}
int rows = pBar->img.rows;
int cols = pBar->img.cols;
int dims = pBar->img.channels();
cout << dims << endl;
Mat mat = Mat::zeros(pBar->img.size(), pBar->img.type());
float beta = 30;
float alpha = 0.1f + (float)pBar->curBright / 10.0;
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
if (dims == 1)
{
float bgr = pBar->img.at<uchar>(i, j);
mat.at<uchar>(i, j) = saturate_cast<uchar>(bgr * alpha + beta);
}
else if (dims == 3)
{
float g = pBar->img.at<Vec3b>(i, j)[0];
float b = pBar->img.at<Vec3b>(i, j)[1];
float r = pBar->img.at<Vec3b>(i, j)[2];
mat.at<Vec3b>(i, j)[0] = saturate_cast<uchar>(g * alpha + beta);
mat.at<Vec3b>(i, j)[1] = saturate_cast<uchar>(b * alpha + beta);
mat.at<Vec3b>(i, j)[2] = saturate_cast<uchar>(r * alpha + beta);
}
else
return;
}
}
imshow("trackBar", mat);
}
int main()
{
TrackBar* pBar = new TrackBar;
namedWindow("trackBar");
createTrackbar("亮度调整", "trackBar", pBar->GetData(), pBar->GetMaxBright(), &TrackBar::On_Trackbar, pBar);
waitKey(0);
return 0;
}