Adding a User-Controlled Camera Feature To Our Python GUI Clock
Tags: python, programming, beginners, tutorial
Published: 2024-06-30 10:12:03

In our previous [tutorial](https://blog.learnhub.africa/2024/06/21/how-to-build-a-gui-clock-with-python-a-comprehensive-step-by-step-guide/), 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
![](https://paper-attachments.dropboxusercontent.com/s_8E5720D65FB153C6EEF0C5707C535BEDF7504A1EC617B22E29977E06F123F4F8_1719307290734_Screenshot+2024-06-25+at+10.21.24.png)


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. 

```python
    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:

```python
    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.
 ```python
    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.

```python
    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.

```python

    if not os.path.exists("captured_images"):
        os.makedirs("captured_images")
```
This part creates a special folder to store our pictures:
```python
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.

```python
    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.
```python
    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:

```python
    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:

1. 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.
        
2. 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.
        
3. 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.
 ```python
    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.


    
![](https://paper-attachments.dropboxusercontent.com/s_8E5720D65FB153C6EEF0C5707C535BEDF7504A1EC617B22E29977E06F123F4F8_1719595618306_Screenshot+2024-06-28+at+18.26.50.png)

    

In summary, this function does the following:

1. Opens an image file (read operation).
2. Resize the image to fit nicely in our GUI window.
3. Converts the image to a format our GUI system (Tkinter) can understand.
4. 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:

```python
    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**
- [How to Identify a Phishing Email in 2024](https://blog.learnhub.africa/2024/06/10/how-to-identify-a-phishing-email-in-2024/)
- [Build Your First Password Cracker](https://blog.learnhub.africa/2024/02/29/build-your-first-password-cracker/)
- [Python for Beginners](https://www.python.org/about/gettingstarted/)