思路
- 设置视频来源
- 设置各种参数,包括储存,窗口,过程参数等
- 捕获第一帧图像
- 进入循环
- 将第一帧图像赋给过程frame
- 对图像进行灰度处理
- 对图像执行高斯模糊,使其尽可能减小灰度的变化梯度
- 将两幅灰度图像相减,从而将背景删除
- 给出阈值,将相减后的图像转化为黑白图
- 将多余的零星变化白点置为黑色
- 检测白色色块的大小和边缘
- 按照阈值检测白色色块的边缘
- 绘出动态变化物体的边缘矩形
- 显示
- 储存到本地
- 按下esc退出循环
- 清零
注意点
- 在储存时彩色图像和灰度黑白图像的制式不同,需要分别指出各自的制式,否则无法保存到本地。高斯模糊的阈值、相减时的阈值、色块大小的阈值、灰度变化的阈值需要不断调节,最终结果受到光影、运动、物体明暗程度、场景环境的诸多影像,和视频源也有极大的关系
- 循环较长,各种逻辑关系必须非常清楚
- 网上例程很多,但基本上不可能拿来即用,本例程基本上算是最新的
- 后附各种图像和动画,以供参考
- 本例程采用手机的摄像头作为无线IP视频源,可能会有些卡滞,640x480的质量差强人意,转化为2M大小的GIF更是打了折扣,但程序毫无疑问是畅通的。
- 将手机作为无线视频源也是一个技术点,在后续的学习笔记中再行记录吧。
import cv2
import numpy as np
#设置窗口大小
cv2.namedWindow("Video",0)
cv2.resizeWindow("Video", 640, 480)
cv2.namedWindow("Video_gray",0)
cv2.resizeWindow("Video_gray", 640, 480)
cv2.namedWindow("Video_wb",0)
cv2.resizeWindow("Video_wb", 640, 480)
#打开USB摄像头,本例程采用手机作为无线IP摄像头,可能会有些卡
video="http://aikes:[email protected]:8080//video"#在不同的路由连接下会有不同的IP地址
camera = cv2.VideoCapture(video)
frame_now=camera.read()
#这是直接采用笔记本自带摄像头的定义
'''camera = cv2.VideoCapture(0)
frame_now=camera.read()'''
frame_old=None
#这是处理本地的视频
#camera= cv2.VideoCapture("c://girl.avi")
#fps,size码率及尺寸
#fps = camera.get(cv2.CV_CAP_PROP_FPS)
#size = (int(camera.get(cv2.CV_CAP_PROP_FRAME_WIDTH)), int(camera.get(cv2.CV_CAP_PROP_FRAME_HEIGHT)))
fps=10
size=640,480
#指定写视频的格式
out_now = cv2.VideoWriter('c://object_detect_now.avi', cv2.VideoWriter_fourcc(*'DIVX'), fps, size) #彩色视频
out_gray = cv2.VideoWriter('c://object_detect_gray.avi', cv2.VideoWriter_fourcc(*'DIVX'), fps, size,0) #灰度视频
out_wb = cv2.VideoWriter('c://object_detect_wb.avi', cv2.VideoWriter_fourcc(*'DIVX'), fps, size,0) #黑白视频
while (1):
ret,frame_now = camera.read() #返回frame,维持循环的重要步骤
#print (frame_now)
if not ret:
break
frame_gray=cv2.cvtColor(frame_now,cv2.COLOR_BGR2GRAY) #转化为灰度图像
frame_gray=cv2.GaussianBlur(frame_gray,(15,15),0) #高斯模糊
if frame_old is None:
frame_old=frame_gray #赋给过渡帧
continue
#获得与背景的差值,背景很重要,最好是除了移动的主体之外,什么都不懂,且背景中没有移动的主体
frame_delta = cv2.absdiff(frame_old,frame_gray) #相减
#获得黑白的图片
thresh = cv2.threshold(frame_delta, 25, 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=2)
#获得移动物体的轮廓
cnts, hierarchy, rr = cv2.findContours(thresh.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
#print cnts
#画出轮廓
#cv2.drawContours(frame_now, hierarchy, -1, (0, 255, 0), 3)
for c in hierarchy:
# if the contour is too small, ignore it
# 轮廓面积
#area = cv2.contourArea(c)
#print area
# 周长,或者说,弧长;第二个参数的True表示该轮廓是否封闭
#perimeter = cv2.arcLength(c,True)
#sprint perimeter
if cv2.contourArea(c) <= 5000: #阈值
continue
# compute the bounding box for the contour, draw it on the frame,
# and update the text
# 计算轮廓的边界框,在当前帧中画出该框
x,y,w,h = cv2.boundingRect(c)
#x,y,w,h=cv2.boundingRect(thresh)
frame_now=cv2.rectangle(frame_now,(x,y),(x+w,y+h),(0,0,255),3)
# 计算的最小轮廓
#rect = cv2.minAreaRect(c)
#print rect
print('save video....\n')
out_now.write(frame_now) #储存图像
out_gray.write(thresh)
out_wb.write(frame_delta)
cv2.imshow("Video", frame_now) #显示图像
cv2.imshow("Video_gray", thresh)
cv2.imshow("Video_wb", frame_delta)
if cv2.waitKey(1) == ord("q") or cv2.waitKey(1) == 27: #按下‘q’或者esc退出
print('exit!\n')
break
#清零
out_now.release()
out_gray.release()
out_wb.release()
camera.release()
cv2.destroyAllWindows()
![python3.6.3+opencv3.3.0学习笔记九--动态物体检测_第1张图片](http://img.e-com-net.com/image/info8/538e7ea979e8430abec412bad40ea8fa.jpg)
![python3.6.3+opencv3.3.0学习笔记九--动态物体检测_第2张图片](http://img.e-com-net.com/image/info8/4196ec35f64d426598f642431df963ff.jpg)
![python3.6.3+opencv3.3.0学习笔记九--动态物体检测_第3张图片](http://img.e-com-net.com/image/info8/17a6c7d8a7864d27a5a56463f831836c.jpg)
![python3.6.3+opencv3.3.0学习笔记九--动态物体检测_第4张图片](http://img.e-com-net.com/image/info8/f1afceeb53b140cda9eeac3eadec33da.jpg)
![python3.6.3+opencv3.3.0学习笔记九--动态物体检测_第5张图片](http://img.e-com-net.com/image/info8/1f70dc5ba91644c6b287547d94076f13.gif)
![python3.6.3+opencv3.3.0学习笔记九--动态物体检测_第6张图片](http://img.e-com-net.com/image/info8/bdc235758c3547bdac6cca002d2ce958.gif)