1. fmask 前景(二值图像)
  2. learningRate 学习速率,值为0-1,为0时背景不更新,为1时逐帧更新,默认为-1,即算法自动更新;

然后进入循环

while(True):
    ret, frame = cap.read()
    fgmask = fgbg.apply(frame)
    #形态学开运算去噪点
    fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
    #寻找视频中的轮廓
    contours, hierarchy = cv2.findContours(fgmask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

首先我们先来ret, frame = cap.read()用于摄像头或视频文件中,捕获帧信息。返回的两个值分别是:

  • ret 是返回的捕获到的帧,如果没有帧被捕获到,则该值为空。
  • frame表示帧捕获是否成功,如果成功,retval为True,失败为False。

然后利用cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel开运算。
在进行膨胀操作的时候我们介绍到了这个:
1.图像被腐蚀后,去除了噪声,但是会压缩图像。
2.对腐蚀过的图像,进行膨胀处理,可以去除噪声,并保持原有形状。

*开运算(image)=膨胀(腐蚀(image))*

在这里插入图片描述
开运算就是先把图像进行腐蚀操作,然后进行膨胀操作的一个过程!
在这里插入图片描述

如果我们对于有噪声的图像单独的进行腐蚀操作,就会对图像进行压缩,如果我们想要恢复到原始图像就要进行相同程度上的膨胀,这个操作我们就成为开运算。

🌔开运算操作函数介绍
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)

img:原始图像
cv2.MORPH_OPEN:表示进行开运算,相同的我们所知道的还有闭运算。
kernel:卷积核,同样我们对开运算的卷积核要进行设定。
然后contours, hierarchy = cv2.findContours这里是寻找轮廓,这里注意的是新的版本返回的是两个数值,旧的版本是3个数值。

for c in contours:
        #计算各轮廓的周长
        perimeter = cv2.arcLength(c,True)
        if perimeter > 188:
            #找到一个直矩形(不会旋转)
            x,y,w,h = cv2.boundingRect(c)
            #画出这个矩形
            cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)  

遍历每一个轮廓,然后计算轮廓的周长,进行筛选如果周长的数值大于188,那么我们把这个矩阵给画出来。

cv2.imshow('frame',frame)
    cv2.imshow('fgmask', fgmask)
    k = cv2.waitKey(150) & 0xff
    if k == 27:
        break
 
cap.release()
cv2.destroyAllWindows()

然后这里就结束了。我们来看一下视频。

这个是项目中的视频的结果。然后我们继续做一下开头投篮的一个背景建模视频。

在这里插入图片描述

这里和官方视频有很大的差距,分析了一下主要原因是由于我们手工录制的视频他一直在发抖,摄像头一直在抖动,稳定性不高导致的背景中的噪音点较多,但是我们去掉这个缺陷之后呢,可以看到运动中的篮球和人物展示的效果都是非常不错的。篮球在空中飞的过程中刻画的也是非常的清晰。

⭐️光流估计

光流是空间运动的物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如说目标追踪。
在这里插入图片描述
这里我们假设车在移动的过程中,第一帧和第二帧图像,他们像素点的移动过程是分速度的大小的,右图所示。这个过程中有很多个小概念需要知道:
1.亮度恒定:同一点随着时间的变化,我们认为他的亮度是不发生改变的。也就是说第一帧和第二帧我们忽略了亮度对于光流的影响。
2. 小运动:随着时间的变化不会引起位置的剧烈变化,只有在小运动的情况下才能用前后帧之间的单位位置变化的偏导数。
3. 空间一致:一个场景上临近的点投影到图像上也是临近点,且临近点速度一致。因为光流法基本方程约束只有一个,要求x,y方向的速度,有两个位置变量,所以需要联立n个方程求解。

🔎Lucas-Kanade算法

根据上述的条件,我们可以进行一下约束方程的书写:
在这里插入图片描述
这里很简单,就是说前后帧的图像进行了位置的一个等式,我们认为他是一个小运动。且符合亮度恒定,然后进行了一阶泰勒公式展开。得到的结果进行左右约掉了一部分,然后我们可以得到:
在这里插入图片描述
继续推导:
在这里插入图片描述
这里面有两个未知数,u和v。那么我们至少要需要两个方程才能解决这个问题。所以我们构造方程使用了多个点进行构造,这就符合了我们第三个条件,就是空间一致。
在这里插入图片描述
这里面我们用了25个方程来构造这个函数,那么2个未知数,用了25个方程他有一个什么好处呢?就是说和我们在机器学习中的一元线性回归任务当中基于很多点选择一条完美的直线很类似,就是要把这个解弄得完美一点。
在这里插入图片描述差不多这个意思。
在这里插入图片描述
然后我们最后通过最小二乘法进行了求解,但是这里有一个问题就是出现了一个逆矩阵,那么我们知道逆矩阵是要符合条件的,那么就需要λ1和λ2,当是角点的时候。才可逆。所以我们在检测的过程中拿到的点都要是角点才可以。

⭐️光流估计实战演示

cv2.calcOpticalFlowPyrLK():这个函数简单介绍一下
参数

prevImage: 前一帧图像
nextImage: 当前帧图像
prevPts: 待跟踪的特征点向量
winSize: 搜索窗口的大小
maxLevel: 最大的金字塔层数

返回

nextPts 输出跟踪特征点向量
status 特征点是否找到,找到的状态为1,未找到的状态为0

读入库和视频

import numpy as np
import cv2
cap = cv2.VideoCapture('aaa.mp4')

首先我们要进行一下角点检测,先定义出来角点检测的函数。以及lucas kanade算法的参数。定义追踪颜色条,然后对每一帧图像做预处理操作。

feature_params = dict( maxCorners = 100,
                       qualityLevel = 0.3,
                       minDistance = 7)
# lucas kanade参数
lk_params = dict( winSize  = (10,10),
                  maxLevel = 2)
# 随机颜色条
color = np.random.randint(0,255,(100,3))
# 拿到第一帧图像
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
p0 = cv2.goodFeaturesToTrack(old_gray, mask = None, \*\*feature_params)
# 创建一个mask
mask = np.zeros_like(old_frame)

然后绘制主体,把相应的参数传入进去。

while(True):
    ret,frame = cap.read()
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
    #p0 = cv2.goodFeaturesToTrack(old\_gray, mask = None, \*\*feature\_params)

    # 需要传入前一帧和当前图像以及前一帧检测到的角点
    p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, \*\*lk_params)

    # st=1表示
    good_new = p1[st==1]
    good_old = p0[st==1]

    # 绘制轨迹
    for i,(new,old) in enumerate(zip(good_new,good_old)):
        a,b = new.ravel()
        c,d = old.ravel()
        mask = cv2.line(mask, (int(a),int(b)),(int(c),int(d)), color[i].tolist(), 2)
        frame = cv2.circle(frame,(int(a),int(b)),5,color[i].tolist(),-1)
    img = cv2.add(frame,mask)

    cv2.imshow('frame',img)
    k = cv2.waitKey(150) & 0xff
    if k == 27:
        break

    # 更新
    old_gray = frame_gray.copy() 
    p0 = good_new.reshape(-1,1,2)

cv2.destroyAllWindows()
cap.release()

结果展示:

在这里插入图片描述

在这里插入图片描述

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

14548875751)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐