引言
在树莓派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()
实践总结
通过逐步实验,我成功解决了以下问题:
-
确认了摄像头的基本功能。
-
实现了灰度图像和彩色图像的捕获与显示。
-
通过颜色空间转换改善了颜色准确性。
-
引入多线程机制优化了帧率和程序性能。
这些实践为在树莓派5B上搭建高效的OpenCV图像处理系统提供了参考。如果有更多更好的方法,欢迎大家留言评论区,一起学习!