C++OpenCV(3):基础交互(视频与鼠标操作)

🔆 文章首发于我的个人博客:欢迎大佬们来逛逛
🔆 OpenCV项目地址及源代码:点击这里

文章目录

  • 鼠标交互
    • 案例
  • 视频读写交互
    • 视频(摄像头)转图像显示
    • 视频转图片并且保存
    • 摄像头转图片并保存
  • 滑动条交互
    • 滑动条调整图片的亮度

鼠标交互

openCV中使用鼠标的交互的函数是:setMouseCallback

可以使得激活winname为标题的窗口进行onMouse回调函数执行的鼠标交互操作,并且可以传递用户自定义变量给userdata

void setMouseCallback(const String& winname, MouseCallback onMouse, void* userdata = 0);
/*******************************************************************
*			winname: 			监听窗口名称
*			onMouse:			  鼠标事件回调函数
*			userdata:			递给回调函数的可选参数
*********************************************************************/

关于MouseCallBack回调函数:

  • 就是一个函数指针
  • 传递的参数必须一致:event鼠标点击事件, ∗ ∗ ( x , y ) ∗ ∗ **(x,y)** (x,y)坐标,flag鼠标拖拽事件,void* 类型的param可以转为用户自定义变量。
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
*********************************************************************/

关于event和flag的枚举类型:

  • event:鼠标点击
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 	//鼠标滚轮 正数和负数分别表示向右和向左滚动  };
  • flag:鼠标拖拽
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拖动};

案例

在一张图片中左键点击画圆,右键点击画矩形。

有关如何在openCV中绘制图形请参见:

OpenCV(2):图像处理基础概念与操作 | HugeYlh

关键之处就是要有一个鼠标回调函数:

可以声明为类的静态成员函数,然后利用params进行强制转换为本类类型。

接着判断event点击的事件进行绘制即可。

static void mouseEvent(int event, int x, int y, int flag, void* params) {DrawShape* obj = static_cast<DrawShape*>(params);if (event == cv::EVENT_FLAG_LBUTTON) {//左键画圆obj->drawCircle(x, y, 20);}else if (event == cv::EVENT_FLAG_RBUTTON) {obj->drawRectangle(x, y, 20, 20);}}

然后在主程序中我们要激活这个回调函数,设置鼠标点击:

  • 其中传递回调函数要使用函数指针的形式,即传递类的静态成员函数的地址
  • p表示我们需要传递自定义变量,以便在回调函数中params转换为我们需要操作的obj
int main()
{DrawShape* p = new DrawShape();//鼠标处理过程cv::namedWindow("mainWindow");//typedef void (*MouseCallback)//			(int event, int x, int y, int flags, void* userdata);cv::setMouseCallback("mainWindow", &DrawShape::mouseEvent, p);while (true) {p->show();if (cv::waitKey(10) == 27) {break;}}delete p;p = nullptr;return 0;
}

完整代码参见此Github项目


视频读写交互

使用openCV做视频操作可能不会如你想象的那么容易,因为openCV是一个强大的计算机视觉库,而不是专注于视频操作的多媒体库。

使用openCV做视频处理不能添加音频

也许FFmpeg 库会满足你做多媒体开发的需求。


**VideoCapture**类型:对视频进行读取或者打开摄像头。

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;
};

读取一个视频:传递给视频的文件地址即可,如果我们传递了 0,则会打开摄像头(如果存在,否则报错)

cv::VideoCapture vap("cat.MP4");if (!vap.isOpened()) {std::cout << "视频打开失败!\n";return -1;}cv::VideoCapture vap2(0);if (!vap2.isOpened()) { std::cout << "摄像头打开失败!\n";return;}

获取基本视频中的信息:get 函数

通过传递枚举类型来获取指定的信息:

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的布尔标记.......};

例如:

void testProerity(cv::VideoCapture vap) {std::cout << "宽度: " << vap.get(cv::CAP_PROP_FRAME_WIDTH) << '\n';std::cout << "高度: " << vap.get(cv::CAP_PROP_FRAME_HEIGHT) << '\n';std::cout << "帧数: " << vap.get(cv::CAP_PROP_FRAME_COUNT) << '\n';std::cout << "帧率: " << vap.get(cv::CAP_PROP_FPS) << '\n';
}

视频(摄像头)转图像显示

我们加载好视频后,注意到VideoCapture重载了 >> 运算符,因此可以将其重定向到一张Mat上面。

然后再一直显示这张Mat,就可以做到一张一张的图片显示,看起来像视频一样。

如果我们按下ESC则退出或者播放完成后,图片为null

void testCameraToImageShow(cv::VideoCapture vedio) {//显示视频cv::Mat image;while (true) {vedio >> image;if (image.empty() || cv::waitKey(10) == 27) {break;//为null则结束}cv::imshow("cat", image);}vedio.release();
}

对于摄像头的转图片显示,我们只需要传递一个 VideoCapture xxx(0) 即可其他的全是一样的。


视频转图片并且保存

基本操作与上类似,只不过在**imshow**的地方我们改成了保存的操作(当然你也可以一边显示一边保存)

保存过程:imwrite函数

  • name:第一个参数表示保存的路径,传递前缀文件名字后缀来完成:cat/1.png
  • image:保存的图片
void testCameraToPngImageSave(cv::VideoCapture vedio,std::string& prefilename) {cv::Mat image;int index = 1;while (true) {vedio >> image;if (image.empty() || cv::waitKey(10) == 27) {break;}std::string name = prefilename + std::to_string(index++) + ".png";cv::imwrite(name, image);}vedio.release();
}

摄像头转图片并保存

如果是摄像头则我们不能用:imwrite

有一个**VideoWriter** 提供了这样的操作:通过创建一个VideoWriter类型的变量,然后通过 << 重载往它里面写入来完成。

注意**VideoWriter** 的创建:

  • “save.avi” :表示保存的视频路径
  • cv::VideoWriter::fourcc(‘M’, ‘J’, ‘P’, ‘G’):视频的解码器,MJPG表示mp4格式,点击了解更多格式
  • 30:fps帧率
  • cv::Size(width,height):保存的尺寸大小
  • true:是否显示颜色(三通道)
save.open("save.avi", cv::VideoWriter::fourcc('M', 'J', 'P', 'G'),30, cv::Size(width,height), true);

具体操作如下:

void CameraSave() {cv::VideoCapture cap(0);if (!cap.isOpened()) {std::cout << "摄像头打开失败!\n";return;}//获取宽度和高度int width = cap.get(cv::CAP_PROP_FRAME_WIDTH);int height = cap.get(cv::CAP_PROP_FRAME_HEIGHT);cv::VideoWriter save{};save.open("save.avi", cv::VideoWriter::fourcc('M', 'J', 'P', 'G'),30, cv::Size(width,height), true);cv::Mat image;while (true) {cap >> image;cv::imshow("摄像头", image);save << image; //往流中写入if (cv::waitKey(10) == 27) {break;}}cap.release();save.release();
}

滑动条交互

对于滑动条交互也是和鼠标交互类似的:

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:			  用户回传给回调函数的数据
*********************************************************************/

TrackbarCallback 回调函数:

typedef void (*TrackbarCallback)(int pos, void* userdata);
void On_Trackbar(int pos, void* userdata);
/*******************************************************************
*			pos: 			    位置
*			userdata:			用户回传给回调函数的数据
*********************************************************************/

滑动条调整图片的亮度

涉及到对图片的像素操作

详细请看上节内容:

OpenCV(2):图像处理基础概念与操作 | HugeYlh

我们规定一个初始值:current和一个最大值:maxValue,通过调节可以调整此值:

定义:

  • 一个beta表示偏移量
  • alpha表示亮度的调整值
  • copyMat:对一个新的Mat进行像素运算操作,否则无法还原。

对于三通道RGB来说:

  • 如果我们调整为最小值:0
    • 则RGB为(30,30,30)此时为黑色,因此beta就是我们的最小颜色值,即偏移量
  • 然后alpha会根据我们当前滑动条的值进行调整,变大
    • 然后执行像素运算后(xxx,xxx,xxx)就会越来越大,达到亮度提高的效果。

最后显示此图像即可。


对于此回调函数的实现:

//滑动条回调函数static void OnTrack(int pos,void* params){TrackBar* obj = static_cast<TrackBar*>(params);cv::Mat copyMat = cv::Mat::zeros(obj->mt.size(), obj->mt.type());int dims = obj->mt.channels();float beta = 30, alpha = 0.1 + (float)pos / 10.0;for (int i = 0; i < obj->mt.rows; i++) {for (int j = 0; j < obj->mt.cols; j++) {if (dims == 1) {uchar pix = obj->mt.at<uchar>(i, j);copyMat.at<uchar>(i,j) = cv::saturate_cast<uchar>(pix * alpha + beta);}else if (dims == 3) {cv::Vec3b vec = obj->mt.at<cv::Vec3b>(i, j);float b = vec[0], g = vec[1], r = vec[2];copyMat.at<cv::Vec3b>(i, j)[0] = cv::saturate_cast<uchar>(b * alpha + beta);copyMat.at<cv::Vec3b>(i, j)[1] = cv::saturate_cast<uchar>(g * alpha + beta);copyMat.at<cv::Vec3b>(i, j)[2] = cv::saturate_cast<uchar>(r * alpha + beta);}else {return;}}		}cv::imshow("trackBarWindow", copyMat); //显示操作后的图像}

完整代码详见Github项目源码。

https://github.com/luumod/openCV-learning-record

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/6308.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis应用(2)——Redis的项目应用(一):验证码 ---> UUID到雪花ID JMeter高并发测试 下载安装使用

目录 引出Redis的项目应用&#xff08;一&#xff09;&#xff1a;验证码1.整体流程2.雪花ID1&#xff09;UUID&#xff08;Universally Unique Identifier&#xff0c;通用唯一识别码&#xff09;2&#xff09;Twitter 的雪花算法&#xff08;SnowFlake&#xff09; 雪花ID优缺…

HTML <optgroup> 标签

实例 通过 <optgroup> 标签把相关的选项组合在一起: <select><optgroup label="Swedish Cars"><option value ="volvo">Volvo</option><option value ="saab">Saab</option></optgroup><…

【Java】一个简单的接口例子(帮助理解接口+多态)

要求&#xff1a; 请实现笔记本电脑使用USB鼠标、USB键盘的例子 1. USB 接口&#xff1a;包含打开设备、关闭设备功能 2. 笔记本类&#xff1a;包含开机功能、关机功能、使用 USB 设备功能 3. 鼠标类&#xff1a;实现 USB 接口&#xff0c;并具备点击功能 4. 键盘类&am…

磁盘分区形式MBR与GPT介绍

磁盘分区形式MBR与GPT介绍 磁盘分区形式有两种&#xff1a; 1、MBR&#xff08;主启动记录&#xff09;形式&#xff0c;它是存在于磁盘驱动器开始部分的一个特殊的启动扇区&#xff1b; 2、GPT&#xff08;GUID分区表&#xff09;形式&#xff0c;它是一种使用UEFI启动的磁盘…

C#使用Linq和Loop计算集合的平均值、方差【标准差】

方差【标准差】 标准差公式是一种数学公式。标准差也被称为标准偏差&#xff0c;或者实验标准差&#xff0c;公式如下所示&#xff1a; 样本标准差方差的算术平方根ssqrt(((x1-x)^2 (x2-x)^2 ......(xn-x)^2)/n) 总体标准差σsqrt(((x1-x)^2 (x2-x)^2 ......(xn-x)^2)/n ) …

❤️创意网页:抖音汉字鬼抓人小游戏复刻——附带外挂(“鬼鬼定身术”和“鬼鬼消失术”)坚持60秒轻轻松松(●‘◡‘●)

✨博主&#xff1a;命运之光 &#x1f338;专栏&#xff1a;Python星辰秘典 &#x1f433;专栏&#xff1a;web开发&#xff08;简单好用又好看&#xff09; ❤️专栏&#xff1a;Java经典程序设计 ☀️博主的其他文章&#xff1a;点击进入博主的主页 前言&#xff1a;欢迎踏入…

OpenCv之图像形态学

目录 一、形态学 二、图像全局二值化 三、自适应阈值二值化 四、腐蚀操作 五、获取形态学卷积核 六、膨胀操作 七、开运算 八、闭运算 一、形态学 定义: 指一系列处理图像形状特征的图像处理技术形态学的基本思想是利用一种特殊的结构元(本质上就是卷积核)来测量或提取输…

什么是Java的Apache Commons库?

首先&#xff0c;让我们来谈谈字符串处理。你知道吗&#xff0c;有时候我们需要从一段文本中提取出特定的信息&#xff0c;比如提取出一段字符串中的数字。这时候&#xff0c;我们可以使用Apache Commons Lang库中的NumberUtils类。不信&#xff1f;看这里&#xff0c;让我给你…

Flink简介及部署模式

文章目录 1、Flink简介2、Flink部署2.1 本地模式2.1 Standalone模式部署2.2 Standalone模式下的高可用2.3 Yarn模式Yarn模式的高可用配置&#xff1a;yarn模式中三种子模式的区别&#xff1a; 3、并行度4、提交命令执行指定任务Application Mode VS yarn per-job 5、注意事项5、…

4.1 Bootstrap UI 编辑器

文章目录 1. Bootstrap Magic2. BootSwatchr3. Bootstrap Live Editor4. Fancy Boot5. Style Bootstrap6. Lavish7. Bootstrap ThemeRoller8. LayoutIt!9. Pingendo10. Kickstrap11. Bootply12. X-editable13. Jetstrap14. DivShot15. PaintStrap 以下是 15 款最好的 Bootstrap…

Vue--微信和uniapp配置环境地址

一、uniapp 在uni-app中配置小程序的接口地址&#xff0c;可以按照以下步骤进行&#xff1a; 1.在uni-app项目的根目录下创建一个名为 ​config.js​的文件&#xff0c;并确保文件的后缀是 ​.js​。在 ​config.js​文件中定义不同运行环境下的接口地址。例如&#xff1a; …

2023C语言暑假作业day1

1 选择题 1 执行下面程序&#xff0c;正确的输出是 int x5,y7; void swap() { int z; zx; xy; yz; } int main() { int x3,y8; swap(); printf("%d,%d\n"&#xff0c;x, y); return 0; }A: 5,7 B: 7,5 C: 3,8 D: 8,3 答案解析&#xff1a; 正确答案&#xff1a;C…

Linux的tcpdump命令详解

tcpdump 一款sniffer工具&#xff0c;是Linux上的抓包工具&#xff0c;嗅探器 补充说明 tcpdump命令 是一款抓包&#xff0c;嗅探器工具&#xff0c;它可以打印所有经过网络接口的数据包的头信息&#xff0c;也可以使用-w选项将数据包保存到文件中&#xff0c;方便以后分析。…

基于Matlab自抗扰控制器及其PID控制(附上完整源码+数据)

文章目录 说明完整源码数据下载 说明 自抗扰控制器&#xff08;Active Disturbance Rejection Control, ADRC&#xff09;是一种新型的控制策略&#xff0c;它具有强大的抗干扰能力和良好的控制性能。与传统的PID控制器相比&#xff0c;ADRC能够更好地抑制系统的干扰&#xff…

ffplay播放器剖析(5)----视频输出剖析

文章目录 1.视频输出模块1.1 视频输出初始化1.1.1 视频输出初始化主要流程1.1.2 calculate_display_rect初始化显示窗口大小 1.2 视频输出逻辑1.2.1 event_loop开始处理SDL事件1.2.2 video_refresh1.2.2.1 计算上一帧显示时长,判断是否还要继续上一帧1.2.2.2 估算当前帧显示时长…

笔记本电脑的电池健康:确保长时间使用和优异性能的关键

笔记本电脑已经成为我们日常生活中不可或缺的工具&#xff0c;无论是办公、学习还是娱乐&#xff0c;我们都依赖着它的便携性和高效性能。而在所有的硬件组件中&#xff0c;电池健康被认为是确保长时间使用和良好性能的关键因素之一。一块健康的电池不仅能提供持久的续航时间&a…

CHI协议保序之Compack保序

一致性系统中&#xff0c;使用三种保序方式&#xff1b; Completion ack response ⭕Completion acknowledgment&#xff1a; □ 该域段主要是用来&#xff0c; □ 决定 RN 发送的 trans&#xff0c;与其他 RN 发送的命令产生的 SNP 之间的顺序&#xff1b; …

MySQL存储过程——系统变量

1.存储过程中的变量 1.1 查看系统变量 查看所有的系统变量 show variables;查看会话级别的系统变量 show session variables&#xff1b;查看会话和auto相关的变量 show session variables like auto%;查看全局的和auto相关变量 show global variables like auto%;查看某一…

R语言贝叶斯METROPOLIS-HASTINGS GIBBS 吉布斯采样器估计变点指数分布分析泊松过程车站等待时间...

原文链接&#xff1a;http://tecdat.cn/?p26578 指数分布是泊松过程中事件之间时间的概率分布&#xff0c;因此它用于预测到下一个事件的等待时间&#xff0c;例如&#xff0c;您需要在公共汽车站等待的时间&#xff0c;直到下一班车到了&#xff08;点击文末“阅读原文”获取…

CPU,GPU,MCU,SOC,NPU,DPU,内核,架构简略区分

1.架构 架构由不同的指令集构成&#xff0c;不同的侧重方向的指令集构成不同的软件架构&#xff0c;如ARM架构和X86架构等。 2.内核 内核可以看做是不同的软件架构&#xff0c;铺设上一些外设之后构成&#xff0c;相当于软件架构的载体实现&#xff0c;架构是一堆软件代码&a…