树莓派5B opencv使用csi摄像头解决方法

引言

在树莓派5B上通过OpenCV和Picamera2库调用CSI摄像头进行图像处理时,我进行了多次实验和调试,逐步排查和解决了图像捕获、灰度转换、RGB颜色处理及显示中的问题。以下是实践过程中按照顺序的完整操作步骤及代码说明。

实践步骤

第一步:初始灰度图像捕获

在初始实验中,我编写了一段代码,通过Picamera2库捕获图像并使用OpenCV将图像转换为灰度图像显示。

实现代码:

from picamera2 import Picamera2, Preview
import cv2
import numpy as np

# 初始化 Picamera2 摄像头
picam2 = Picamera2()

# 配置摄像头为静态图像模式,分辨率设置为 640x480
camera_config = picam2.create_still_configuration(main={"size": (640, 480)})
picam2.configure(camera_config)

# 启动摄像头
picam2.start()

# 创建一个窗口,用于显示图像
cv2.namedWindow("Picamera2 OpenCV Example", cv2.WINDOW_AUTOSIZE)

while True:
    # 捕获图像帧
    frame = picam2.capture_array()

    # 将捕获的图像帧转换为灰度图像
    gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 在窗口中显示灰度图像
    cv2.imshow("Picamera2 OpenCV Example", gray_frame)

    # 检测键盘输入,如果按下 'q' 键则退出循环
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源,关闭窗口和摄像头
cv2.destroyAllWindows()
picam2.stop()

结果截图:

 

这张图片显示了捕获到的灰度图像输出,证明摄像头正常工作,但仅限于单通道灰度显示。

第二步:捕获并显示彩色图像

接下来,我尝试去掉灰度转换,直接捕获并显示原始彩色图像。

实现代码:

from picamera2 import Picamera2, Preview
import cv2
import numpy as np

# 初始化 Picamera2 摄像头
picam2 = Picamera2()

# 配置摄像头为静态图像模式,分辨率设置为 640x480
camera_config = picam2.create_still_configuration(main={"size": (640, 480)})
picam2.configure(camera_config)

# 启动摄像头
picam2.start()

# 创建一个窗口,用于显示图像
cv2.namedWindow("Picamera2 OpenCV Example", cv2.WINDOW_AUTOSIZE)

while True:
    # 捕获图像帧
    frame = picam2.capture_array()

    # 直接显示捕获的彩色图像帧(未进行任何颜色空间转换)
    cv2.imshow("Picamera2 OpenCV Example", frame)

    # 检测键盘输入,如果按下 'q' 键则退出循环
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源,关闭窗口和摄像头
cv2.destroyAllWindows()
picam2.stop()

结果截图:

 

这张图片展示了彩色图像输出,说明摄像头能捕获并正确输出彩色图像。但在现实场景中,图像颜色有失真的现象。

颜色失真的原因:

在这一步中,我直接使用OpenCV的 imshow() 方法展示了从Picamera2捕获的彩色图像,但并未进行颜色空间的转换。由于OpenCV的 imshow() 默认将输入的图像数据解释为BGR格式,而Picamera2输出的图像数据是RGB格式,因此,红色和蓝色通道会被互换,导致显示的颜色不准确,从而出现显示的图像颜色失真的现象。

第三步:RGB颜色空间转换

为了解决颜色失真的问题,确保颜色输出与实际一致,我添加了从RGB到BGR的颜色空间转换,通过OpenCV的 cv2.cvtColor() 函数将图像从RGB转换为BGR格式,这样可以用OpenCV准确地显示和处理图像。

实现代码:

from picamera2 import Picamera2, Preview
import cv2
import numpy as np

# 初始化 Picamera2 摄像头
picam2 = Picamera2()

# 配置摄像头为静态图像模式,分辨率设置为 640x480
camera_config = picam2.create_still_configuration(main={"size": (640, 480)})
picam2.configure(camera_config)

# 启动摄像头
picam2.start()

# 创建一个窗口,用于显示图像
cv2.namedWindow("Picamera2 OpenCV Example", cv2.WINDOW_AUTOSIZE)

while True:
    # 捕获图像帧
    frame = picam2.capture_array()

    # 将 RGB 格式图像转换为 BGR 格式,确保颜色在 OpenCV 中正确显示
    bgr_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

    # 在窗口中显示转换后的图像
    cv2.imshow("Picamera2 OpenCV Example", bgr_frame)

    # 检测键盘输入,如果按下 'q' 键则退出循环
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 释放资源,关闭窗口和摄像头
cv2.destroyAllWindows()
picam2.stop()

结果截图:

这张图片展示了在加入颜色空间转换后,显示的图像颜色与实际颜色完全一致,不再有颜色失真的问题。经过转换后的图像,颜色准确,效果符合预期。

第四步:多线程优化

为进一步提升性能,我加入了多线程机制,将图像捕获和图像显示分离开。这样可以提高程序的帧率,减轻主线程的压力。

实现代码:

from picamera2 import Picamera2, Preview
import cv2
import threading
import numpy as np

# 初始化 Picamera2 摄像头
picam2 = Picamera2()

# 配置摄像头为静态图像模式,分辨率设置为 320x240(较低分辨率提高性能)
camera_config = picam2.create_still_configuration(main={"size": (320, 240)})
picam2.configure(camera_config)

# 启动摄像头
picam2.start()

# 创建一个窗口,用于显示图像
cv2.namedWindow("Picamera2 OpenCV Example", cv2.WINDOW_AUTOSIZE)

# 定义一个全局变量用于存储图像帧
frame = None

# 定义线程函数,用于持续捕获图像帧
def capture_frames():
    global frame
    while True:
        # 捕获图像帧并存储到全局变量 frame
        frame = picam2.capture_array()

# 启动后台线程捕获图像帧
capture_thread = threading.Thread(target=capture_frames)
capture_thread.daemon = True  # 设置为守护线程,在主程序退出时自动停止
capture_thread.start()

# 设置帧率延迟,约 30 FPS(1000 毫秒 / 30 = 33 毫秒)
frame_rate_delay = 30

while True:
    if frame is not None:
        # 将 RGB 格式图像转换为 BGR 格式,确保颜色在 OpenCV 中正确显示
        bgr_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

        # 显示转换后的图像帧
        cv2.imshow("Picamera2 OpenCV Example", bgr_frame)

    # 检测键盘输入,如果按下 'q' 键则退出循环
    if cv2.waitKey(frame_rate_delay) & 0xFF == ord('q'):
        break

# 释放资源,关闭窗口和摄像头
cv2.destroyAllWindows()
picam2.stop()

实践总结

通过逐步实验,我成功解决了以下问题:

  1. 确认了摄像头的基本功能。

  2. 实现了灰度图像和彩色图像的捕获与显示。

  3. 通过颜色空间转换改善了颜色准确性。

  4. 引入多线程机制优化了帧率和程序性能。

这些实践为在树莓派5B上搭建高效的OpenCV图像处理系统提供了参考。如果有更多更好的方法,欢迎大家留言评论区,一起学习!