您好,
会员登录 快速注册
退出 ( 条未读消息)
关于本站 意见反馈 首页

公告:小宅博客网可以开发票了,需要发票的,去群里找群主哈!!
全部文章分类
  • 人工智能 >

  • 编程语言 >

  • WPF系列 >

  • ASP.NET系列 >

  • Linux >

  • 数据库 >

  • 嵌入式 >

  • WEB技术 >

  • PLC系列 >

  • 微服务与框架 >

  • 小宅DIY >

  • 学习资料 >

OpenCv基础 ANN车牌识别 yolov5车牌识别 指针式仪表识别 ROS系列 YOLO Halcon Detectron2 昇腾AI ChatGPT在线体验 英伟达JETSON ChatGLM ChatTTS FunASR 地平线 ByteTrack 魔搭社区 LangChain
C C# C++ Python Java Go
WPF
ASP.NET小功能 GPS定位系统-MVC GPS定位系统-VUE ASP.NET WebRTC
Linux Linux内核 Shell MakeFile
MySql SqlServer Oracle
STM8 STM32 51单片机
VUE入门 HTML JavaScript CSS layui镜像网站 ElementUi中文官网 element-plus 图标
三菱 欧姆龙 西门子 施耐德 松下 台达
IOTSharp IOTGateway ABP FRAMEWORK Docker
亚克力音响 编程仙途:智驭万法
面试题与技巧 Python入门技能树 微软C#教程
首页 编程之美 工具下载 全国就业 流量地图 文心一言
OpenCv基础
内容介绍与资料分享 C# OpenCv环境搭建 C++ OpenCv环境搭建 Python OpenCv环境搭建 Java OpenCv环境搭建 OpenCv组件结构解析 OpenCv命名规范 OpenCv基本专业术语与方法 OpenCV 常用函数与构造体详细说明 创建画布 打开一张图片 利用imwrite生成透明png图像 图像打开、混合显示和输出 图像腐蚀 blur图像模糊(均值滤波) sobel边缘检测 canny边缘检测 Scharr滤波器 程序性能检测及优化 视频播放 摄像头录像与播放 双摄像头操作与图像相似度检测 颜色空间转换与物体追踪 彩色目标追踪 光流法运动目标检测 OpenCV中的稠密光流 背景减除 点追踪 人脸识别 支持向量机之SVM引导 支持向量机之处理线性不可分数据 ROI矩形截取 鼠标绘制矩形 用OpenCV进行基本绘图 绘图函数(python中文显示) 把鼠标当画笔 用滑动条做调色板 图像的基础操作 图像上的算术运算 多通道图像混合 图像的亮度、对比度调整 XML和YAML文件的写入 XML和YAML文件的读取 卷积操作 三种线性滤波 两种非线性滤波 7种图像处理形态学(1) 7种图像处理形态学(2) 漫水填充 图像缩放与图像金字塔 二值化基本阈值操作 图像阈值 Laplacian图像变换(拉普拉斯算子) 霍夫变换HoughLines边缘检测与线性矢量 霍夫变换HoughLinesP边缘检测与线性矢量 霍夫变换HoughCircles边缘检测与线性矢量 LSD快速直线检测 几何变换 remap重映射 remap实现多种重映射 仿射变换综合示例 直方图均衡化 CLAHE有限对比适应性直方图均衡化 draw最大的轮廓 轮廓的性质 点到多边形的最短距离 形状匹配 椭圆拟合与直线拟合 基础轮廓查找 查找并绘制轮廓综合示例 凸缺陷/凸包检测 凸包检测 创建包围轮廓的矩形边界 创建包围轮廓的圆形边 创建包围轮廓的矩形和圆形边界框 查找和绘制图片轮廓矩 分水岭算法 图像修补 H-S二维直方图的绘制/2D直方图 一维直方图的绘制 RGB三色直方图的绘制 直方图对比 使用掩膜绘制直方图 直方图反向投影 模板匹配 多对象模板匹配 cornerHarris角点检测 cornerHarris角点检测综合示例 Shi-Tomasi角点检测 亚像素级角点检测 角点检测的FAST算法(FAST特征检测器) 颜色识别 warpPerspective透视变换 SURF/SIFT特征点检测 SURF/SIFT特征描述 使用FLANN进行特征点匹配 FLANN结合SURF/SIFT进行关键点的描述和匹配 寻找已知物体(一) 寻找已知物体(二) 目标查找与跟踪 - Meanshift与CamShift BRIEF描述符 ORB ORB算法描述与匹配 LUT 图像灰度调整 离散傅里叶变换 双目摄像头与图像拼接 环境亮度检测 stitching 全景拼接 Maze-Solver迷宫解密 使用Haar分类器之面部检测 使用Haar分类器之行人检测 OpenCv Haar/LBP/HOG分类器-人脸识别 斑点检测 使用GrabCut算法进行交互式前景提取 对极几何 摄像机标定 姿势估计 立体图像中的深度地图 OpenCv中的KNN KNN手写数字识别 ​SVM手写数字识别(使用SVM进行手写数据OCR) 英文字母的OCR 预测手写数字(预测不准) K值聚类(一) K值聚类(二) 计算摄影学-图像去噪 高动态范围成像(HDRI或HDR) MSER区域检测 二维码、条形码识别 删除图像中的水印 OpenCv深度学习dnn Kinect-深度相机 OpenCv常用数学算法 360度旋转直线绘制 向量延长线上的像素扫描 Tools工具包-窗体分配
颜色空间转换与物体追踪
光流法运动目标检测
激萌の小宅 小宅博客网 OpenCv基础

文章作者:激萌の小宅

促销:¥0

价格:¥0

配送方式: 购买后立即生效(如购买异常,请联系站长)
付款之后一定要等待自动跳转结束,否则购买可能会失败
  • 0 天

    有效期

  • 0

    总销量

  • 2

    累计评价

彩色目标追踪

       彩色目标追踪,C++版本是采用毛星云的demo修改的,C#和Python版本则是在C++版本基础上延伸出来的,由于各种语言之间OpenCv的API有不少差异,尤其是在针对像素的操作上。这就导致了C++版本上的部分功能或者操作在C#和Python版本上没调通,毕竟官方demo很多操作都没有demo。


视频讲解如下:



当前系列所有demo下载地址:

https://github.com/GaoRenBao/OpenCv4-Demo

不同编程语言对应的OpenCv版本以及开发环境信息如下: 

语言

OpenCv版本

IDE

C#

OpenCvSharp4.4.8.0.20230708

Visual Studio 2022

C++

OpenCv-4.5.5-vc14_vc15

Visual Studio 2022

Python

OpenCv-Python (4.6.0.66)

PyCharm Community Edition 2022.1.3


C#版本代码如下:

C#版本需要安装“OpenCvSharp4”、“OpenCvSharp4.runtime.win”两个库才行。不然会报错。

如果需要使用“ BitmapConverter.ToBitmap”操作,则需要追加安装“OpenCvSharp4.Extensions”库。


早期版本是opencv3的,目前已改成opencv4,但是3版本的代码,我也顺便保留,给大家做个对比参考。

下面我们先来看一下C#版本的操作,C#版本不是很稳定,偶尔会异常,不过基础功能倒是实现了。。。

效果演示如下:


C# OpenCv3版本代码如下:

using OpenCvSharp;
using System;
using System.Windows.Forms;

namespace WindowsFormsApp
{
    public partial class Form1 : Form
    {
        // 声明全局变量
        public Mat image = new Mat();
        public bool selectObject = false;
        public int trackObject = 0;
        public Rect selection;
        public Point origin;

        /// <summary>
        /// 视频操作
        /// </summary>
        public VideoCapture Cap = new VideoCapture();

        public Form1()
        {
            InitializeComponent();
        }

        public void onMouse(MouseEvent @event, int x, int y, MouseEvent flags, IntPtr userdata)
        {
            //当左键按下,框选标志为真,执行如下程序得到矩形区域selection
            if (selectObject)
            {
                selection.X = Math.Min(x, origin.X);
                selection.Y = Math.Min(y, origin.Y);
                selection.Width = Math.Abs(x - origin.X);
                selection.Height = Math.Abs(y - origin.Y);
                //矩形区域与image进行与运算,结果保存到矩形区域中
                selection &= new Rect(0, 0, image.Cols, image.Rows);
            }
            if (@event == MouseEvent.LButtonDown)
            {
                origin = new Point(x, y);
                selection = new Rect(x, y, 0, 0);
                selectObject = true;
            }
            if (@event == MouseEvent.LButtonUp)
            {
                selectObject = false;
                if (selection.Width > 0 && selection.Height > 0)
                    trackObject = -1;
            }
        }

        // 打开摄像头
        private void button1_Click(object sender, EventArgs e)
        {
            int hsize = 16;
            float[] phranges = { 0, 180 };
            Rect trackWindow = new Rect();

            // 打开ID为0的摄像头
            Cap.Open(0);
            // 判断摄像头是否成功打开
            if (!Cap.IsOpened())
            {
                MessageBox.Show("摄像头打开失败.");
                return;
            }
            // 设置采集的图像尺寸为:640*480
            Cap.Set(CaptureProperty.FrameHeight, 480);
            Cap.Set(CaptureProperty.FrameWidth, 640);

            Mat frame = new Mat();
            Mat hsv = new Mat();
            Mat hue = new Mat();
            Mat mask = new Mat();
            Mat hist = new Mat();
            Mat backproj = new Mat();

            Cv2.NamedWindow("Histogram");
            Cv2.NamedWindow("CamShift Demo");

            CvMouseCallback GetRGBCvMouseCallback = new CvMouseCallback(onMouse);
            Cv2.SetMouseCallback("CamShift Demo", GetRGBCvMouseCallback);

            while (true)
            {
                //读取当前帧
                if (!Cap.Read(frame)) continue;
                if (frame.Empty()) break;

                frame.CopyTo(image); //将当前帧复制到image中
                Cv2.CvtColor(image, hsv, ColorConversionCodes.BGR2HSV); //将image转为hsv色彩空间,保存到hsv中
                if (trackObject != 0)//如果有操作,trackobject等于1或-1
                {
                    // 亮度范围设置
                    int _vmin = 10, _vmax = 256;
                    // 色彩范围检测
                    // Scalar: 色调、饱和度、亮度,第一个Scalar是最小值,第二个Scalar是最大值
                    Cv2.InRange(hsv, new Scalar(0, 30, Math.Min(_vmin, _vmax)), new Scalar(180, 256, Math.Max(_vmin, _vmax)), mask);
                    hue.Create(hsv.Size(), hsv.Depth());//创建一个与hsv尺寸和深度一样的hue

                    // 从输入中拷贝某通道到输出中特定的通道。
                    // 官方代码参考位置:./Sample-4.1.0-20190417/SamplesCS/Samples/MergeSplitSample.cs:51:
                    int[] ch = { 0, 0 };
                    Mat[] input = { hsv };
                    Mat[] output = { hue, };
                    Cv2.MixChannels(input, output, ch);

                    Rangef[] range = new Rangef[3];//三个通道,范围
                    range[0].Start = phranges[0];//从0开始(含)
                    range[0].End = phranges[1];  //到180结束(不含)
                    range[1] = range[0];//通道2和通道1一样
                    range[2] = range[0];//通道3和通道1一样

                    if (trackObject < 0)//如果为-1,代表左键弹起,划定了区域
                    {
                        //hue是视频帧处理后的图像,selection是鼠标选定的矩形区域,同时创建一个感兴趣区域和一个标记感兴趣区域
                        Mat roi = new Mat(hue, selection);
                        Mat maskroi = new Mat(mask, selection);
                        Cv2.CalcHist(images: new[] { roi }, channels: new[] { 0 }, mask: maskroi, hist: hist, dims: 1,
                            histSize: new[] { 16 }, ranges: new[] { new Rangef(0, 180) });
                        Cv2.Normalize(hist, hist, 0, 255, NormTypes.MinMax);
                        trackWindow = selection;
                        trackObject = 1;
                    }

                    Mat[] arrs2 = { hue };
                    Cv2.CalcBackProject(arrs2, channels: new[] { 0 }, hist, backproj, range);
                    backproj &= mask;
                    RotatedRect trackBox = Cv2.CamShift(backproj, ref trackWindow, new TermCriteria(CriteriaType.Count | CriteriaType.Eps, 10, 1));

                    if ((trackWindow.Width * trackWindow.Height) <= 1)
                    {
                        int cols = backproj.Cols, rows = backproj.Rows, r = (Math.Min(cols, rows) + 5) / 6;
                        trackWindow = new Rect(trackWindow.X - r, trackWindow.Y - r,
                            trackWindow.X + r, trackWindow.Y + r) &
                            new Rect(0, 0, cols, rows);
                    }

                    // 投影视图
                    // Cv2.CvtColor(backproj, image, ColorConversionCodes.GRAY2BGR);

                    Cv2.Ellipse(image, trackBox, new Scalar(0, 0, 255), 3, LineTypes.AntiAlias);
                }

                if (selectObject && selection.Width > 0 && selection.Height > 0)
                {
                    Mat roi = new Mat(image, selection);
                    Cv2.BitwiseNot(roi, roi);
                }
                Cv2.ImShow("CamShift Demo", image);

                if ((char)Cv2.WaitKey(10) == 27) break;
            }
        }
    }
}


C# OpenCv4版本代码如下:

using OpenCvSharp;
using System;

namespace ConsoleApp
{
    internal class Program
    {
        // 声明全局变量
        public static Mat image = new Mat();
        public static bool selectObject = false;
        public static int trackObject = 0;
        public static Rect selection;
        public static Point origin;

        /// <summary>
        /// 视频操作
        /// </summary>
        public static VideoCapture Cap = new VideoCapture();

        private static void onMouse(MouseEventTypes @event, int x, int y, MouseEventFlags flags, IntPtr userData)
        {
            //当左键按下,框选标志为真,执行如下程序得到矩形区域selection
            if (selectObject)
            {
                selection.X = Math.Min(x, origin.X);
                selection.Y = Math.Min(y, origin.Y);
                selection.Width = Math.Abs(x - origin.X);
                selection.Height = Math.Abs(y - origin.Y);
                //矩形区域与image进行与运算,结果保存到矩形区域中
                selection &= new Rect(0, 0, image.Cols, image.Rows);
            }
            if (@event == MouseEventTypes.LButtonDown)
            {
                origin = new Point(x, y);
                selection = new Rect(x, y, 0, 0);
                selectObject = true;
            }
            if (@event == MouseEventTypes.LButtonUp)
            {
                selectObject = false;
                if (selection.Width > 0 && selection.Height > 0)
                    trackObject = -1;
            }
        }

        static void Main(string[] args)
        {
            int hsize = 16;
            float[] phranges = { 0, 180 };
            Rect trackWindow = new Rect();

            // 打开ID为0的摄像头
            Cap.Open(0);
            // 判断摄像头是否成功打开
            if (!Cap.IsOpened())
            {
                Console.WriteLine("摄像头打开失败.");
                return;
            }
            // 设置采集的图像尺寸为:640*480
            Cap.Set(VideoCaptureProperties.FrameHeight, 480);
            Cap.Set(VideoCaptureProperties.FrameWidth, 640);

            Mat frame = new Mat();
            Mat hsv = new Mat();
            Mat hue = new Mat();
            Mat mask = new Mat();
            Mat hist = new Mat();
            Mat backproj = new Mat();

            Cv2.NamedWindow("Histogram");
            Cv2.NamedWindow("CamShift Demo");

            MouseCallback GetRGBCvMouseCallback = new MouseCallback(onMouse);
            Cv2.SetMouseCallback("CamShift Demo", GetRGBCvMouseCallback);

            while (true)
            {
                //读取当前帧
                if (!Cap.Read(frame)) continue;
                if (frame.Empty()) break;

                frame.CopyTo(image); //将当前帧复制到image中
                Cv2.CvtColor(image, hsv, ColorConversionCodes.BGR2HSV); //将image转为hsv色彩空间,保存到hsv中
                if (trackObject != 0)//如果有操作,trackobject等于1或-1
                {
                    // 亮度范围设置
                    int _vmin = 10, _vmax = 256;
                    // 色彩范围检测
                    // Scalar: 色调、饱和度、亮度,第一个Scalar是最小值,第二个Scalar是最大值
                    Cv2.InRange(hsv, new Scalar(0, 30, Math.Min(_vmin, _vmax)), new Scalar(180, 256, Math.Max(_vmin, _vmax)), mask);
                    hue.Create(hsv.Size(), hsv.Depth());//创建一个与hsv尺寸和深度一样的hue

                    // 从输入中拷贝某通道到输出中特定的通道。
                    // 官方代码参考位置:./Sample-4.1.0-20190417/SamplesCS/Samples/MergeSplitSample.cs:51:
                    int[] ch = { 0, 0 };
                    Mat[] input = { hsv };
                    Mat[] output = { hue, };
                    Cv2.MixChannels(input, output, ch);

                    Rangef[] range = new Rangef[3];//三个通道,范围
                    range[0] = new Rangef(phranges[0], phranges[1]); //从0开始(含),到180结束(不含)
                    range[1] = range[0];//通道2和通道1一样
                    range[2] = range[0];//通道3和通道1一样

                    if (trackObject < 0)//如果为-1,代表左键弹起,划定了区域
                    {
                        //hue是视频帧处理后的图像,selection是鼠标选定的矩形区域,同时创建一个感兴趣区域和一个标记感兴趣区域
                        Mat roi = new Mat(hue, selection);
                        Mat maskroi = new Mat(mask, selection);
                        Cv2.CalcHist(images: new[] { roi }, channels: new[] { 0 }, mask: maskroi, hist: hist, dims: 1,
                            histSize: new[] { 16 }, ranges: new[] { new Rangef(0, 180) });
                        Cv2.Normalize(hist, hist, 0, 255, NormTypes.MinMax);
                        trackWindow = selection;
                        trackObject = 1;
                    }

                    Mat[] arrs2 = { hue };
                    Cv2.CalcBackProject(arrs2, channels: new[] { 0 }, hist, backproj, range);
                    backproj &= mask;
                    RotatedRect trackBox = Cv2.CamShift(backproj, ref trackWindow, new TermCriteria(CriteriaTypes.Count | CriteriaTypes.Eps, 10, 1));

                    if ((trackWindow.Width * trackWindow.Height) <= 1)
                    {
                        int cols = backproj.Cols, rows = backproj.Rows, r = (Math.Min(cols, rows) + 5) / 6;
                        trackWindow = new Rect(trackWindow.X - r, trackWindow.Y - r,
                            trackWindow.X + r, trackWindow.Y + r) &
                            new Rect(0, 0, cols, rows);
                    }

                    // 投影视图
                    // Cv2.CvtColor(backproj, image, ColorConversionCodes.GRAY2BGR);

                    Cv2.Ellipse(image, trackBox, new Scalar(0, 0, 255), 3, LineTypes.AntiAlias);
                }

                if (selectObject && selection.Width > 0 && selection.Height > 0)
                {
                    Mat roi = new Mat(image, selection);
                    Cv2.BitwiseNot(roi, roi);
                }
                Cv2.ImShow("CamShift Demo", image);

                if ((char)Cv2.WaitKey(10) == 27) break;
            }
        }
    }
}


下面这是官方提供的关于CalcHist直方图的操作demo。

代码位置在:Sample-4.1.0-20190417/OpenCvSharp.Tests/imgproc/ImgProcTest.cs:600

效果呢,可以给大家看下,就是下面这个样子。

官方代码如下:

public void CalcHist()
{
    using var src = new Mat(@"_data/image/mandrill.png", ImreadModes.Grayscale);

    using var hist = new Mat();
    Cv2.CalcHist(
        images: new[] { src },
        channels: new[] {0},
        mask: null,
        hist: hist,
        dims: 1,
        histSize: new[] {256},
        ranges: new[] { new Rangef(0, 256) });

    if (Debugger.IsAttached)
    {
        const int histW = 512;
        const int histH = 400; 
        var binW = Math.Round((double)histW / 256);
        using var histImage = new Mat(histH, histW, MatType.CV_8UC3, Scalar.All(0));
        Cv2.Normalize(hist, hist, 0, histImage.Rows, NormTypes.MinMax, -1);

        for (int i = 0; i < 256; i++)
        {
            var pt1 = new Point2d(binW * (i - 1), histH - Math.Round(hist.At<float>(i - 1)));
            var pt2 = new Point2d(binW * (i), histH - Math.Round(hist.At<float>(i)));
            Cv2.Line(
                histImage, (Point)pt1, (Point)pt2,
                Scalar.Red, 1, LineTypes.Link8);
        }

        Window.ShowImages(src, histImage);
    }
}


C++版本

C++版本是毛星云的版本简化来的,去掉了很多没必要的操作界面,直接保留了核心功能。

效果演示如下:

彩色目标追踪2 (1).gif

代码如下:

#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <ctype.h>

using namespace cv;
using namespace std;

// 声明全局变量
Mat image;
//bool backprojMode = false;
bool selectObject = false;
int trackObject = 0;
Rect selection;
Point origin;

// 鼠标操作回调:鼠标状态每改变一次,此函数就执行一次
void onMouse(int event, int x, int y, int, void*)
{
    //当左键按下,框选标志为真,执行如下程序得到矩形区域selection
    if (selectObject)
    {
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);
        //矩形区域与image进行与运算,结果保存到矩形区域中
        selection &= Rect(0, 0, image.cols, image.rows);
    }

    switch (event)
    {
        //此句代码的OpenCV2版为:
        //case CV_EVENT_LBUTTONDOWN:

        //此句代码的OpenCV3版为:
        //当左键按下,记录原点,创建矩形区域,框选标志置为真
    case EVENT_LBUTTONDOWN:
        origin = Point(x, y);
        selection = Rect(x, y, 0, 0);
        selectObject = true;
        break;

        //此句代码的OpenCV2版为:
        //case CV_EVENT_LBUTTONUP:

        //此句代码的OpenCV3版为:
        //当左键弹起,将框选标志置为假,如果矩形区域的长宽都大于零,令跟踪标志为-1
    case EVENT_LBUTTONUP:
        selectObject = false;
        if (selection.width > 0 && selection.height > 0)
            trackObject = -1;
        break;
    }
}

int main()
{
    int hsize = 16;
    float hranges[] = { 0,180 };
    const float* phranges = hranges;
    Rect trackWindow;

    VideoCapture cap;
    cap.open(0);
    if (!cap.isOpened())
    {
        cout << "初始化摄像头失败\n";
        while (true);
    }

    namedWindow("Histogram", 1);
    namedWindow("CamShift Demo", 1);
    // 鼠标事件检测
    setMouseCallback("CamShift Demo", onMouse, 0);

    Mat frame, hsv, hue, mask, hist, backproj;

    while (true)
    {
        cap >> frame;//读取当前帧
        if (frame.empty())
            break;

        frame.copyTo(image);//将当前帧复制到image中

        cvtColor(image, hsv, COLOR_BGR2HSV);//将image转为hsv色彩空间,保存到hsv中
        if (trackObject)//如果有操作,trackobject等于1或-1
        {
            // 亮度范围设置
            int _vmin = 10, _vmax = 256;
            // 色彩范围检测
            // Scalar: 色调、饱和度、亮度,第一个Scalar是最小值,第二个Scalar是最大值
            inRange(hsv, Scalar(0, 30, MIN(_vmin, _vmax)), Scalar(180, 256, MAX(_vmin, _vmax)), mask);

            int ch[] = { 0, 0 };
            hue.create(hsv.size(), hsv.depth());//创建一个与hsv尺寸和深度一样的hue
            // 从输入中拷贝某通道到输出中特定的通道。
            mixChannels(&hsv, 1, &hue, 1, ch, 1);

            if (trackObject < 0)//如果为-1,代表左键弹起,划定了区域
            {
                //hue是视频帧处理后的图像,selection是鼠标选定的矩形区域,同时创建一个感兴趣区域和一个标记感兴趣区域
                Mat roi(hue, selection), maskroi(mask, selection);
                imshow("ROI", roi);
                imshow("maskROI", maskroi);
                calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
                normalize(hist, hist, 0, 255, NORM_MINMAX);
                trackWindow = selection;
                trackObject = 1;
            }

            calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
            backproj &= mask;
            RotatedRect trackBox = CamShift(backproj, trackWindow, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1));

            if (trackWindow.area() <= 1)
            {
                int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5) / 6;
                trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
                    trackWindow.x + r, trackWindow.y + r) &
                    Rect(0, 0, cols, rows);
            }

            // 投影视图
            // cvtColor(backproj, image, COLOR_GRAY2BGR);

            ellipse(image, trackBox, Scalar(0, 0, 255), 3, LINE_AA);
        }
        if (selectObject && selection.width > 0 && selection.height > 0)
        {
            Mat roi(image, selection);
            bitwise_not(roi, roi);
        }
        cv::imshow("CamShift Demo", image);

        char c = (char)waitKey(10);
        if (c == 27) break;
    }
}


Python版本

Python版本正好在网上看到有人改过这个版本,我这里分享一下链接,顺便对他的摄像头调用做了小调整,效果和前面的差不多,但是他这个包围图形是方形

链接:https://blog.csdn.net/zhangruijerry/article/details/79088945

演示效果如下:

代码如下:

import cv2
import numpy as np

xs,ys,ws,hs = 0,0,0,0  #selection.x selection.y
xo,yo=0,0 #origin.x origin.y
selectObject = False
trackObject = 0

#创建回调函数
def onMouse(event,x,y,flags,param):
    global xs,ys,ws,hs,selectObject,xo,yo,trackObject
    if selectObject == True:
        xs = min(x, xo)
        ys = min(y, yo)
        ws = abs(x-xo)
        hs = abs(y-yo)
    if event == cv2.EVENT_LBUTTONDOWN:
        xo,yo = x, y
        xs,ys,ws,hs= x, y, 0, 0
        selectObject = True
    elif event == cv2.EVENT_LBUTTONUP:
        selectObject = False
        trackObject = -1

# 打开摄像头
Cap = cv2.VideoCapture(0)
# 判断视频是否打开
if (Cap.isOpened() == False):
    print('Open Camera Error.')
else:
    Cap.set(cv2.CAP_PROP_FRAME_WIDTH,640)  # 设置图像宽
    Cap.set(cv2.CAP_PROP_FRAME_HEIGHT,480) # 设置图像高
    Cap.set(cv2.CAP_PROP_EXPOSURE, -3)      # 设置曝光值
    # 读取设置的参数
    size = (int(Cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(Cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    baog = int(Cap.get(cv2.CAP_PROP_EXPOSURE))
    # 输出参数
    print('摄像头设置,尺寸:' + str(size))
    print('摄像头设置,曝光:' + str(baog))

    cv2.namedWindow("CamShift Demo", 1)
    cv2.setMouseCallback("CamShift Demo", onMouse)
    term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )

    # 读取图像
    while True:
        grabbed, frame = Cap.read()
        if frame is None:
            continue
        if trackObject != 0:
            hsv =  cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
            mask = cv2.inRange(hsv, np.array((0., 30.,10.)), np.array((180.,256.,255.)))
            if trackObject == -1:
                track_window=(xs,ys,ws,hs)
                maskroi = mask[ys:ys+hs, xs:xs+ws]
                hsv_roi = hsv[ys:ys+hs, xs:xs+ws]
                roi_hist = cv2.calcHist([hsv_roi],[0],maskroi,[180],[0,180])
                cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)
                trackObject = 1
            dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
            dst &= mask
            ret, track_window = cv2.CamShift(dst, track_window, term_crit)
            pts = cv2.boxPoints(ret)
            pts = np.int0(pts)
            img2 = cv2.polylines(frame,[pts],True, 255,2)
        
        if selectObject == True and ws>0 and hs>0:
            cv2.imshow('imshow1',frame[ys:ys+hs,xs:xs+ws])
            cv2.bitwise_not(frame[ys:ys+hs,xs:xs+ws],frame[ys:ys+hs,xs:xs+ws])
        cv2.imshow('CamShift Demo',frame)
        if  cv2.waitKey(10)==27:
            break
    cv2.destroyAllWindows()
颜色空间转换与物体追踪
光流法运动目标检测

友情链接: CSDN激萌の小宅 95知识库 自考题库 罗分明个人网络博客 精益编程leanboot

小宅博客  www.bilibili996.com All Rights Reserved. 备案号: 闽ICP备2024034575号

网站经营许可证  福建省福州市 Copyright©2021-2025 版权所有

小宅博客
首页 智能家居 地图定位
公告:小宅博客网可以开发票了,需要发票的,去群里找群主哈!!

文章作者:激萌の小宅

促销:¥0

价格:¥0

配送方式: 购买后立即生效(如购买异常,请联系站长)
付款之后一定要等待自动跳转结束,否则购买可能会失败
  • 0 天

    有效期

  • 0

    总销量

  • 2

    累计评价

彩色目标追踪

       彩色目标追踪,C++版本是采用毛星云的demo修改的,C#和Python版本则是在C++版本基础上延伸出来的,由于各种语言之间OpenCv的API有不少差异,尤其是在针对像素的操作上。这就导致了C++版本上的部分功能或者操作在C#和Python版本上没调通,毕竟官方demo很多操作都没有demo。


视频讲解如下:



当前系列所有demo下载地址:

https://github.com/GaoRenBao/OpenCv4-Demo

不同编程语言对应的OpenCv版本以及开发环境信息如下: 

语言

OpenCv版本

IDE

C#

OpenCvSharp4.4.8.0.20230708

Visual Studio 2022

C++

OpenCv-4.5.5-vc14_vc15

Visual Studio 2022

Python

OpenCv-Python (4.6.0.66)

PyCharm Community Edition 2022.1.3


C#版本代码如下:

C#版本需要安装“OpenCvSharp4”、“OpenCvSharp4.runtime.win”两个库才行。不然会报错。

如果需要使用“ BitmapConverter.ToBitmap”操作,则需要追加安装“OpenCvSharp4.Extensions”库。


早期版本是opencv3的,目前已改成opencv4,但是3版本的代码,我也顺便保留,给大家做个对比参考。

下面我们先来看一下C#版本的操作,C#版本不是很稳定,偶尔会异常,不过基础功能倒是实现了。。。

效果演示如下:


C# OpenCv3版本代码如下:

using OpenCvSharp;
using System;
using System.Windows.Forms;

namespace WindowsFormsApp
{
    public partial class Form1 : Form
    {
        // 声明全局变量
        public Mat image = new Mat();
        public bool selectObject = false;
        public int trackObject = 0;
        public Rect selection;
        public Point origin;

        /// <summary>
        /// 视频操作
        /// </summary>
        public VideoCapture Cap = new VideoCapture();

        public Form1()
        {
            InitializeComponent();
        }

        public void onMouse(MouseEvent @event, int x, int y, MouseEvent flags, IntPtr userdata)
        {
            //当左键按下,框选标志为真,执行如下程序得到矩形区域selection
            if (selectObject)
            {
                selection.X = Math.Min(x, origin.X);
                selection.Y = Math.Min(y, origin.Y);
                selection.Width = Math.Abs(x - origin.X);
                selection.Height = Math.Abs(y - origin.Y);
                //矩形区域与image进行与运算,结果保存到矩形区域中
                selection &= new Rect(0, 0, image.Cols, image.Rows);
            }
            if (@event == MouseEvent.LButtonDown)
            {
                origin = new Point(x, y);
                selection = new Rect(x, y, 0, 0);
                selectObject = true;
            }
            if (@event == MouseEvent.LButtonUp)
            {
                selectObject = false;
                if (selection.Width > 0 && selection.Height > 0)
                    trackObject = -1;
            }
        }

        // 打开摄像头
        private void button1_Click(object sender, EventArgs e)
        {
            int hsize = 16;
            float[] phranges = { 0, 180 };
            Rect trackWindow = new Rect();

            // 打开ID为0的摄像头
            Cap.Open(0);
            // 判断摄像头是否成功打开
            if (!Cap.IsOpened())
            {
                MessageBox.Show("摄像头打开失败.");
                return;
            }
            // 设置采集的图像尺寸为:640*480
            Cap.Set(CaptureProperty.FrameHeight, 480);
            Cap.Set(CaptureProperty.FrameWidth, 640);

            Mat frame = new Mat();
            Mat hsv = new Mat();
            Mat hue = new Mat();
            Mat mask = new Mat();
            Mat hist = new Mat();
            Mat backproj = new Mat();

            Cv2.NamedWindow("Histogram");
            Cv2.NamedWindow("CamShift Demo");

            CvMouseCallback GetRGBCvMouseCallback = new CvMouseCallback(onMouse);
            Cv2.SetMouseCallback("CamShift Demo", GetRGBCvMouseCallback);

            while (true)
            {
                //读取当前帧
                if (!Cap.Read(frame)) continue;
                if (frame.Empty()) break;

                frame.CopyTo(image); //将当前帧复制到image中
                Cv2.CvtColor(image, hsv, ColorConversionCodes.BGR2HSV); //将image转为hsv色彩空间,保存到hsv中
                if (trackObject != 0)//如果有操作,trackobject等于1或-1
                {
                    // 亮度范围设置
                    int _vmin = 10, _vmax = 256;
                    // 色彩范围检测
                    // Scalar: 色调、饱和度、亮度,第一个Scalar是最小值,第二个Scalar是最大值
                    Cv2.InRange(hsv, new Scalar(0, 30, Math.Min(_vmin, _vmax)), new Scalar(180, 256, Math.Max(_vmin, _vmax)), mask);
                    hue.Create(hsv.Size(), hsv.Depth());//创建一个与hsv尺寸和深度一样的hue

                    // 从输入中拷贝某通道到输出中特定的通道。
                    // 官方代码参考位置:./Sample-4.1.0-20190417/SamplesCS/Samples/MergeSplitSample.cs:51:
                    int[] ch = { 0, 0 };
                    Mat[] input = { hsv };
                    Mat[] output = { hue, };
                    Cv2.MixChannels(input, output, ch);

                    Rangef[] range = new Rangef[3];//三个通道,范围
                    range[0].Start = phranges[0];//从0开始(含)
                    range[0].End = phranges[1];  //到180结束(不含)
                    range[1] = range[0];//通道2和通道1一样
                    range[2] = range[0];//通道3和通道1一样

                    if (trackObject < 0)//如果为-1,代表左键弹起,划定了区域
                    {
                        //hue是视频帧处理后的图像,selection是鼠标选定的矩形区域,同时创建一个感兴趣区域和一个标记感兴趣区域
                        Mat roi = new Mat(hue, selection);
                        Mat maskroi = new Mat(mask, selection);
                        Cv2.CalcHist(images: new[] { roi }, channels: new[] { 0 }, mask: maskroi, hist: hist, dims: 1,
                            histSize: new[] { 16 }, ranges: new[] { new Rangef(0, 180) });
                        Cv2.Normalize(hist, hist, 0, 255, NormTypes.MinMax);
                        trackWindow = selection;
                        trackObject = 1;
                    }

                    Mat[] arrs2 = { hue };
                    Cv2.CalcBackProject(arrs2, channels: new[] { 0 }, hist, backproj, range);
                    backproj &= mask;
                    RotatedRect trackBox = Cv2.CamShift(backproj, ref trackWindow, new TermCriteria(CriteriaType.Count | CriteriaType.Eps, 10, 1));

                    if ((trackWindow.Width * trackWindow.Height) <= 1)
                    {
                        int cols = backproj.Cols, rows = backproj.Rows, r = (Math.Min(cols, rows) + 5) / 6;
                        trackWindow = new Rect(trackWindow.X - r, trackWindow.Y - r,
                            trackWindow.X + r, trackWindow.Y + r) &
                            new Rect(0, 0, cols, rows);
                    }

                    // 投影视图
                    // Cv2.CvtColor(backproj, image, ColorConversionCodes.GRAY2BGR);

                    Cv2.Ellipse(image, trackBox, new Scalar(0, 0, 255), 3, LineTypes.AntiAlias);
                }

                if (selectObject && selection.Width > 0 && selection.Height > 0)
                {
                    Mat roi = new Mat(image, selection);
                    Cv2.BitwiseNot(roi, roi);
                }
                Cv2.ImShow("CamShift Demo", image);

                if ((char)Cv2.WaitKey(10) == 27) break;
            }
        }
    }
}


C# OpenCv4版本代码如下:

using OpenCvSharp;
using System;

namespace ConsoleApp
{
    internal class Program
    {
        // 声明全局变量
        public static Mat image = new Mat();
        public static bool selectObject = false;
        public static int trackObject = 0;
        public static Rect selection;
        public static Point origin;

        /// <summary>
        /// 视频操作
        /// </summary>
        public static VideoCapture Cap = new VideoCapture();

        private static void onMouse(MouseEventTypes @event, int x, int y, MouseEventFlags flags, IntPtr userData)
        {
            //当左键按下,框选标志为真,执行如下程序得到矩形区域selection
            if (selectObject)
            {
                selection.X = Math.Min(x, origin.X);
                selection.Y = Math.Min(y, origin.Y);
                selection.Width = Math.Abs(x - origin.X);
                selection.Height = Math.Abs(y - origin.Y);
                //矩形区域与image进行与运算,结果保存到矩形区域中
                selection &= new Rect(0, 0, image.Cols, image.Rows);
            }
            if (@event == MouseEventTypes.LButtonDown)
            {
                origin = new Point(x, y);
                selection = new Rect(x, y, 0, 0);
                selectObject = true;
            }
            if (@event == MouseEventTypes.LButtonUp)
            {
                selectObject = false;
                if (selection.Width > 0 && selection.Height > 0)
                    trackObject = -1;
            }
        }

        static void Main(string[] args)
        {
            int hsize = 16;
            float[] phranges = { 0, 180 };
            Rect trackWindow = new Rect();

            // 打开ID为0的摄像头
            Cap.Open(0);
            // 判断摄像头是否成功打开
            if (!Cap.IsOpened())
            {
                Console.WriteLine("摄像头打开失败.");
                return;
            }
            // 设置采集的图像尺寸为:640*480
            Cap.Set(VideoCaptureProperties.FrameHeight, 480);
            Cap.Set(VideoCaptureProperties.FrameWidth, 640);

            Mat frame = new Mat();
            Mat hsv = new Mat();
            Mat hue = new Mat();
            Mat mask = new Mat();
            Mat hist = new Mat();
            Mat backproj = new Mat();

            Cv2.NamedWindow("Histogram");
            Cv2.NamedWindow("CamShift Demo");

            MouseCallback GetRGBCvMouseCallback = new MouseCallback(onMouse);
            Cv2.SetMouseCallback("CamShift Demo", GetRGBCvMouseCallback);

            while (true)
            {
                //读取当前帧
                if (!Cap.Read(frame)) continue;
                if (frame.Empty()) break;

                frame.CopyTo(image); //将当前帧复制到image中
                Cv2.CvtColor(image, hsv, ColorConversionCodes.BGR2HSV); //将image转为hsv色彩空间,保存到hsv中
                if (trackObject != 0)//如果有操作,trackobject等于1或-1
                {
                    // 亮度范围设置
                    int _vmin = 10, _vmax = 256;
                    // 色彩范围检测
                    // Scalar: 色调、饱和度、亮度,第一个Scalar是最小值,第二个Scalar是最大值
                    Cv2.InRange(hsv, new Scalar(0, 30, Math.Min(_vmin, _vmax)), new Scalar(180, 256, Math.Max(_vmin, _vmax)), mask);
                    hue.Create(hsv.Size(), hsv.Depth());//创建一个与hsv尺寸和深度一样的hue

                    // 从输入中拷贝某通道到输出中特定的通道。
                    // 官方代码参考位置:./Sample-4.1.0-20190417/SamplesCS/Samples/MergeSplitSample.cs:51:
                    int[] ch = { 0, 0 };
                    Mat[] input = { hsv };
                    Mat[] output = { hue, };
                    Cv2.MixChannels(input, output, ch);

                    Rangef[] range = new Rangef[3];//三个通道,范围
                    range[0] = new Rangef(phranges[0], phranges[1]); //从0开始(含),到180结束(不含)
                    range[1] = range[0];//通道2和通道1一样
                    range[2] = range[0];//通道3和通道1一样

                    if (trackObject < 0)//如果为-1,代表左键弹起,划定了区域
                    {
                        //hue是视频帧处理后的图像,selection是鼠标选定的矩形区域,同时创建一个感兴趣区域和一个标记感兴趣区域
                        Mat roi = new Mat(hue, selection);
                        Mat maskroi = new Mat(mask, selection);
                        Cv2.CalcHist(images: new[] { roi }, channels: new[] { 0 }, mask: maskroi, hist: hist, dims: 1,
                            histSize: new[] { 16 }, ranges: new[] { new Rangef(0, 180) });
                        Cv2.Normalize(hist, hist, 0, 255, NormTypes.MinMax);
                        trackWindow = selection;
                        trackObject = 1;
                    }

                    Mat[] arrs2 = { hue };
                    Cv2.CalcBackProject(arrs2, channels: new[] { 0 }, hist, backproj, range);
                    backproj &= mask;
                    RotatedRect trackBox = Cv2.CamShift(backproj, ref trackWindow, new TermCriteria(CriteriaTypes.Count | CriteriaTypes.Eps, 10, 1));

                    if ((trackWindow.Width * trackWindow.Height) <= 1)
                    {
                        int cols = backproj.Cols, rows = backproj.Rows, r = (Math.Min(cols, rows) + 5) / 6;
                        trackWindow = new Rect(trackWindow.X - r, trackWindow.Y - r,
                            trackWindow.X + r, trackWindow.Y + r) &
                            new Rect(0, 0, cols, rows);
                    }

                    // 投影视图
                    // Cv2.CvtColor(backproj, image, ColorConversionCodes.GRAY2BGR);

                    Cv2.Ellipse(image, trackBox, new Scalar(0, 0, 255), 3, LineTypes.AntiAlias);
                }

                if (selectObject && selection.Width > 0 && selection.Height > 0)
                {
                    Mat roi = new Mat(image, selection);
                    Cv2.BitwiseNot(roi, roi);
                }
                Cv2.ImShow("CamShift Demo", image);

                if ((char)Cv2.WaitKey(10) == 27) break;
            }
        }
    }
}


下面这是官方提供的关于CalcHist直方图的操作demo。

代码位置在:Sample-4.1.0-20190417/OpenCvSharp.Tests/imgproc/ImgProcTest.cs:600

效果呢,可以给大家看下,就是下面这个样子。

官方代码如下:

public void CalcHist()
{
    using var src = new Mat(@"_data/image/mandrill.png", ImreadModes.Grayscale);

    using var hist = new Mat();
    Cv2.CalcHist(
        images: new[] { src },
        channels: new[] {0},
        mask: null,
        hist: hist,
        dims: 1,
        histSize: new[] {256},
        ranges: new[] { new Rangef(0, 256) });

    if (Debugger.IsAttached)
    {
        const int histW = 512;
        const int histH = 400; 
        var binW = Math.Round((double)histW / 256);
        using var histImage = new Mat(histH, histW, MatType.CV_8UC3, Scalar.All(0));
        Cv2.Normalize(hist, hist, 0, histImage.Rows, NormTypes.MinMax, -1);

        for (int i = 0; i < 256; i++)
        {
            var pt1 = new Point2d(binW * (i - 1), histH - Math.Round(hist.At<float>(i - 1)));
            var pt2 = new Point2d(binW * (i), histH - Math.Round(hist.At<float>(i)));
            Cv2.Line(
                histImage, (Point)pt1, (Point)pt2,
                Scalar.Red, 1, LineTypes.Link8);
        }

        Window.ShowImages(src, histImage);
    }
}


C++版本

C++版本是毛星云的版本简化来的,去掉了很多没必要的操作界面,直接保留了核心功能。

效果演示如下:

彩色目标追踪2 (1).gif

代码如下:

#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <ctype.h>

using namespace cv;
using namespace std;

// 声明全局变量
Mat image;
//bool backprojMode = false;
bool selectObject = false;
int trackObject = 0;
Rect selection;
Point origin;

// 鼠标操作回调:鼠标状态每改变一次,此函数就执行一次
void onMouse(int event, int x, int y, int, void*)
{
    //当左键按下,框选标志为真,执行如下程序得到矩形区域selection
    if (selectObject)
    {
        selection.x = MIN(x, origin.x);
        selection.y = MIN(y, origin.y);
        selection.width = std::abs(x - origin.x);
        selection.height = std::abs(y - origin.y);
        //矩形区域与image进行与运算,结果保存到矩形区域中
        selection &= Rect(0, 0, image.cols, image.rows);
    }

    switch (event)
    {
        //此句代码的OpenCV2版为:
        //case CV_EVENT_LBUTTONDOWN:

        //此句代码的OpenCV3版为:
        //当左键按下,记录原点,创建矩形区域,框选标志置为真
    case EVENT_LBUTTONDOWN:
        origin = Point(x, y);
        selection = Rect(x, y, 0, 0);
        selectObject = true;
        break;

        //此句代码的OpenCV2版为:
        //case CV_EVENT_LBUTTONUP:

        //此句代码的OpenCV3版为:
        //当左键弹起,将框选标志置为假,如果矩形区域的长宽都大于零,令跟踪标志为-1
    case EVENT_LBUTTONUP:
        selectObject = false;
        if (selection.width > 0 && selection.height > 0)
            trackObject = -1;
        break;
    }
}

int main()
{
    int hsize = 16;
    float hranges[] = { 0,180 };
    const float* phranges = hranges;
    Rect trackWindow;

    VideoCapture cap;
    cap.open(0);
    if (!cap.isOpened())
    {
        cout << "初始化摄像头失败\n";
        while (true);
    }

    namedWindow("Histogram", 1);
    namedWindow("CamShift Demo", 1);
    // 鼠标事件检测
    setMouseCallback("CamShift Demo", onMouse, 0);

    Mat frame, hsv, hue, mask, hist, backproj;

    while (true)
    {
        cap >> frame;//读取当前帧
        if (frame.empty())
            break;

        frame.copyTo(image);//将当前帧复制到image中

        cvtColor(image, hsv, COLOR_BGR2HSV);//将image转为hsv色彩空间,保存到hsv中
        if (trackObject)//如果有操作,trackobject等于1或-1
        {
            // 亮度范围设置
            int _vmin = 10, _vmax = 256;
            // 色彩范围检测
            // Scalar: 色调、饱和度、亮度,第一个Scalar是最小值,第二个Scalar是最大值
            inRange(hsv, Scalar(0, 30, MIN(_vmin, _vmax)), Scalar(180, 256, MAX(_vmin, _vmax)), mask);

            int ch[] = { 0, 0 };
            hue.create(hsv.size(), hsv.depth());//创建一个与hsv尺寸和深度一样的hue
            // 从输入中拷贝某通道到输出中特定的通道。
            mixChannels(&hsv, 1, &hue, 1, ch, 1);

            if (trackObject < 0)//如果为-1,代表左键弹起,划定了区域
            {
                //hue是视频帧处理后的图像,selection是鼠标选定的矩形区域,同时创建一个感兴趣区域和一个标记感兴趣区域
                Mat roi(hue, selection), maskroi(mask, selection);
                imshow("ROI", roi);
                imshow("maskROI", maskroi);
                calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
                normalize(hist, hist, 0, 255, NORM_MINMAX);
                trackWindow = selection;
                trackObject = 1;
            }

            calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
            backproj &= mask;
            RotatedRect trackBox = CamShift(backproj, trackWindow, TermCriteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1));

            if (trackWindow.area() <= 1)
            {
                int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5) / 6;
                trackWindow = Rect(trackWindow.x - r, trackWindow.y - r,
                    trackWindow.x + r, trackWindow.y + r) &
                    Rect(0, 0, cols, rows);
            }

            // 投影视图
            // cvtColor(backproj, image, COLOR_GRAY2BGR);

            ellipse(image, trackBox, Scalar(0, 0, 255), 3, LINE_AA);
        }
        if (selectObject && selection.width > 0 && selection.height > 0)
        {
            Mat roi(image, selection);
            bitwise_not(roi, roi);
        }
        cv::imshow("CamShift Demo", image);

        char c = (char)waitKey(10);
        if (c == 27) break;
    }
}


Python版本

Python版本正好在网上看到有人改过这个版本,我这里分享一下链接,顺便对他的摄像头调用做了小调整,效果和前面的差不多,但是他这个包围图形是方形

链接:https://blog.csdn.net/zhangruijerry/article/details/79088945

演示效果如下:

代码如下:

import cv2
import numpy as np

xs,ys,ws,hs = 0,0,0,0  #selection.x selection.y
xo,yo=0,0 #origin.x origin.y
selectObject = False
trackObject = 0

#创建回调函数
def onMouse(event,x,y,flags,param):
    global xs,ys,ws,hs,selectObject,xo,yo,trackObject
    if selectObject == True:
        xs = min(x, xo)
        ys = min(y, yo)
        ws = abs(x-xo)
        hs = abs(y-yo)
    if event == cv2.EVENT_LBUTTONDOWN:
        xo,yo = x, y
        xs,ys,ws,hs= x, y, 0, 0
        selectObject = True
    elif event == cv2.EVENT_LBUTTONUP:
        selectObject = False
        trackObject = -1

# 打开摄像头
Cap = cv2.VideoCapture(0)
# 判断视频是否打开
if (Cap.isOpened() == False):
    print('Open Camera Error.')
else:
    Cap.set(cv2.CAP_PROP_FRAME_WIDTH,640)  # 设置图像宽
    Cap.set(cv2.CAP_PROP_FRAME_HEIGHT,480) # 设置图像高
    Cap.set(cv2.CAP_PROP_EXPOSURE, -3)      # 设置曝光值
    # 读取设置的参数
    size = (int(Cap.get(cv2.CAP_PROP_FRAME_WIDTH)),int(Cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
    baog = int(Cap.get(cv2.CAP_PROP_EXPOSURE))
    # 输出参数
    print('摄像头设置,尺寸:' + str(size))
    print('摄像头设置,曝光:' + str(baog))

    cv2.namedWindow("CamShift Demo", 1)
    cv2.setMouseCallback("CamShift Demo", onMouse)
    term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )

    # 读取图像
    while True:
        grabbed, frame = Cap.read()
        if frame is None:
            continue
        if trackObject != 0:
            hsv =  cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
            mask = cv2.inRange(hsv, np.array((0., 30.,10.)), np.array((180.,256.,255.)))
            if trackObject == -1:
                track_window=(xs,ys,ws,hs)
                maskroi = mask[ys:ys+hs, xs:xs+ws]
                hsv_roi = hsv[ys:ys+hs, xs:xs+ws]
                roi_hist = cv2.calcHist([hsv_roi],[0],maskroi,[180],[0,180])
                cv2.normalize(roi_hist,roi_hist,0,255,cv2.NORM_MINMAX)
                trackObject = 1
            dst = cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)
            dst &= mask
            ret, track_window = cv2.CamShift(dst, track_window, term_crit)
            pts = cv2.boxPoints(ret)
            pts = np.int0(pts)
            img2 = cv2.polylines(frame,[pts],True, 255,2)
        
        if selectObject == True and ws>0 and hs>0:
            cv2.imshow('imshow1',frame[ys:ys+hs,xs:xs+ws])
            cv2.bitwise_not(frame[ys:ys+hs,xs:xs+ws],frame[ys:ys+hs,xs:xs+ws])
        cv2.imshow('CamShift Demo',frame)
        if  cv2.waitKey(10)==27:
            break
    cv2.destroyAllWindows()