Tkinter集成OpenCV播放视频时灰度直方图无法动态更新问题求助
问题排查与修复方案
核心错误原因
- 变量名冲突:初始化时你先将
self.canvas_hist定义为Matplotlib嵌入Tkinter的画布实例(FigureCanvasTkAgg类型),后续调用ax.plot()生成折线时,又将折线对象覆盖赋值给了self.canvas_hist,导致无法调用画布的重绘方法,这也是你之前调用draw()触发参数缺失报错的原因——你实际是在调用折线对象的draw方法,该方法要求传入renderer参数,而画布对象的draw方法不需要。 - 更新数据后未触发重绘:调用
set_ydata仅修改了折线的内存数据,没有触发画布刷新操作,界面上的直方图自然不会更新。
修正后的核心代码
仅需要修改App类中直方图初始化和calc_hist方法即可:
import tkinter import cv2 import PIL.Image, PIL.ImageTk from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import numpy as np import matplotlib.pyplot as plt class App: def __init__(self, window, window_title, video_source=0): self.window = window self.window.title(window_title) self.video_source = video_source self.vid = MyVideoCapture(self.video_source) # 视频画布 self.canvas = tkinter.Canvas(window, width = 640, height = 480) self.canvas.grid(row=0, column = 0) # 直方图区域 self.frame_hist = tkinter.Frame(window) self.frame_hist.grid(row=0, column = 1) self.figure = plt.Figure(figsize=(5,4), dpi = 100) self.ax = self.figure.add_subplot() # 重命名画布变量,避免和后续折线对象冲突 self.hist_canvas = FigureCanvasTkAgg(self.figure, self.frame_hist) self.hist_canvas.get_tk_widget().pack(fill = tkinter.BOTH, side = tkinter.TOP) self.ax = self.figure.gca() x = np.linspace(0, 255, 256) y = np.linspace(10, 100000, 256) # 折线对象单独命名 self.line_hist, = self.ax.plot(x,y) self.ax.set_ylabel('Nombre pixel', fontsize = 15) self.ax.set_xlabel('Valeur pixel', fontsize = 15) self.ax.set_yscale('log') self.delay = 15 self.update() self.window.mainloop() def update(self): ret, frame = self.vid.get_frame() if ret : self.gris = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) self.smaller_image = cv2.resize(self.gris,(640,480)) self.photo = PIL.ImageTk.PhotoImage(image = PIL.Image.fromarray(self.smaller_image)) self.canvas.create_image(0, 0, image = self.photo, anchor = tkinter.NW) self.calc_hist(self.gris) self.window.after(self.delay, self.update) def calc_hist(self, gris) : self.histogram = cv2.calcHist([gris], [0], None, [256], [0, 256]) self.line_hist.set_ydata(self.histogram) # 触发画布重绘,draw_idle适配Tkinter事件循环,不会出现卡顿 self.hist_canvas.draw_idle()
MyVideoCapture类无需修改,按你原有代码保留即可。修改后直方图会随视频帧同步更新,也不会再出现draw_wrapper参数缺失的报错。
内容的提问来源于stack exchange,提问作者lapasq
相关产品推荐
相关产品推荐

