Volg dit uitgebreide project om meer te leren over Python en beeldverwerking.

Of je nu aan een boeiend Python-project wilt werken of verschillende facetten van Python-programmeren wilt verkennen, het bouwen van een camera-applicatie dient dit doel. Het omvat het combineren van verschillende aspecten van Python-programmering, zoals de ontwikkeling van een grafische gebruikersinterface (GUI), beeld- en videoverwerking en multi-threading.

Bovendien helpt het oplossen van praktische uitdagingen zoals deze uw probleemoplossende vaardigheden aanscherpen. Deze vaardigheden zijn waardevol bij elke programmeerinspanning.

Uw omgeving instellen

Start op het creëren van een nieuwe virtuele omgeving. Dit zal uw project isoleren en ervoor zorgen dat er geen conflict is tussen verschillende versies van de pakketten die u installeert. Voer vervolgens deze terminalopdracht uit:

pip install opencv-python pillow

Met deze opdracht wordt het OpenCV bibliotheek en PIL (Python Imaging Library) in uw virtuele omgeving. Je gebruikt OpenCV voor computervisiefunctionaliteit en PIL voor beeldmanipulatie.

instagram viewer

De volledige broncode van dit project is beschikbaar in een GitHub-opslagplaats.

De vereiste bibliotheken importeren

Zodra je deze bibliotheken hebt geïnstalleerd, kun je ze samen met andere noodzakelijke modules uit de standaardbibliotheek van Python importeren:

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

Je zult gebruik tkinter om een ​​grafische gebruikersinterface te creëren voor uw toepassing en de besturingssysteem-, threading- en tijdmodules voor de bijbehorende functionaliteit. Door een deel van uw code in threads te verdelen, kunt u dat doen zorgen ervoor dat het gelijktijdig kan worden uitgevoerd.

Een galerijmap maken en globale variabelen en vlaggen definiëren

Maak een map om vastgelegde afbeeldingen en opgenomen video's op te slaan. Deze stap zorgt ervoor dat de map bestaat voordat u doorgaat met het vastleggen of opnemen van video's.

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

Definieer vervolgens afbeelding_miniaturen En video_miniaturen variabelen. Hiermee worden miniaturen van afbeeldingen en video's in de galerij opgeslagen.

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

De update_camera vlag regelt updates van de camerafeed.

Beelden vastleggen vanuit de camerafeed

Definieer een functie die OpenCV gebruikt om een ​​afbeelding uit de camerafeed vast te leggen. Het zou dan een frame van de camera moeten ophalen en opslaan in het galerij map en geef deze weer met behulp van toon_afbeelding.

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)

Video-opname starten en stoppen

Voordat je een video kunt weergeven, heb je een manier nodig om deze te maken. Om dit te bereiken, maakt u een functie die het video-opnameproces initieert wanneer de gebruiker een video wil opnemen. De functie moet ook de Dossier knop (om meerdere opnames tegelijk te voorkomen) en schakel de Stop met opnemen knop. Dit geeft aan dat er wordt opgenomen.

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

Maak vervolgens een functie die de video-opname stopt en de videoschrijver vrijgeeft.

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)

Deze functie werkt ook de gebruikersinterface bij, waardoor de Dossier knop en het uitschakelen van de Stop met opnemen knop. Dit geeft aan dat de opname is gestopt.

Video's opnemen en weergeven

Creëer een functie die continu frames van de camera vastlegt, verwerkt en op de GUI weergeeft als camerafeed. Dit zou zij moeten doen, tenzij de Stop met opnemen knop wordt ingedrukt.

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)

De functie berekent ook de verstreken tijd sinds de opname is gestart en geeft deze weer op het videoframe.

Vastgelegde afbeeldingen en video's weergeven

Nu je de afbeeldingen hebt gemaakt en de video's hebt opgenomen, heb je een manier nodig om ze weer te geven.

Om de afbeeldingen weer te geven, maakt u een functie die een afbeelding opent en weergeeft in de camerafeed. Dit wordt bereikt door de afbeelding te openen met behulp van de PIL, en converteer het vervolgens naar een formaat dat tkinter kan weergeven en ten slotte de camerafeedwidget bijwerken met de nieuwe afbeelding.

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

Om de vastgelegde video's weer te geven, maakt u een functie die een videospelervenster opent waarin de gebruiker opgenomen video's kan bekijken. Het pauzeert ook updates van de camerafeed terwijl de video wordt afgespeeld.

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)

Het pauzeren van updates van de camerafeed zorgt voor een soepele kijkervaring.

Videominiatuur maken en de galerij openen

Maak een functie die een miniatuurafbeelding voor een bepaalde video genereert. Dit maakt het voor gebruikers gemakkelijker om de video waarin ze geïnteresseerd zijn te identificeren.

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

Maak vervolgens een functie die een video afspeelt wanneer een gebruiker op de miniatuur van de video in het galerijvenster klikt:

defplay_video_from_thumbnail(video_path):
play_video(video_path)

Maak vervolgens een functie die een nieuw venster creëert waarin de gebruiker de vastgelegde afbeeldingen en video's kan bekijken.

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

Er worden miniaturen gemaakt voor zowel afbeeldingen als video's. Dit betekent dat u erop kunt klikken om de afbeelding op volledige grootte te bekijken of de video af te spelen.

De hoofdgebruikersinterface voor uw toepassing creëren

Begin met het maken van de belangrijkste tkinter toepassingsvenster en geef het een titel.

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)

Gebruik de Grid Layout Manager om de knoppen in het hoofdvenster te ordenen.

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)

Maak een widget om de camerafeed weer te geven en te initialiseren.

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

Maak vervolgens een functie die voortdurend de camerafeed bijwerkt die wordt weergegeven in de tkinter raam.

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

Begin ten slotte met het hoofdgerecht tkinter gebeurtenis lus.

root.mainloop()

Deze lus is verantwoordelijk voor het afhandelen van gebruikersinteracties.

De app-functies testen

Deze video demonstreert verschillende functies van de app:

Verscherp uw Python-vaardigheden met OpenCV

OpenCV domineert als het gaat om computer vision. Het werkt met veel verschillende bibliotheken, waardoor je veel coole projecten kunt maken. Je kunt het met Python gebruiken om je programmeervaardigheden te oefenen en aan te scherpen.