首页 文章

opencv-tkinter集成中的闪烁视频

提问于
浏览
1

我试图通过将opencv组件集成到程序中,在Windows 8上使用python 3.6.4 64位中的tkinter构建GUI . 我可以播放视频,但是有明显的闪烁 . 也就是说,与原生tkinter背景颜色相同的屏幕每秒会短暂地显示几次 . 我已经测试了几个具有相似结果的相机,并通过原生视频播放软件仔细检查了相机是否正常工作 . 这是我的代码:

from tkinter import *
from PIL import Image, ImageTk
import cv2
import threading

cap = cv2.VideoCapture(0)

root = Tk()
def videoLoop():
    global root
    global cap
    vidLabel = None
    while True:
        ret, frame = cap.read()
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        frame = Image.fromarray(frame)
        frame = ImageTk.PhotoImage(frame)
        if vidLabel: vidLabel.configure(image=frame)
        else:
            vidLabel = Label(root, image=frame, anchor=NW)
            vidLabel.pack(expand=YES, fill=BOTH)

videoThread = threading.Thread(target=videoLoop, args=())
videoThread.start()
root.mainloop()

任何人都可以建议我可能做错了什么?我确实听说过tkinter并不总能很好地与线程配合,但这就是我能想到的全部内容 . 为了回应建议闪烁是由标签更新引起的评论,我添加了一些仍然从视频中读取并在循环内更新标签的代码,但使用在循环外部加载的图像来更新标签 . 闪烁然后消失,虽然(据我的理解)循环的效率和标签的更新没有改变 . 这是改变的videoLoop函数(闪烁消失):def videoLoop():global root vidLabel = None cap = cv2.VideoCapture(0)

ret, frame = cap.read()
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    frame = Image.fromarray(frame)
    frame = ImageTk.PhotoImage(frame)

    while True:
        ret, lame = cap.read()
        lame = cv2.cvtColor(lame, cv2.COLOR_BGR2RGB)
        lame = Image.fromarray(lame)
        lame = ImageTk.PhotoImage(lame)

        if vidLabel:
            vidLabel.configure(image=None)
            vidLabel.configure(image=frame)
        else:
            vidLabel = Label(root, image=frame, anchor=NW)
            vidLabel.pack(expand=YES, fill=BOTH)

2 回答

  • 1

    解决方案:确保图像配置调用先于将图像存储在标签 image 属性中 . 我完全明白为什么它有效,因为我是一个python / tkinter新手 . 我现在将发布解决方案,并在我找到对此行为的正确解释时更新答案 . 我最好的猜测是,在label属性中存储图像实际上是导致它在屏幕上更新,而configure方法只是声明会附加一个图像,这会导致循环必须经过另一次迭代在获取更新映像更新语句之前 . 以下代码工作正常,没有闪烁:

    from tkinter import *
    from PIL import Image, ImageTk
    import cv2
    import threading
    
    cap = cv2.VideoCapture(0)
    
    root = Tk()
    def videoLoop():
        global root
        global cap
        vidLabel = Label(root, anchor=NW)
        vidLabel.pack(expand=YES, fill=BOTH)
        while True:
            ret, frame = cap.read()
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame = Image.fromarray(frame)
            frame = ImageTk.PhotoImage(frame)
            vidLabel.configure(image=frame)
            vidLabel.image = frame
    
    videoThread = threading.Thread(target=videoLoop, args=())
    videoThread.start()
    root.mainloop()
    
  • 0

    在tkinter中为了显示图像,图像需要具有全局引用reference that doesn't go out of scope and then gets garbage-collected,或许闪烁是由于缺少这样的引用 . 请参阅以下具有此类图像引用的代码,并且还将 if/else 与更好的结构放弃:

    from tkinter import *
    from PIL import Image, ImageTk
    import cv2
    import threading
    
    cap = cv2.VideoCapture(0)
    
    root = Tk()
    def videoLoop():
        global root
        global cap
        vidLabel = Label(root, anchor=NW)
        vidLabel.pack(expand=YES, fill=BOTH)
        while True:
            ret, frame = cap.read()
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame = Image.fromarray(frame)
            vidLabel.image = ImageTk.PhotoImage(frame)
            vidLabel.configure(image=vidLabel.image)
    
    videoThread = threading.Thread(target=videoLoop, args=())
    videoThread.start()
    root.mainloop()
    

相关问题