Siga este proyecto integral para aprender más sobre Python y el procesamiento de imágenes.
Ya sea que desee trabajar en un proyecto atractivo de Python o explorar varias facetas de la programación de Python, crear una aplicación de cámara sirve para este propósito. Implica combinar diferentes aspectos de la programación Python, como el desarrollo de una interfaz gráfica de usuario (GUI), el procesamiento de imágenes y videos y el subproceso múltiple.
Además, resolver desafíos prácticos como este ayuda a mejorar sus habilidades para resolver problemas. Estas habilidades son valiosas en cualquier esfuerzo de programación.
Configurando su entorno
Comienza por creando un nuevo entorno virtual. Esto aislará su proyecto y garantizará que no haya conflictos entre las diferentes versiones de los paquetes que instale. Luego, ejecute este comando de terminal:
pip install opencv-python pillow
Este comando instalará el OpenCV biblioteca y PILA (Python Imaging Library) en su entorno virtual. Utilizará OpenCV para la funcionalidad de visión por computadora y PIL para la manipulación de imágenes.
El código fuente completo de este proyecto está disponible en un repositorio de GitHub.
Importar las bibliotecas necesarias
Una vez que haya instalado estas bibliotecas, puede importarlas junto con otros módulos necesarios de la biblioteca estándar de Python:
import tkinter as tk
import cv2
from PIL import Image, ImageTk
import os
import threading
import time
tu lo harás usar tkinter para crear una interfaz gráfica de usuario para su aplicación y los módulos de sistema operativo, subprocesamiento y tiempo para su funcionalidad asociada. Al separar parte de su código en subprocesos, podrá permitir que se ejecute simultáneamente.
Crear un directorio de galería y definir variables y indicadores globales
Cree un directorio para almacenar imágenes capturadas y videos grabados. Este paso garantizará que el directorio exista antes de proceder a capturar o grabar videos.
ifnot os.path.exists("gallery"):
os.makedirs("gallery")
Luego define imagen_miniaturas y Miniaturas de vídeo variables. Estos almacenarán miniaturas de imágenes y videos en la galería.
# Initialize image_thumbnails as a global list
image_thumbnails = []
video_thumbnails = [] # New list for video thumbnails
update_camera = True
El actualizar_camara flag controlará las actualizaciones de la transmisión de la cámara.
Capturar imágenes desde la transmisión de la cámara
Defina una función que utilizará OpenCV para capturar una imagen de la transmisión de la cámara. Luego debería recuperar un fotograma de la cámara, guardarlo en el galería directorio y mostrarlo usando mostrar imagen.
defcapture_image():
ret, frame = cap.read()
if ret:
# Generate a unique filename with a timestamp
timestamp = time.strftime("%Y%m%d%H%M%S")
image_path = os.path.join("gallery", f"captured_image_{timestamp}.jpg")
cv2.imwrite(image_path, frame)
show_image(image_path)
Iniciar y detener la grabación de vídeo
Antes de mostrar un vídeo, necesita una forma de crearlo. Para lograr esto, cree una función que inicie el proceso de grabación de video cuando el usuario quiera capturar un video. La función también debería desactivar el Registro (para evitar grabaciones múltiples simultáneamente) y habilitar la Para de grabar botón. Esto indica que la grabación está en curso.
defstart_recording():
global video_writer, recording_start_time, recording_stopped, update_cameraifnot video_writer:
timestamp = time.strftime("%Y%m%d%H%M%S")
video_path = os.path.join("gallery", f"recorded_video_{timestamp}.mp4")# Use mp4v codec (or try other codecs)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')# Adjust frame rate and resolution if needed
video_writer = cv2.VideoWriter(video_path, fourcc, 20.0,
(640, 480))recording_start_time = time.time()
recording_stopped = False
record_button.config(state=tk.DISABLED)
stop_button.config(state=tk.NORMAL)
# Start a separate thread for recording and time-lapse display
recording_thread = threading.Thread(target=record_and_display)
recording_thread.start()
Luego, cree una función que detenga la grabación del video y libere al escritor del video.
defstop_recording():
global video_writer, recording_stopped
if video_writer:
video_writer.release()
recording_stopped = True
record_button.config(state=tk.NORMAL)
stop_button.config(state=tk.DISABLED)
Esta función también actualiza la interfaz de usuario, lo que permite Registro y desactivando el Para de grabar botón. Esto indica que la grabación se ha detenido.
Grabación y visualización de vídeos
Cree una función que capture continuamente fotogramas de la cámara, los procese y los muestre en la GUI como transmisión de la cámara. Debería hacerlo a menos que el Para de grabar se presiona el botón.
defrecord_and_display():
global recording_stopped, update_camerawhile video_writer andnot recording_stopped:
ret, frame = cap.read()if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# Calculate elapsed time and add it to the frame
elapsed_time = time.time() - recording_start_time
timestamp = f"Time Elapsed: {int(elapsed_time)}s"cv2.putText(frame, timestamp, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
0.5, (255, 255, 255), 2)img = Image.fromarray(frame)
photo = ImageTk.PhotoImage(image=img)
camera_feed.config(image=photo)
camera_feed.image = photovideo_writer.write(frame)
time.sleep(0.05)
camera_feed.after(10, update_camera_feed)
La función también calcula el tiempo transcurrido desde que comenzó la grabación y lo muestra en el fotograma del vídeo.
Visualización de imágenes y vídeos capturados
Ahora que ha capturado las imágenes y grabado los vídeos, necesita una forma de mostrarlos.
Para mostrar las imágenes, cree una función que abra una imagen y la muestre en la transmisión de la cámara. Esto se logra abriendo la imagen usando el PILAy luego convertirlo a un formato que tkinter puede mostrar y, finalmente, actualizar el widget de alimentación de la cámara con la nueva imagen.
defshow_image(image_path):
image = Image.open(image_path)
photo = ImageTk.PhotoImage(image=image)
camera_feed.config(image=photo)
camera_feed.image = photo
Para mostrar los videos capturados, cree una función que abra una ventana del reproductor de video donde el usuario pueda ver los videos grabados. También pausa las actualizaciones de la cámara mientras se reproduce el vídeo.
defplay_video(video_path):
defclose_video_player():
video_player.destroy()
global update_camera
update_camera = Trueglobal update_camera
update_camera = Falsevideo_player = tk.Toplevel(root)
video_player.title("Video Player")video_cap = cv2.VideoCapture(video_path)
defupdate_video_frame():
ret, frame = video_cap.read()if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = Image.fromarray(frame)
photo = ImageTk.PhotoImage(image=img)
video_label.config(image=photo)
video_label.image = photo# Get the actual frame rate of the video
frame_rate = video_cap.get(cv2.CAP_PROP_FPS)
delay = int(1000 / frame_rate)video_player.after(delay, update_video_frame)
else:
video_player.destroy()video_label = tk.Label(video_player)
video_label.pack()update_video_frame()
video_player.protocol("WM_DELETE_WINDOW", close_video_player)
Pausar las actualizaciones de la transmisión de la cámara garantiza una experiencia de visualización fluida.
Crear miniatura de video y abrir la galería
Cree una función que genere una imagen en miniatura para un video determinado. Esto facilitará a los usuarios la identificación del vídeo de interés.
defcreate_video_thumbnail(video_path):
video_cap = cv2.VideoCapture(video_path)
ret, frame = video_cap.read()if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
thumbnail = Image.fromarray(frame).resize((100, 100))
thumbnail_photo = ImageTk.PhotoImage(image=thumbnail)
return thumbnail_photo, os.path.basename(video_path)
returnNone, None
A continuación, cree una función que reproduzca un vídeo cuando un usuario haga clic en la miniatura del vídeo en la ventana de la galería:
defplay_video_from_thumbnail(video_path):
play_video(video_path)
Luego cree una función que cree una nueva ventana donde el usuario pueda ver las imágenes y videos capturados.
defopen_gallery():
global update_camera
update_camera = Falsegallery_window = tk.Toplevel(root)
gallery_window.title("Gallery")defback_to_camera():
gallery_window.destroy()
global update_camera# Resume updating the camera feed
update_camera = Trueback_button = tk.Button(gallery_window, text="Back to Camera",
command=back_to_camera)back_button.pack()
gallery_dir = "gallery"
image_files = [f for f in os.listdir(gallery_dir) if f.endswith(".jpg")]
video_files = [f for f in os.listdir(gallery_dir) if f.endswith(".mp4")]# Clear the existing image_thumbnails and video_thumbnails lists
del image_thumbnails[:]
del video_thumbnails[:]for image_file in image_files:
image_path = os.path.join(gallery_dir, image_file)
thumbnail = Image.open(image_path).resize((100, 100))
thumbnail_photo = ImageTk.PhotoImage(image=thumbnail)
image_name = os.path.basename(image_file)defshow_image_in_gallery(img_path, img_name):
image_window = tk.Toplevel(gallery_window)
image_window.title("Image")
img = Image.open(img_path)
img_photo = ImageTk.PhotoImage(img)
img_label = tk.Label(image_window, image=img_photo)
img_label.image = img_photo
img_label.pack()
img_label_name = tk.Label(image_window, text=img_name)
img_label_name.pack()thumbnail_label = tk.Label(gallery_window, image=thumbnail_photo)
thumbnail_label.image = thumbnail_photothumbnail_label.bind("
" , lambda event,
img_path=image_path,
img_name=image_name:
show_image_in_gallery(img_path, img_name))thumbnail_label.pack()
image_thumbnails.append(thumbnail_photo)# Display the image filename below the thumbnail
image_name_label = tk.Label(gallery_window, text=image_name)
image_name_label.pack()for video_file in video_files:
video_path = os.path.join(gallery_dir, video_file)# Create a video thumbnail and get the filename
thumbnail_photo, video_name = create_video_thumbnail(video_path)if thumbnail_photo:
video_thumbnail_button = tk.Button(
gallery_window,
image=thumbnail_photo,
command=lambda path=video_path: play_video_from_thumbnail(path)
)video_thumbnail_button.pack()
# Store the video thumbnail PhotoImage objects
video_thumbnails.append(thumbnail_photo)
# Display the video filename below the thumbnail
video_name_label = tk.Label(gallery_window, text=video_name)
video_name_label.pack()
Se crean miniaturas tanto para imágenes como para vídeos. Esto significa que puede hacer clic en ellos para ver la imagen en tamaño completo o reproducir el vídeo.
Creación de la interfaz de usuario principal para su aplicación
Comience creando el principal tkinter ventana de la aplicación y luego asígnele un título.
root = tk.Tk()
root.title("Camera Application")
Luego inicialice las variables requeridas.
video_writer = None
recording_start_time = 0# Initialize recording start time
recording_stopped = False# Initialize recording_stopped flag
Luego crea botones para varias acciones.
capture_button = tk.Button(root, text="Capture", command=capture_image)
record_button = tk.Button(root, text="Record", command=start_recording)
stop_button = tk.Button(root, text="Stop Recording", command=stop_recording)
gallery_button = tk.Button(root, text="Gallery", command=open_gallery)
quit_button = tk.Button(root, text="Quit", command=root.quit)
Utilice el administrador de diseño de cuadrícula para organizar los botones en la ventana principal.
capture_button.grid(row=0, column=0, padx=10, pady=10)
record_button.grid(row=0, column=1, padx=10, pady=10)
stop_button.grid(row=0, column=2, padx=10, pady=10)
gallery_button.grid(row=0, column=3, padx=10, pady=10)
quit_button.grid(row=0, column=4, padx=10, pady=10)
Cree un widget para mostrar la transmisión de la cámara e inicialícelo.
camera_feed = tk.Label(root)
camera_feed.grid(row=1, column=0, columnspan=5)
cap = cv2.VideoCapture(0)
Luego, cree una función que actualice continuamente la transmisión de la cámara que se muestra en el tkinter ventana.
defupdate_camera_feed():
if update_camera:
ifnot video_writer:
ret, frame = cap.read()if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = Image.fromarray(frame)
photo = ImageTk.PhotoImage(image=img)
camera_feed.config(image=photo)
camera_feed.image = photoroot.after(10, update_camera_feed)
update_camera_feed()
Finalmente, inicie el principal. tkinter bucle de eventos.
root.mainloop()
Este bucle es responsable de manejar las interacciones del usuario.
Prueba de las funciones de la aplicación
Este vídeo muestra varias características de la aplicación:
Mejora tus habilidades en Python con OpenCV
OpenCV domina cuando se trata de visión por computadora. Funciona con muchas bibliotecas diferentes, lo que le permite crear muchos proyectos interesantes. Puedes usarlo con Python para practicar y perfeccionar tus habilidades de programación.