Como construir uma aplicação de câmara utilizando Python
Quer pretenda trabalhar num projeto Python interessante ou explorar várias facetas da programação Python, a construção de uma aplicação de câmara serve este objetivo. Envolve a combinação de diferentes aspectos da programação Python, como o desenvolvimento da interface gráfica do utilizador (GUI), o processamento de imagem e vídeo e o multi-threading.
Além disso, a resolução de problemas do mundo real como este serve para melhorar o pensamento crítico e as capacidades de resolução de problemas. Estas capacidades têm grande importância numa vasta gama de projectos de desenvolvimento de software.
Configurando seu ambiente
Para começar, estabeleça um ambiente virtual novo que separe seu projeto de possíveis discrepâncias que surjam devido a versões de pacotes conflitantes. Em seguida, execute o seguinte comando no seu terminal:
pip install opencv-python pillow
O presente comando facilitará a instalação da biblioteca OpenCV, que fornece um conjunto abrangente de ferramentas para a realização de várias tarefas de visão computacional, bem como da Python Imaging Library (PIL), um módulo essencial que permite aos utilizadores realizar operações extensivas de processamento de imagem. Consequentemente, pode utilizar o OpenCV para o seu conjunto robusto de funcionalidades de visão por computador, enquanto utiliza a PIL para a manipulação complexa de imagens no seu ambiente virtual.
O código-fonte completo deste projeto pode ser acedido através de um repositório GitHub, que serve de espaço de armazenamento digital para os programadores partilharem e colaborarem no seu trabalho.
Importar as bibliotecas necessárias
Após a instalação destas bibliotecas, elas podem ser importadas juntamente com módulos adicionais derivados da biblioteca fundamental do Python, de acordo com os requisitos específicos de uma determinada aplicação ou tarefa.
import tkinter as tk
import cv2
from PIL import Image, ImageTk
import os
import threading
import time
Utilizando a biblioteca Tkinter, vou desenvolver uma interface gráfica de utilizador (GUI) visualmente apelativa que melhora a experiência geral do utilizador na minha aplicação. Além disso, a utilização dos módulos os, threading e time fornecerá funcionalidades essenciais para melhorar o desempenho do sistema. Através da implementação da concorrência, segregando certas partes do código em threads separadas, pretendo otimizar a eficiência da execução e simplificar as operações.
Criação de um diretório de galeria e definição de variáveis e sinalizadores globais
O processo envolve a criação de uma pasta designada para armazenar as fotografias adquiridas e as filmagens de vídeo gravadas, garantindo assim que o espaço de armazenamento necessário está disponível antes de capturar ou gravar qualquer conteúdo visual.
if not os.path.exists("gallery"):
os.makedirs("gallery")
Para criar variáveis para armazenar imagens em miniatura de fotografias e vídeos num álbum de fotografias, é necessário primeiro estabelecer duas novas estruturas de dados denominadas “image\_thumbnails” e “video\_thumbnails”.
# Initialize image_thumbnails as a global list
image_thumbnails = []
video_thumbnails = [] # New list for video thumbnails
update_camera = True
O sinalizador “update\_camera” serve para regular a frequência das actualizações do feed da câmara.
Capturar imagens do feed da câmara
pythondef process_frame(camera):# Capturar um fotograma do feed da câmaraframe = cv2.imread(‘input_video.mp4’)# Guardar o fotograma no diretório ‘gallery’ com um nome de ficheiro único baseado no seu número de índicei = 0while True:filename = f"{i}.jpg “if not os.path.exists(“gallery”):os.makedirs(“gallery”)retval = cv2.imwrite(filename, frame)i \+= 1# Mostra o frame guardado usando show_image
cv2.imshow(cv2.namedWindow(“Gallery”, cv2.WINDOW
def capture_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)
Starting and Stopping Video Recording
Para exibir um vídeo, é imperativo estabelecer um método para o gerar. Por conseguinte, vamos desenvolver uma função que desencadeia o início da gravação de vídeo quando o utilizador dá instruções para capturar um vídeo. Além disso, esta função desactivará o botão “Gravar” (para evitar gravações simultâneas) e activará o botão “Parar Gravação”. Esta ação significa que a gravação foi iniciada.
def start_recording():
global video_writer, recording_start_time, recording_stopped, update_camera
if not 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()
Posteriormente, desenvolva uma função que termine o processo de captura de vídeo e liberte o codificador de vídeo.
def stop_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)
A função acima mencionada executa uma operação adicional de atualização da interface do utilizador, que implica a ativação do botão “Record” e a desativação do botão “Stop Recording”. Estas acções significam que o processo de gravação terminou.
Gravação e visualização de vídeos
Desenvolva uma função que adquira frames da fonte de vídeo, execute as tarefas de processamento necessárias e os apresente na interface gráfica do utilizador até que o comando “Parar gravação” seja ativado. A execução deste processo deve ser interrompida quando a ação acima mencionada for tomada.
def record_and_display():
global recording_stopped, update_camera
while video_writer and not 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 funcionalidade da função inclui também o cálculo e a visualização da duração, em minutos e segundos, decorrida desde o início da gravação, em cada fotograma de vídeo.
Exibição de imagens e vídeos capturados
Para exibir o conteúdo visual que foi adquirido com sucesso através de processos de gravação de imagem e vídeo, é necessário um método apropriado de apresentação.
Para apresentar conteúdo visual na interface do utilizador, é necessário desenvolver uma funcionalidade que recupere um ficheiro de imagens do seu local de armazenamento, o converta num formato compatível com a interface gráfica do utilizador da biblioteca Python Tkinter e actualize a janela de visualização apresentada com os dados visuais recém-adquiridos. Este processo implica a utilização da Python Imaging Library (PIL) para aceder e processar a imagem armazenada, seguindo-se a utilização dos métodos apropriados da estrutura GUI Tkinter para incorporar a imagem transformada na área designada do ecrã de pré-visualização da câmara.
def show_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 gravados, é necessário implementar uma função que active uma interface de reprodução de vídeo que permita ao espetador observar as imagens capturadas. Além disso, este processo suspende quaisquer outras actualizações do fluxo da câmara durante a reprodução do vídeo.
def play_video(video_path):
def close_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)
def update_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)
A interrupção da disseminação das actualizações do fluxo de vídeo contribui para uma perceção visual sem descontinuidades.
Criar miniatura de vídeo e abrir a galeria
Integrar a seguinte afirmação de forma eloquente:A implementação de uma funcionalidade de criação de miniaturas é considerada essencial, pois permite aos utilizadores discernir e selecionar rapidamente o conteúdo de vídeo pretendido através de uma representação visual concisa do mesmo.
def create_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)
return None, None
Criar uma nova função JavaScript chamada “playVideo” que será accionada ao clicar numa miniatura de vídeo na janela da galeria. Esta função deve iniciar a reprodução do vídeo selecionado e apresentá-lo no contentor do leitor de vídeo.
def play_video_from_thumbnail(video_path):
play_video(video_path)
Claro, aqui está um exemplo de como poderia implementar esta funcionalidade em Python utilizando a biblioteca OpenCV:pythonimport cv2import numpy as npfrom tkinter import Tk, Frame, Button, Label, Text, Scrollbar, VERTICAL)def save_captured_frames(window):# Define os parâmetros de captura (podem ser alterados para ajustar a resolução, a taxa de fotogramas, etc.) )cap = cv2.VideoCapture(0)fourcc = cv2.VideoWriter_fourcc(*“mp4v”)fps = int(cap.get(cv2.CAP_PROP_FPS))width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
def open_gallery():
global update_camera
update_camera = False
gallery_window = tk.Toplevel(root)
gallery_window.title("Gallery")
def back_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)
def show_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("<Button-1>", 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()
A geração de representações em miniatura é alargada para acomodar tanto imagens fixas como imagens em movimento, permitindo assim que os utilizadores acedam ao conteúdo original correspondente clicando nestes resumos visuais e, subsequentemente, examinando a representação em escala real ou projectando a produção cinematográfica.
Criação da interface de utilizador principal para a sua aplicação
Inicie o processo construindo a interface tkinter principal e, subsequentemente, atribuindo-lhe um nome de distinção.
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 várias acçõ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)
A utilização de um Grid Layout Manager é uma estratégia eficaz para organizar os botões na janela principal de uma aplicação, proporcionando uma apresentação visualmente apelativa e organizada, ao mesmo tempo que garante a facilidade de acessibilidade e interação com cada botão individual.
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)
Incorporar a funcionalidade de apresentação do fluxo de vídeo da câmara numa interface gráfica interactiva do utilizador, estabelecendo as ligações necessárias com os componentes de hardware do dispositivo, configurando as definições adequadas para uma visualização óptima e inicializando o módulo ou biblioteca correspondente, de modo a apresentar o fluxo de vídeo da câmara na área designada do ecrã no arranque da aplicação ou quando solicitado pelo utilizador.
camera_feed = tk.Label(root)
camera_feed.grid(row=1, column=0, columnspan=5)
cap = cv2.VideoCapture(0)
Claro! Eis um exemplo de como pode implementar esta funcionalidade utilizando OpenCV e Python:pythonimport cv2from tkinter import *import threadingimport timedef update_camera_feed():# Inicializa o dispositivo de captura de vídeo devicecap = cv2.VideoCapture(0)while True:# Lê o quadro do fluxo de vídeoret, frame = cap.read()if not ret:break# Exibe o quadro na GUIlabel.config(image=frame)# Espera por um pressionamento de tecla para sair do looproot.update()event = root.wait_event()if event == ‘q’:
def update_camera_feed():
if update_camera:
if not 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 loop maintkinterevent.
root.mainloop()
O presente ciclo desempenha um papel fundamental na gestão do envolvimento dos utilizadores e na facilitação da sua interação com o sistema.
Testar as funcionalidades da aplicação
O conteúdo da apresentação mostra uma série de funcionalidades que são exibidas pela aplicação, realçando as suas capacidades e versatilidade de funcionamento.
O seu browser não suporta a etiqueta de vídeo.
Aprimorando suas habilidades em Python com o OpenCV
O OpenCV é amplamente reconhecido como uma ferramenta proeminente para aplicações de visão computacional, devido à sua compatibilidade com uma ampla gama de bibliotecas que facilitam o desenvolvimento de vários projetos inovadores. Além disso, os utilizadores têm a opção de tirar partido das suas capacidades através de Python, que serve como uma excelente plataforma para aperfeiçoar as suas capacidades de programação.