原文出处:http://blog.topspeedsnail.com/archives/10797
本帖使用OpenCV检测移动的物体(洋文:Motion Detection)。它的应用非常广泛,常用在视频监控(当摄像头内有移动物体出现时,摄像头会自动抓拍,并保存图像/视频)、车流量监控等等。
我喜欢听着音乐上大号,我就想有没有办法在我上大号时自动播放音乐,智能马桶的滚粗(能放音乐的应该不多)。这时,我想起了闲置的树莓派,使用OpenCV+树莓派做Motion Detection,只要检测到有移动的东西(人)就开始播放音乐。恩,没错,本人相当懒。另外,在上大号时被摄像头照着也挺别扭。
Motion Detection的实现方法有很多,我使用的方法是Background subtraction、tutorial_py_bg_subtraction。
Background subtraction基本原理:首先取一张静态的背景图(不包含要检测的移动物体),然后比较监控图像(包含移动物体)和背景图,找到不同区域,这个区域就是要检测的物体。在现实环境中要复杂的多,我们还要考虑到光线变化、阴影、反射等等影响背景环境的因素。
本帖代码运行环境:Ubuntu + OpenCV 3.1,稍作修改即可在树莓派上运行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
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
(
)
|
我在摄像头前稍有移动,它就检测出来了。如果我在摄像头前保持静止,由于前一帧和当前帧没有大的变化,它就认为场景内没有移动的东西。
下面只要起一个线程播放音乐就大公告成了。
Python播放mp3的方法非常多,由于我使用Linux系统,最简单的方式是直接调用mplayer,连线程都省了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
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
(
)
|
树莓派读摄像头代码片段:
1
2
3
4
5
6
7
8
|
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
#...
|
相关资源