iT邦幫忙

2025 iThome 鐵人賽

DAY 18
0
生成式 AI

AI 三十天,哎呀每天都很難:OpenAI API 生存指南系列 第 18

Day 18:圖片會說話!Image Captioning 自動加標題

  • 分享至 

  • xImage
  •  

昨天我們讓 AI 看懂一張圖並描述內容。
今天更進一步 —— 做一個 Image Captioning 小工具,能為多張圖片自動產生標題/說明,適合相簿、商品圖片、知識庫圖像標註等情境。

功能說明

  • 讀取資料夾中的 .jpg/.jpeg/.png 圖片
  • 轉為 base64 data URI
  • 送到支援 Vision 的模型
  • 產出 1 句標題(簡短)、與 2–3 句說
  • 存成 captions.csv,日後可匯入 CMS/相簿
import os, base64, mimetypes
import pandas as pd
from glob import glob
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

MODEL = "gpt-4o-mini"
IMAGE_DIR = "images"          # 放圖片的資料夾
OUTPUT_CSV = "captions.csv"   # 產出結果

PROMPT_TITLE = "請用最精煉的一句繁體中文,為這張圖片產生一個吸睛標題(不超過20字)。"
PROMPT_DESC  = "再用 2-3 句繁體中文描述圖片重點與氛圍,避免主觀臆測與不確定資訊。"

def to_data_uri(path: str) -> str:
    mime, _ = mimetypes.guess_type(path)
    if mime is None:
        # 依副檔名猜測,fallback
        if path.lower().endswith(".png"):
            mime = "image/png"
        else:
            mime = "image/jpeg"
    with open(path, "rb") as f:
        b64 = base64.b64encode(f.read()).decode("utf-8")
    return f"data:{mime};base64,{b64}"

def caption_one(image_path: str) -> dict:
    data_uri = to_data_uri(image_path)

    # 一次送兩個子任務:標題 + 說明
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{
            "role": "user",
            "content": [
                {"type": "text", "text": f"{PROMPT_TITLE}\n{PROMPT_DESC}"},
                {"type": "image_url", "image_url": {"url": data_uri}},
            ],
        }],
        temperature=0.5,
        max_tokens=220
    )

    text = resp.choices[0].message.content.strip()

    # 簡單切兩段(你也可改成 JSON 格式更穩)
    # 期待模型回覆格式:
    # 標題:xxx
    # 說明:yyy
    title, desc = "", ""
    for line in text.splitlines():
        s = line.strip()
        if s.startswith("標題:"):
            title = s.replace("標題:", "").strip()
        elif s.startswith("說明:"):
            desc = s.replace("說明:", "").strip()

    # 若模型未嚴格遵守格式,退回全文為說明,並抓首句當標題
    if not title:
        title = text.split("。")[0].replace("\n", " ").strip()[:20]
    if not desc:
        desc = text

    return {"file": os.path.basename(image_path), "title": title, "desc": desc}

def main():
    os.makedirs(IMAGE_DIR, exist_ok=True)
    paths = []
    for ext in ("*.jpg", "*.jpeg", "*.png"):
        paths.extend(glob(os.path.join(IMAGE_DIR, ext)))

    if not paths:
        print(f"請把圖片放到資料夾:{IMAGE_DIR}/ 再執行")
        return

    rows = []
    for i, p in enumerate(paths, 1):
        print(f"[{i}/{len(paths)}] 處理:{p}")
        try:
            rows.append(caption_one(p))
        except Exception as e:
            rows.append({"file": os.path.basename(p), "title": "", "desc": f"ERROR: {e}"})

    df = pd.DataFrame(rows, columns=["file", "title", "desc"])
    df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
    print(f"完成!已輸出 {OUTPUT_CSV}(共 {len(df)} 筆)")

if __name__ == "__main__":
    main()

像我們昨天給出了一張正在打球的圖片,看他會輸出什麼給我們:
https://ithelp.ithome.com.tw/upload/images/20251002/201693762WNbVWsImD.png

我們可調整的小技巧像是:
控制語氣:把 PROMPT_TITLE/PROMPT_DESC 改得更生活一點
輸出結構化:讓模型回傳 JSON,解析更穩
去除主觀:在系統指令加上避免猜測品牌或地點
成本最佳化:多張圖可以用 批次處理,也可調低 max_tokens

今天完成了可以批次為圖片生成標題與說明的工具:
Vision 讀圖之後讓Caption 產生最後存成 CSV
可用於知識庫、商品圖、旅遊相簿等情境
明天我們要把這些文字變成簡報大綱,直接讓 GPT 幫你把一篇文章或多張圖片的描述,整理成PPT 架構!


上一篇
Day 17:看得懂圖了!圖片理解
下一篇
Day 19:報告有了!AI 自動生成簡報大綱
系列文
AI 三十天,哎呀每天都很難:OpenAI API 生存指南20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言