OpenCV3-Python之MOG2、KNN和GMG背景分割器
admin 于 2018年09月12日 发表在 计算机视觉
在上篇博文《OpenCV3-Python简单移动目标跟踪》中介绍了简单移动目标跟踪方法,也提到在实际应用中,由于场景复杂其跟踪效果并不好;因此,本篇介绍常用的几种更有效的跟踪方法——背景分割器。
1. 背景分割器
OpenCV3中常用的背景分割器有三种:Mixture of Gaussians(MOG2)、K-Nearest(KNN)、Geometric Multigid(GMG) 。
OpenCV中提供了一个称为BackgroundSubtractor的类,在分割前景和背景时有两方面的优势:
<1> 专门用来进行视频分析,即:BackgroundSubtractor类会对每帧的环境进行 "学习" ;
<2> 可以计算阴影,通过检测阴影,可排除检测图像的阴影区域,从而更关注实际特征;
2. 应用举例
(1)MOG2
import cv2 import numpy as np ''' retval = cv.createBackgroundSubtractorMOG2( [, history[, varThreshold[, detectShadows]]] ) Parameters history Length of the history. varThreshold Threshold on the squared Mahalanobis distance between the pixel and the model to decide whether a pixel is well described by the background model. This parameter does not affect the background update. detectShadows If true, the algorithm will detect shadows and mark them. It decreases the speed a bit, so if you do not need this feature, set the parameter to false. url: https://docs.opencv.org/3.4.2/de/de1/group__video__motion.html#ga2beb2dee7a073809ccec60f145b6b29c ''' #MOG背景分割器 mog = cv2.createBackgroundSubtractorMOG2(detectShadows = True) camera = cv2.VideoCapture("traffic.flv") ret, frame = camera.read() while ret: fgmask = mog.apply(frame) th = cv2.threshold(np.copy(fgmask), 244, 255, cv2.THRESH_BINARY)[1] th = cv2.erode(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)), iterations = 2) dilated = cv2.dilate(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8,3)), iterations = 2) image, contours, hier = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: if cv2.contourArea(c) > 1000: (x,y,w,h) = cv2.boundingRect(c) cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 255, 0), 2) cv2.imshow("mog", fgmask) cv2.imshow("thresh", th) cv2.imshow("diff", frame & cv2.cvtColor(fgmask, cv2.COLOR_GRAY2BGR)) cv2.imshow("detection", frame) ret, frame = camera.read() #读取视频帧数据 if cv2.waitKey(100) & 0xff == ord("q"): break camera.release() cv2.destroyAllWindows()
(2)KNN
import cv2 import numpy as np ''' retval = cv.createBackgroundSubtractorKNN([, history[, dist2Threshold[, detectShadows]]]) Parameters history Length of the history. dist2Threshold Threshold on the squared distance between the pixel and the sample to decide whether a pixel is close to that sample. This parameter does not affect the background update. detectShadows If true, the algorithm will detect shadows and mark them. It decreases the speed a bit, so if you do not need this feature, set the parameter to false. ''' #KNN背景分割器 knn = cv2.createBackgroundSubtractorKNN(detectShadows = True) camera = cv2.VideoCapture("traffic.flv") def drawCnt(fn, cnt): if cv2.contourArea(cnt) > 1600: (x, y, w, h) = cv2.boundingRect(cnt) cv2.rectangle(fn, (x, y), (x + w, y + h), (255, 255, 0), 2) while True: ret, frame = camera.read() if not ret: break fgmask = knn.apply(frame) th = cv2.threshold(np.copy(fgmask), 244, 255, cv2.THRESH_BINARY)[1] es = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) dilated = cv2.dilate(th, es, iterations = 2) image, contours, hierarchy = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: drawCnt(frame, c) cv2.imshow("knn", fgmask) cv2.imshow("thresh", th) cv2.imshow("detection", frame) if cv2.waitKey(100) & 0xff == ord("q"): break camera.release() cv2.destroyAllWindows()
(2)GMG
import numpy as np import cv2 ''' retval = cv.bgsegm.createBackgroundSubtractorGMG( [, initializationFrames[, decisionThreshold]] ) Parameters initializationFrames number of frames used to initialize the background models. decisionThreshold Threshold value, above which it is marked foreground, else background. ''' #GMG背景分割器 fgbg = cv2.bgsegm.createBackgroundSubtractorGMG() camera = cv2.VideoCapture('traffic.flv') ret, frame = camera.read() while ret: fgmask = fgbg.apply(frame) th = cv2.threshold(np.copy(fgmask), 244, 255, cv2.THRESH_BINARY)[1] th = cv2.erode(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)), iterations = 2) dilated = cv2.dilate(th, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (8,3)), iterations = 2) image, contours, hier = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for c in contours: if cv2.contourArea(c) > 1000: (x,y,w,h) = cv2.boundingRect(c) cv2.rectangle(frame, (x,y), (x+w, y+h), (255, 255, 0), 2) cv2.imshow("GMG", fgmask) cv2.imshow("thresh", th) cv2.imshow("diff", frame & cv2.cvtColor(fgmask, cv2.COLOR_GRAY2BGR)) cv2.imshow("detection", frame) ret, frame = camera.read() #读取视频帧数据 if cv2.waitKey(100) & 0xff == ord("q"): break camera.release() cv2.destroyAllWindows()
根据以上效果对比知:
MOG2算法阴影检测并不完美,但它有助于将目标轮廓按原始形状进行还原;KNN的精确性和阴影检测能力较好,即使是相邻对象也没有在一起检测,运动检测的结果相当精确。