Skip to content

Commit b69f818

Browse files
committed
Displaying a video feed with OpenCV and Tkinter
1 parent a3d761d commit b69f818

File tree

2 files changed

+141
-0
lines changed

2 files changed

+141
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# -*- coding: utf-8 -*-
2+
# @Time : 2018/2/8 16:09
3+
# @Author : play4fun
4+
# @File : Displaying a video feed with OpenCV and Tkinter.py
5+
# @Software: PyCharm
6+
7+
"""
8+
Displaying a video feed with OpenCV and Tkinter.py:
9+
https://www.pyimagesearch.com/2016/05/30/displaying-a-video-feed-with-opencv-and-tkinter/
10+
11+
"""
12+
13+
# import the necessary packages
14+
from __future__ import print_function
15+
from photoboothapp import PhotoBoothApp
16+
from imutils.video import VideoStream
17+
import argparse
18+
import time
19+
20+
# construct the argument parse and parse the arguments
21+
ap = argparse.ArgumentParser()
22+
ap.add_argument("-o", "--output", required=True,
23+
help="path to output directory to store snapshots")
24+
ap.add_argument("-p", "--picamera", type=int, default=-1,
25+
help="whether or not the Raspberry Pi camera should be used")
26+
args = vars(ap.parse_args())
27+
28+
# initialize the video stream and allow the camera sensor to warmup
29+
print("[INFO] warming up camera...")
30+
vs = VideoStream(usePiCamera=args["picamera"] > 0).start()
31+
time.sleep(2.0)
32+
33+
# start the app
34+
pba = PhotoBoothApp(vs, args["output"])
35+
pba.root.mainloop()

cv-Tkinter-GUI/photoboothapp.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# -*- coding: utf-8 -*-
2+
# @Time : 2018/2/8 16:10
3+
# @Author : play4fun
4+
# @File : photoboothapp.py
5+
# @Software: PyCharm
6+
7+
"""
8+
photoboothapp.py:
9+
"""
10+
11+
# import the necessary packages
12+
from __future__ import print_function
13+
from PIL import Image
14+
from PIL import ImageTk
15+
import tkinter as tki
16+
import threading
17+
import datetime
18+
import imutils
19+
import cv2
20+
import os
21+
22+
23+
class PhotoBoothApp:
24+
def __init__(self, vs, outputPath):
25+
# store the video stream object and output path, then initialize
26+
# the most recently read frame, thread for reading frames, and
27+
# the thread stop event
28+
self.vs = vs
29+
self.outputPath = outputPath
30+
self.frame = None
31+
self.thread = None
32+
self.stopEvent = None
33+
34+
# initialize the root window and image panel
35+
self.root = tki.Tk()
36+
self.panel = None
37+
38+
# create a button, that when pressed, will take the current
39+
# frame and save it to file
40+
btn = tki.Button(self.root, text="Snapshot!",
41+
command=self.takeSnapshot)
42+
btn.pack(side="bottom", fill="both", expand="yes", padx=10,
43+
pady=10)
44+
45+
# start a thread that constantly pools the video sensor for
46+
# the most recently read frame
47+
self.stopEvent = threading.Event()
48+
self.thread = threading.Thread(target=self.videoLoop, args=())
49+
self.thread.start()
50+
51+
# set a callback to handle when the window is closed
52+
self.root.wm_title("PyImageSearch PhotoBooth")
53+
self.root.wm_protocol("WM_DELETE_WINDOW", self.onClose)
54+
55+
def videoLoop(self):
56+
# DISCLAIMER:
57+
# I'm not a GUI developer, nor do I even pretend to be. This
58+
# try/except statement is a pretty ugly hack to get around
59+
# a RunTime error that throws due to threading
60+
try:
61+
# keep looping over frames until we are instructed to stop
62+
while not self.stopEvent.is_set():
63+
# grab the frame from the video stream and resize it to
64+
# have a maximum width of 300 pixels
65+
self.frame = self.vs.read()
66+
self.frame = imutils.resize(self.frame, width=300)
67+
68+
# represents images in BGR order; however PIL
69+
# represents images in RGB order, so we need to swap
70+
# the channels, then convert to PIL and ImageTk format
71+
image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
72+
image = Image.fromarray(image)
73+
image = ImageTk.PhotoImage(image)
74+
75+
# if the panel is not None, we need to initialize it
76+
if self.panel is None:
77+
self.panel = tki.Label(image=image)
78+
self.panel.image = image
79+
self.panel.pack(side="left", padx=10, pady=10)
80+
81+
# otherwise, simply update the panel
82+
else:
83+
self.panel.configure(image=image)
84+
self.panel.image = image
85+
86+
except RuntimeError as e:
87+
print("[INFO] caught a RuntimeError")
88+
89+
def takeSnapshot(self):
90+
# grab the current timestamp and use it to construct the
91+
# output path
92+
ts = datetime.datetime.now()
93+
filename = "{}.jpg".format(ts.strftime("%Y-%m-%d_%H-%M-%S"))
94+
p = os.path.sep.join((self.outputPath, filename))
95+
96+
# save the file
97+
cv2.imwrite(p, self.frame.copy())
98+
print("[INFO] saved {}".format(filename))
99+
100+
def onClose(self):
101+
# set the stop event, cleanup the camera, and allow the rest of
102+
# the quit process to continue
103+
print("[INFO] closing...")
104+
self.stopEvent.set()
105+
self.vs.stop()
106+
self.root.quit()

0 commit comments

Comments
 (0)