OpenCV连续自适应跟踪算法CAMShift实现视频对象跟踪
一、概述
案例:使用OpenCV的CAMShift算法实现视频中对象跟踪
算法API介绍:
CamShift( InputArray probImage, CV_IN_OUT Rect& window,
TermCriteria criteria );
probImage:要跟踪对象的直方图反向投影矩阵
window:跟踪的目标区域
criteria:迭代停止条件
算法实现步骤:
1.实例化VideoCapture
2.使用VideoCapture的open方法打开视频
3.while循环读取视频帧
4.检测是否是读取的第一帧,如果是第一帧则对第一帧选取roi区域,并生成roi区域的直方图矩阵
5.否则就使用计算过的直方图数据制作脂肪头的反射投影矩阵
6.使用CAMShift算法跟踪对象,并输入跟踪对象矩阵
7.使用跟踪矩阵数据绘制外接圆
8.循环4~7步骤,直到视频帧读取结束
二、代码示例
CAM_Shift_Video_Object_Tracking::CAM_Shift_Video_Object_Tracking(QWidget *parent) : MyGraphicsView{parent} { this->setWindowTitle("CAMShift对象跟踪"); QPushButton *btn = new QPushButton(this); btn->setText("选择视频"); connect(btn,&QPushButton::clicked,[=](){ choiceVideo(); }); } void CAM_Shift_Video_Object_Tracking::choiceVideo(){ path = QFileDialog::getOpenFileName(this,"请选择视频","/Users/yangwei/Downloads/",tr("Image Files(*.mp4 *.avi)")); qDebug()<<"视频路径:"<<path; videoObjectTracking(path.toStdString().c_str()); } void CAM_Shift_Video_Object_Tracking::videoObjectTracking(const char *filePath){ VideoCapture capture; capture.open(filePath); if(!capture.isOpened()){ qDebug()<<"打开视频失败"; return; } bool isFirstRead = true;//是否读取的第一帧 Mat frame;//视频帧图像 Mat hsv;//hsv色彩空间图像数据 Rect selection;//选中区域 Mat mask;//颜色过滤的遮罩 Mat hue;//h通道数据 Mat hist;//图像直方图数据 Mat backprojection;//直方图反向投影的输出 float hrange[] = { 0, 180 }; const float* hranges = hrange; int bins = 16; Mat drawImg = Mat::zeros(300, 300, CV_8UC3);//直方图就绘制在这个图像中 while(capture.read(frame)){ if(isFirstRead){//如果是第一帧就需要选取roi区域,并对selection填充数据 Rect2d rect = selectROI(frame); selection.x = rect.x; selection.y = rect.y; selection.width = rect.width; selection.height = rect.height; qDebug()<<"第一帧已选取完成"; } qDebug()<<"转HSV"; //转换hsv色彩空间 cvtColor(frame,hsv,COLOR_BGR2HSV); //使用inRange过滤像素 // inRange(hsv,Scalar(26,43,46),Scalar(34,255,255),mask); inRange(hsv,Scalar(13,30,32),Scalar(50,255,255),mask); //使用mixChanngles获取H通道的数据 int channels[] = { 0, 0 }; qDebug()<<"过滤H通道"; hue = Mat(hsv.size(), hsv.depth()); mixChannels(&hsv, 1, &hue, 1, channels, 1); if(isFirstRead){//如果是第一帧,就计算roi区域的直方图 qDebug()<<"计算并绘制直方图"; Mat roi(hue,selection); Mat maskRoi(mask,selection); calcHist(&roi,1,0,maskRoi,hist,1,&bins,&hranges); //将直方图数据归一化到0~255 normalize(hist,hist,0,255,NORM_MINMAX); //绘制直方图数据 int binw = drawImg.cols / bins; Mat colorIndex = Mat(1, bins, CV_8UC3); for (int i = 0; i < bins; i++) { colorIndex.at<Vec3b>(0, i) = Vec3b(saturate_cast<uchar>(i * 180 / bins), 255, 255); } cvtColor(colorIndex, colorIndex, COLOR_HSV2BGR); for (int i = 0; i < bins; i++) { int val = saturate_cast<int>(hist.at<float>(i)*drawImg.rows / 255); rectangle(drawImg, Point(i*binw, drawImg.rows), Point((i + 1)*binw, drawImg.rows - val), Scalar(colorIndex.at<Vec3b>(0, i)), -1, 8, 0); } } //对直方图执行反向投影(作为camshift函数会用到),作为输入 calcBackProject(&hue,1,0,hist,backprojection,&hranges); //执行CAMShift跟踪 backprojection &= mask;//此处是为了让结果更加精准 RotatedRect trackBox = CamShift(backprojection,selection,TermCriteria((TermCriteria::COUNT | TermCriteria::EPS), 10, 1)); //绘制roi区域的外接圆 ellipse(frame,trackBox,Scalar(0,255,255),3); if(isFirstRead){ isFirstRead= false; } imshow("frame",frame); imshow("hist",drawImg); int c = waitKey(1); if(c==27){ break; } } capture.release(); }
三、图像演示
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库