Följ det här omfattande projektet för att lära dig mer om Python och bildbehandling.

Oavsett om du vill arbeta med ett engagerande Python-projekt eller utforska olika aspekter av Python-programmering, tjänar detta syfte att bygga en kameraapplikation. Det handlar om att kombinera olika aspekter av Python-programmering, såsom utveckling av grafiskt användargränssnitt (GUI), bild- och videobehandling och multi-threading.

Att lösa praktiska utmaningar som den här hjälper också till att vässa dina problemlösningsförmåga. Dessa färdigheter är värdefulla i alla programmeringssträvanden.

Ställa in din miljö

Börja med skapa en ny virtuell miljö. Detta kommer att isolera ditt projekt och säkerställa att det inte finns någon konflikt mellan olika versioner av paketen du installerar. Kör sedan detta terminalkommando:

pip install opencv-python pillow

Detta kommando kommer att installera OpenCV bibliotek och PIL (Python Imaging Library) i din virtuella miljö. Du kommer att använda OpenCV för datorseende funktionalitet och PIL för bildmanipulation.

instagram viewer

Den fullständiga källkoden för detta projekt är tillgänglig i en GitHub-förråd.

Importera de obligatoriska biblioteken

När du har installerat dessa bibliotek kan du importera dem tillsammans med andra nödvändiga moduler från Pythons standardbibliotek:

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

Du kommer använda sig av tkinter för att skapa ett grafiskt användargränssnitt för din applikation och OS, threading och tidsmoduler för deras tillhörande funktionalitet. Genom att dela upp en del av din kod i trådar kommer du gör att den kan köras samtidigt.

Skapa en gallerikatalog och definiera globala variabler och flaggor

Skapa en katalog för att lagra tagna bilder och inspelade videor. Det här steget säkerställer att katalogen finns innan du fortsätter att spela in eller spela in videor.

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

Definiera sedan image_thumbnails och video_thumbnails variabler. Dessa kommer att lagra miniatyrer av bilder och videor i galleriet.

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

De update_camera flaggan styr kameraflödesuppdateringar.

Ta bilder från kameraflödet

Definiera en funktion som använder OpenCV för att ta en bild från kameraflödet. Den ska sedan hämta en ram från kameran, spara den i Galleri katalog och visa den med hjälp av visa_bild.

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)

Starta och stoppa videoinspelning

Innan du visar en video behöver du ett sätt att skapa den. För att uppnå detta, skapa en funktion som initierar videoinspelningsprocessen när användaren vill spela in en video. Funktionen bör också inaktivera Spela in (för att förhindra flera inspelningar samtidigt) och aktivera Stoppa inspelning knapp. Detta indikerar att inspelning pågår.

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

Skapa sedan en funktion som stoppar videoinspelningen och släpper videoskrivaren.

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)

Den här funktionen uppdaterar också användargränssnittet och aktiverar Spela in knappen och inaktivera Stoppa inspelning knapp. Detta indikerar att inspelningen har stoppats.

Spela in och visa videor

Skapa en funktion som kontinuerligt fångar bildrutor från kameran, bearbetar dem och visar dem på GUI som kameraflöde. Det bör göra det om inte Stoppa inspelning knappen är nedtryckt.

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)

Funktionen beräknar också den tid som förflutit sedan inspelningen startade och visar den på videoramen.

Visa tagna bilder och videor

Nu när du har tagit bilderna och spelat in videorna behöver du ett sätt att visa dem.

För att visa bilderna skapar du en funktion som öppnar en bild och visar den i kameraflödet. Detta uppnås genom att öppna bilden med hjälp av PIL, sedan konvertera den till ett format som tkinter kan visa, och slutligen uppdatera kameraflödeswidgeten med den nya bilden.

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

För att visa de inspelade videorna, skapa en funktion som öppnar ett videospelarfönster där användaren kan se inspelade videor. Det pausar också kameraflödesuppdateringar medan videon spelas upp.

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)

Att pausa kameraflödesuppdateringar säkerställer en smidig tittarupplevelse.

Skapa videominiatyr och öppna galleriet

Skapa en funktion som genererar en miniatyrbild för en given video. Detta kommer att göra det lättare för användare att identifiera videon av intresse.

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

Skapa sedan en funktion som spelar upp en video när en användare klickar på miniatyren av videon i gallerifönstret:

defplay_video_from_thumbnail(video_path):
play_video(video_path)

Skapa sedan en funktion som skapar ett nytt fönster där användaren kan se de tagna bilderna och videorna.

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

Miniatyrer skapas för både bilder och videor. Det betyder att du kan klicka på dem för att se bilden i full storlek eller spela upp videon.

Skapa huvudanvändargränssnittet för din applikation

Börja med att skapa huvudet tkinter programfönstret och ge det sedan en titel.

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

Initiera sedan de nödvändiga variablerna.

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

Skapa sedan knappar för olika åtgärder.

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)

Använd rutnätslayouthanteraren för att organisera knapparna i huvudfönstret.

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)

Skapa en widget för att visa kameraflödet och initiera det.

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

Skapa sedan en funktion som kontinuerligt uppdaterar kameraflödet som visas i tkinter fönster.

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

Slutligen, börja huvudet tkinter händelseslinga.

root.mainloop()

Denna loop är ansvarig för att hantera användarinteraktioner.

Testa appens funktioner

Den här videon visar olika funktioner i appen:

Skärpa dina Python-färdigheter med OpenCV

OpenCV dominerar när det kommer till datorseende. Det fungerar med många olika bibliotek som gör att du kan skapa många coola projekt. Du kan använda den med Python för att öva och vässa dina programmeringsfärdigheter.