【opencv】picamera与opencv库详解

来源:互联网 发布:网络大电影众筹方案 编辑:程序博客网 时间:2024/06/08 07:55


树莓派(Raspberry Pi)中PiCamera+OpenCV的使用

参考:

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. capture 和 capture_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 sleepfrom picamera import PiCameradef open_preview():    with PiCamera() as camera:        camera.resolution = (320, 240)        camera.start_preview()        sleep(5)if __name__ == '__main__':    open_preview()

函数 open_preview() 用于打开摄像头进行预览

首先,获取一个 PiCamera 对象:

with PiCamera() as camera:

可以设置摄像头的分辨率,当前设为宽 320,高 240

camera.resolution = (320, 240)

打开摄像头进行预览:

camera.start_preview()

暂停 5 秒,即预览 5 秒:

sleep(5)

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

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

或者

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

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

mmal: mmal_vc_component_enable: failed to enable component: ENOSPCmmal: camera component couldn't be enabledmmal: main: Failed to create camera componentmmal: 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(i)            camera.capture(str(i) + ".jpg", resize=(80, 60))

函数 capture_preview() 仅比 open_preview() 多了一条捕获图像函数:

camera.capture(str(i) + ".jpg")

还可以在捕获图像的时候进行图像缩放:

camera.capture("te.jpg", resize=(80, 60))

函数功能:捕获图像,命名为 te.jpg,同时缩放至宽 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")

capture 和 capture_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 sleepfrom picamera import PiCameradef 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 += 1if __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 timeimport picamerawith 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)        camera.stop_recording()

函数 record_video 进行视频录制

首先获取 PiCamera 对象:

with PiCamera() as camera:

可以设置分辨率,当前设为 (320, 240)

camera.resolution = (320, 240)

打开预览,便于视频录制:

camera.start_preview()

开始录制,录制内容保存为 my.h264

camera.start_recording('my.h264')

设置录制时间,当前录制 10 秒视频:

camera.wait_recording(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 timeimport picameraimport numpy as npimport cv2with 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 timeimport picameraimport numpy as npimport cv2with 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 iofrom time import sleepimport picameraimport numpy as npimport cv2with 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 picameraimport picamera.arraywith 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 picameraimport picamera.arraywith 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 picameraimport picamera.arrayimport cv2from time import sleepwith 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 cv2cap = 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

重启,即可