python - 在 python + picamera + opencv 的线程内使用 "with"

标签 python opencv raspberry-pi

我正在使用带有 picamera 和 opencv python 模块的树莓派来尝试进行一些快速捕获和处理。 目前我正在使用 http://picamera.readthedocs.org/en/latest/recipes2.html#rapid-capture-and-processing 中的食谱将每个图像捕获到 BytesIO 流。然后我在 ImageProccessor 类中添加了代码,将每个流转换为 opencv 对象并“即时”进行一些分析。

因此,我当前的代码看起来像这样:

import io
import time
import threading
import picamera
import cv2
import picamera.array
import numpy as np


# Create a pool of image processors
done = False
lock = threading.Lock()
pool = []

class ImageProcessor(threading.Thread):
    def __init__(self):
        super(ImageProcessor, self).__init__()
        self.stream = io.BytesIO()
        self.event = threading.Event()
        self.terminated = False
        self.start()

    def run(self):
        # This method runs in a separate thread
        global done
        while not self.terminated:
            # Wait for an image to be written to the stream
            if self.event.wait(1):
                try:
                    self.stream.seek(0)
                    # Read the image and do some processing on it
                    # Construct a numpy array from the stream
                    data = np.fromstring(self.stream.getvalue(), dtype=np.uint8)
                    # "Decode" the image from the array, preserving colour
                    image = cv2.imdecode(data, 1)

                    # Here goes more opencv code doing image proccessing

                    # Set done to True if you want the script to terminate
                    # at some point
                    #done=True
                finally:
                    # Reset the stream and event
                    self.stream.seek(0)
                    self.stream.truncate()
                    self.event.clear()
                    # Return ourselves to the pool
                    with lock:
                        pool.append(self)

def streams():
    while not done:
        with lock:
            if pool:
                processor = pool.pop()
            else:
                processor = None
        if processor:
            yield processor.stream
            processor.event.set()
        else:
            # When the pool is starved, wait a while for it to refill
            print ("Waiting")            
            time.sleep(0.1)

with picamera.PiCamera() as camera:
    pool = [ImageProcessor() for i in range(4)]
    camera.resolution = (640, 480)
    camera.framerate = 30
    camera.start_preview()
    time.sleep(2)
    camera.capture_sequence(streams(), use_video_port=True)

# Shut down the processors in an orderly fashion
while pool:
    with lock:
        processor = pool.pop()
    processor.terminated = True
    processor.join()

问题在于,这涉及到每个图像的 JPEG 编码和解码,这是有损且耗时的。建议的替代方案是捕获到 picamera.ar​​ray: http://picamera.readthedocs.org/en/latest/recipes1.html#capturing-to-an-opencv-object ,对于单个图像,代码:

import time
import picamera
import picamera.array
import cv2

with picamera.PiCamera() as camera:
    camera.start_preview()
    time.sleep(2)
    with picamera.array.PiRGBArray(camera) as stream:
        camera.capture(stream, format='bgr')
        # At this point the image is available as stream.array
        image = stream.array

效果很好,但我不知道如何组合这两段代码,以便 ImageProcessor 类定义 picamera.ar​​ray 而不是 BytesIO 流。需要使用“with”语句来生成 picamera.ar​​ray 的流让我感到困惑(我是 python 新手......;))。 感谢您的指点。 天使

最佳答案

我发现你可以引用 picamera 模块的源代码。

def raw_resolution(resolution):
    """
    Round a (width, height) tuple up to the nearest multiple of 32 horizontally
    and 16 vertically (as this is what the Pi's camera module does for
    unencoded output).
    """
    width, height = resolution
    fwidth = (width + 31) // 32 * 32
    fheight = (height + 15) // 16 * 16
    return fwidth, fheight


def bytes_to_rgb(data, resolution):
    """
    Converts a bytes objects containing RGB/BGR data to a `numpy`_ array.
    """
    width, height = resolution
    fwidth, fheight = raw_resolution(resolution)
    if len(data) != (fwidth * fheight * 3):
        raise PiCameraValueError(
            'Incorrect buffer length for resolution %dx%d' % (width, height))
    # Crop to the actual resolution
    return np.frombuffer(data, dtype=np.uint8).\
            reshape((fheight, fwidth, 3))[:height, :width, :]

您可以通过调用进行转换

image = bytes_to_rgb(self.stream.getvalue(),resolution)

其中分辨率是(宽度,高度)。 camera 传递给 PiRGBArray 的原因是为了能够引用相机的分辨率。

关于python - 在 python + picamera + opencv 的线程内使用 "with",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29065624/

相关文章:

python - 类型错误 : 'numpy.int64' object is not callable — What does that mean in laymans terms?

python - 陷入无限循环

python - 将 IP 摄像机流从 Raspberry 重定向到我的网站

python - 在 Linux 中获取和设置 X11 剪贴板

python - 读取两行的值并用python写入一行

python - 仅检查 OpenCV 中视频源的特定部分

python - 是否可以在 Windows 10 上禁用网络摄像头的自动对焦?

python - 寻找一种将矩形拟合到轮廓点的方法

hadoop - 如何使用 Hadoop 发送、存储和分析传感器数据

python - 步进电机直线加速