灰度转彩色后用OpenCV添加彩色线条(Vispy集成显示异常)
问题描述
- 需求:导入灰度图像(2D数组),转换为RGB格式(3D数组)后添加红色/蓝色彩色线条,要求灰度图像视觉特性不变,仅线条为彩色。
- 异常情况:单独用OpenCV处理时彩色线条显示正常,但集成到包含Vispy的PySide2脚本后,线条仅显示黑色或白色,且已确认传递的图像为3D数组。
- 脚本逻辑:按固定频率循环展示同一张添加了彩色线条的图像。
问题原因
- Vispy颜色映射冲突:初始化
scene.visuals.Image时指定了cmap='grays',该参数会强制将所有输入图像(包括RGB格式)通过灰度颜色映射处理,导致彩色线条被转为灰度显示。 - 颜色通道顺序不匹配:OpenCV的
COLOR_GRAY2BGR生成的是BGR顺序的3D数组,而Vispy默认期望RGB顺序,这会导致颜色显示异常。 - 画布布局缺失:原代码未将Vispy画布添加到界面布局中,可能导致图像显示区域异常。
解决方案
修改代码中的三个关键部分:
- 调整颜色通道顺序,将OpenCV的BGR格式转为Vispy支持的RGB格式。
- 初始化Image对象时移除灰度颜色映射,明确指定颜色通道位置。
- 将Vispy画布添加到界面布局,确保正常显示。
修改后的完整代码:
import sys from PySide2 import QtWidgets, QtCore from vispy import scene from PySide2.QtCore import QMetaObject from PySide2.QtWidgets import * import numpy as np import time import imageio as iio import cv2 # 替换为你的灰度图像路径 my_image = "your_gray_image.png" class CameraThread(QtCore.QThread): new_image = QtCore.Signal(object) def __init__(self, parent=None): QtCore.QThread.__init__(self, parent) def run(self): try: while True: frame = iio.imread(my_image) print("shape before conversion: ", frame.data.shape) # 灰度转BGR后,再转为Vispy支持的RGB格式 frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR) frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) print("shape after conversion: ", frame.data.shape) # 添加红色线条(RGB顺序:(255,0,0)) cv2.line(frame, pt1=(100, 300), pt2=(400, 300), color=(255, 0, 0), thickness=10) self.new_image.emit(frame.data) time.sleep(3.0) except Exception as e: print(f"problem: {e}") finally: print('end!') class Ui_MainWindow(object): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 400) self.centralwidget = QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QGridLayout(self.centralwidget) self.gridLayout.setObjectName("gridLayout") self.groupBox = QGroupBox(self.centralwidget) self.groupBox.setObjectName("groupBox") # 为groupBox添加布局,用于放置Vispy画布 self.gridLayout_box = QGridLayout(self.groupBox) self.gridLayout_box.setObjectName("gridLayout_box") self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 1) MainWindow.setCentralWidget(self.centralwidget) QMetaObject.connectSlotsByName(MainWindow) class MainWindow(QtWidgets.QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) # OpenGL drawing surface self.canvas = scene.SceneCanvas(keys='interactive') self.canvas.create_native() # 将画布添加到groupBox的布局中 self.ui.gridLayout_box.addWidget(self.canvas.native) self.setWindowTitle('MyApp') self.view = self.canvas.central_widget.add_view() self.view.bgcolor = '#ffffff' # 设置画布背景为白色 # 初始化Image对象:移除灰度颜色映射,明确颜色通道位置 self.image = scene.visuals.Image(np.zeros((1, 1, 3)), interpolation='nearest', parent=self.view.scene, channel_axis=2, clim=(0, 2 ** 8 - 1)) self.view.camera = scene.PanZoomCamera(aspect=1) self.view.camera.flip = (0, 1, 0) self.view.camera.set_range() self.view.camera.zoom(1000, (0, 0)) self._camera_runner = CameraThread(parent=self) self._camera_runner.new_image.connect(self.new_image, type=QtCore.Qt.BlockingQueuedConnection) self._camera_runner.start() @QtCore.Slot(object) def new_image(self, img): try: print("shape when emitting: ", img.shape) self.image.set_data(img) self.image.update() except Exception as e: print(f"problem sending image: {e}") def main(): import ctypes ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID('my_gui') app = QtWidgets.QApplication([]) main_window = MainWindow() main_window.show() sys.exit(app.exec_()) if __name__ == '__main__': main()
关键修改点说明
- 颜色通道转换:添加
cv2.cvtColor(frame, cv2.COLOR_BGR2RGB),将OpenCV生成的BGR数组转为Vispy默认的RGB格式。 - Image对象配置:
- 移除
cmap='grays'参数,避免强制灰度映射。 - 添加
channel_axis=2,明确告知Vispy颜色通道位于数组的最后一维。
- 移除
- 界面布局修正:为groupBox添加布局并将Vispy画布加入其中,确保图像显示区域正常。
内容的提问来源于stack exchange,提问作者Josh.h
相关产品推荐
相关产品推荐

