Adding a User-Controlled Camera Feature To Our Python GUI Clock
Scofield Idehen
Posted on June 30, 2024
In our previous tutorial, we built a customizable GUI clock using Python and Tkinter. Let's take it a step further by adding a camera feature that allows users to capture and save images on demand. This project will introduce you to working with camera input in Python, enhancing your skills in GUI development and file handling.
Setting Up the Environment
Before we begin, ensure you have the necessary libraries installed. We'll be using OpenCV for camera handling. Install it using pip:
pip install opencv-python
Next, we are going to Install Pillow
using pip.
pip install Pillow
Now that we have installed all the dependencies, we can add the camera. We are going to create two kinds of cameras: a regular camera and a camera hidden behind clicks.
Stay with me.
import cv2
from PIL import Image, ImageTk
import os
from datetime import datetime
Creating the Camera Function
Let's add a function to handle camera capture:
def capture_image():
# Initialize the camera
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Error: Could not open camera.")
return
# Capture a frame
ret, frame = cap.read()
if not ret:
print("Error: Could not capture image.")
cap.release()
return
# Create a directory to store images if it doesn't exist
if not os.path.exists("captured_images"):
os.makedirs("captured_images")
# Generate a unique filename using timestamp
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"captured_images/image_{timestamp}.png"
# Save the image
cv2.imwrite(filename, frame)
print(f"Image saved as {filename}")
# Release the camera
cap.release()
# Display the captured image
display_image(filename)
Let's break down the capture_image()
function in a way that's easy for beginners to understand. We'll go through each part step-by-step, explaining what's happening and why.
`def capture_image()`
This line creates a new function called capture_image()
. Think of a function as a set of instructions we can use whenever we want to take a picture.
`cap = cv2.VideoCapture(0)`
Here, we're setting up our camera. Imagine you're turning on a digital camera:
-
cv2
is a tool (library) that helps us work with cameras and images in Python. -
VideoCapture(0)
is like pressing the camera's power button. The 0 means "use the first camera you find" (usually the built-in webcam on a laptop). - We're calling this camera setup
cap
(short for capture), so we can refer to it later.
if not cap.isOpened():
print("Error: Could not open camera.")
return
This part checks if the camera turned on properly:
-
if not cap.isOpened():
asks, "Did the camera fail to turn on?" - If it did fail, we print an error message.
-
return
means "stop here and exit the function" if there's a problem.ret, frame = cap.read()
Now we're taking the actual picture:
cap.read()
is like pressing the shutter button on a camera.
It gives us two things:
-
ret
: A yes/no answer to "Did the picture take successfully?" -
frame
: The actual picture, if it was taken.
if not ret:
print("Error: Could not capture image.")
cap.release()
return
This checks if the picture was taken successfully:
- If
ret
is "no" (which means the picture failed), we: Print an error message.
cap.release()
turns off the camera.return
exits the function.
if not os.path.exists("captured_images"):
os.makedirs("captured_images")
This part creates a special folder to store our pictures:
if not os.path.exists("captured_images"):` checks if a folder named "captured_images" already exists.
- If it doesn't exist,
os.makedirs("captured_images")
creates this folder. - It's like creating a new album to store your photos.
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"captured_images/image_{timestamp}.png"
Here, we're creating a unique name for our picture:
datetime.now()
gets the current date and time.
.strftime("%Y%m%d_%H%M%S")
formats this time into a string like "20240628_152059" (Year-Month-Day_HourMinuteSecond).
- We use this to create a filename like "captured_images/image_20240628_152059.png".
- This ensures each picture has a unique name based on when it was taken.
cv2.imwrite(filename, frame)
print(f"Image saved as {filename}")
Now we're saving the picture.
v2.imwrite(filename, frame)
saves our picture (frame
) with the filename we created.
We then print a message saying where the image was saved.
`cap.release()`
This line turns off the camera, like pressing the power button again when you're done.
`display_image(filename)`
Finally, we call another function to show the picture we just took on the screen.
In summary, this function does the following.
- Turns on the camera
- Check if the camera is working
- Takes a picture
- Makes sure the picture was taken successfully
- Creates a folder to store pictures if it doesn't exist
- Gives the picture a unique name based on the current time
- Saves the picture in the folder
- Turns off the camera
Each step has checks to ensure things are working correctly, and if there's a problem at any point, the function will stop and let us know what went wrong.
Displaying the Captured Image
Add a function to display the captured image:
def display_image(filename):
# Open the image file
img = Image.open(filename)
# Resize the image to fit in the window
img = img.resize((300, 200), Image.LANCZOS)
# Convert the image for Tkinter
photo = ImageTk.PhotoImage(img)
# Update the image label
image_label.config(image=photo)
image_label.image = photo
Let's start with a beginner-friendly explanation of file operations and then dive into the code.
File Operations for Beginners:
-
Read:
- This is like opening a book and looking at its contents.
- In programming, reading a file means accessing its content without changing it.
- Example: Opening an image to view it.
-
Write:
- This is like writing in a notebook.
- In programming, writing means adding new content to a file or changing existing content.
- Example: Saving a new image or modifying an existing one.
-
Execute:
- This is like following a set of instructions.
- In programming, executing usually refers to running a program or script.
- For images, we don't typically "execute" them, but we can process or display them.
Now, let's focus on the display_image(filename)
function:
`def display_image(filename)`
This line defines a function named display_image
that takes a filename
as input. This filename is the path to the image we want to display.
`img = Image.open(filename)`
Here's where we use the "read" operation:
-
Image.open()
is a function from the PIL (Python Imaging Library) that opens an image file. - It's like telling the computer, "Please look at this picture for me."
- The opened image is stored in the variable
img
. -
This operation doesn't change the original file; it allows us to work with its contents.
img = img.resize((300, 200), Image.LANCZOS)
This line resizes the image:
-
img.resize()
changes the size of the image. -
(300, 200)
sets the new width to 300 pixels and height to 200 pixels. -
Image.LANCZOS
is a high-quality resizing method that helps maintain image quality.photo = ImageTk.PhotoImage(img)
This line converts the image for use with Tkinter (the GUI library we're using):
-
ImageTk.PhotoImage()
takes our resized image and converts it into a format that Tkinter can display. - This converted image is stored in the
photo
variable.
image_label.config(image=photo)
image_label.image = photo
These lines update the GUI to show the image:
-
image_label
is a Tkinter widget (like a container) that can display images. -
config(image=photo)
tells this label to display our processed image. -
image_label.image = photo
is a special line that prevents the image from being deleted by Python's garbage collector.
In summary, this function does the following:
- Opens an image file (read operation).
- Resize the image to fit nicely in our GUI window.
- Converts the image to a format our GUI system (Tkinter) can understand.
- Updates a label in our GUI to display this image.
This process doesn't involve writing to the file or executing it. We're simply reading the image, processing it in memory, and displaying it in our application.
Adding GUI Elements
Update your existing GUI to include a button for image capture and a label to display the image:
# Add this after your existing GUI elements
capture_button = tk.Button(window, text="Capture Image", command=capture_image)
capture_button.pack(anchor='center', pady=5)
image_label = tk.Label(window)
image_label.pack(anchor='center', pady=10)
- Adjusting the Window Size:
You may need to adjust the window size to accommodate the new elements:
window.geometry("350x400") # Increase the height
- Complete Code:
Here's the complete code incorporating the new camera feature:
import tkinter as tk
from time import strftime
import cv2
from PIL import Image, ImageTk
import os
from datetime import datetime
window = tk.Tk()
window.title("Python GUI Clock with Camera")
window.geometry("350x400")
is_24_hour = True
def update_time():
global is_24_hour
time_format = '%H:%M:%S' if is_24_hour else '%I:%M:%S %p'
time_string = strftime(time_format)
date_string = strftime('%B %d, %Y')
time_label.config(text=time_string)
date_label.config(text=date_string)
time_label.after(1000, update_time)
def change_color():
colors = ['black', 'red', 'green', 'blue', 'yellow', 'purple', 'orange']
current_bg = time_label.cget("background")
next_color = colors[(colors.index(current_bg) + 1) % len(colors)]
time_label.config(background=next_color)
date_label.config(background=next_color)
def toggle_format():
global is_24_hour
is_24_hour = not is_24_hour
def capture_image():
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Error: Could not open camera.")
return
ret, frame = cap.read()
if not ret:
print("Error: Could not capture image.")
cap.release()
return
if not os.path.exists("captured_images"):
os.makedirs("captured_images")
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"captured_images/image_{timestamp}.png"
cv2.imwrite(filename, frame)
print(f"Image saved as {filename}")
cap.release()
display_image(filename)
def display_image(filename):
img = Image.open(filename)
img = img.resize((300, 200), Image.LANCZOS)
photo = ImageTk.PhotoImage(img)
image_label.config(image=photo)
image_label.image = photo
time_label = tk.Label(window, font=('calibri', 40, 'bold'), background='black', foreground='white')
time_label.pack(anchor='center')
date_label = tk.Label(window, font=('calibri', 24), background='black', foreground='white')
date_label.pack(anchor='center')
color_button = tk.Button(window, text="Change Color", command=change_color)
color_button.pack(anchor='center', pady=5)
format_button = tk.Button(window, text="Toggle 12/24 Hour", command=toggle_format)
format_button.pack(anchor='center', pady=5)
capture_button = tk.Button(window, text="Capture Image", command=capture_image)
capture_button.pack(anchor='center', pady=5)
image_label = tk.Label(window)
image_label.pack(anchor='center', pady=10)
update_time()
window.mainloop()
Conclusion
You've now enhanced your GUI clock with a user-controlled camera feature. This addition demonstrates how to integrate hardware interactions into a Python GUI application, handle file operations, and dynamically update the interface.
Always respect user privacy and obtain the necessary permissions when working with camera features in your applications.
Resource
Posted on June 30, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.