praxmon
praxmon

Reputation: 5121

Tkinter display other windows

Is it possible to display a window which has been made by OpenCV using Tkinter? I want to open it using Tkinter so that I can provide more GUI functions. Has this been done before? I checked google and SO itself but did not find anything.

So as kobejohn suggested, I am attaching the code for the camera capture and display.

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)

Upvotes: 0

Views: 2584

Answers (1)

KobeJohn
KobeJohn

Reputation: 7545

This code is based on the discussion in comments. It doesn't put the opencv window into tkinter. It just takes opencv images and puts them into tkinter.

Prakhar, I don't have an available IP camera so can you try this? I have confirmed that it works with the USB code at the bottom of this answer.

Basically, I just inserted your jpg reading code into a simplified version of this SO question to get the code below. It uses a 2-step conversion: bytes --> opencv image --> tkinter image. There may be a more efficient way to convert directly from the bytes to a tkinter image but you can fix that if performance becomes a problem.


IP Camera

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 Camera

*edit - I have confirmed that the code below works to take video from a USB camera using opencv and send it to a tkinter window. So hopefully the above code will work for your ip camera.

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()

Upvotes: 3

Related Questions