Pratite ovaj sveobuhvatni projekt kako biste saznali više o Pythonu i obradi slika.

Bilo da želite raditi na zanimljivom Python projektu ili istraživati ​​razne aspekte Python programiranja, izrada aplikacije kamere služi ovoj svrsi. Uključuje kombiniranje različitih aspekata programiranja u Pythonu, kao što je razvoj grafičkog korisničkog sučelja (GUI), obrada slika i videa te višenitnost.

Također, rješavanje praktičnih izazova poput ovog pomaže u izoštravanju vaših vještina rješavanja problema. Ove vještine su vrijedne u svakom programerskom pothvatu.

Postavljanje vašeg okruženja

Počni od stvaranje novog virtualnog okruženja. Ovo će izolirati vaš projekt i osigurati da nema sukoba između različitih verzija paketa koje instalirate. Zatim pokrenite ovu terminalsku naredbu:

pip install opencv-python pillow

Ova naredba će instalirati OpenCV knjižnica i PIL (Python Imaging Library) u vašem virtualnom okruženju. Koristit ćete OpenCV za funkcionalnost računalnog vida i PIL za manipulaciju slikama.

instagram viewer

Puni izvorni kod ovog projekta dostupan je u a GitHub spremište.

Uvoz potrebnih biblioteka

Nakon što instalirate te biblioteke, možete ih uvesti zajedno s ostalim potrebnim modulima iz Python standardne biblioteke:

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

Vi ćete koristiti tkinter za izradu grafičkog korisničkog sučelja za vašu aplikaciju i os, threading i vremenske module za njihovu pridruženu funkcionalnost. Odvajanjem dijela vašeg koda u niti, vi ćete omogućiti istovremeno pokretanje.

Stvaranje direktorija galerije i definiranje globalnih varijabli i zastavica

Stvorite direktorij za pohranjivanje snimljenih slika i video zapisa. Ovaj korak će osigurati da direktorij postoji prije nastavka snimanja ili snimanja videozapisa.

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

Zatim definirajte sličice_slike i video_thumbnails varijable. One će pohraniti minijature slika i videozapisa u galeriju.

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

The ažuriraj_kameru zastavica će kontrolirati ažuriranja feedova kamere.

Snimanje slika iz feeda kamere

Definirajte funkciju koja će koristiti OpenCV za snimanje slike iz feeda kamere. Zatim bi trebao dohvatiti okvir s fotoaparata i spremiti ga u galerija imenik i prikažite ga pomoću prikaži_sliku.

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)

Pokretanje i zaustavljanje video snimanja

Prije nego što prikažete video, potreban vam je način na koji ćete ga stvoriti. Da biste to postigli, izradite funkciju koja pokreće proces snimanja videozapisa kada korisnik želi snimiti videozapis. Funkcija bi također trebala onemogućiti Snimiti gumb (kako biste spriječili više snimanja istovremeno) i omogućite Zaustavi snimanje dugme. Ovo označava da je snimanje u tijeku.

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

Zatim stvorite funkciju koja zaustavlja video snimanje i oslobađa video zapisivač.

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)

Ova funkcija također ažurira UI omogućavajući Snimiti gumb i onemogućavanje Zaustavi snimanje dugme. Ovo znači da je snimanje zaustavljeno.

Snimanje i prikazivanje videa

Stvorite funkciju koja će kontinuirano snimati okvire iz kamere, obrađivati ​​ih i prikazivati ​​na GUI-ju kao feed kamere. To bi trebalo učiniti osim ako Zaustavi snimanje tipka je pritisnuta.

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)

Funkcija također izračunava proteklo vrijeme od početka snimanja i prikazuje ga na video okviru.

Prikaz snimljenih slika i videa

Sada kada ste snimili slike i videozapise, potreban vam je način da ih prikažete.

Za prikaz slika stvorite funkciju koja otvara sliku i prikazuje je u feedu kamere. To se postiže otvaranjem slike pomoću PIL, zatim ga pretvara u format koji tkinter može prikazati i konačno ažuriranje widgeta feeda kamere s novom slikom.

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

Za prikaz snimljenih videozapisa stvorite funkciju koja otvara prozor videoplayera u kojem korisnik može pogledati snimljene videozapise. Također pauzira ažuriranja feedova kamere dok se videozapis reproducira.

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)

Pauziranje ažuriranja feedova kamere osigurava glatko iskustvo gledanja.

Stvaranje sličice videozapisa i otvaranje galerije

Napravite funkciju koja će generirati sličicu za određeni videozapis. To će korisnicima olakšati prepoznavanje videozapisa koji ih zanima.

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

Zatim izradite funkciju koja reproducira videozapis kada korisnik klikne minijaturu videozapisa u prozoru galerije:

defplay_video_from_thumbnail(video_path):
play_video(video_path)

Zatim izradite funkciju koja stvara novi prozor u kojem korisnik može vidjeti snimljene slike i videozapise.

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

Sličice se izrađuju i za slike i za videozapise. To znači da možete kliknuti na njih kako biste vidjeli sliku u punoj veličini ili reproducirali video.

Stvaranje glavnog korisničkog sučelja za vašu aplikaciju

Započnite stvaranjem glavnog tkinter prozor aplikacije, a zatim mu dodijelite naslov.

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

Zatim inicijalizirajte potrebne varijable.

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

Zatim izradite gumbe za razne akcije.

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)

Upotrijebite upravitelj rasporeda rešetki za organiziranje gumba u glavnom prozoru.

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)

Izradite widget za prikaz feeda kamere i inicijalizirajte ga.

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

Zatim stvorite funkciju koja kontinuirano ažurira feed kamere prikazan u tkinter prozor.

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

Na kraju počnite s glavnim tkinter petlja događaja.

root.mainloop()

Ova je petlja odgovorna za rukovanje korisničkim interakcijama.

Testiranje značajki aplikacije

Ovaj video prikazuje razne značajke aplikacije:

Izoštravanje vještina Pythona uz OpenCV

OpenCV dominira kada je računalni vid u pitanju. Radi s puno različitih biblioteka što vam omogućuje stvaranje mnogo cool projekata. Možete ga koristiti s Pythonom za vježbanje i izoštravanje svojih programerskih vještina.