diff --git a/courses/day/README.md b/courses/day/README.md index 5dd3814..1941a63 100644 --- a/courses/day/README.md +++ b/courses/day/README.md @@ -41,9 +41,11 @@ ## 開課前待補教材 -- `media/image`:色彩、解析度、格式、壓縮與 metadata 的小型實驗。 -- `media/audio`:取樣、量化、波形與常見格式比較。 -- `media/video`:frame、fps、container/codec 與基本剪輯/轉碼。 -- `media/ethics`:著作權、Creative Commons、個資、肖像與生成式媒體標示。 +以下教材已採用 Colab 友善的 `.ipynb` 格式;每份依序提供目標、環境設定、分格實作、檢查與延伸挑戰。學生先完成基礎必做,再視能力進行標準實作或進階挑戰。 -這些模組完成前,可先將概念放在 HackMD、實作沿用現有 OpenCV/Apps;完成後再由本頁連入,避免一次搬動舊教材。 +- [`media/image`](../../media/image/README.md):色彩、解析度、格式、壓縮與 metadata 的小型實驗。 +- [`media/audio`](../../media/audio/README.md):取樣、量化、波形與常見格式比較。 +- [`media/video`](../../media/video/README.md):frame、fps、container/codec 與基本剪輯/轉碼。 +- [`media/ethics`](../../media/ethics/README.md):著作權、Creative Commons、個資、肖像與生成式媒體標示。 + +日間部主線仍以影像處理與視覺安全為核心:`media/image` 與 `media/ethics` 可直接對應主要週次;音訊與視訊作為導論或專題延伸活動,避免分散核心進度。 diff --git a/media/audio/README.md b/media/audio/README.md new file mode 100644 index 0000000..293b523 --- /dev/null +++ b/media/audio/README.md @@ -0,0 +1,46 @@ +# 數位音訊:取樣、量化與波形 + +## 學習目標 + +- 說明取樣率、位元深度、聲道與資料量的意義。 +- 用波形辨識振幅、時間與失真風險。 +- 比較 WAV 與常見壓縮音訊格式的使用情境。 + +## 核心概念 + +未壓縮 PCM WAV 的粗略資料量: + +`秒數 × 取樣率 × 位元深度 ÷ 8 × 聲道數` + +例如 10 秒、44.1 kHz、16-bit、雙聲道約為 1.76 MB。MP3/AAC 通常較小,但屬有損壓縮;WAV 適合編輯與保存中間版本。 + +## 小實驗 + +```bash +uv run --with matplotlib python audio_lab.py sample.wav +``` + +程式會讀取 WAV 標頭、計算時長與未壓縮估計值,並輸出波形圖。建議使用 5–15 秒、授權清楚的短音檔。 + +## 任務 + +### 基礎必做 + +1. 執行程式並打開波形圖。 +2. 在波形中圈出一段音量較大與一段較小的位置。 + +### 標準實作 + +1. 比較兩個 WAV:取樣率、聲道、位元深度與檔案大小。 +2. 找出一段音量明顯變化的位置,從波形說明原因。 +3. 針對「語音備忘錄、音樂母帶、網頁背景音」各選擇一種合適格式並說明理由。 + +### 進階挑戰 + +將左右聲道各畫一張波形圖,並比較單聲道與雙聲道素材的差異。 + +## 繳交問題 + +- 取樣率提高會影響什麼?它不保證改善什麼? +- 單聲道與雙聲道各適合哪些情境? +- 何時應保留未壓縮版本? diff --git "a/media/audio/\346\225\270\344\275\215\351\237\263\350\250\212_\345\217\226\346\250\243\350\210\207\346\263\242\345\275\242.ipynb" "b/media/audio/\346\225\270\344\275\215\351\237\263\350\250\212_\345\217\226\346\250\243\350\210\207\346\263\242\345\275\242.ipynb" new file mode 100644 index 0000000..7b64da9 --- /dev/null +++ "b/media/audio/\346\225\270\344\275\215\351\237\263\350\250\212_\345\217\226\346\250\243\350\210\207\346\263\242\345\275\242.ipynb" @@ -0,0 +1,124 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a29239e2", + "metadata": {}, + "source": [ + "# 數位音訊:取樣、量化與波形\n", + "\n", + "日間部一年級分層教材。先完成基礎必做,再選擇標準實作或進階挑戰。" + ] + }, + { + "cell_type": "markdown", + "id": "d13feab9", + "metadata": {}, + "source": [ + "## Goal\n", + "\n", + "以波形把音訊的時間、振幅、取樣率與聲道變成可觀察結果。" + ] + }, + { + "cell_type": "markdown", + "id": "2bad87c4", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "在 Colab 安裝必要套件並上傳一個 16-bit PCM WAV 短音檔。" + ] + }, + { + "cell_type": "markdown", + "id": "74464f2a", + "metadata": {}, + "source": [ + "## Steps" + ] + }, + { + "cell_type": "markdown", + "id": "307ae1dd", + "metadata": {}, + "source": [ + "### 1. 安裝與上傳\n", + "\n", + "基礎必做:上傳一個合法使用的 WAV 檔。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40f456d5", + "metadata": {}, + "outputs": [], + "source": [ + "!pip -q install numpy matplotlib\n", + "from google.colab import files\n", + "uploaded = files.upload()\n", + "source_name = next(iter(uploaded))" + ] + }, + { + "cell_type": "markdown", + "id": "33c43099", + "metadata": {}, + "source": [ + "### 2. 讀取與繪圖\n", + "\n", + "標準實作:讀取 WAV 規格,畫出第一聲道波形。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5941849", + "metadata": {}, + "outputs": [], + "source": [ + "import wave, numpy as np, matplotlib.pyplot as plt\n", + "with wave.open(source_name, 'rb') as w:\n", + " ch, width, rate, frames = w.getnchannels(), w.getsampwidth(), w.getframerate(), w.getnframes()\n", + " data = np.frombuffer(w.readframes(frames), dtype=np.int16).reshape(-1, ch)\n", + "print({'channels': ch, 'sample_rate': rate, 'bit_depth': width*8, 'seconds': frames/rate})\n", + "t = np.arange(frames)/rate\n", + "plt.plot(t, data[:,0], linewidth=.4); plt.xlabel('seconds'); plt.ylabel('amplitude'); plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "34c0ffbd", + "metadata": {}, + "source": [ + "## Checks\n", + "\n", + "能否在圖上指出音量較大與較小的片段,並解釋取樣率與聲道的意義?" + ] + }, + { + "cell_type": "markdown", + "id": "ebc8b898", + "metadata": {}, + "source": [ + "## Next Steps\n", + "\n", + "進階挑戰:分別繪出左右聲道並比較差異。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/media/ethics/README.md b/media/ethics/README.md new file mode 100644 index 0000000..48f49c9 --- /dev/null +++ b/media/ethics/README.md @@ -0,0 +1,53 @@ +# 媒體倫理與發布:來源、授權、個資與生成式媒體 + +## 學習目標 + +- 在作品發布前辨識著作權、授權、肖像與個資風險。 +- 能依素材來源建立可追溯的標示。 +- 對使用生成式 AI 或第三方 API 的部分做透明揭露。 + +## 發布前檢查表 + +- [ ] 我有權使用每一份圖片、音訊、視訊、字型與程式碼嗎? +- [ ] 是否記錄來源、作者、網址、授權條款與修改內容? +- [ ] 素材是否含有人臉、姓名、學號、定位、車牌、通訊紀錄或其他可辨識資訊? +- [ ] 是否取得必要的同意,或已遮蔽、移除、改用替代素材? +- [ ] 是否清楚標示生成式 AI、第三方 API 及其資料可能傳送的範圍? +- [ ] 是否避免把「網路上找得到」誤認為「可任意使用」? + +## Creative Commons 快速判讀 + +| 標示 | 一句話理解 | +|---|---| +| CC BY | 可使用與改作,但需署名。 | +| CC BY-SA | 改作後通常須以相同條款分享。 | +| CC BY-NC | 不得作商業用途。 | +| CC BY-ND | 不得散布改作版本。 | +| CC0 | 作者放棄大部分著作權利,但仍宜保留來源紀錄。 | + +授權條款有細節與例外;不確定時,選擇替代素材、向權利人確認,或暫不公開。 + +## 專題 README 必填欄位 + +```text +素材名稱: +來源與作者: +授權: +本專題如何使用/修改: +人物或個資處理: +生成式 AI/第三方 API:使用目的、傳送資料類型、人工修改: +``` + +## 討論案例 + +### 基礎必做 + +從自己的練習素材選一項,填完「來源與作者、授權、如何使用」三欄。 + +### 標準實作 + +以小組專題為例,找出一項「可以做但需要標示」與一項「應先取得同意或改用素材」的情境,寫出處置理由。 + +### 進階挑戰 + +為期末作品建立一份發布前檢查流程,指定由誰在何時確認素材授權、個資與 AI 揭露。 diff --git "a/media/ethics/\345\252\222\351\253\224\345\200\253\347\220\206_\347\231\274\345\270\203\345\211\215\346\252\242\346\237\245.ipynb" "b/media/ethics/\345\252\222\351\253\224\345\200\253\347\220\206_\347\231\274\345\270\203\345\211\215\346\252\242\346\237\245.ipynb" new file mode 100644 index 0000000..0099df9 --- /dev/null +++ "b/media/ethics/\345\252\222\351\253\224\345\200\253\347\220\206_\347\231\274\345\270\203\345\211\215\346\252\242\346\237\245.ipynb" @@ -0,0 +1,121 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c8711ce1", + "metadata": {}, + "source": [ + "# 媒體倫理:發布前檢查與 AI 揭露\n", + "\n", + "日間部一年級分層教材。先完成基礎必做,再選擇標準實作或進階挑戰。" + ] + }, + { + "cell_type": "markdown", + "id": "d6fe70a8", + "metadata": {}, + "source": [ + "## Goal\n", + "\n", + "在發布前辨識素材授權、個資、肖像與生成式 AI 揭露需求。" + ] + }, + { + "cell_type": "markdown", + "id": "7f79c21c", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "此單元不需要安裝套件;直接填寫下列欄位並存下自己的專題紀錄。" + ] + }, + { + "cell_type": "markdown", + "id": "a2b7e5a5", + "metadata": {}, + "source": [ + "## Steps" + ] + }, + { + "cell_type": "markdown", + "id": "1c93c5d5", + "metadata": {}, + "source": [ + "### 1. 素材紀錄\n", + "\n", + "基礎必做:完成一筆素材來源紀錄。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d8f09846", + "metadata": {}, + "outputs": [], + "source": [ + "asset = {\n", + " '素材名稱': '', '來源與作者': '', '授權': '',\n", + " '使用或修改方式': '', '人物或個資處理': '',\n", + " 'AI或第三方API揭露': ''\n", + "}\n", + "asset" + ] + }, + { + "cell_type": "markdown", + "id": "94c428c2", + "metadata": {}, + "source": [ + "### 2. 發布前檢查\n", + "\n", + "標準實作:逐項確認;有任何一項不確定就先不要公開。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "433e47da", + "metadata": {}, + "outputs": [], + "source": [ + "checklist = ['來源與授權清楚', '無未同意的人臉或個資', 'AI/API 使用已揭露', '沒有在版本庫放入金鑰']\n", + "for item in checklist: print('□', item)" + ] + }, + { + "cell_type": "markdown", + "id": "744a9307", + "metadata": {}, + "source": [ + "## Checks\n", + "\n", + "能否說出一個需要標示的情境,以及一個應先取得同意或改用素材的情境?" + ] + }, + { + "cell_type": "markdown", + "id": "a807986a", + "metadata": {}, + "source": [ + "## Next Steps\n", + "\n", + "進階挑戰:為期末作品訂出由誰、何時完成發布前審核的流程。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/media/image/README.md b/media/image/README.md new file mode 100644 index 0000000..866b99e --- /dev/null +++ b/media/image/README.md @@ -0,0 +1,48 @@ +# 數位影像:從像素到檔案格式 + +## 學習目標 + +- 說明解析度、色彩模式、檔案大小與壓縮之間的關係。 +- 讀取影像 metadata,辨識方向與拍攝資訊可能造成的呈現差異。 +- 用 Python 輸出不同尺寸與格式的同一張圖片並比較結果。 + +## 課堂流程 + +| 時間 | 活動 | 產出 | +|---|---|---| +| 15 分 | 觀察同一張圖在手機、投影與網頁的顯示差異 | 兩項猜測 | +| 20 分 | 說明像素、RGB、解析度、JPEG/PNG/WebP | 規格表 | +| 35 分 | 執行小實驗,縮放與轉存圖片 | `output/` 圖檔 | +| 20 分 | 比較檔案大小與畫質 | 觀察紀錄 | +| 10 分 | metadata 與素材授權提醒 | 結論 | + +## 安裝與執行 + +```bash +uv run --with pillow python image_lab.py sample.jpg +``` + +沒有 `sample.jpg` 時,先使用自己拍攝、可公開使用或教師提供的素材。不要使用未取得授權的網路圖片。 + +## 實驗任務 + +### 基礎必做 + +1. 執行程式,打開輸出的三張不同尺寸 JPEG。 +2. 從 1200、800、400 像素中選一張你覺得最適合課堂網頁的版本,寫一句理由。 + +### 標準實作 + +1. 比較原圖、寬度 1200、800、400 像素的檔案大小與可讀性。 +2. 比較 JPEG(品質 90、60)與 PNG;說明哪一種較適合照片、哪一種較適合含文字或透明背景的圖。 +3. 查看 EXIF,判斷是否包含拍攝時間、裝置或 GPS 等隱私資訊;若有,說明公開前的處理方式。 + +### 進階挑戰 + +把程式改成可從命令列指定輸出寬度與 JPEG 品質;輸入錯誤路徑時,提供清楚的中文錯誤訊息。 + +## 繳交問題 + +- 為何解析度較高不一定代表網頁呈現較好? +- 你選擇的輸出格式如何平衡畫質、容量與用途? +- 這份素材是否需要移除 metadata?為什麼? diff --git "a/media/image/\346\225\270\344\275\215\345\275\261\345\203\217_\350\211\262\345\275\251\350\210\207\346\240\274\345\274\217.ipynb" "b/media/image/\346\225\270\344\275\215\345\275\261\345\203\217_\350\211\262\345\275\251\350\210\207\346\240\274\345\274\217.ipynb" new file mode 100644 index 0000000..0870d3c --- /dev/null +++ "b/media/image/\346\225\270\344\275\215\345\275\261\345\203\217_\350\211\262\345\275\251\350\210\207\346\240\274\345\274\217.ipynb" @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "71825a2a", + "metadata": {}, + "source": [ + "# 數位影像:色彩、解析度、格式與 metadata\n", + "\n", + "日間部一年級分層教材。先完成基礎必做,再選擇標準實作或進階挑戰。" + ] + }, + { + "cell_type": "markdown", + "id": "9b73e6f7", + "metadata": {}, + "source": [ + "## Goal\n", + "\n", + "讀取影像規格,建立縮放與轉檔結果,並用檔案大小與畫面用途做判讀。" + ] + }, + { + "cell_type": "markdown", + "id": "2c2e03df", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "在 Colab 執行下一格安裝 Pillow;接著上傳一張自己拍攝、教師提供或授權清楚的圖片。" + ] + }, + { + "cell_type": "markdown", + "id": "21ee5c9c", + "metadata": {}, + "source": [ + "## Steps" + ] + }, + { + "cell_type": "markdown", + "id": "733ceda3", + "metadata": {}, + "source": [ + "### 1. 安裝與上傳素材\n", + "\n", + "基礎必做:先安裝套件並上傳一張圖片。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae63ed27", + "metadata": {}, + "outputs": [], + "source": [ + "!pip -q install pillow\n", + "from google.colab import files\n", + "from PIL import Image\n", + "uploaded = files.upload()\n", + "source_name = next(iter(uploaded))" + ] + }, + { + "cell_type": "markdown", + "id": "cee622c3", + "metadata": {}, + "source": [ + "### 2. 查看影像資訊\n", + "\n", + "基礎必做:記下尺寸、色彩模式與格式。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f5069bf", + "metadata": {}, + "outputs": [], + "source": [ + "with Image.open(source_name) as im:\n", + " print('size:', im.size, 'mode:', im.mode, 'format:', im.format)\n", + " print('EXIF fields:', len(im.getexif()))" + ] + }, + { + "cell_type": "markdown", + "id": "a5292dac", + "metadata": {}, + "source": [ + "### 3. 比較尺寸與格式\n", + "\n", + "標準實作:輸出不同尺寸與品質,觀察容量和畫面差異。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40b8f930", + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "out = Path('output'); out.mkdir(exist_ok=True)\n", + "with Image.open(source_name) as im:\n", + " im = im.convert('RGB')\n", + " for width in (1200, 800, 400):\n", + " h = round(im.height * width / im.width)\n", + " result = im.resize((width, h))\n", + " result.save(out / f'image_{width}_q90.jpg', quality=90)\n", + " result.save(out / f'image_{width}_q60.jpg', quality=60)\n", + "for p in sorted(out.iterdir()): print(p.name, round(p.stat().st_size/1024, 1), 'KB')" + ] + }, + { + "cell_type": "markdown", + "id": "8ecf8f45", + "metadata": {}, + "source": [ + "## Checks\n", + "\n", + "能否說出一種適合網頁的輸出版本與理由?metadata 是否可能含有不宜公開的資訊?" + ] + }, + { + "cell_type": "markdown", + "id": "ac964654", + "metadata": {}, + "source": [ + "## Next Steps\n", + "\n", + "進階挑戰:加入命令列或表單參數,讓使用者選擇輸出寬度與 JPEG 品質。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/media/video/README.md b/media/video/README.md new file mode 100644 index 0000000..7812e69 --- /dev/null +++ b/media/video/README.md @@ -0,0 +1,41 @@ +# 數位視訊:畫格、幀率、容器與編碼 + +## 學習目標 + +- 區分畫格(frame)、幀率(fps)、解析度、容器與 codec。 +- 根據用途選擇輸出規格,並理解檔案大小、畫質與播放相容性的取捨。 +- 以 Python 擷取指定畫格,建立可驗證的觀察結果。 + +## 先釐清兩個常見誤解 + +- **MP4 是容器,不等於 codec**:容器可裝影像、音訊、字幕與 metadata;H.264、H.265、AV1 是常見影像編碼方式。 +- **fps 不等於畫質**:fps 影響動作流暢度;解析度、位元率、壓縮方式及素材本身也影響觀感。 + +## 小實驗 + +```bash +uv run --with opencv-python python video_lab.py sample.mp4 +``` + +程式輸出影像尺寸、fps、總畫格、估計時長,並在影片的 0%、50%、90% 位置擷取畫格。若某些編碼無法讀取,應記錄播放器、作業系統與 codec 支援情況,而不是直接判定檔案損毀。 + +## 任務 + +### 基礎必做 + +1. 執行程式,打開開始、中段、結尾三張畫格。 +2. 說出影片的尺寸與 fps,並用一句話說明 fps 代表什麼。 + +### 標準實作 + +1. 比較兩段影片的尺寸、fps、時長與容量。 +2. 選一段快速移動畫面,說明低 fps 或高壓縮可能造成的視覺問題。 +3. 為「手機直式短片、課堂投影、網頁嵌入」各提出一組合理輸出規格,並說明取捨。 + +### 進階挑戰 + +讓程式接受秒數而非比例,擷取指定時間點的畫格,並處理超出影片時長的輸入。 + +## 基本轉碼原則 + +轉碼會再壓縮。保留原始檔、將輸出目的說清楚,並以短片測試相容性;不要在不明確需求下反覆轉檔。 diff --git "a/media/video/\346\225\270\344\275\215\350\246\226\350\250\212_\347\225\253\346\240\274\350\210\207\345\271\200\347\216\207.ipynb" "b/media/video/\346\225\270\344\275\215\350\246\226\350\250\212_\347\225\253\346\240\274\350\210\207\345\271\200\347\216\207.ipynb" new file mode 100644 index 0000000..6202b4c --- /dev/null +++ "b/media/video/\346\225\270\344\275\215\350\246\226\350\250\212_\347\225\253\346\240\274\350\210\207\345\271\200\347\216\207.ipynb" @@ -0,0 +1,125 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b7e992a8", + "metadata": {}, + "source": [ + "# 數位視訊:畫格、幀率、容器與 codec\n", + "\n", + "日間部一年級分層教材。先完成基礎必做,再選擇標準實作或進階挑戰。" + ] + }, + { + "cell_type": "markdown", + "id": "1df21512", + "metadata": {}, + "source": [ + "## Goal\n", + "\n", + "讀取視訊規格並擷取開始、中段與結尾畫格,建立 fps 與畫格的直覺。" + ] + }, + { + "cell_type": "markdown", + "id": "939c96da", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "在 Colab 安裝 OpenCV,並上傳短 MP4 檔;素材應具有使用權。" + ] + }, + { + "cell_type": "markdown", + "id": "a652fef5", + "metadata": {}, + "source": [ + "## Steps" + ] + }, + { + "cell_type": "markdown", + "id": "1c6792c0", + "metadata": {}, + "source": [ + "### 1. 安裝與上傳\n", + "\n", + "基礎必做:上傳短影片。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1150c2d6", + "metadata": {}, + "outputs": [], + "source": [ + "!pip -q install opencv-python-headless\n", + "from google.colab import files\n", + "uploaded = files.upload()\n", + "source_name = next(iter(uploaded))" + ] + }, + { + "cell_type": "markdown", + "id": "b343161d", + "metadata": {}, + "source": [ + "### 2. 讀取與擷取\n", + "\n", + "標準實作:顯示尺寸、fps、時長並擷取三個位置。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3db3fdb", + "metadata": {}, + "outputs": [], + "source": [ + "import cv2, matplotlib.pyplot as plt\n", + "cap=cv2.VideoCapture(source_name)\n", + "frames=int(cap.get(cv2.CAP_PROP_FRAME_COUNT)); fps=cap.get(cv2.CAP_PROP_FPS)\n", + "print({'frames':frames, 'fps':fps, 'seconds':frames/fps})\n", + "for ratio in (0, .5, .9):\n", + " cap.set(cv2.CAP_PROP_POS_FRAMES, int(frames*ratio)); ok, frame=cap.read()\n", + " if ok: plt.figure(); plt.imshow(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)); plt.axis('off')\n", + "cap.release()" + ] + }, + { + "cell_type": "markdown", + "id": "8f197c9a", + "metadata": {}, + "source": [ + "## Checks\n", + "\n", + "能否區分 MP4 容器與 codec,並說出 fps 對觀看感受的影響?" + ] + }, + { + "cell_type": "markdown", + "id": "8e61721b", + "metadata": {}, + "source": [ + "## Next Steps\n", + "\n", + "進階挑戰:讓使用者輸入秒數,擷取指定時間點。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}