当前位置: 首页 > news >正文

OpenCV 滑动条

案例一、通过滑动条修改高、低阈值控制边缘检测

在QuickDemo.h中添加

#pragma once #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; class QuickDemo { void track_bar(); }

在主程序main.cpp中调用

#include "QuickDemo.h" #include <iostream> using namespace cv; using namespace std; int main() { QuickDemo qd; qd.track_bar(); }

在QuickDemo.cpp中编辑函数主体

Mat src, dst; int minValue = 100;//Canny算法的第三个参数:低阈值 int maxValue = 200;//Canny算法的第四个参数:高阈值 void onChange(int,void*)//2. { Canny(src,dst,minValue,maxValue); imshow("滑动条操作窗口",dst); } /// <summary> /// 滑动条控制 /// </summary> void QuickDemo::track_bar() { //1.加载图片图像数据 src = imread("D:\\img\\image\\004.png"); if (src.empty()) { cout << "图片加载失败";return; } imshow("src",src); /*Mat dst; Canny(src,dst,100,200); imshow("dst",dst);*/ namedWindow("滑动条操作窗口",1); //第一步:创建滑动条,指定依附的窗口,并设置指定的滑动条回调函数 createTrackbar("低阈值","滑动条操作窗口",&minValue,255, onChange,0); createTrackbar("高阈值", "滑动条操作窗口", &maxValue, 255, onChange, 0); while (true) { //imshow("滑动条操作窗口", src); int key = waitKey(20); if (key == 27) break; } src.release(); destroyAllWindows(); }

案例二、OpenCV视频+滑动条控制思路

难点1:如何获取总时长、当前时长

解决: 获取视频的帧率,总帧数 视频总时长=总帧数/帧率

int fps = vcp.get(CAP_PROP_FPS);//获取帧率 int frame_count = vcp.get(CAP_PROP_FRAME_COUNT);//总帧数 int second_total = frame_count / fps;//总时长

当前时长=当前帧数/帧率

double frame_current = vcp.get(CAP_PROP_POS_FRAMES);//当前帧数 int second_current = frame_current / fps;//当前时长

难点2:多次回调,程序崩溃

解决:设置手动拖动锁,自动刷新锁

bool isDragging = false;//用户手动拖动滑块锁
bool autoSyncLock = false; // 代码自动刷新滑块锁

在视频播放while循环中编辑

if (!isDragging) { autoSyncLock = true; //上锁:告知回调这是代码自动刷新 setTrackbarPos("播放进度", "显示视频", (int)frame_current); autoSyncLock = false; //解锁 }

在滑动条回调函数中编辑

void on_trackbar_video(int, void*) { if (autoSyncLock) return; //代码自动更新滑块时,直接跳过回调,阻断递归 isDragging = true;//标记正在拖拽,暂停自动刷新 play_video(vcp,frame_current); }

难点3:播放、暂停

int isPlay = 1; // 1播放 0暂停,存储滑动条的值 bool isPlayFlag = true; //是否播放

在滑动条回调函数中编辑

void on_stop_video(int, void*) { isPlayFlag = (isPlay == 1) ? true : false; }

在视频播放while循环中添加

while(true) { if(isPlayFlag) { } }

上面是核心代码,下面是全部代码

在QuickDemo.h中添加

void trackbar_video();

在主程序main.cpp中调用

QuickDemo qd; qd.trackbar_video();

在QuickDemo.cpp中编辑函数主体

/// <summary> /// 返回总时长 /// </summary> /// <param name="seconds"></param> /// <returns></returns> string getDuration(int second_total) { //不超过1小时 int minute = second_total / 60; int second = second_total % 60; string min_str = (minute >= 10) ? to_string(minute) : "0" + to_string(minute); string sec_str = (second >= 10) ? to_string(second) : "0" + to_string(second); return min_str + ':' + sec_str; } /// <summary> /// 根据当前帧数,返回当前播放进度 /// </summary> /// <param name="frame_current"></param> /// <returns></returns> string getCurrentProgress(int frame_current,int fps) { int second_current = frame_current / fps; int minute = second_current / 60; int second = second_current % 60; string min_str = (minute>=10) ? to_string(minute) : "0" + to_string(minute); string sec_str = (second>=10)? to_string(second) : "0" + to_string(second); return min_str + ':' + sec_str; } int frame_current; VideoCapture vcp; bool isDragging = false;//用户手动拖动滑块锁 bool autoSyncLock = false; // 代码自动刷新滑块锁 int isPlay = 1; // 1播放 0暂停,存储滑动条的值 bool isPlayFlag = true; //是否播放 /// <summary> /// 正常从0帧播放视频 /// </summary> /// <param name="vcp"></param> void play_video(VideoCapture vcp) { int fps = vcp.get(CAP_PROP_FPS);//获取帧率 int frame_count = vcp.get(CAP_PROP_FRAME_COUNT);//总帧数 int second_total = frame_count / fps;//总时长 //cout << "帧率:" << fps << "总帧数:" << frame_count << "总时长:" << second_total << endl; while (true) { if(isPlayFlag) { Mat frame;//创建图片数据对象 vcp.read(frame); if (frame.empty()) { break; }//读取为空则结束 //获取当前帧数 double frame_current = vcp.get(CAP_PROP_POS_FRAMES); cout << "当前帧数:"<<frame_current << endl; if (!isDragging) { autoSyncLock = true; //上锁:告知回调这是代码自动刷新 setTrackbarPos("播放进度", "显示视频", (int)frame_current); autoSyncLock = false; //解锁 } string result = getCurrentProgress((int)frame_current, fps) + "/" + getDuration(second_total); result += " fps:" + to_string(fps)+"fps_current:"+ to_string(frame_current); putText(frame, result,Point(30,30),1,2,Scalar(0,0,255),2,8); imshow("显示视频", frame); } int key = waitKey(20); if (key == 27) break; isDragging = false; } vcp.release(); destroyAllWindows(); } /// <summary> /// 从当前帧播放视频 /// </summary> /// <param name="vcp">视频数据</param> /// <param name="frame_current">当前帧</param> void play_video(VideoCapture vcp, double frame_current) { int fps = vcp.get(CAP_PROP_FPS);//获取帧率 int frame_count = vcp.get(CAP_PROP_FRAME_COUNT);//总帧数 int second_total = frame_count / fps;//总时长 cout << "帧率:" << fps << "总帧数:" << frame_count << "总时长:" << second_total << endl; vcp.set(CAP_PROP_POS_FRAMES, frame_current); //校验是否跳转成功(很多时候不会精准跳转到100,会跳到 最近1帧) frame_current = vcp.get(CAP_PROP_POS_FRAMES); cout << "跳转后实际所在帧:" << frame_current << endl; while (true) { if(isPlayFlag) { Mat frame;//创建图片数据对象 vcp.read(frame); if (frame.empty()) { break; }//读取为空则结束 namedWindow("显示视频", WINDOW_FREERATIO);//方便调节大小 //获取当前帧数 frame_current = vcp.get(CAP_PROP_POS_FRAMES); cout << "当前帧数:" << frame_current << endl; if (!isDragging) { autoSyncLock = true; //上锁:告知回调这是代码自动刷新 setTrackbarPos("播放进度", "显示视频", (int)frame_current); autoSyncLock = false; //解锁 } string result = getCurrentProgress((int)frame_current, fps) + "/" + getDuration(second_total); result += " fps:" + to_string(fps) + "fps_current:" + to_string(frame_current); putText(frame, result, Point(30, 30), 1, 2, Scalar(0, 0, 255), 2, 8); imshow("显示视频", frame); } int key = waitKey(20); if (key == 27) break; isDragging = false; } vcp.release(); destroyAllWindows(); } void on_trackbar_video(int, void*) { if (autoSyncLock) return; //代码自动更新滑块时,直接跳过回调,阻断递归 isDragging = true;//标记正在拖拽,暂停自动刷新 play_video(vcp,frame_current); } void on_stop_video(int, void*) { isPlayFlag = (isPlay == 1) ? true : false; } /// <summary> /// 滑动条控制视频播放 /// </summary> void QuickDemo::trackbar_video() { vcp.open("D:\\img\\video\\test.avi"); if (!vcp.isOpened()) { cout << "视频打开失败!"; return; } frame_current = 0; int frame_count = vcp.get(CAP_PROP_FRAME_COUNT);//总帧数 //cout << "总帧数:" << frame_count; namedWindow("显示视频", WINDOW_FREERATIO); createTrackbar("播放进度", "显示视频", &frame_current, frame_count, on_trackbar_video, 0); createTrackbar("播放/暂停","显示视频",&isPlay,1,on_stop_video,0); play_video(vcp); }

案例三 滑动条调节图片亮度

在QuickDemo.h中添加

void trackbar_bright();

在主程序main.cpp中调用

QuickDemo qd; qd.trackbar_bright();//调节亮度

在QuickDemo.cpp中编辑函数主体

int brightness = 0; Mat src = imread("D:\\img\\image\\baboon.jpg"); Mat temp = src.clone();//副本 /// <summary> /// 调节像素 /// </summary> /// <param name="a">原像素</param> /// <param name="b">增、减像素</param> /// <returns></returns> int adjustBright(int a,int b) { if (a + b >= 255) return 255; else if (a + b <= 0) return 0; else return a + b; } void onTrackbar(int, void*) { int width = src.rows; int height = src.cols; for (int i = 0;i < width;i++) { for (int j = 0;j < height;j++) { temp.at<Vec3b>(i, j)[0] = adjustBright(src.at<Vec3b>(i, j)[0], brightness); temp.at<Vec3b>(i, j)[1] = adjustBright(src.at<Vec3b>(i, j)[1], brightness); temp.at<Vec3b>(i, j)[2] = adjustBright(src.at<Vec3b>(i, j)[2], brightness); } } imshow("src", temp); } /// <summary> /// 滑动条调节亮度 /// </summary> void QuickDemo::trackbar_bright() { if (src.empty()) { cout << "图片加载失败!";return; } namedWindow("src", 1); createTrackbar("调节亮度", "src", &brightness, 255, onTrackbar,0); setTrackbarMin("调节亮度", "src",-255); showPic("src", src); waitKey(0); destroyAllWindows(); }

文件下载

通过网盘分享的文件:070303img.zip 链接: 百度网盘 请输入提取码 提取码: 772p

文件下载后,修改文件夹名为"img",存放D盘。

以上不足,请同行、业界大佬批评指正。

http://www.jsqmd.com/news/1181502/

相关文章:

  • 2026闲置LV邮差包出手渠道对比,逸程估价统一不看人乱报价 - 逸程奢侈品回收中心
  • Wand-Enhancer终极指南:5分钟解锁完整游戏修改体验
  • MySQL数据库基础篇(一):数据库以及Centos 8环境下数据库的安装
  • 基于yolov8目标检测的垃圾识别分类系统 13(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_文章底部可以扫码
  • 为什么你的Claude总在关键推理节点“跳步”?揭秘Token分配盲区与思维链保真度校验公式(附可运行Python验证脚本)
  • 如何解决Gemini到word的格式问题?AI 导出鸭打通格式转换全链路
  • AAA企业信用等级证书在哪里申请?投标能带来什么加分优势? - 叮咚办真方便
  • Agent 架构从单体到分布式:多 Agent 系统怎么拆分和编排部署
  • 工程项目行业管理软件实用解读:通用软件不好用怎么办
  • 【免费领源码】SpringBoot+Vue一对一家教平台:预约家教、课程安排、作业反馈全流程05435
  • 如何彻底解锁Wand专业版:终极增强工具完整指南
  • 市场正规的光子嫩肤淡化色斑口碑
  • 学 Simulink — 无线充电系统中 DC‑DC 变换器的恒功率(CP)控制仿真
  • Drab Commander实战教程:编写你的第一个实时交互功能
  • 家庭团建聚餐优选!蒙阴地道炒鸡哪家香?福地锦园木柴鸡解锁传承老味道 - 宁夏壹山网络
  • Bolts-Swift错误处理最佳实践:优雅处理异步任务中的异常情况
  • 汇川easyPLC_小白免费入门100步_74步 昆仑通泰触摸屏跟汇川easyPLC建立MODUBUS TCP 通讯
  • 基于TVA、VLA和世界模型的三大具身智能范式(14)
  • TVA与具身智能融合的内在必然性(16)
  • 2026年7月最新泰州天梭官方售后热线及客户服务网点地址 - 天梭服务中心
  • Gemma-4-E4B-it-8bit常见问题解答:解决安装和使用的15个难题
  • Step-3.5-Flash-MXFP4深度解析:MXFP4量化技术如何实现97.6%精度恢复
  • 西安安防智能系统设备富驰:西北出入口安防选型干货与竞品客观对比 - 百航
  • 深度残差网络ResNet:从理论到实践,手把手教你复现经典模型
  • Chrome 扩展程序 MV3 架构组件概览
  • 为什么Llama-3.2-3B-Instruct_rai_1.7.1_npu_4K是边缘AI计算的理想选择
  • 基于TVA、VLA和世界模型的三大具身智能范式(15)
  • Agent 高可用设计:多实例部署下的状态同步和故障转移策略
  • 2026年新鲜出炉!泰州别墅装修企业排名大揭秘 - 信息热点
  • SPT-AKI存档编辑器终极指南:3分钟掌握离线塔科夫存档修改秘籍 [特殊字符]