Python-OpenCv实现出入口计数并显示

前言

这是我们数字图像处理课完成的一个实验项目,参考了网上的一些代码,针对我们老师给的需要统计人数的视频进行了一些修改。

源代码下载

一、背景剔除并二值化

高斯模糊:

gray = cv2.GaussianBlur(frame, (31, 31), 0)

作用:视频因为自然震动、光照变化或者摄像头本身等原因产生的噪声,对噪声进行平滑为了避免在运动和跟踪时将其检测出来。

Python-OpenCv实现出入口计数并显示_第1张图片

背景剔除

fgbg = cv2.createBackgroundSubtractorKNN()

生成蒙版

fgmask = fgbg.apply(gray)

Python-OpenCv实现出入口计数并显示_第2张图片

二值化:

ret,imBin= cv2.threshold(fgmask,200,255,cv2.THRESH_BINARY)

Python-OpenCv实现出入口计数并显示_第3张图片

Opening (erode->dilate)

mask = cv2.morphologyEx(imBin, cv2.MORPH_OPEN, kerne3)

开操作(腐蚀->膨胀)消除噪声

mask =  cv2.morphologyEx(mask , cv2.MORPH_CLOSE, kerne3)

Closing (dilate -> erode)

膨胀--最好能使形状比较均匀, 将破碎的区域连接起来

Python-OpenCv实现出入口计数并显示_第4张图片

用于形态学处理的核:

调整参数效果会有所改变

kernel = np.ones((3,3),np.uint8)

kerne2 = np.ones((5,5),np.uint8)

kerne3 = np.ones((11,11),np.uint8)

二、目标跟踪

找到边界:

_, contours0, hierarchy = cv2.findContours(mask2, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

对每个矩形框:

边框:rect = cv2.boundingRect(cnt)

计算面积:area=cv2.contourArea(cnt)

计算重心:

M=cv2.moments(cnt)

cx=int(M['m10']/M['m00'])

cy=int(M['m01']/M['m00'])

长宽:x, y, w, h = cv2.boundingRect(cnt)

对每个跟踪目标建立MyPerson类:

存储每个矩形框的重心坐标,状态

 

def __init__(self, i, xi, yi, max_age):
        self.i = i
        self.x = xi
        self.y = yi
        self.tracks = []
        self.R = randint(0,255)
        self.G = randint(0,255)
        self.B = randint(0,255)
        self.done = False
        self.state = '0'
        self.age = 0
        self.max_age = max_age
        self.dir = None

将所有识别到的人存储在数组中:

class MultiPerson:
    def __init__(self, persons, xi, yi):
        self.persons = persons
        self.x = xi
        self.y = yi
        self.tracks = []
        self.R = randint(0,255)
        self.G = randint(0,255)
        self.B = randint(0,255)
        self.done = False

三、计数算法

跟踪记录:

先在已有的persons中找到距离最近的,判断其属于同一个人,并更新位置数据

判断方向

画了两条线,一条出口,一条入口,以及limit线(白色):

白线的作用是将已经超过白线范围且记过数的目标人从数组中清除掉,清除内存,加快遍历查找速度

Python-OpenCv实现出入口计数并显示_第5张图片

进入:

self.tracks[-1][1] < mid_end and self.tracks[-2][1] >= mid_end

最后一个矩形框的重心坐标小于倒数第二个,且最后一个坐标在入口线的上方,前一个坐标在入口线的下方

Python-OpenCv实现出入口计数并显示_第6张图片

出去:

self.tracks[-1][1] > mid_start and self.tracks[-2][1] <= mid_start

最后一个矩形框的重心坐标大于倒数第二个,且最后一个坐标在出口线的下方,前一个坐标在出口线的上方

Python-OpenCv实现出入口计数并显示_第7张图片

Python-OpenCv实现出入口计数并显示_第8张图片

记录状态:

如果已经记过数则记下状态,之后不再重复计数,提高准确率。

清除人:

已经记过数且超出limit,则将其从内存清除

并排行走改进:

1、对与挨着一起走的人,无法将其完全分开,先记录一个人的宽度,判断其大于一个人的宽度,则用宽度除以每个人的宽度w.

Python-OpenCv实现出入口计数并显示_第9张图片

2、修改前面使用的形态学的核,将参数设为长方形或者椭圆形,这样识别单人会更加准确,也可以解决两人并排走的问题。

三、结果分析

 

进入

出去

实际人数

18/19

18

程序计数

18

21

准确率

100%

83.3%

四、存在的问题

漏识别:

对于衣服颜色和背景差不多的人会在某些位置无法识别,影响计数

Python-OpenCv实现出入口计数并显示_第10张图片

Python-OpenCv实现出入口计数并显示_第11张图片

原因:

图像处理后将其分的太碎导致矩形框面积太小不被识别为跟踪对象,需要进一步调整参数

错误计数

当人数过多时或受周围环境影响,识别的矩形框形状变化频繁,导致重心抖动,过线计数时会多记或者出入记反:

Python-OpenCv实现出入口计数并显示_第12张图片

保存输出视频

Cv2.VideoWriter(filename, fourcc, fps, frameSize[, isColor]) 

fourcc = cv2.VideoWriter_fourcc(*'XVID')

第一个参数是要保存的文件的路径

fourcc 指定编码器

fps 要保存的视频的帧率

frameSize 要保存的文件的画面尺寸

isColor 指示是黑白画面还是彩色的画面

编码的含义为:CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec

Python-OpenCv实现出入口计数并显示_第13张图片

你可能感兴趣的:(Python-OpenCv实现出入口计数并显示)