You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

灰度转彩色后用OpenCV添加彩色线条(Vispy集成显示异常)

问题描述
  • 需求:导入灰度图像(2D数组),转换为RGB格式(3D数组)后添加红色/蓝色彩色线条,要求灰度图像视觉特性不变,仅线条为彩色。
  • 异常情况:单独用OpenCV处理时彩色线条显示正常,但集成到包含Vispy的PySide2脚本后,线条仅显示黑色或白色,且已确认传递的图像为3D数组。
  • 脚本逻辑:按固定频率循环展示同一张添加了彩色线条的图像。
问题原因
  1. Vispy颜色映射冲突:初始化scene.visuals.Image时指定了cmap='grays',该参数会强制将所有输入图像(包括RGB格式)通过灰度颜色映射处理,导致彩色线条被转为灰度显示。
  2. 颜色通道顺序不匹配:OpenCV的COLOR_GRAY2BGR生成的是BGR顺序的3D数组,而Vispy默认期望RGB顺序,这会导致颜色显示异常。
  3. 画布布局缺失:原代码未将Vispy画布添加到界面布局中,可能导致图像显示区域异常。
解决方案

修改代码中的三个关键部分:

  1. 调整颜色通道顺序,将OpenCV的BGR格式转为Vispy支持的RGB格式。
  2. 初始化Image对象时移除灰度颜色映射,明确指定颜色通道位置。
  3. 将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 04:31:05