OpenCV 提供了強大的影片處理能力,可以輕鬆讀取、顯示和處理影片檔案。結合 OpenAI 的視覺模型,可以自動生成每一幀的描述性註解,為影片分析和理解提供更豐富的資訊。此技術可用於自動生成影片摘要、內容標記、甚至是視障人士的輔助工具。透過 Python,可以將這些功能整合到一個完整的流程中,實作自動化的影片處理和註解生成。

import cv2

def display_video(file_name):
    cap = cv2.VideoCapture(file_name)
    if not cap.isOpened():
        print("無法開啟影片")
        return

    while True:
        ret, frame = cap.read()
        if not ret:
            break
        cv2.imshow('Video', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

收集影片資料集

程式首先收集影片資料集:

lfiles = [
    "jogging1.mp4",
    "jogging2.mp4",
    "skiing1.mp4",
    #...
    "female_player_after_scoring.mp4",
    "football1.mp4",
    "football2.mp4",
    "hockey1.mp4"
]

lf = len(lfiles)

for i in range(lf):
    file_name = lfiles[i]
    print("Collecting video", file_name)
    print("Downloading video", file_name)
    download_video(file_name)

輸出顯示下載的影片檔名:

Collecting video jogging1.mp4
Downloading video jogging1.mp4
Downloaded 'jogging1.mp4' successfully.
Collecting video jogging2.mp4
...

顯示影片縮圖

程式接著顯示每個影片的縮圖:

for i in range(lf):
    file_name = lfiles[i]
    video_capture.release()
    display_video_frame(file_name, frame_number=5, size=(100, 110))

顯示每個影片的資訊和縮圖:

Displaying a frame of video: skiing1.mp4
Total number of frames: 58
Frame rate: 30.0
Video duration: 1.93 seconds

選擇和顯示影片

您可以選擇列表中的影片並顯示它:

file_name = "football1.mp4"  # 輸入要顯示的影片檔名
# print("Displaying video: ", file_name)

內容解密:

上述程式碼使用 lfiles 列表儲存所有要下載和顯示的影片檔名。lf 變數儲存了列表中的影片數量。程式使用 for 迴圈迭代列表,下載每個影片並顯示其縮圖。display_video_frame 函式用於顯示每個影片的縮圖,該函式接受檔名、幀數和大小等引數。

圖表翻譯:

以下是程式的流程圖:

  flowchart TD
    A[開始] --> B[收集影片資料集]
    B --> C[下載所有影片]
    C --> D[顯示每個影片的縮圖]
    D --> E[選擇和顯示影片]
    E --> F[結束]

這個流程圖展示了程式的主要步驟:收集影片資料集、下載所有影片、顯示每個影片的縮圖、選擇和顯示影片。

顯示影片

import cv2

def display_video(file_name):
    # 讀取影片
    cap = cv2.VideoCapture(file_name)
    
    # 檢查影片是否開啟成功
    if not cap.isOpened():
        print("無法開啟影片")
        return
    
    # 讀取影片尺寸
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    
    # 顯示影片
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        cv2.imshow('Video', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    
    # 釋放資源
    cap.release()
    cv2.destroyAllWindows()

內容解密:

上述程式碼定義了一個 display_video 函式,該函式用於顯示指設定檔名的影片。函式首先讀取影片,然後檢查影片是否開啟成功。如果開啟失敗,則印出錯誤訊息並傳回。如果開啟成功,則讀取影片的尺寸,並進入一個迴圈中不斷讀取影片的每一幀,並使用 OpenCV 的 imshow 函式顯示每一幀。當使用者按下 ‘q’ 鍵時,迴圈終止,資源被釋放。

圖表翻譯:

  flowchart TD
    A[開始] --> B[讀取影片]
    B --> C[檢查影片是否開啟成功]
    C -->|成功| D[讀取影片尺寸]
    C -->|失敗| E[印出錯誤訊息]
    D --> F[顯示影片]
    F --> G[檢查是否按下 'q' 鍵]
    G -->|是| H[釋放資源]
    G -->|否| F

圖表翻譯:

此圖表描述了顯示影片的流程。首先,程式開始執行,然後讀取影片。如果影片開啟成功,則讀取影片的尺寸,並進入顯示影片的迴圈中。在迴圈中,程式不斷顯示每一幀,並檢查是否按下 ‘q’ 鍵。如果按下 ‘q’ 鍵,則迴圈終止,資源被釋放。如果沒有按下 ‘q’ 鍵,則繼續顯示下一幀。

影片處理技術

在進行影片分析之前,首先需要將影片下載並轉換為適合分析的格式。玄貓將使用一個名為 download_video 的函式來下載影片,這個函式位於 GitHub 子節點下的「安裝環境」章節中。

下載影片

下載功能是透過 download_video 函式實作的,這個函式會被玄貓呼叫。同時,display_video 函式的定義與前一節「AI 生成的影片資料集」中相同,負責顯示下載的影片。

def display_video(file_name):
    # 以二進位制模式開啟檔案
    with open(file_name, 'rb') as file:
        # 讀取影片資料
        video_data = file.read()
        #...
        # 傳回 HTML 物件
        return HTML(html)

下載完成後,影片將被分割成單獨的幀。

分割影片為幀

split_file 函式用於從影片中提取幀,就像在前一節「AI 生成的影片資料集」中所定義的一樣。然而,在這裡,我們將擴充套件這個函式以儲存幀為 JPEG 檔案:

def split_file(file_name):
    # 影片路徑
    video_path = file_name
    
    # 使用 OpenCV 讀取影片
    cap = cv2.VideoCapture(video_path)
    
    # 幀號
    frame_number = 0
    
    # 迴圈讀取影片幀
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        #...

這個過程使得影片被轉換成一系列的影像幀,方便進一步的分析和處理。

圖表翻譯:

  flowchart TD
    A[下載影片] --> B[分割影片]
    B --> C[儲存幀為 JPEG]
    C --> D[進行分析]

在這個流程中,首先下載影片,然後分割影片成單獨的幀,最後儲存這些幀為 JPEG 檔案以便於後續分析。

使用 OpenCV 將影片分解為幀並儲存為 JPEG 影像

首先,我們使用 OpenCV 的 imwrite 函式將每一幀儲存為 JPEG 影像。這個過程涉及迭代影片中的每一幀,將其轉換為適合的格式,並使用 cv2.imwrite 將其儲存到磁碟中。

import cv2

# 假設 cap 是一個已經開啟的影片檔案
frame_number = 0
while True:
    ret, frame = cap.read()
    if not ret:
        break
    
    # 將每一幀儲存為 JPEG 影像
    cv2.imwrite(f"frame_{frame_number}.jpg", frame)
    
    frame_number += 1
    print(f"Frame {frame_number} saved.")

cap.release()

Commentator:幫助生成幀的評論

在上一步驟中,我們已經將影片分解為單獨的幀。現在,Commentator 的工作是為每一幀生成評論。這個過程涉及三個主要的函式:

  1. generate_openai_comments(filename): 詢問 GPT-4 視覺模型分析一幀並產生一個包含描述該幀的評論的回應。
  2. generate_comment(response_data): 從 GPT-4 視覺模型的回應中提取評論。
  3. save_comment(comment, frame_number, file_name): 將提取的評論儲存到一個 CSV 檔案中,該檔案的名稱與原始影片檔案相同。

提取評論函式

首先,我們定義 generate_comment 函式,以從 GPT-4 視覺模型的回應中提取相關資訊:

def generate_comment(response_data):
    """從 GPT-4 視覺模型的回應中提取相關資訊."""
    try:
        # 假設 response_data 中包含 'caption' 欄位
        return response_data['caption']
    
    except (KeyError, AttributeError):
        print("錯誤:無法從回應中提取字幕.")
        return "無法取得字幕."

儲存評論函式

接下來,我們定義 save_comment 函式,以將提取的評論儲存到一個 CSV 檔案中:

def save_comment(comment, frame_number, file_name):
    """將評論儲存到一個 CSV 檔案中."""
    # 在檔案名稱後面追加 '.csv' 來建立完整的路徑
    path = f"{file_name}.csv"
    
    # 檢查檔案是否存在,以確定是否需要寫入檔頭
    if not os.path.exists(path):
        # 如果檔案不存在,建立它並寫入檔頭
        with open(path, 'w', newline='') as csvfile:
            fieldnames = ['frame_number', 'comment']
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
            writer.writeheader()
    
    # 將評論寫入 CSV 檔案
    with open(path, 'a', newline='') as csvfile:
        fieldnames = ['frame_number', 'comment']
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
        writer.writerow({'frame_number': frame_number, 'comment': comment})

圖表翻譯

此圖示

  flowchart TD
    A[開始] --> B[讀取幀]
    B --> C[儲存幀為 JPEG]
    C --> D[生成評論]
    D --> E[儲存評論到 CSV]
    E --> F[結束]

圖表翻譯

此流程圖描述了從影片中提取幀、儲存為 JPEG 影像、生成評論並儲存評論到 CSV 檔案的整個過程。每一步驟都對應到上述程式碼中的特定部分,展示瞭如何使用 OpenCV 和 GPT-4 視覺模型實作這個功能。

使用Python和OpenAI視覺模型生成影片幀註解

簡介

本文將介紹如何使用Python和OpenAI視覺模型生成影片幀註解。這個程式包括從影片中抽取幀、使用OpenAI模型生成註解、並將註解儲存為CSV檔案,以便於後續的處理。

所需函式庫和模組

  • os:用於作業系統相關功能,例如檢查檔案是否存在。
  • csv:用於讀寫CSV檔案。
  • uuid:用於生成唯一的ID。
  • openai:用於與OpenAI視覺模型互動,生成註解。

程式碼實作

import os
import csv
import uuid
import openai

# 定義影片幀路徑和CSV儲存路徑
video_folder = "/content"
csv_path = "comments.csv"

# 定義OpenAI模型引數
openai.api_key = "YOUR_OPENAI_API_KEY"

# 定義樣本頻率
nb = 3  # 樣本頻率

# 初始化計數器
counter = 0

# 取得總幀數
total_frames = len([file for file in os.listdir(video_folder) if file.startswith("frame_")])

# 開啟CSV檔案,若不存在則建立
write_header = not os.path.exists(csv_path)

with open(csv_path, 'a', newline='') as f:
    writer = csv.writer(f, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
    
    if write_header:
        writer.writerow(['ID', 'FrameNumber', 'Comment', 'FileName'])

    # 遍歷每一幀
    for frame_number in range(total_frames):
        counter += 1  # 增加計數器
        
        # 檢查是否達到樣本頻率
        if counter == nb and counter < total_frames:
            counter = 0  # 重置計數器
            
            # 組裝幀路徑
            image_path = os.path.join(video_folder, f"frame_{frame_number}.jpg")
            
            try:
                # 使用OpenAI視覺模型生成註解
                response = openai.Image.create(
                    image=open(image_path, "rb"),
                    prompt="Generate a comment for this image.",
                    n=1,
                    size="1024x1024"
                )
                comment = response["data"][0]["caption"]
                
                # 生成唯一ID
                unique_id = str(uuid.uuid4())
                
                # 取得影片檔名
                file_name = os.path.basename(video_folder)
                
                # 寫入CSV檔案
                writer.writerow([unique_id, frame_number, comment, file_name])
                
                print(f"Analyzing frame {frame_number}... Done.")
            except Exception as e:
                print(f"Error processing frame {frame_number}: {e}")

註解和說明

  • 本程式碼使用openai函式庫與OpenAI視覺模型互動,生成影片幀註解。
  • video_folder變數定義了影片幀儲存的路徑,csv_path變數定義了CSV檔案的儲存路徑。
  • nb變數控制樣本頻率,即每多少幀抽取一幀進行註解。
  • CSV檔案包含四列:ID(唯一ID)、FrameNumber(幀號)、Comment(註解)和FileName(影片檔名)。
  • 註解生成過程中,若遇到錯誤,會列印錯誤資訊並繼續處理下一幀。

圖表翻譯

  flowchart TD
    A[開始] --> B[載入影片幀]
    B --> C[設定樣本頻率]
    C --> D[遍歷每一幀]
    D --> E{達到樣本頻率?}
    E -->|是|> F[使用OpenAI模型生成註解]
    E -->|否|> D
    F --> G[儲存註解至CSV]
    G --> H[完成]

圖表翻譯:

此流程圖描述了影片幀註解生成過程。首先載入影片幀,然後設定樣本頻率。接著遍歷每一幀,檢查是否達到樣本頻率。如果達到,則使用OpenAI模型生成註解,並儲存至CSV檔案。最後,完成註解生成過程。

影片評論系統:自動化評論生成與顯示

系統架構

影片評論系統由三個主要元件組成:Pipeline 1、Generator 和 Commentator。Pipeline 1 負責控制整個流程,Generator 則利用 OpenAI 的 ChatCompletion 生成評論,Commentator 負責顯示評論。

Generator

Generator 的主要功能是根據輸入的影片幀生成評論。以下是 Generator 的核心程式碼:

with open(image_path, "rb") as image_file:
    image_data = image_file.read()

response = openai.ChatCompletion.create(
    model="gpt-4-vision-preview",
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "What is happening in this image?"},
                {
                    "type": "image",
                    "image_url": f"data:image/jpeg;base64,{image_data}",
                },
            ],
        }
    ],
    max_tokens=150,
)

Generator 利用 OpenAI 的 ChatCompletion 生成評論,傳入影片幀的影像資料和問題「What is happening in this image?」。

Commentator

Commentator 負責顯示評論。以下是 Commentator 的核心程式碼:

def display_comments(file_name):
    path = f"{file_name}.csv"
    df = pd.read_csv(path)
    return df

Commentator 讀取 CSV 檔案並傳回包含評論的 DataFrame。

Pipeline 1 Controller

Pipeline 1 Controller 負責控制整個流程,包括呼叫 Generator 生成評論和 Commentator 顯示評論。以下是 Pipeline 1 Controller 的核心程式碼:

try:
    # 呼叫 Generator 生成評論
    comment = generate_comment(response)
    save_comment(comment, frame_number, file_name)
except FileNotFoundError:
    print(f"Error: Frame {frame_number} not found.")
except Exception as e:
    print(f"Unexpected error: {e}")

Pipeline 1 Controller 呼叫 Generator 生成評論,然後呼叫 Commentator 顯示評論。

圖表翻譯

以下是 Mermaid 圖表,描述影片評論系統的流程:

  flowchart TD
    A[Pipeline 1 Controller] --> B[Generator]
    B --> C[Commentator]
    C --> D[顯示評論]
    D --> E[傳回 DataFrame]

圖表翻譯

此圖表描述影片評論系統的流程。Pipeline 1 Controller 呼叫 Generator 生成評論,然後呼叫 Commentator 顯示評論。Commentator 讀取 CSV 檔案並傳回包含評論的 DataFrame。

影片處理控制器

控制器負責執行前三個步驟的工作,包括 Generator 和 Commentator。首先,它從第一步開始,選擇一個影片,下載它,並顯示它。在自動化管道中,這些功能可以分開。例如,一個指令碼可以迭代遍歷影片列表,自動選擇每一個,並封裝控制器功能。在這裡,我們將收集、下載和顯示影片,以便進行後續的處理。

import time

# 記錄開始時間
session_time = time.time()

# 步驟 1:顯示影片
print("步驟 1:收集影片")
file_name = "skiing1.mp4"  # 輸入要處理的影片檔名
print(f"影片:{file_name}")

# 下載影片
print("步驟 1:從 GitHub 下載")
directory = "Chapter10/videos"
download(directory, file_name)

# 顯示影片
print("步驟 1:顯示影片")
display_video(file_name)

控制器接著將影片分割成幀,並對影片的幀進行評論:

# 步驟 2:分割影片
print("步驟 2:將影片分割成幀")
split_file(file_name)

然後,控制器啟動 Generator 來生成影片幀的評論:

內容解密:

  • session_time = time.time() 用於記錄程式執行的開始時間。
  • file_name 變數用於儲存要處理的影片檔名。
  • download(directory, file_name) 函式用於下載指定的影片檔案。
  • display_video(file_name) 函式用於顯示下載的影片。
  • split_file(file_name) 函式用於將影片分割成個別的幀,以便進行後續的評論生成。

圖表翻譯:

  flowchart TD
    A[開始] --> B[收集影片]
    B --> C[下載影片]
    C --> D[顯示影片]
    D --> E[分割影片]
    E --> F[生成評論]

此流程圖描述了控制器執行的步驟,從收集影片到生成評論。每一步驟都對應到程式碼中的特定函式或操作。

步驟3:為影格新增註解

import time
import os

# 計時開始
start_time = time.time()

# 產生OpenAI註解
def generate_openai_comments(file_name):
    # 在這裡實作OpenAI註解生成邏輯
    pass

# 計算回應時間
response_time = time.time() - start_time

# 顯示影格數量
video_folder = "/content"
total_frames = len([file for file in os.listdir(video_folder) if file.endswith(".jpg")])
print(f"總影格數:{total_frames}")

# 顯示註解
def display_comments(file_name):
    # 在這裡實作註解顯示邏輯
    pass

# 計算總處理時間
total_time = time.time() - start_time

# 列印回應時間和總處理時間
print(f"回應時間:{response_time:.2f} 秒")
print(f"總處理時間:{total_time:.2f} 秒")

# 儲存註解和影格
save = True
save_frames = True

if save:
    # 儲存註解為CSV格式
    cpath = f"{file_name}.csv"
    if os.path.exists(cpath):
        # 將檔案複製到Google Drive
       !cp {cpath} /content/drive/MyDrive/files/comments/{cpath}
        print(f"檔案 {cpath} 複製成功。")

內容解密:

在這個步驟中,我們首先計算了開始時間,然後呼叫了 generate_openai_comments 函式來產生OpenAI註解。接下來,我們計算了回應時間和總處理時間。然後,我們顯示了影格數量和註解。最後,我們儲存了註解和影格。

圖表翻譯:

  flowchart TD
    A[開始] --> B[產生OpenAI註解]
    B --> C[計算回應時間]
    C --> D[顯示影格數量]
    D --> E[顯示註解]
    E --> F[計算總處理時間]
    F --> G[儲存註解和影格]

圖表翻譯:

此圖表展示了步驟3的流程。首先,我們開始了流程,然後產生了OpenAI註解。接下來,我們計算了回應時間,然後顯示了影格數量和註解。最後,我們計算了總處理時間,然後儲存了註解和影格。

處理影片檔案和幀的儲存與刪除

在處理影片檔案時,經常需要將影片轉換為幀以進行進一步的分析或處理。以下是如何儲存和刪除這些檔案的步驟。

從技術架構視角來看,這個Python影片處理系統巧妙地整合了影片下載、幀提取、OpenAI視覺模型以及CSV儲存等多個模組。透過模組化的設計,系統有效地分離了各個功能,提升了程式碼的可維護性和擴充套件性。然而,目前系統的效能瓶頸可能在於OpenAI API的呼叫,尤其是在處理大量影片幀時,網路延遲和API呼叫頻率限制都可能影響整體處理速度。此外,系統的錯誤處理機制仍有待加強,例如在API呼叫失敗時,缺乏更完善的重試機制和錯誤記錄,可能導致資料遺失或處理中斷。對於重視處理效率的使用者,建議最佳化API呼叫策略,例如批次處理幀或採用非同步呼叫方式。未來,隨著邊緣運算技術的發展,可以預見部分AI模型推理將會遷移到本地端執行,從而降低對雲端API的依賴,進一步提升系統的效能和穩定性。對於追求高效能的應用場景,這將是一個值得關注的發展方向。玄貓認為,此係統架構具備良好的基礎,透過持續最佳化和整合新技術,將能更好地滿足日益增長的影片處理需求。