Siga este projeto abrangente para aprender mais sobre Python e processamento de imagens.

Se você deseja trabalhar em um projeto Python envolvente ou explorar várias facetas da programação Python, construir um aplicativo de câmera atende a esse propósito. Envolve a combinação de diferentes aspectos da programação Python, como desenvolvimento de interface gráfica do usuário (GUI), processamento de imagem e vídeo e multithreading.

Além disso, resolver desafios práticos como este ajuda a aprimorar suas habilidades de resolução de problemas. Essas habilidades são valiosas em qualquer empreendimento de programação.

Configurando seu ambiente

Começar por criando um novo ambiente virtual. Isso isolará seu projeto e garantirá que não haja conflito entre as diferentes versões dos pacotes que você instalar. Em seguida, execute este comando de terminal:

pip install opencv-python pillow

Este comando irá instalar o OpenCV biblioteca e PIL (Python Imaging Library) em seu ambiente virtual. Você usará OpenCV para funcionalidade de visão computacional e PIL para manipulação de imagens.

instagram viewer

O código fonte completo deste projeto está disponível em um Repositório GitHub.

Importando as bibliotecas necessárias

Depois de instalar essas bibliotecas, você pode importá-las junto com outros módulos necessários da biblioteca padrão do Python:

import tkinter as tk
import cv2
from PIL import Image, ImageTk
import os
import threading
import time

Você vai usar tkinter para criar uma interface gráfica de usuário para seu aplicativo e os módulos os, threading e time para suas funcionalidades associadas. Ao separar parte do seu código em threads, você permitir que ele seja executado simultaneamente.

Criando um diretório de galeria e definindo variáveis ​​e sinalizadores globais

Crie um diretório para armazenar imagens capturadas e vídeos gravados. Esta etapa garantirá que o diretório exista antes de prosseguir com a captura ou gravação de vídeos.

ifnot os.path.exists("gallery"):
os.makedirs("gallery")

Então defina imagem_thumbnails e Miniaturas de vídeo variáveis. Eles armazenarão miniaturas de imagens e vídeos na galeria.

# Initialize image_thumbnails as a global list
image_thumbnails = []
video_thumbnails = [] # New list for video thumbnails
update_camera = True

O câmera_atualização flag controlará as atualizações de feed da câmera.

Capturando imagens do feed da câmera

Defina uma função que usará OpenCV para capturar uma imagem do feed da câmera. Ele deverá então recuperar um quadro da câmera, salvá-lo no galeria diretório e exibi-lo usando mostrar_imagem.

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)

Iniciando e Parando a Gravação de Vídeo

Antes de exibir um vídeo, você precisa encontrar uma maneira de criá-lo. Para isso, crie uma função que inicie o processo de gravação de vídeo quando o usuário deseja capturar um vídeo. A função também deve desativar o Registro botão (para evitar múltiplas gravações simultaneamente) e ativar o Pare de gravar botão. Isso indica que a gravação está em andamento.

defstart_recording():
global video_writer, recording_start_time, recording_stopped, update_camera

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

Em seguida, crie uma função que interrompa a gravação do vídeo e libere o gravador do vídeo.

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 função também atualiza a UI permitindo o Registro botão e desabilitando o Pare de gravar botão. Isso indica que a gravação foi interrompida.

Gravação e exibição de vídeos

Crie uma função que irá capturar continuamente quadros da câmera, processá-los e exibi-los na GUI como imagem da câmera. Deveria fazê-lo, a menos que o Pare de gravar botão é pressionado.

defrecord_and_display():
global recording_stopped, update_camera

while 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 = photo

video_writer.write(frame)
time.sleep(0.05)

camera_feed.after(10, update_camera_feed)

A função também calcula o tempo decorrido desde o início da gravação e o exibe no quadro do vídeo.

Exibindo imagens e vídeos capturados

Agora que você capturou as imagens e gravou os vídeos, você precisa encontrar uma forma de exibi-los.

Para exibir as imagens, crie uma função que abra uma imagem e a exiba no feed da câmera. Isto é conseguido abrindo a imagem usando o PILe, em seguida, convertê-lo para um formato que tkinter pode exibir e, finalmente, atualizar o widget de feed da câmera com a nova imagem.

defshow_image(image_path):
image = Image.open(image_path)
photo = ImageTk.PhotoImage(image=image)
camera_feed.config(image=photo)
camera_feed.image = photo

Para exibir os vídeos capturados, crie uma função que abre uma janela do player de vídeo onde o usuário pode visualizar os vídeos gravados. Ele também pausa as atualizações do feed da câmera enquanto o vídeo está sendo reproduzido.

defplay_video(video_path):
defclose_video_player():
video_player.destroy()
global update_camera
update_camera = True

global update_camera
update_camera = False

video_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 as atualizações do feed da câmera garante uma experiência de visualização tranquila.

Criando miniatura de vídeo e abrindo a galeria

Crie uma função que irá gerar uma imagem em miniatura para um determinado vídeo. Isso tornará mais fácil para os usuários identificarem o vídeo de interesse.

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 seguir, crie uma função que reproduza um vídeo quando um usuário clicar na miniatura do vídeo na janela da galeria:

defplay_video_from_thumbnail(video_path):
play_video(video_path)

Em seguida, crie uma função que crie uma nova janela onde o usuário poderá visualizar as imagens e vídeos capturados.

defopen_gallery():
global update_camera
update_camera = False

gallery_window = tk.Toplevel(root)
gallery_window.title("Gallery")

defback_to_camera():
gallery_window.destroy()
global update_camera

# Resume updating the camera feed
update_camera = True

back_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_photo

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

Miniaturas são criadas para imagens e vídeos. Isso significa que você pode clicar neles para ver a imagem em tamanho real ou reproduzir o vídeo.

Criando a interface de usuário principal para seu aplicativo

Comece criando o principal tkinter janela do aplicativo e, em seguida, dê um título a ela.

root = tk.Tk()
root.title("Camera Application")

Em seguida, inicialize as variáveis ​​necessárias.

video_writer = None
recording_start_time = 0# Initialize recording start time
recording_stopped = False# Initialize recording_stopped flag

Em seguida, crie botões para diversas ações.

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)

Use o gerenciador de layout de grade para organizar os botões na janela 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)

Crie um widget para exibir o feed da câmera e inicializá-lo.

camera_feed = tk.Label(root)
camera_feed.grid(row=1, column=0, columnspan=5)
cap = cv2.VideoCapture(0)

Em seguida, crie uma função que atualize continuamente o feed da câmera exibido no tkinter janela.

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 = photo

root.after(10, update_camera_feed)

update_camera_feed()

Finalmente, inicie o principal tkinter ciclo de eventos.

root.mainloop()

Este loop é responsável por lidar com as interações do usuário.

Testando os recursos do aplicativo

Este vídeo demonstra vários recursos do aplicativo:

Aprimorando suas habilidades em Python com OpenCV

OpenCV domina quando se trata de visão computacional. Ele funciona com várias bibliotecas diferentes, permitindo criar muitos projetos interessantes. Você pode usá-lo com Python para praticar e aprimorar suas habilidades de programação.