[AI][Python]OpenCV自動開啟視訊攝像頭、並擷取影像

  • 60
  • 0
  • AI
  • 2025-05-19

文、意如

自動開啟視訊攝像頭、
當使用者按下Y鍵就會擷取影像存檔

 

程式碼:

py11.py

import cv2  # 匯入 OpenCV 函式庫,用於影像處理

# 建立一個命名的視窗,視窗名稱為 "myimg"
cv2.namedWindow("myimg")

# 開啟預設攝影機(0 為第一個攝影機裝置)
cap = cv2.VideoCapture(0)

# 檢查攝影機是否成功開啟
while cap.isOpened():
    # 讀取一幀影像(ret 為是否成功讀取,img 為影像資料)
    ret, img = cap.read()
    
    if ret:  # 若成功讀取影像
        # 在視窗中顯示影像
        cv2.imshow("myimg", img)
        
        # 等待 100 毫秒,並接收鍵盤輸入(回傳按鍵的 ASCII 值)
        w = cv2.waitKey(100)

        # 若按下 "Y" 或 "y" 鍵(大小寫都接受)
        if w == ord("Y") or w == ord("y"):
            # 儲存目前畫面為圖片,指定儲存路徑
            cv2.imwrite("media/myimg.jpg", img)
            print("已儲存圖片:media/myimg.jpg")  # 顯示成功訊息
            break  # 跳出迴圈,結束程式

# 釋放攝影機資源(避免占用)
cap.release()

# 關閉所有由 OpenCV 建立的視窗
cv2.destroyAllWindows()
加上拍照按鈕

py12.py

import cv2                      # 匯入 OpenCV,用於影像擷取與處理
import tkinter as tk            # 匯入 tkinter,建立 GUI 視窗與按鈕
from tkinter import messagebox  # 匯入訊息框模組,用於顯示提示訊息
from PIL import Image, ImageTk  # 匯入 PIL 模組,用於影像格式轉換與顯示

# 圖片儲存的路徑
SAVE_PATH = "media/myimg.jpg"

# 建立主視窗(視窗物件)
root = tk.Tk()
root.title("拍照相機")  # 設定視窗標題

# 建立一個 Label 元件,用來顯示攝影機畫面
label = tk.Label(root)
label.pack()  # 將 Label 放入視窗中

# 開啟預設攝影機(參數 0 代表第一台攝影機)
cap = cv2.VideoCapture(0)

def update_frame():
    """
    持續更新攝影機畫面,顯示在 GUI 上的 Label 元件中
    """
    ret, frame = cap.read()  # 讀取攝影機一張影像(ret:成功與否, frame:影像本身)
    if ret:
        # 將 OpenCV 的 BGR 顏色格式轉換為 RGB(因為 tkinter 不支援 BGR)
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        # 將 numpy 陣列轉為 PIL 的影像物件
        img_pil = Image.fromarray(frame_rgb)

        # 將 PIL 影像轉為 tkinter 可顯示的格式
        imgtk = ImageTk.PhotoImage(image=img_pil)

        # 保留影像參考,否則會顯示空白
        label.imgtk = imgtk

        # 將影像顯示在 Label 元件上
        label.configure(image=imgtk)

    # 每 30 毫秒再次執行 update_frame,達到不斷更新畫面效果
    root.after(30, update_frame)

def take_photo():
    """
    按下按鈕時拍照並儲存圖片
    """
    ret, frame = cap.read()  # 再次擷取一張畫面
    if ret:
        # 儲存圖片到指定路徑
        cv2.imwrite(SAVE_PATH, frame)
        # 顯示訊息視窗:圖片已儲存
        messagebox.showinfo("提示", f"圖片已儲存:{SAVE_PATH}")
    else:
        # 若拍照失敗,顯示錯誤訊息
        messagebox.showerror("錯誤", "無法擷取圖片")

# 建立一個按鈕,點擊後執行 take_photo 函式(拍照)
btn = tk.Button(root, text="📸 拍照", font=("Arial", 14), command=take_photo)
btn.pack(pady=10)  # 加入視窗並設定間距

# 啟動第一次影像更新(之後會自動每30毫秒呼叫一次)
update_frame()

def on_close():
    """
    當視窗關閉時執行,釋放攝影機並關閉視窗
    """
    cap.release()      # 釋放攝影機資源
    root.destroy()     # 關閉 tkinter 視窗

# 當使用者關閉視窗時,呼叫 on_close 函式
root.protocol("WM_DELETE_WINDOW", on_close)

# 開始進入 tkinter 的主事件迴圈(等待互動)
root.mainloop()
另存照片

py13.py

✅ 按下拍照鍵時再跳出輸入視窗 (輸入另存新檔的檔名)

✅ 自動在圖片右下角疊加當下時間戳記

✅ 儲存檔案名稱附加時間戳記

 

# 匯入所需模組
import cv2  # OpenCV:用來存取攝影機與處理影像
import tkinter as tk  # 建立 GUI 視窗
from tkinter import messagebox, simpledialog  # tkinter 的訊息視窗與輸入對話框
from PIL import Image, ImageTk  # 用來將 OpenCV 影像轉為 tkinter 可用格式
import datetime  # 處理日期與時間
import os  # 處理檔案與資料夾操作

# 建立主視窗
root = tk.Tk()
root.title("拍照相機")  # 設定視窗標題

# 建立影像顯示區域,之後會用來顯示即時影像
label = tk.Label(root)
label.pack()

# 啟動攝影機,參數 0 代表預設攝影機(通常是筆電內建的)
cap = cv2.VideoCapture(0)

def update_frame():
    """從攝影機取得影像並更新到畫面上(每 30 毫秒執行一次)"""
    ret, frame = cap.read()  # 從攝影機讀取一張影像
    if ret:
        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # OpenCV 預設是 BGR,要轉成 RGB 才能給 tkinter 顯示
        img_pil = Image.fromarray(frame_rgb)  # 將 NumPy 陣列轉成 PIL 影像物件
        imgtk = ImageTk.PhotoImage(image=img_pil)  # 將 PIL 影像轉成 tkinter 影像格式

        label.imgtk = imgtk  # 儲存影像避免被垃圾回收
        label.configure(image=imgtk)  # 將影像顯示在 Label 上

    root.after(30, update_frame)  # 每 30 毫秒呼叫一次自己(達成即時畫面)

def take_photo():
    """按下拍照按鈕時呼叫此函式,會拍照、加上時間戳記、讓使用者輸入檔名並儲存"""
    ret, frame = cap.read()  # 讀取一張影像
    if not ret:
        messagebox.showerror("錯誤", "拍照失敗")  # 如果讀取失敗,跳出錯誤訊息
        return

    now = datetime.datetime.now()  # 取得目前的日期與時間
    timestamp_str = now.strftime("%Y-%m-%d %H:%M:%S")  # 產生格式化的時間字串(顯示用)
    filename_time = now.strftime("%Y%m%d_%H%M%S")  # 產生檔名用的時間字串(不含特殊符號)

    # 加入時間戳記到影像的右下角
    font = cv2.FONT_HERSHEY_SIMPLEX  # 使用 OpenCV 內建字型
    font_scale = 0.6  # 字型大小
    thickness = 2  # 線條粗細
    color = (0, 255, 255)  # 文字顏色為黃色(BGR)

    # 計算文字寬高
    (text_width, text_height), baseline = cv2.getTextSize(timestamp_str, font, font_scale, thickness)
    x = frame.shape[1] - text_width - 10  # 計算文字的 X 座標(右邊預留 10 px)
    y = frame.shape[0] - 10  # Y 座標設在底部往上 10 px

    # 在影像上加上時間戳記
    cv2.putText(frame, timestamp_str, (x, y), font, font_scale, color, thickness, cv2.LINE_AA)

    # 彈出視窗讓使用者輸入自訂檔名
    user_filename = simpledialog.askstring("輸入檔名", "請輸入檔名(不含副檔名):")
    if not user_filename:
        messagebox.showwarning("警告", "未輸入檔名,取消儲存")  # 使用者未輸入則取消拍照
        return

    save_folder = "media"  # 要儲存圖片的資料夾名稱
    os.makedirs(save_folder, exist_ok=True)  # 若資料夾不存在就自動建立

    # 組合完整檔案名稱,例如:myphoto_20250519_153045.jpg
    full_filename = f"{user_filename}_{filename_time}.jpg"
    save_path = os.path.join(save_folder, full_filename)  # 組合完整路徑

    # 儲存圖片到指定路徑
    cv2.imwrite(save_path, frame)

    # 顯示儲存成功的提示訊息
    messagebox.showinfo("成功", f"圖片已儲存:\n{save_path}")

# 建立拍照按鈕,按下時會呼叫 take_photo 函式
btn = tk.Button(root, text="拍照", font=("Arial", 14), command=take_photo)
btn.pack(pady=10)  # 加入一些垂直間距

# 啟動即時畫面更新(呼叫上面的 update_frame 函式)
update_frame()

def on_close():
    """當使用者關閉視窗時,釋放攝影機資源並結束程式"""
    cap.release()  # 釋放攝影機資源
    root.destroy()  # 關閉 tkinter 主視窗

# 設定關閉視窗時要執行的清理動作
root.protocol("WM_DELETE_WINDOW", on_close)

# 啟動 tkinter 主迴圈(GUI 開始執行)
root.mainloop()

 

Yiru@Studio - 關於我 - 意如