文章目录
背景分割器介绍
在OpenCV中,背景分割器是处理视频或图像序列以区分前景(如移动物体)和背景的重要工具。以下是对OpenCV中几种常用背景分割器(MOG2、KNN、GMG)的使用场景、优缺点的详细解释:
一、Mixture of Gaussians (MOG2)
使用场景:
- 适用于场景中存在很多变化和动态光照条件的情况。
- 在处理光照变化和动态背景时表现良好。
优点:
- 对光照变化有较好的适应性。
- 在动态背景环境下表现良好。
缺点:
- 对于相对静态的背景可能效果不佳。
二、K-Nearest Neighbors (KNN)
使用场景:
- 在处理运动目标和部分遮挡情况时可能更有效。
优点:
- 根据像素的颜色特征和邻近像素的情况进行分类,因此在处理运动目标和部分遮挡时可能更有效。
缺点:
- 在复杂动态背景下表现可能欠佳。
三、Geometric Multigrid (GMG)
使用场景:
- 在动态背景和光照变化下表现较好。
优点:
- 结合了几何学和统计学的方法,对动态背景和光照变化具有较好的鲁棒性。
缺点:
- 对于较为静态的场景可能不够精确。
四、总结
MOG2 更适合光照变化和动态背景较多的场景。
KNN 在处理运动目标和部分遮挡时可能更有效,但在复杂动态背景下可能表现不佳。
GMG 在动态背景和光照变化下表现良好,但可能在静态场景下不够精确。
在选择背景分割器时,需要根据具体的应用场景和需求进行权衡。例如,如果场景中光照变化较大,那么MOG2可能是更好的选择;而如果主要目标是检测运动目标并处理部分遮挡,那么KNN可能更为合适。
opencv 中背景分割器可借助 BackgroundSubtractor 类,检测阴影,用阈值排除阴影,从而关注实际特征
cv2.createBackgroundSubtractorMOG2
createBackgroundSubtractorMOG2 是 OpenCV 库中的一个函数,用于创建基于混合高斯模型(Mixture of Gaussians, MOG2)的背景减除器。以下是对 createBackgroundSubtractorMOG2 的中文文档,清晰地分点表示和归纳了其主要内容:
一、函数概述
createBackgroundSubtractorMOG2 是 OpenCV 中用于背景/前景分割的算法之一,基于混合高斯模型(MOG2)进行背景建模和前景检测。该函数允许用户通过调整参数来适应不同的应用场景。
二、函数原型
retval = cv2.createBackgroundSubtractorMOG2([, history[, varThreshold[, detectShadows]]])
三、参数解释
history(可选,整型,默认值 200):
- 表示用于训练背景模型的时间长度,单位是帧数。它决定了背景模型更新的速度,值越大,背景模型更新的速度就越慢——过往帧数,500帧,选择history = 1就变成两帧差
varThreshold(可选,浮点型,默认值 15):
- 用于判断像素是否为背景的阈值。这个参数对结果有很大影响,值越小,检测到的运动物体就越多,但也可能增加误检——像素与模型之间的马氏距离,值越大,只有那些最新的像素会被归到前景,值越小前景对光照越敏感。
detectShadows(可选,布尔型,默认值 True):
- 一个布尔值,用于指示算法是否检测阴影并对其进行标记。启用阴影检测会稍微降低速度,因此如果不需要此功能,建议将其设置为 False。
四、返回值
该函数返回一个背景减除器对象,该对象可以用于对视频帧或图像序列进行前景检测。
五、工作原理
模型初始化:在开始时,算法会对视频中的每个像素建立一个混合高斯模型。这个模型会学习并适应场景中的背景变化。
背景建模:随着新帧的到来,算法会更新每个像素的高斯分布。对于与现有高斯分布匹配良好的像素,这些分布会被更新以反映最新的像素值。对于不匹配任何现有分布的像素,会创建新的高斯分布或替换最不可能代表背景的高斯分布。
前景检测:如果某个像素的值与所有高斯分布都不匹配,或者只与表示前景的高斯分布匹配,则该像素被视为前景像素。
阴影检测(如果启用):算法还可以检测并标记出由于前景对象遮挡而产生的阴影区域。
六、使用场景
动态背景:在背景经常变化的情况下,如光照变化、树叶摇动等,MOG2 表现出较好的鲁棒性。
视频监控:在视频监控系统中,用于检测运动物体或行人。
实时分析:由于 MOG2 的计算效率较高,因此适用于需要实时处理的应用场景。
七、注意事项
参数调整:根据具体的应用场景和需求,可能需要调整 history、varThreshold 和 detectShadows 等参数以获得最佳效果。
性能考虑:虽然 MOG2 在大多数情况下都能提供较好的性能,但在某些极端情况下(如快速变化的光照条件),可能需要考虑使用其他更复杂的背景减除算法。
import cv2
import os
# bs = cv2.createBackgroundSubtractorKNN(detectShadows=True)
bs = cv2.createBackgroundSubtractorMOG2(detectShadows=True)
os.makedirs("frame1", exist_ok=True)
os.makedirs("frame2", exist_ok=True)
os.makedirs("frame3", exist_ok=True)
camera = cv2.VideoCapture('car.mkv')
index = 0
while True:
ret, frame = camera.read()
index += 1
frame_h, frame_w, _ = frame.shape
fgmask = bs.apply(frame)
th = cv2.threshold(fgmask.copy(), 244, 255, cv2.THRESH_BINARY)[1]
dilated = cv2.dilate(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)),
iterations=2)
contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
# if cv2.contourArea(c) > frame_w*0.075 * frame_h*0.075:
if cv2.contourArea(c) > 1000:
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 0, 255), 5)
cv2.imshow("mog", fgmask)
cv2.imwrite("./frame1/{}.jpg".format(index), fgmask)
cv2.imshow("thresh", th)
cv2.imwrite("./frame2/{}.jpg".format(index), th)
cv2.imshow("detection", frame)
cv2.imwrite("./frame3/{}.jpg".format(index), frame)
if cv2.waitKey(30) & 0xff == ord("q"):
break
camera.release()
cv2.destroyAllWindows()
做 gif 的时候只设置了播放一次,重复播放需要刷新该页面
cv2.createBackgroundSubtractorKNN
用法基本和 cv2.createBackgroundSubtractorMOG2
一致,工作原理如下
模型初始化:在开始时,KNN 算法会收集一系列初始帧来构建背景模型。
背景建模:对于每个新的帧,KNN 算法会计算当前像素与背景模型中所有样本之间的距离,并基于这些距离来决定该像素是前景还是背景。
前景检测:如果当前像素与所有背景模型中的样本距离都大于 dist2Threshold,则该像素被视为前景。
阴影检测(如果启用):如果 detectShadows 设置为 True,KNN 算法会尝试检测并标记出前景中的阴影区域。
import cv2
import numpy as np
bs = cv2.createBackgroundSubtractorKNN(detectShadows=True)
camera = cv2.VideoCapture('car.mkv')
index = 0
while True:
ret, frame = camera.read()
index += 1
frame_h, frame_w, _ = frame.shape
fgmask = bs.apply(frame)
th = cv2.threshold(fgmask.copy(), 244, 255, cv2.THRESH_BINARY)[1]
dilated = cv2.dilate(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)),
iterations=2)
contours, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
# if cv2.contourArea(c) > frame_w*0.075 * frame_h*0.075:
if cv2.contourArea(c) > 1000:
(x, y, w, h) = cv2.boundingRect(c)
cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 0, 255), 5)
cv2.imshow("mog", fgmask)
cv2.imwrite("./frame1/{}.jpg".format(index), fgmask)
cv2.imshow("thresh", th)
cv2.imwrite("./frame2/{}.jpg".format(index), th)
cv2.imshow("detection", frame)
cv2.imwrite("./frame3/{}.jpg".format(index), frame)
if cv2.waitKey(30) & 0xff == ord("q"):
break
camera.release()
cv2.destroyAllWindows()
附录
cv2.threshold
cv2.threshold 是 OpenCV 库中的一个重要函数,用于对图像进行阈值化处理。阈值化处理是数字图像处理中常用的一种方法,可以将图像转换为二值图像,即图像中每个像素只有黑白两种颜色。以下是 cv2.threshold 函数的详细中文文档:
一、函数原型
retval, dst = cv2.threshold(src, thresh, maxval, type[, dst])
二、参数说明
src:输入图像,必须是单通道灰度图像。
thresh:阈值,用于对像素值进行比较的界限值。可以是一个固定的数值,也可以是一个自适应阈值算法。
maxval:当像素值大于阈值时,赋予的新像素值。在二值化处理中,通常设置为 255(即白色)。
type:阈值类型,决定了对像素值大于或小于阈值的像素进行何种操作。常见的阈值类型包括:
- cv2.THRESH_BINARY:大于阈值的像素设置为 maxval,小于等于阈值的像素设置为 0。
- cv2.THRESH_BINARY_INV:大于阈值的像素设置为 0,小于等于阈值的像素设置为 maxval。
- cv2.THRESH_TRUNC:大于阈值的像素设置为阈值,小于等于阈值的像素保持不变。
- cv2.THRESH_TOZERO:大于阈值的像素保持不变,小于等于阈值的像素设置为 0。
- cv2.THRESH_TOZERO_INV:大于阈值的像素设置为 0,小于等于阈值的像素保持不变。
dst:输出图像,可选参数。如果未提供,将创建一个新的图像来存储结果。
三、返回值
retval:选取的阈值。在某些情况下,如果使用了自适应阈值算法,这个值可能有所不同。
dst:输出图像,与输入图像具有相同的大小和类型。
四、应用场景
阈值处理在图像处理中有广泛的应用,包括但不限于:
- 图像分割:将图像中的目标物体与背景进行分离。
- 目标检测:使用轮廓提取等方法进行目标检测和识别。
- 图像增强:改善图像的对比度和清晰度。
- 文字识别:更容易地提取出文字区域。
- 图像压缩:减小图像文件的大小,实现图像的压缩和存储。
cv2.dilate
cv2.dilate 是 OpenCV 库中的一个函数,用于对图像进行膨胀操作。膨胀是一种形态学操作,它可以用来增加图像中物体的大小,填充图像中的空洞,连接相邻的物体等。以下是 cv2.dilate 函数的详细中文文档:
一、函数原型
dst = cv2.dilate(src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])
二、参数说明
src:输入图像,可以是灰度图像或彩色图像。
kernel:
- 用于膨胀操作的结构元素,控制膨胀的形状和大小。
- 可以使用 cv2.getStructuringElement() 函数来创建结构元素,该函数接受形状、大小等参数。
- 常见的形状有:MORPH_RECT(矩形)、MORPH_CROSS(交叉形)、MORPH_ELLIPSE(椭圆形)。
dst:
- 输出图像,与输入图像具有相同的尺寸和深度。
- 可选参数,如果未提供,将创建一个新的图像来存储结果。
anchor:
- 结构元素的锚点位置,决定了结构元素在图像上的位置。
- 默认为 (-1, -1),表示锚点位于结构元素的中心。
iterations:
- 膨胀操作的迭代次数。
- 默认为 1,表示只进行一次膨胀操作。
borderType:
- 边界扩充的类型。
- 默认为 BORDER_CONSTANT。
borderValue:
- 边界扩充的数值。
- 默认为 0。
三、返回值
dst:膨胀后的输出图像。
四、用法解释
cv2.dilate 函数的作用是将图像中的物体进行膨胀操作,使其变大。膨胀操作的效果取决于所使用的结构元素的形状和大小。通常情况下,结构元素可以是矩形、圆形或者自定义形状。膨胀操作会将结构元素覆盖区域内的像素值取最大值(对于灰度图像)或进行逻辑运算(对于二值图像),从而使目标物体的边界变得更加平滑,填充空洞,连接相邻的物体。
cv2.findContours
cv2.findContours 是 OpenCV 库中用于在二值图像中查找轮廓的函数。以下是对 cv2.findContours 函数的详细中文文档,包括函数原型、参数说明、返回值以及示例代码。
一、函数原型
contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
二、参数说明
image:
- 输入的二值化图像,一般为灰度图像或二值图像。
mode:轮廓检索模式,指定轮廓的层级关系。
- cv2.RETR_EXTERNAL:只返回最外层的轮廓。
- cv2.RETR_LIST:返回所有轮廓,不建立轮廓间的层级关系。
- cv2.RETR_TREE:返回所有轮廓,并建立完整的层级关系。
- cv2.RETR_CCOMP:返回所有轮廓,并重建嵌套轮廓的完整层次结构(二级)。
method:轮廓逼近方法,指定轮廓的表示方式。
- cv2.CHAIN_APPROX_NONE:保存所有的轮廓点。
- cv2.CHAIN_APPROX_SIMPLE:仅保存轮廓的端点。
- cv2.CHAIN_APPROX_TC89_L1 和 cv2.CHAIN_APPROX_TC89_KCOS:应用 Teh-Chin 链逼近算法。
contours(可选):
- 用于存储检测到的轮廓的变量,如果传递了该参数,则不会返回此值。
hierarchy(可选):
- 用于存储轮廓的层次关系信息的变量,如果传递了该参数,则不会返回此值。
offset(可选):
- 可选的偏移量,用于在输出轮廓坐标中移动每个点。默认为 Point()。
三、返回值
contours:
轮廓列表,其中每个轮廓都是一个 NumPy 数组,包含该轮廓上所有点的坐标。
hierarchy:
轮廓的层次关系信息的 NumPy 数组,其中每个轮廓的层次关系由四个整数 [next, previous, first child, parent] 组成。
cv2.boundingRect
cv2.boundingRect 是 OpenCV 库中的一个函数,用于计算点集或灰度图像中非零像素的最小外接矩形(边界框)。以下是关于 cv2.boundingRect 函数的详细中文文档:
一、函数原型
rect = cv2.boundingRect(points)
或者
x, y, w, h = cv2.boundingRect(points)
二、参数说明
points:
- 输入的轮廓点集合,可以是 numpy.ndarray 类型,通常通过 cv2.findContours 函数获取。
三、返回值
rect(或者 x, y, w, h):
- 返回一个矩形边界框的信息。
- 如果返回单个变量 rect,它是一个包含四个整数值的元组,即 (x, y, w, h)。
- 如果返回四个单独的变量,则 x 和 y 是矩形左上角的坐标(通常是整数),w 是矩形的宽度,h 是矩形的高度。
四、细节解析
坐标系统:在 OpenCV 中,坐标系的原点 (0, 0) 位于图像的左上角,x 轴向右为正方向,y 轴向下为正方向。
边界框属性:
- (x, y):矩形左上角的坐标。
- w:矩形的宽度(水平方向上的像素数)
- h:矩形的高度(垂直方向上的像素数)
与 cv2.findContours 的关系:
- 通常,cv2.boundingRect 函数用于处理 cv2.findContours 函数返回的轮廓数据。cv2.findContours 可以从二值图像中检测出轮廓,并返回轮廓的点集信息。