Python + OpenCv实现视频中的车辆检测计数(车流量统计)

文章目录

  • 1.序言
  • 2.设计思路以及遇到的问题
  • 3.实现过程
  • 4. 总结&吐槽

1.序言

最近由于毕业设计相关,疯狂学习计算机视觉的相关内容,该博文为我毕业设计的初步结果,由于尚未完全解决,因此这里主要说一下遇到的问题以及想法,如有问题欢迎大家指正。

2.设计思路以及遇到的问题

  1. 第一步是完成物体(也就是车辆)的检测,这里有两种解决办法,第一种办法是使用opencv的形态学处理,比如背景消除、做帧差、膨胀腐蚀等等,这个办法比较基础,但是要处理好需要调整诸多细节,我的细节调整的不够好,因此实现时会遇到许多小问题。第二个办法是直接实现物体的识别,需要用到一定的训练模型,我测试过googlenet和SSD,最终选择了SSD,如果大家有能力也能自己训练,可能效果更好。
  2. 第二步是追踪,这里我看到很多博文都提到了opencv自带的追踪器,比如kcf等,但是我对于追踪器没有成功使用,放弃了这个选择,并选择了最简单粗暴的方法:逐帧读取视频并寻找车辆,一帧一帧画出来。
  3. 第三步是计数,这里我卡了一个星期,遇到了各种问题,为此我几乎翻遍了CSDN关于这块的文章,有些文章确实给到了一些思路,但大部分都没给出具体过程。第一个问题是怎么判断是否计数的问题,我最开始的想法是:当车辆轮廓的y坐标碰到检测线(这里假定为700)时加1,但接下里的测试却非常失败,很多车辆在爱检测线附近会掉帧或者检测不到或者其他原因,总之仅仅靠一个y轴直接判断肯定是不够的,后来我改成往下大于检测线1(700),往上大于检测线2(400),发现问题更大了,你会一直检测(这里我划分ROI区域没有解决,可能是我方法不对)。之后在CSDN 中找到一篇博文,提到的做法是建立一个类,每次出现新的目标就创建一个类,旧的目标就替换坐标,这个做法后来证实的确有效。但问题是如何判断这一帧的车辆是否新的目标,我给出的解决办法是创建一个列表,将第一帧的所有目标(也就是每一个对象)存入,第二帧的时候遍历每一个目标与列表的每一辆车,判断x,y的距离,如果变化不超过车的长度和宽度,就认为这是同一辆车(也有学长告诉为特征值匹配的办法,也许更可行,但我能力不够没有学到这里,所以没有采用)。第三个问题 是来去方向问题,最开始的想法是读取质心,将每一辆车变成点,然后读取帧,当这一帧的这一辆车的y坐标相较于上一辆车增加时,就认为这辆车方向向下,否者认为方向向上,后来的测试证明我大错特错,有些车的轮廓会来回浮动,质点也会来回浮动,因此有时候下一帧中方向向下的车辆的y坐标甚至低于上一帧,所以我没有采取这种方式。最终只能考虑最简单粗暴的办法:根据x坐标给定方向,视频中x轴1000往左为下,1000往右为上,我承认这种办法确实很笨,但我确实没有想出好的办法来,如有同学有办法解决,恳请您大胆指出。第四个问题回到了计数判断环节,这里由于上面问题的解决,所以我给出的判断条件是y坐标+方向+是否已经计数。最后有个非常重要的步骤是车辆跨越一定限度后删除对象,节约计算时间。

3.实现过程

1.物体检测识别和追中请看我的上几篇博文,链接1 opencv检测 链接2SSD车辆识别
结果如下:
Python + OpenCv实现视频中的车辆检测计数(车流量统计)_第1张图片

2.定义类:(其实id没啥用,方便测试)

class Car:
    def __init__(self,c_id,c_x,c_y,direction,c_count):	#初始化
        self.c_id = c_id	#车辆编号
        self.c_x=c_x	#车辆坐标(实时更新)
        self.c_y=c_y
        self.direction = direction	#车辆方向
        self.c_count = c_count	#车辆是否已经计数


    def updateCoords(self,x,y):	#更新坐标
        self.c_x= x
        self.c_y=y

3.计数

                for i in cars:
                    if abs(cx - i.c_x) < width and abs(cy - i.c_y) < height: # 找到这辆车与上一帧中最近的车
                        new = False
                        #最开始的想法,Y轴坐标比上一帧大方向向下,比上一帧小方向向上,但失败了
                        # if cy > i.c_y:
                        #     i.direction = 'down'
                        # if cy < i.c_y:
                        #     i.direction = 'up'

                        i.updateCoords(cx, cy)
                        if i.c_y >= 700 and i.direction == 'down' and i.c_count == False:
                            count_down += 1
                            i.c_count = True
                        if i.c_y < 400 and i.direction == 'up' and i.c_count == False:
                            count_up += 1
                            i.c_count = True
                            #删除对象
                    if i.c_y >= 790 or i.c_y <= 290:
                        cars.remove(i)

                if new == True:
                    p = Car(pid, cx, cy, 'unknow', False)
                    #判断方向,这里我实在没找到好的办法,只能从简,大家测试的时候需要修改
                    #如果有好的办法请您指点
                    if p.c_x > 1000:
                        p.direction = 'up'
                    else:
                        p.direction = 'down'
                    cars.append(p)
                    pid += 1
                print(len(cars))
                cv.circle(image, (cx, cy), 5, (0, 0, 255), -1)
                cv.rectangle(image, (int(left), int(top)), (int(right), int(bottom)), (255, 0, 0), thickness=2)

4.结果(由于视频画质原因,遇到一些车辆比较模糊时会出现很多框,因此还需改进)

4. 总结&吐槽

由于代码还不够完善,这里就不给大家一一贴出来了,主要是跟大家说一下我的思路,要是有小伙伴想参考的话,我就放一个下载链接吧,其实这个东西只要想明白了应该不是什么难事(虽然我现在也有点晕),作为计算机视觉还在入门的新人,欢迎大家指出我的错误以便改进,也欢迎同样是计算机视觉新手的小伙伴们一起学习,本博客将一直更新相关内容,我会把计算机视觉入门过程中所遇到的重要问题和自己的想法分享给大家,同时也希望能收到大家的点赞或者指点迷津。
我在学习过程同遇到很多有经验的同学,他们有的使用了yolo v3算法,有的使用tensorflow训练模型,深感自己能力的不足,现在我会继续学习这方面的内容,希望能有更多思路和内容分享给大家。
吐槽:算法确实挺难的,但更难的是找测试素材,这十字路口的监控录像上哪找去(各大视频网站愣是没找到几个能用的,给跪了orz)

代码下载链接:
https://download.csdn.net/download/qq_43601378/12281842

有问题欢迎联系我:
[email protected]
[email protected]

你可能感兴趣的:(Python + OpenCv实现视频中的车辆检测计数(车流量统计))