文中需要安装pygame和PIL

调用摄像头的方式

在windows中,python 可以使用VideoCapture库来调用摄像头,使用非常简单,主页是这个页面

安装whl文件可以在这个页面中找到。

pip install <your whl file>

在Mac中你可以使用openCV来使用摄像头, 我们是使用其中的VideoCapture类来调用摄像头的。它的使用我会在后面的代码中加上。

初次使用

VideoCapture 版本:

1
2
3
4
from VideoCapture import Device
cam = Device()
cam.setResolution(320, 240)
cam.saveSnapshot('demo.jpg')
  • 会有提示can’t set resolution。因为你的摄像头可能不支持该分辨率。直接注释掉其中的第三句即可。
  • 会可能提示你VideoCapture中的一个tostring函数已经被取代了,你需要把其中一个文件的这个函数换成tobytes

openCV版本:

1
2
3
4
5
import cv2
cam = cv2.VideoCapture(0)
ret, im = cam.read()
im.imwrite('demo.jpg', im)
cap.release() # close the capture

正确运行这个程序之后,会出现一个demo.jpg。那就是你的摄像头的一个截图。我电脑上花费的时间是一秒左右。然而摄像头获取的时间其实并没有多少,但是将它作为一个文件存到电脑中才是占的时间比较多的步骤。

使用pygame作播放器

之后使用pygame作为一个播放器,持续播放我们从摄像头获取的图片,就相当于连续的影像了。

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
# coding: utf-8
from VideoCapture import Device
import sys
import pygame

pygame.init()
size = width, height = 640, 480
pygame.display.set_caption('视频窗口')
screen = pygame.display.set_mode(size)
pygame.display.flip()

cam = Device()
# cv version:
# cam = cv2.VideoCapture(0)

while True:
im = cam.getImage().tobytes()
# cv version:
# ret, im = cap.read()
camshot = pygame.image.frombuffer(im, size, "RGB")
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.blit(camshot, (0, 0))
pygame.display.update()

用socket传输摄像头的影像

没有设置socket的缓冲区大小,只能传递160, 120大小的图片。

服务器端:获取摄像头的图片并传给客户端

1
2
3
4
5
6
7
8
9
10
11
12
import socket
from VideoCapture import Device
cam = Device()

clisocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
PORT = 2333

while True:
im = cam.getImage()
im = im.resize((160, 120))
data = im.tobytes()
clisocket.sendto(data, ('127.0.0.1', PORT))

客户端:接受服务器的图片并用pygame将其显示出来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# coding: utf-8
import socket
import sys
import pygame

pygame.init()
screen = pygame.display.set_mode((160, 120))
pygame.display.set_caption("视频窗口")
pygame.display.flip()

svrsocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
PORT = 2333
svrsocket.bind(("127.0.0.1", PORT))

while True:
data, address = svrsocket.recvfrom(80000)
camshot = pygame.image.frombuffer(data, (160, 120), "RGB")
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.blit(camshot, (0, 0))
pygame.display.update()

==================================================

附加: js调用摄像头

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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>video test</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
<video id="video" width="640" height="480" autoplay></video>
</body>
<script type="text/javascript">
var constraints = {
video: {
width: 1280,
height: 720
}
};

navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
var video = document.querySelector('video');
video.src = window.URL.createObjectURL(stream);
video.onloadedmetadata = function(e) {
video.play();
};
}).catch(function(err) {
console.log(err.name + ": " + err.message);
});
</script>
</html>

在Firefox上是可以正常使用的。但是为了更好的兼容性,我们可能需要更多的限制:

比如,需要注意的是:
navigator.getUserMedia已经被弃用,API改名为MediaDevices.getUserMedia ^1

兼容性更好的版本参见:这里

里面还漏了一个window.URL的兼容性:

window.URL = (window.URL || window.webkitURL || window.mozURL || window.msURL);