【问题标题】:Tkinter display other windowsTkinter 显示其他窗口
【发布时间】:2014-03-25 14:36:25
【问题描述】:

是否可以显示 OpenCV 使用 Tkinter 制作的窗口?我想用 Tkinter 打开它,这样我就可以提供更多的 GUI 功能。以前有这样做过吗?我检查了 google 和 SO 本身,但没有找到任何东西。

所以正如 kobejohn 建议的那样,我附上了相机捕捉和显示的代码。

import cv2
import urllib 
import numpy as np
import subprocess

stream=urllib.urlopen('IP Address')
bytes=''
while True:
    bytes+=stream.read(1024)
    a = bytes.find('\xff\xd8')
    b = bytes.find('\xff\xd9')
    if a!=-1 and b!=-1:
        jpg = bytes[a:b+2]
        bytes= bytes[b+2:]
        i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8),cv2.CV_LOAD_IMAGE_COLOR)
        cv2.imshow('i',i)
        if cv2.waitKey(1) ==27:
            exit(0)

【问题讨论】:

  • 直接回答,我不知道怎么做,除非我有充分的理由避免使用其他解决方案,否则我不会尝试。能不能把图片数据直接转换成tkinter?我认为你的开发时间会少很多。
  • @kobejohn 问题是我不是在处理视频,而是在处理 mjpeg 流。我不知道如何使用 tkinter 访问它。如果我考虑我得到的图像并将它们转换然后在 Tkinter 中显示它们,那么我该怎么做呢?如果我不使用 tkinter,我可以使用其他东西来构建一个支持这个的 GUI 吗?像 wxwidgets、pygtk 或 qt 之类的东西?
  • 您可以使用 Qt 作为 GUI 后端构建 OpenCV(当您从源代码编译 opencv 时,有一个 WITH_QT 选项)。然后您将能够使用 Qt 构建更复杂的 GUI
  • @remi 在 Windows 上。你知道如何在 Windows 上做到这一点吗?
  • @PrakharMohanSrivastava 你能发布一段非常简单的代码来在opencv中显示视频吗?然后有人可以向您展示如何将视频/图像转换为 tkinter 格式。

标签: python opencv user-interface tkinter


【解决方案1】:

此代码基于 cmets 中的讨论。它不会将 opencv 窗口放入 tkinter。它只需要 opencv 图像并将它们放入 tkinter。

Prakhar,我没有可用的 IP 摄像头,你可以试试这个吗?我已经确认它可以与此答案底部的 USB 代码一起使用。

基本上,我只是将您的 jpg 阅读代码插入到this SO question 的简化版本中,以获取以下代码。它使用两步转换:字节 --> opencv 图像 --> tkinter 图像。可能有一种更有效的方法可以直接从字节转换为 tkinter 图像,但如果性能成为问题,您可以修复它。


网络摄像机

import cv2
import numpy as np
import PIL.Image
import PIL.ImageTk
import Tkinter as tk
import urllib

stream = urllib.urlopen('IP Address')
bytes_ = ''


def update_image(image_label):
    global bytes_
    bytes_ += stream.read(1024)
    a = bytes_.find('\xff\xd8')
    b = bytes_.find('\xff\xd9')
    if (a != -1) and (b != -1):
        jpg = bytes_[a:b+2]
        bytes_ = bytes_[b+2:]
        cv_image = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8),
                                cv2.CV_LOAD_IMAGE_COLOR)
        cv_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
        pil_image = PIL.Image.fromarray(cv_image)
        tk_image = PIL.ImageTk.PhotoImage(image=pil_image)
        image_label.configure(image=tk_image)
        image_label._image_cache = tk_image  # avoid garbage collection
        root.update()


def update_all(root, image_label):
    if root.quit_flag:
        root.destroy()  # this avoids the update event being in limbo
    else:
        update_image(image_label)
        root.after(1, func=lambda: update_all(root, image_label))


if __name__ == '__main__':
    root = tk.Tk()
    setattr(root, 'quit_flag', False)
    def set_quit_flag():
        root.quit_flag = True
    root.protocol('WM_DELETE_WINDOW', set_quit_flag)
    image_label = tk.Label(master=root)  # label for the video frame
    image_label.pack()
    root.after(0, func=lambda: update_all(root, image_label))
    root.mainloop()

USB 摄像头

*edit - 我已经确认下面的代码可以使用 opencv 从 USB 摄像头获取视频并将其发送到 tkinter 窗口。所以希望上面的代码适用于你的网络摄像机。

import cv2
import PIL.Image
import PIL.ImageTk
import Tkinter as tk


def update_image(image_label, cv_capture):
    cv_image = cv_capture.read()[1]
    cv_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
    pil_image = PIL.Image.fromarray(cv_image)
    tk_image = PIL.ImageTk.PhotoImage(image=pil_image)
    image_label.configure(image=tk_image)
    image_label._image_cache = tk_image  # avoid garbage collection
    root.update()


def update_all(root, image_label, cv_capture):
    if root.quit_flag:
        root.destroy()  # this avoids the update event being in limbo
    else:
        update_image(image_label, cv_capture)
        root.after(10, func=lambda: update_all(root, image_label, cv_capture))


if __name__ == '__main__':
    cv_capture = cv2.VideoCapture()
    cv_capture.open(0)  # have to use whatever your camera id actually is
    root = tk.Tk()
    setattr(root, 'quit_flag', False)
    def set_quit_flag():
        root.quit_flag = True
    root.protocol('WM_DELETE_WINDOW', set_quit_flag)  # avoid errors on exit
    image_label = tk.Label(master=root)  # the video will go here
    image_label.pack()
    root.after(0, func=lambda: update_all(root, image_label, cv_capture))
    root.mainloop()

【讨论】:

  • 谢谢!它有效,但严重滞后。有什么原因吗?
  • 您需要添加一些时间或使用分析来找出需要时间的内容。我的 USB 设置工作正常,帧速率合理(可能是 15~20?)所以我猜字节读取代码很慢或者您使用的是高分辨率图像?与cv2.imshow(...) 一起工作是否很快? PIL(或 PILLOW)是 Python 的标准基本图像库。 PIL.ImageTk.PhotoImage 是一个与 tkinter 一起工作的特殊对象。在 tkinter 中,简单的图像只是粘贴到标签上,所以我们将 PhotoImage 粘贴到 image_label。不幸的是,_image_cache 是避免垃圾收集所必需的。
  • 我想通了。 update_all 函数在 10 秒/毫秒的间隔后调用 update_image 函数。我将时间减少到 0,现在它工作正常。我希望我没有做任何会破坏代码的错误。另外,如果我必须在同一个窗口中显示一个画布,我该怎么办?除了标签之外只是一个基本的画布?
  • @PrakharMohanSrivastava 哦,对了。很抱歉耽误了这么大的时间。我将删除它,以免对其他人造成问题。我很高兴它有效!对于其他 tkinter 工作,您绝对应该尝试 tkinter 教程,看看您能做什么。您可以将其放在同一个窗口中,也可以将其放在不同的窗口中。
猜你喜欢
  • 2013-04-29
  • 1970-01-01
  • 2014-07-07
  • 2018-01-08
  • 1970-01-01
  • 1970-01-01
  • 2015-04-03
  • 2021-07-15
相关资源
最近更新 更多