Een cameratoepassing maken met Python
Of je nu wilt werken aan een boeiend Python-project of verschillende facetten van Python-programmeren wilt verkennen, het bouwen van een cameratoepassing dient dit doel. Het gaat om het combineren van verschillende aspecten van Python programmeren, zoals grafische gebruikersinterface (GUI) ontwikkeling, beeld- en videoverwerking en multi-threading.
Daarnaast is het aanpakken van echte problemen zoals deze nuttig om iemands kritisch denken en probleemoplossend vermogen te vergroten. Zulke vaardigheden zijn van groot belang in een groot aantal softwareontwikkelingsprojecten.
Uw omgeving instellen
Om te beginnen maakt u een nieuwe virtuele omgeving aan die uw project vrijwaart van mogelijke afwijkingen als gevolg van conflicterende pakketversies. Voer vervolgens het volgende commando uit in je terminal:
pip install opencv-python pillow
Dit commando vergemakkelijkt de installatie van zowel de OpenCV bibliotheek, die een uitgebreide set tools biedt voor het uitvoeren van verschillende computer vision taken, als de Python Imaging Library (PIL), een essentiële module waarmee gebruikers uitgebreide beeldbewerkingsoperaties kunnen uitvoeren. Bijgevolg kun je OpenCV gebruiken voor zijn robuuste reeks computervisiefuncties, terwijl je PIL gebruikt voor de ingewikkelde manipulatie van afbeeldingen binnen je virtuele omgeving.
De volledige broncode voor dit project is toegankelijk via een GitHub repository, die dient als digitale opslagruimte voor ontwikkelaars om hun werk te delen en samen te werken.
De benodigde bibliotheken importeren
Na installatie van deze bibliotheken kunnen ze worden geïmporteerd naast aanvullende modules die zijn afgeleid van de basisbibliotheek van Python, in overeenstemming met de specifieke eisen van een bepaalde toepassing of taak.
import tkinter as tk
import cv2
from PIL import Image, ImageTk
import os
import threading
import time
Met behulp van de Tkinter-bibliotheek zal ik een visueel aantrekkelijke grafische gebruikersinterface (GUI) ontwikkelen die de algehele gebruikerservaring van mijn applicatie verbetert. Daarnaast zal het gebruik van de os, threading en time modules zorgen voor essentiële functionaliteiten om de systeemprestaties te verbeteren. Door concurrency te implementeren door bepaalde delen van de code te scheiden in aparte threads, wil ik de uitvoeringsefficiëntie optimaliseren en bewerkingen stroomlijnen.
Een galeriemap maken en globale variabelen en vlaggen definiëren
Het proces omvat het maken van een aangewezen map voor het opslaan van zowel verworven foto’s als opgenomen videobeelden, waarbij ervoor wordt gezorgd dat de vereiste opslagruimte beschikbaar is voordat visuele inhoud wordt vastgelegd of opgenomen.
if not os.path.exists("gallery"):
os.makedirs("gallery")
Om variabelen te maken voor het opslaan van miniatuurafbeeldingen van foto’s en video’s in een fotoalbum, moeten we eerst twee nieuwe gegevensstructuren maken genaamd “image_thumbnails” en “video_thumbnails”.
# Initialize image_thumbnails as a global list
image_thumbnails = []
video_thumbnails = [] # New list for video thumbnails
update_camera = True
De “update_camera” vlag dient om de frequentie van updates voor de camera feed te regelen.
Beelden vastleggen van de camera feed
pythondef process_frame(camera):# Leg een frame vast van de camera feedframe = cv2.imread(‘input_video.mp4’)# Sla het frame op in de ‘gallery’ directory met een unieke bestandsnaam gebaseerd op het indexnummeri = 0while True:bestandsnaam = f"{i}.jpg"if not os.path.exists(“gallery”):os.makedirs(“galerie”)retval = cv2.imwrite(bestandsnaam, frame)i \+= 1# Geef het opgeslagen frame weer met show_image
cv2.imshow(cv2.namedWindow(“galerie”, 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)
Video-opname starten en stoppen
Om een video te kunnen vertonen is het noodzakelijk een methode te hebben om deze te genereren. Daarom zullen we een functie ontwikkelen die de video-opname start na een instructie van de gebruiker om een video op te nemen. Bovendien deactiveert deze functie de knop “Opnemen” (om gelijktijdige opnamen te voorkomen), terwijl de knop “Opname stoppen” wordt geactiveerd. Deze actie geeft aan dat de opname is gestart.
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()
Ontwikkel vervolgens een functie die het video-opnameproces beëindigt en de video-encoder vrijgeeft.
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)
De bovengenoemde functie voert een extra handeling uit om de gebruikersinterface bij te werken, wat inhoudt dat de knop “Opnemen” wordt geactiveerd terwijl de knop “Opname stoppen” wordt gedeactiveerd. Dit betekent dat het opnameproces is gestopt.
Video’s opnemen en weergeven
Ontwikkel een functie die naadloos frames van de videobron opneemt, de noodzakelijke verwerkingstaken uitvoert en deze in de grafische gebruikersinterface weergeeft totdat het commando “Stop opname” wordt geactiveerd. De uitvoering van dit proces moet worden stopgezet wanneer de bovengenoemde actie wordt ondernomen.
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)
De functionaliteit van de functie omvat ook de berekening en weergave van de duur, in minuten en seconden, die sinds het begin van de opname in elk afzonderlijk videoframe is verstreken.
Vastgelegde beelden en video’s weergeven
Om de visuele inhoud die met succes is verkregen door middel van beeld- en video-opnameprocessen weer te geven, is een geschikte presentatiemethode nodig.
Om visuele inhoud op de gebruikersinterface weer te geven, is het nodig om een functionaliteit te ontwikkelen die een beeldbestand ophaalt van de opslaglocatie, het converteert naar een formaat dat compatibel is met de grafische gebruikersinterface van de Python Tkinter-bibliotheek en de weergegeven viewport bijwerkt met de nieuw verkregen visuele gegevens. Dit proces omvat het gebruik van de Python Imaging Library (PIL) voor toegang tot en verwerking van het opgeslagen beeld, gevolgd door het gebruik van de juiste methoden van het Tkinter GUI-framework om het getransformeerde beeld op te nemen in het aangewezen gebied van het voorbeeldscherm van de camera.
def show_image(image_path):
image = Image.open(image_path)
photo = ImageTk.PhotoImage(image=image)
camera_feed.config(image=photo)
camera_feed.image = photo
Om de opgenomen video’s te vertonen, moet een functie worden geïmplementeerd die een video-afspeelinterface activeert, zodat de kijker de opgenomen beelden kan bekijken. Bovendien onderbreekt dit proces alle verdere updates van de camerastream tijdens het afspelen van de video.
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)
Het stopzetten van de verspreiding van videostream updates draagt bij aan een naadloze visuele perceptie.
Een miniatuurafbeelding van een video maken en de galerij openen
De volgende verklaring op een welsprekende manier opnemen: De implementatie van een functie voor het maken van miniatuurafbeeldingen wordt essentieel geacht, omdat gebruikers hiermee snel de gewenste video-inhoud kunnen onderscheiden en selecteren door middel van een visueel beknopte weergave van dezelfde inhoud.
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
Maak een nieuwe JavaScript-functie genaamd “playVideo” die wordt geactiveerd wanneer er op een videominiatuur in het galerijvenster wordt geklikt. Deze functie moet het afspelen van de geselecteerde video starten en deze weergeven in de container van de videospeler.
def play_video_from_thumbnail(video_path):
play_video(video_path)
Zeker, hier is een voorbeeld van hoe je deze functionaliteit zou kunnen implementeren in Python met behulp van de OpenCV-bibliotheek:pythonimport cv2import numpy as npfrom tkinter import Tk, Frame, Button, Label, Text, Scrollbar, VERTICAL)def save_captured_frames(window):# Definieer capture parameters (kan worden gewijzigd om resolutie, framerate, enz. aan te passen. )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()
Het genereren van miniaturen wordt uitgebreid om zowel stilstaande beelden als bewegende beelden te kunnen gebruiken, zodat gebruikers toegang krijgen tot de overeenkomstige originele inhoud door op deze visuele samenvattingen te klikken en vervolgens de volledige afbeelding te bekijken of de filmproductie te vertonen.
De hoofdgebruikersinterface voor je toepassing maken
Begin het proces met het maken van de primaire tkinterface en geef deze vervolgens een onderscheidende naam.
root = tk.Tk()
root.title("Camera Application")
Initialiseer vervolgens de vereiste variabelen.
video_writer = None
recording_start_time = 0 # Initialize recording start time
recording_stopped = False # Initialize recording_stopped flag
Maak vervolgens knoppen voor verschillende acties.
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)
Het gebruik van een Grid Layout Manager is een effectieve strategie voor het rangschikken van knoppen in het primaire venster van een toepassing, waarbij een visueel aantrekkelijke en georganiseerde presentatie wordt geboden en tegelijkertijd wordt gezorgd voor eenvoudige toegankelijkheid en interactie met elke afzonderlijke knop.
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)
De functionaliteit voor het weergeven van de camerafeed opnemen in een interactieve grafische gebruikersinterface door de nodige verbindingen tot stand te brengen met de hardwarecomponenten van het apparaat, de juiste instellingen te configureren voor een optimale visualisatie en de bijbehorende module of bibliotheek te initialiseren om de videostream van de camera weer te geven op het aangewezen deel van het scherm bij het opstarten van de toepassing of wanneer daarom wordt gevraagd door gebruikersinvoer.
camera_feed = tk.Label(root)
camera_feed.grid(row=1, column=0, columnspan=5)
cap = cv2.VideoCapture(0)
Zeker! Hier is een voorbeeld van hoe je deze functionaliteit kunt implementeren met OpenCV en Python:pythonimport cv2from tkinter import *import threadingimport timedef update_camera_feed():# Initialiseer de video-opname devicecap = cv2.VideoCapture(0)while True:# Lees het frame uit de video streamret, frame = cap.read()if not ret:break# Geef het frame weer op de GUIlabel.config(image=frame)# Wacht op een druk op de knop om de 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()
Start ten slotte de maintkinterevent-lus.
root.mainloop()
De huidige lus speelt een centrale rol in het beheren van gebruikersbetrokkenheden en het faciliteren van hun interactie met het systeem.
Het testen van de appfuncties
De presentatie-inhoud toont een reeks functionaliteiten die door de applicatie worden tentoongesteld en benadrukt de mogelijkheden en veelzijdigheid van de applicatie.
Uw browser ondersteunt de videotag niet.
Je Python-vaardigheden aanscherpen met OpenCV
OpenCV wordt algemeen erkend als een tool bij uitstek voor computervisietoepassingen, dankzij de compatibiliteit met een uitgebreide reeks bibliotheken die de ontwikkeling van verschillende innovatieve projecten vergemakkelijken. Bovendien hebben gebruikers de optie om de mogelijkheden te benutten via Python, dat dient als een uitstekend platform om iemands programmeervaardigheden aan te scherpen.