Contents

如何使用 Python 建立相機應用程式

無論您是想從事引人入勝的 Python 專案還是探索 Python 程式設計的各個方面,建立相機應用程式都可以實現此目的。它涉及結合 Python 程式設計的不同方面,例如圖形使用者介面 (GUI) 開發、圖像和視訊處理以及多線程。

此外,解決諸如此類的現實問題有助於增強一個人的批判性思維和解決問題的能力。這些功能在廣泛的軟體開發專案中具有重要意義。

設定您的環境

首先,建立一個全新的虛擬環境,將您的專案與由於套件版本衝突而產生的潛在差異隔離。隨後,在終端機中執行以下命令:

 pip install opencv-python pillow 

目前命令將有助於安裝 OpenCV 庫(它提供了用於執行各種計算機視覺任務的一整套工具)以及 Python 成像庫(PIL)(一個使用戶能夠執行廣泛的圖像處理操作的基本模組) 。因此,您可以利用 OpenCV 的強大電腦視覺功能,同時利用 PIL 在虛擬環境中對影像進行複雜的操作。

該專案的完整原始程式碼可以透過 GitHub 儲存庫訪問,該儲存庫充當開發人員共享和協作工作的數位儲存空間。

導入所需的庫

安裝這些庫後,可以根據給定應用程式或任務的特定要求,與從 Python 基礎庫派生的其他模組一起匯入它們。

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

利用 Tkinter 庫,我將開發一個具有視覺吸引力的圖形使用者介面 (GUI),以增強應用程式的整體使用者體驗。此外,利用作業系統、執行緒和時間模組將提供提高系統效能的基本功能。透過將程式碼的某些部分分離到單獨的線程中來實現並發,我的目標是優化執行效率並簡化操作。

建立圖庫目錄並定義全域變數和標誌

該過程涉及建立一個指定的資料夾來儲存所獲取的照片和錄製的影片片段,從而確保在捕獲或記錄任何視覺內容之前有必要的儲存空間可用。

 if not os.path.exists("gallery"):
    os.makedirs("gallery") 

為了創建用於儲存相簿中圖片和視訊縮圖的變量,我們首先需要建立兩個新的資料結構:「image\_thumbnails」和「video\_thumbnails」。

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

「update\_camera」標誌用來調整相機來源的更新頻率。

從相機捕捉影像

pythondef process_frame(camera):# 從相機中捕獲幀feedframe=cv2.imread(‘input_video.mp4’)# 將幀保存到“gallery”目錄中,並使用基於其索引號的唯一文件名i=0while True: filename=f"{i}.jpg"if not os.path.exists(“gallery”):os.makedirs(“gallery”)retval=cv2.imwrite(filename,frame)i +=1# 使用顯示儲存的幀show\_image cv2.imshow(cv2.namedWindow(“圖庫”, 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) 

開始和停止視訊錄製

為了展示視頻,必須建立一種生成視頻的方法。因此,我們將開發一種功能,根據用戶的指令觸發視訊錄製開始以捕獲視訊。此外,此功能將停用「錄製」按鈕(以防止同時錄製),同時啟動「停止錄製」按鈕。此操作表示錄音已開始。

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

隨後,開發一個終止視訊擷取過程並解放視訊編碼器的功能。

 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)

上述功能執行更新使用者介面的附加操作,這需要啟動「錄製」按鈕,同時停用「停止錄製」按鈕。此類操作表示記錄過程已停止。

錄製和顯示視頻

請開發一種功能,可以從視訊來源無縫獲取幀,執行必要的處理任務,並將它們呈現在圖形使用者介面中,直到啟動「停止錄製」命令。採取上述行動後,該流程的執行將停止。

 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)

此功能的功能還包括計算和顯示自錄製開始以來每個單獨視訊畫面內的持續時間(以分鐘和秒為單位)。

顯示捕捉的影像和視頻

為了展示透過影像和錄影過程成功取得的視覺內容,需要適當的呈現方法。

為了在使用者介面上展示視覺內容,需要開發一種功能,從其儲存位置檢索影像文件,將其轉換為與 Python Tkinter 庫的圖形使用者介面相容的格式,並更新顯示的視窗與新獲得的視覺數據。此過程需要利用 Python 成像庫 (PIL) 來存取和處理儲存的影像,然後採用 Tkinter GUI 框架的適當方法將轉換後的影像合併到相機預覽畫面的指定區域中。

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

為了展示錄製的視頻,應該實現一種激活視頻播放介面的功能,使觀看者能夠觀察捕獲的鏡頭。此外,此過程會在視訊播放過程中暫停相機串流的任何進一步更新。

 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)

停止視訊串流更新的傳播有助於實現無縫的視覺感知。

建立影片縮圖並開啟圖庫

以雄辯的方式納入以下陳述:縮圖生成功能的實現被認為是必不可少的,因為它使用戶能夠透過視覺上簡潔的表示來快速辨別和選擇他們想要的視訊內容。

 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 

建立一個名為「playVideo」的新 JavaScript 函數,點擊圖庫視窗中的影片縮圖時將觸發該函數。此函數應啟動所選影片的播放並將其顯示在影片播放器容器中。

 def play_video_from_thumbnail(video_path):
    play_video(video_path) 

當然,這裡有一個如何使用 OpenCV 函式庫在 Python 中實作此功能的範例:pythonimport cv2import numpy as npfrom tkinter import Tk, Frame, Button, Label, Text, Scrollbar, VERTICAL)def save_captured_frames(window):# Define capdowture):# Define capdowtureparameters(windowture):# Define capdowtureparameters(可以)更改來調整解析度、幀率等)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()

縮圖表示的生成被擴展以適應靜止圖像和運動圖片,從而使用戶能夠透過點擊這些視覺摘要並隨後仔細閱讀全尺寸描述或放映電影作品來存取其相應的原始內容。

為您的應用程式建立主用戶介面

透過建立主 tkinter 介面來啟動該過程,隨後授予它一個傑出的頭銜。

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

然後初始化所需的變數。

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

然後為各種操作創建按鈕。

 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)

利用網格佈局管理器是在應用程式的主視窗中排列按鈕的有效策略,提供視覺上吸引人且有組織的演示文稿,同時確保易於存取和與每個按鈕進行互動。

 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)

透過與裝置的硬體元件建立必要的連接,配置適當的設定以實現最佳視覺化,並初始化相應的模組或庫以在互動式圖形使用者介面中呈現來自攝影機的視訊串流,從而將顯示攝影機饋送的功能合併到互動式圖形使用者介面中應用程式啟動時或使用者輸入提示時畫面的指定區域。

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

當然!以下是如何使用 OpenCV 和 Python 實作此功能的範例:pythonimport cv2from tkinter import *import threadingimport timedef update_camera_feed():# 初始化影片擷取 devicecap=cv2.VideoCapture(0)while True:# 從影片中讀取影格-從影片讀取幀=cap.read()if not ret:break#在GUI上顯示幀label.config(image=frame)#等待按鍵退出循環root.update()event=root.wait_event()if事件==‘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()

最後,啟動 maintkinterevent 循環。

 root.mainloop()

目前的循環在管理用戶參與度和促進他們與系統的互動方面發揮關鍵作用。

測試應用程式功能

演示內容展示了應用程式展示的一系列功能,突顯了其功能和操作的多功能性。

您的瀏覽器不支援影片標籤。

使用 OpenCV 提升您的 Python 技能

OpenCV 被廣泛認為是電腦視覺應用的卓越工具,因為它與各種有助於開發各種創新專案的程式庫相容。此外,使用者可以選擇透過 Python 來利用其功能,Python 是磨練程式設計能力的絕佳平台。