OpenCV检测场景内是否有移动物体

转载自:http://blog.topspeedsnail.com/archives/10797

本帖使用OpenCV检测移动的物体(洋文:Motion Detection)。它的应用非常广泛,常用在视频监控(当摄像头内有移动物体出现时,摄像头会自动抓拍,并保存图像/视频)、车流量监控等等。

我喜欢听着音乐上大号,我就想有没有办法在我上大号时自动播放音乐,智能马桶的滚粗(能放音乐的应该不多)。这时,我想起了闲置的树莓派,使用OpenCV+树莓派做Motion Detection,只要检测到有移动的东西(人)就开始播放音乐。恩,没错,本人相当懒。另外,在上大号时被摄像头照着也挺别扭。

Motion Detection的实现方法有很多,我使用的方法是Background subtractiontutorial_py_bg_subtraction

Background subtraction基本原理:首先取一张静态的背景图(不包含要检测的移动物体),然后比较监控图像(包含移动物体)和背景图,找到不同区域,这个区域就是要检测的物体。在现实环境中要复杂的多,我们还要考虑到光线变化、阴影、反射等等影响背景环境的因素。

本帖代码运行环境:Ubuntu + OpenCV 3.1,稍作修改即可在树莓派上运行。

import cv2
import time
 
camera = cv2.VideoCapture(0)
if camera is None:
    print('请先连接摄像头')
    exit()
 
fps = 5 # 帧率
pre_frame = None  # 总是取前一帧做为背景(不用考虑环境影响)
 
play_music = False
 
while True:
    start = time.time()
    res, cur_frame = camera.read()
    if res != True:
        break
    end = time.time()
    seconds = end - start
    if seconds < 1.0/fps:
        time.sleep(1.0/fps - seconds)
    """
    cv2.imshow('img', cur_frame)
    key = cv2.waitKey(30) & 0xff
    if key == 27:
        break
    """
    gray_img = cv2.cvtColor(cur_frame, cv2.COLOR_BGR2GRAY)
    gray_img = cv2.resize(gray_img, (500, 500))
    gray_img = cv2.GaussianBlur(gray_img, (21, 21), 0)
 
    if pre_frame is None:
        pre_frame = gray_img
    else:
        img_delta = cv2.absdiff(pre_frame, gray_img)
        thresh = cv2.threshold(img_delta, 25, 255, cv2.THRESH_BINARY)[1]
        thresh = cv2.dilate(thresh, None, iterations=2)
        image, contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        for c in contours:
            if cv2.contourArea(c) < 1000: # 设置敏感度
                continue
            else:
                #print(cv2.contourArea(c))
                print("前一帧和当前帧不一样了, 有什么东西在动!")
                play_music = True
                break
 
        pre_frame = gray_img
 
camera.release()
cv2.destroyAllWindows()

OpenCV检测移动物体

我在摄像头前稍有移动,它就检测出来了。如果我在摄像头前保持静止,由于前一帧和当前帧没有大的变化,它就认为场景内没有移动的东西

下面只要起一个线程播放音乐就大公告成了。

Python播放mp3的方法非常多,由于我使用Linux系统,最简单的方式是直接调用mplayer,连线程都省了。

import os
import subprocess
import random
import cv2
import time
 
camera = cv2.VideoCapture(0)
if camera is None:
    print('请先连接摄像头')
    exit()
 
fps = 5 # 帧率
pre_frame = None  # 总是取前一帧做为背景
 
mp3_path = '/root/Music'
mp3_filenames = []
for mp3 in os.listdir(mp3_path):
    if mp3.endswith('.mp3'):
        mp3_filenames.append(mp3)
 
while True:
    start = time.time()
    res, cur_frame = camera.read()
    if res != True:
        break
    end = time.time()
    seconds = end - start
    if seconds < 1.0/fps:
        time.sleep(1.0/fps - seconds)
    """
    cv2.imshow('img', cur_frame)
    key = cv2.waitKey(30) & 0xff
    if key == 27:
        break
    """
    gray_img = cv2.cvtColor(cur_frame, cv2.COLOR_BGR2GRAY)
    gray_img = cv2.resize(gray_img, (500, 500))
    gray_img = cv2.GaussianBlur(gray_img, (21, 21), 0)
 
    if pre_frame is None:
        pre_frame = gray_img
    else:
        img_delta = cv2.absdiff(pre_frame, gray_img)
        thresh = cv2.threshold(img_delta, 25, 255, cv2.THRESH_BINARY)[1]
        thresh = cv2.dilate(thresh, None, iterations=2)
        image, contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        for c in contours:
            if cv2.contourArea(c) < 1000: # 设置敏感度
                continue
            else:
                mp3_file = mp3_path + '/' + random.choice(mp3_filenames)
                print("playing", mp3_file)
                p = subprocess.Popen('mplayer ' + mp3_file,stdin=None,stdout=None, shell=True)
                p.wait()
                break
 
        pre_frame = gray_img
 
camera.release()
cv2.destroyAllWindows()

树莓派读摄像头代码片段:

camera = PiCamera()
camera.resolution = (500, 500)
camera.framerate = 5
rawCapture = PiRGBArray(camera)
 
for f in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
    cur_frame = f.array

猜你喜欢

转载自blog.csdn.net/F_hawk189/article/details/86004732