OpenCV视频学习笔记(16)-背景建模

十六、背景建模

怎样捕捉一个物体是前景(运动)还是背景(静止)?有两个方法
方法一:帧差法
由于场景中的目标在运动,目标的影像在不同图像帧中的位置不同。该类算法对时间上连续的两帧图像进行差分运算,不同帧对应的像素点相减,判断灰度差的绝对值,当绝对值超过一定阈值时,即可判断为运动目标,从而实现目标的检测功能。

帧差法非常简单,但会引入噪音和空洞问题。
方法二:混合高斯模型
在进行前景检测前,先对背景进行训练,对图像中每个背景采用一个混合高斯模型进行模拟,每个背景的混合高斯的个数可以自适应。然后在测试阶段,对新来的像素进行GMM匹配,如果该像素值能够匹配其中一个高斯,则认为是背景,否则认为是前景。由于整个过程GMM模型在不断更新学习中,所以对动态背景有一定的鲁棒性。最后通过对一个有树枝摇摆的动态背景进行前景检测,取得了较好的效果。
在视频中对于像素点的变化情况应当是符合高斯分布。

背景的实际分布应当是多个高斯分布混合在一起,每个高斯模型也可以带有权重

混合高斯模型学习方法
1.首先初始化每个高斯模型矩阵参数。
2.取视频中T(200+)帧数据图像用来训练高斯混合模型。来了第一个像素之后用它来当做第一个高斯分布。
3.当后面来的像素值时,与前面已有的高斯的均值比较,如果该像素点的值与其模型均值差在3倍的方差内,则属于该分布,并对其进行参数更新。
4.如果下一次来的像素不满足当前高斯分布,用它来创建一个新的高斯分布。
混合高斯模型测试方法
在测试阶段,对新来像素点的值与混合高斯模型中的每一个均值进行比较,如果其差值在2倍的方差之间的话,则认为是背景,否则认为是前景。将前景赋值为255,背景赋值为0.这样就形成了一副前景二值图。

实现步骤
(1)VideoCapture捕捉视频数据;
(2)创建一个3×3的核;
(3)创建混合高斯模型,背景提取,对象实例化,把这个对象应用到当前每一帧的图像当中;
(4)while操作,一帧一帧的处理;
(5)进行轮廓检测,检测图像中行人的轮廓;
(6)展示结果以及原始图像;
import numpy as np
import cv2

#经典的测试视频
cap = cv2.VideoCapture(‘D:/graduate/test picture/test.avi’)
#形态学操作需要使用
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
#创建混合高斯模型用于背景建模
fgbg = cv2.createBackgroundSubtractorMOG2()

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

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)    

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

cap.release()
cv2.destroyAllWindows()

按Esc键退出;

十七 、光流估计
光流估计
光流是空间运动物体在观测成像平面上的像素运动的“瞬时速度”,根据各个像素点的速度矢量特征,可以对图像进行动态分析,例如目标跟踪。
三个前提:
亮度恒定:同一点随着时间的变化,其亮度(灰度值 )不会发生改变。
小运动:随着时间的变化不会引起位置的剧烈变化,只有小运动情况下才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数。
空间一致:一个场景上邻近的点投影到图像上也是邻近点,且邻近点速度一致。因为光流法基本方程约束只有一个,而要求x,y方向的速度,有两个未知变量。所以需要连立n多个方程求解。

怎么求实际的方向和大小

如何求解方程呢?看起来一个像素点根本不够,在物体移动过程中还有哪些特性呢?
这里可以利用其空间一致性,找到求解的突破口;

这里有25个方程,但只需要两个方程就可以将u、v两个未知数求出来,所以可以想到线性回归法;

做光流估计围绕的其实是一些角点,因为角点才适用于上面这个式子,才满足可逆的条件。
所以在做光流估计之前,要先做角点检测。
cv2.calcOpticalFlowPyrLK():
参数:
prevImage 前一帧图像
nextImage 当前帧图像
prevPts 待跟踪的特征点向量
winSize 搜索窗口的大小
maxLevel 最大的金字塔层数
返回:
nextPts 输出跟踪特征点向量
status 特征点是否找到,找到的状态为1,未找到的状态为0、

OpenCV实现:
import numpy as np
import cv2

cap = cv2.VideoCapture(‘D:/graduate/test picture/test.avi’)
//角点检测所需参数
feature_params = dict( maxCorners = 100,#角点最大的数量
qualityLevel = 0.3,#品质因子,对角点进行筛选
minDistance = 7)#距离,判断哪个角点的品质因子最好
// lucas kanade参数
lk_params = dict( winSize = (15,15),
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)

# 需要传入前一帧和当前图像以及前一帧检测到的角点
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, (a,b),(c,d), color[i].tolist(), 2)
    frame = cv2.circle(frame,(a,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()

新人没有被跟踪到,因为第一帧的角点中没有这些人,经过障碍物后有些人的st值变为0了。就跟丢了。
十八、OpenCV的DNN模块
Caffe网络模型,没有Tensorflow灵活
//导入工具包
import utils_paths
import numpy as np
import cv2

// 标签文件处理
rows = open(“synset_words.txt”).read().strip().split("\n")
classes = [r[r.find(" “) + 1:].split(”,")[0] for r in rows]

// Caffe所需配置文件
net = cv2.dnn.readNetFromCaffe(“bvlc_googlenet.prototxt”,
“bvlc_googlenet.caffemodel”)#读进来一个网络结构(配置文件,权重参数)

// 图像路径
imagePaths = sorted(list(utils_paths.list_images(“images/”)))#读取图像

// 图像数据预处理
image = cv2.imread(imagePaths[0])
resized = cv2.resize(image, (224, 224))第一步
// image scalefactor size mean swapRB
第二步,减均值,剔除掉光照对结果的影响,R、G、B三个通道的值分别减去各自对应的数104\117\123
#blobFromImage建立一张图像的通道
blob = cv2.dnn.blobFromImage(resized, 1, (224, 224), (104, 117, 123))
print(“First Blob: {}”.format(blob.shape))

//得到预测结果
net.setInput(blob)
preds = net.forward()#前向传播

// 排序,取分类可能性最大的
idx = np.argsort(preds[0])[::-1][0]
text = “Label: {}, {:.2f}%”.format(classes[idx],
preds[0][idx] * 100)
cv2.putText(image, text, (5, 25), cv2.FONT_HERSHEY_SIMPLEX,
0.7, (0, 0, 255), 2)

//显示
cv2.imshow(“Image”, image)
cv2.waitKey(0)

// Batch数据制作
images = []

//方法一样,数据是一个batch
for p in imagePaths[1:]:
image = cv2.imread§
image = cv2.resize(image, (224, 224))
images.append(image)

//blobFromImages函数,注意有s
#blobFromImages可以批处理,一批处理4个
blob = cv2.dnn.blobFromImages(images, 1, (224, 224), (104, 117, 123))
print(“Second Blob: {}”.format(blob.shape))

// 获取预测结果
net.setInput(blob)
preds = net.forward()
for (i, p) in enumerate(imagePaths[1:]):
image = cv2.imread§
idx = np.argsort(preds[i])[::-1][0]
text = “Label: {}, {:.2f}%”.format(classes[idx],
preds[i][idx] * 100)
cv2.putText(image, text, (5, 25), cv2.FONT_HERSHEY_SIMPLEX,
0.7, (0, 0, 255), 2)
cv2.imshow(“Image”, image)
cv2.waitKey(0)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值