参考:

Raspberry Pi:https://www.raspberrypi.org/ Index of Packages:https://pypi.python.org/pypi/picamera


最新版本是 picamera 1.13:http://picamera.readthedocs.io/en/release-1.13/

主要内容

  1. 简单测试相机模块是否可以使用
  2. 使用 picamera 进行图像拍摄
  3. capturecapture_continuous 介绍
  4. 使用 picamera 进行视频录制
  5. picamera + OpenCV
  6. OpenCV 无法操作树莓派原装摄像头解决方法

简单测试相机模块是否可以使用

使用命令 raspistill 可以测试树莓派相机模块,最简单的语句如下:

raspistill -o te.jpg

功能:打开摄像头预览,几秒后拍摄一张照片

使用 picamera 进行图像拍摄

*使用 picamera 之前注意不要把文件名保存为 picamera.py*

When trying out these scripts do not name your file picamera.py.
Naming scripts after existing Python modules will cause errors when you try and import those modules
(because Python checks the current directory before checking other paths).

打开摄像头进行预览

代码:

# -*- coding: utf-8 -*-

from time import sleep
from picamera import PiCamera

def open_preview():
    with PiCamera() as camera:
        camera.resolution = (320, 240) # 可以设置摄像头的分辨率

        camera.start_preview()
        sleep(5)

if __name__ == '__main__':
    open_preview()

Note: 当结束摄像头操作后,务必确保调用 close 方法结束,有两种函数结构

camera = PiCamera()
try:
    # do something with the camera
    pass
finally:
    camera.close()

或者

with PiCamera() as camera:
    # do something with the camera
    pass

否则,有可能下次会无法打开,出现以下问题:

mmal: mmal_vc_component_enable: failed to enable component: ENOSPC
mmal: camera component couldn't be enabled
mmal: main: Failed to create camera component
mmal: Failed to run camera app. Please check for firmware updates

此为个人推测,摄像头并没有及时关闭导致(可通过相机模块的红灯判断摄像头是否开启)

对摄像头有一些常用的操作,比如设置分辨率,帧率,是否左右翻转,上下翻转:

def open_preview2():
    with PiCamera() as camera:
        camera.resolution = (320, 240)
        camera.framerate = 24
        camera.hflip = True
        camera.vflip = True

        camera.start_preview()
        sleep(5)

使用 picamera 还可以进行更多复杂功能的设置,比如设定摄像头的 ISO,曝光时间,亮度,对比度等等,可查看文档

拍摄图像

在预览的过程中可以将图片保存下来,函数实现如下:

def capture_preview():
    with PiCamera() as camera:
        camera.resolution = (320, 240)
        camera.start_preview()
        for i in range(5):
            sleep(5)
            camera.capture(str(i) + ".jpg", resize=(80, 60))

Note:当获取到 PiCamera() 对象后,就已经打开摄像头了,所以并不一定需要调用 camera.start_preview() 进行预览后才能保存图像

def capture_preview2():
    """
    打开摄像头,5秒后捕获一张图像
    :return:
    """
    with PiCamera() as camera:
        camera.resolution = (320, 240)

        sleep(5)

        camera.capture("no_preview.jpg")

capturecapture_continuous 介绍

函数 capture 原型:

capture(output, format=None, use_video_port=False, resize=None, splitter_port=0, bayer=False, **options)

源码:capture

功能:从摄像头中捕获图像,保存在 output

关键参数介绍:

  • output - 输出,如果为字符串,则作为文件名使用,比如 te.jpgte2.png等;如果不是字符串,那么必须是一个可读对象
  • format - 保存图像格式,默认为空,不为空,可使用以下格式:

函数 capture 支持图像格式如下:

'jpeg' - Write a JPEG file
'png' - Write a PNG file
'gif' - Write a GIF file
'bmp' - Write a Windows bitmap file
'yuv' - Write the raw image data to a file in YUV420 format
'rgb' - Write the raw image data to a file in 24-bit RGB format
'rgba' - Write the raw image data to a file in 32-bit RGBA format
'bgr' - Write the raw image data to a file in 24-bit BGR format
'bgra' - Write the raw image data to a file in 32-bit BGRA format
'raw' - Deprecated option for raw captures; the format is taken from the deprecated raw_format attribute

Note:当 output 指定图像格式后,如果 format 设置格式与其不一致,无法得到正常图像

  • use_video_port - 使用摄像头的图像或者视频端口进行图像捕获,默认为 False,表示使用图像端口。图像端口捕获速度慢(打开预览可知,捕获时会出现停顿现象),但是图像质量高;如果想要快速的捕获图像,使用视频端口,那么设为 True

如果想要不断捕获图像进行处理,使用图像端口如下:

# -*- coding: utf-8 -*-

from time import sleep
from picamera import PiCamera


def capture_images():
    """
    不断捕获图像
    :return:
    """
    with PiCamera() as camera:
    camera.resolution = (320, 240)
    sleep(2)

    num = 0
    while True:
        camera.capture(str(num) + ".jpg")

        print num
        num += 1

if __name__ == '__main__':
    capture_images()

想要速度更快,可以使用视频端口进行

camera.capture(str(num) + ".jpg", use_video_port=True)

picamera 也提供了一个不断捕获图像的函数 capture_continuous

函数原型:

capture_continuous(output, format=None, use_video_port=False, resize=None, splitter_port=0, burst=False, bayer=False, **options)

源码:capture_continuous

功能:不断从相机中捕获图像,该函数返回一个无穷迭代器。

参数 output - 如果是字符串,函数设定了两个替代项用于保存不同图像

  • {counter} - a simple incrementor that starts at 1 and increases by 1 for each image taken
  • {timestamp} - a datetime instance

使用方法比如:image{counter}.jpgimage{counter:02d}.jpgimage{timestamp}.jpg

*具体可查看文档*

示例函数:

import time
import picamera
with picamera.PiCamera() as camera:
    camera.start_preview()
    try:
    for i, filename in enumerate(
            camera.capture_continuous('image{counter:02d}.jpg')):
        print(filename)
        time.sleep(1)
        if i == 59:
            break
    finally:
    camera.stop_preview()

其他参数同 capture 一致

使用 picamera 进行视频录制

def record_video():
    """
    录制视频
    :return:
    """
    with PiCamera() as camera:
        camera.resolution = (320, 240)

        camera.start_preview()
        camera.start_recording('my.h264')

        camera.wait_recording(10) #设置录制时间,当前录制 10 秒视频:
        camera.stop_recording()

函数 start_recording 支持视频格式如下:

'h264' - Write an H.264 video stream
'mjpeg' - Write an M-JPEG video stream
'yuv' - Write the raw video data to a file in YUV420 format
'rgb' - Write the raw video data to a file in 24-bit RGB format
'rgba' - Write the raw video data to a file in 32-bit RGBA format
'bgr' - Write the raw video data to a file in 24-bit BGR format
'bgra' - Write the raw video data to a file in 32-bit BGRA format

Note:函数 start_preview 同样也不是必须的

picamera + OpenCV

经常使用 OpenCV 进行图像处理,需要 picamera 得到的图像转换为 OpenCV 能够处理的 numpy array 格式

捕获图像并显示:

# -*- coding: utf-8 -*-

import time
import picamera
import numpy as np
import cv2

with picamera.PiCamera() as camera:
    camera.resolution = (320, 240)
    camera.framerate = 24
    time.sleep(2)
    image = np.empty((240 * 320 * 3,), dtype=np.uint8)
    camera.capture(image, 'bgr')
    image = image.reshape((240, 320, 3))

    cv2.imshow("img", image)
    cv2.waitKey(0)

*使用视频端口(use_video_port=True)就无法捕获图像了,没搞懂*

视频流:

# -*- coding: utf-8 -*-

import time
import picamera
import numpy as np
import cv2

with picamera.PiCamera() as camera:
    camera.resolution = (320, 240)
    camera.framerate = 24
    time.sleep(2)

    while True:
        image = np.empty((240 * 320 * 3,), dtype=np.uint8)
        camera.capture(image, format='bgr')
        image = image.reshape((240, 320, 3))

        cv2.imshow("img", image)
        cv2.waitKey(1)

上面这个效果不佳,使用 capture_continuous:

# -*- coding: utf-8 -*-

import io
from time import sleep
import picamera
import numpy as np
import cv2

with picamera.PiCamera() as camera:
    camera.resolution = (320, 240)
    sleep(1)

    stream = io.BytesIO()
    for foo in camera.capture_continuous(stream, format='jpeg', use_video_port=True):
        data = np.fromstring(stream.getvalue(), dtype=np.uint8)
        image = cv2.imdecode(data, cv2.CV_LOAD_IMAGE_UNCHANGED)

        cv2.imshow("img", image)
        cv2.waitKey(1)

        # Truncate the stream to the current position (in case
        # prior iterations output a longer image)
        stream.truncate()
        stream.seek(0)

picamera 也提供了 PIRGBArray 对象,用来保存 RGB 图像

类原型:

class picamera.array.PiRGBArray(camera, size=None)

源码:PIRGBArray

捕获单张:

# -*- coding: utf-8 -*-

import picamera
import picamera.array

with picamera.PiCamera() as camera:
    with picamera.array.PiRGBArray(camera) as output:
        camera.capture(output, 'rgb')
        print('Captured %dx%d image' % (
            output.array.shape[1], output.array.shape[0]))

        print type(output.array)

得到的 output.array 就是 numpy.ndarray 类型,可直接用于 opencv 处理

不过 opencv 中图像格式是 bgr ,所以还需要进行转换:

dst = cv2.cvtColor(output.array, cv2.COLOR_RGB2BGR)

Note:在 capture 函数中设置图像格式为 bgr 没有作用

如果想要重复使用 output,需要在下次捕获前使用函数 truncate(0)

# -*- coding: utf-8 -*-

import picamera
import picamera.array

with picamera.PiCamera() as camera:
    with picamera.array.PiRGBArray(camera) as output:
        camera.resolution = (1280, 720)
        camera.capture(output, 'rgb')
        print('Captured %dx%d image' % (
            output.array.shape[1], output.array.shape[0]))
        output.truncate(0)
        camera.resolution = (640, 480)
        camera.capture(output, 'rgb')
        print('Captured %dx%d image' % (
            output.array.shape[1], output.array.shape[0]))

完整代码如下:

# -*- coding: utf-8 -*-

import picamera
import picamera.array
import cv2
from time import sleep

with picamera.PiCamera() as camera:
    camera.resolution = (320, 240)
    sleep(1)

    with picamera.array.PiRGBArray(camera) as output:
        # camera.capture(output, 'rgb', use_video_port=True)
        for foo in camera.capture_continuous(output, 'rgb', use_video_port=True):
            print('Captured %dx%d image' % (
            output.array.shape[1], output.array.shape[0]))

            dst = cv2.cvtColor(output.array, cv2.COLOR_RGB2BGR)

            cv2.imshow("img", dst)
            cv2.waitKey(1)

            output.truncate(0)

OpenCV 无法操作树莓派原装摄像头解决方法

可以直接使用 opencv 调用摄像头

# -*- coding: utf-8 -*-
import cv2
cap = cv2.VideoCapture(0)
# cap.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 320)
# cap.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 240)
while True:
    # get a frame
    ret, frame = cap.read()
    print "frame.shape: {}".format(frame.shape)

    # show a frame
    cv2.imshow("capture", frame)
    cv2.waitKey(1)

但可能会出现无法打开摄像头,原因:树莓派摄像头模块没有video0

解决方法:

cd /etc/modules-load.d/
sudo vim modules.conf 

加入 bcm2835-v4l2

重启,即可

流媒体播放器

尝试使用树莓派搭建流媒体服务器,试过rtsp-server、easydarwin、h5s

后来在网上看到可以使用nginx搭建流媒体服务器,就想着试试,经过调试,还真成功了,具体步骤见下面连接

https://www.cnblogs.com/qiantuo1234/p/6611845.html

感谢博主

这里记录下文中没有提到或讲的不详细的问题

1、nginx可以下载最新版,地址:http://nginx.org/download/

2、要先安装以下这些库,不然会配置或编译会报错

sudo apt-get install libpcre3 libpcre3-dev  
sudo apt-get install openssl libssl-dev  
sudo apt-get install zlib1g-dev  

3、编译可能遇到的两个错误,这两个错误要修改两个文件,文件位置这里说明下

文件 ngx_http_streaming_module.c 在nginx_mod_h264_streaming-2.2.7/src文件夹中

删除Makefile文件中的 -Werror选项,Makefile文件在nginx-1.19.0/objs文件夹中,删除Makefile文件中CFLAGS后面的-Werror选项

4、nginx配置文件说明,连接文章中配置的安装目录为/usr/local/nginx-stream,因此nginx的配置文件也是要在这个目录中配置,位置/usr/local/nginx-stream/conf目录中nginx.conf文件中。

5、nginx中添加的代码说明,我直接使用博主的代码,运行未成功,我改为了以下代码,位置放在nginx.conf文件中的server段,于原有的location同级

location ~* .*.flv$ {
    flv;
}

location ~* .*.mp4$ {
    mp4;
}

6、启停nginx

sudo /usr/local/nginx-stream/sbin/nginx   #启动nginx服务
sudo /usr/local/nginx-stream/sbin/nginx -s stop  #停止nginx服务