0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AIと作った「写真から長尺+ショート動画を同時生成するアプリ」開発記

0
Posted at

写真から横型・縦型動画を作るイメージ

はじめに

手元には、ブログ取材で撮りためた大量の写真があります。

これをブログだけに眠らせず、YouTubeの長尺動画やSNSのショート動画として残せないか。そこから始まったのが、今回の Photo Story Video(写真アーカイブ動画制作OS) です。

私はプログラマーではありません。最初からコードを書けたわけでも、動画生成の仕組みに詳しかったわけでもありません。それでも、AIと会話しながら仕様を決め、Cursorに実装してもらい、Codexにレビューと実写真テストを任せることで、次のところまで到達できました。

  • 写真をFinderからドラッグ&ドロップ
  • タイトル、導入文、写真ごとの文章を編集
  • 並び順をドラッグで変更
  • プロジェクトを保存・再読込
  • 同じ編集データからYouTube用の横型MP4を生成
  • 同じ編集データからSNS用の縦型MP4を生成
  • iPhoneのJPEG・HEICにも対応
  • 元写真を変更しない

この記事では、完成した機能だけでなく、どうやって非エンジニアが開発を前へ進めたか、そして実写真テストで見つかった失敗も含めてまとめます。

最初の目的は「数万枚の写真を検索資産にする」こと

当初は、iCloudにある写真をスライドショーにしてYouTubeへ保存したい、という素朴なアイデアでした。

ただ写真を流すだけではなく、1話題につき1本の動画にして、タイトルや短い説明を添える。そうすれば過去の写真が、ブログ記事とは別の入口を持つ検索資産になります。

考えた運用は次のようなものです。

ここで重要だったのは、横型動画を作った後に切り抜いて縦型にするのではなく、同じ編集データから、それぞれの画面サイズに合わせて再描画することでした。

CapCut運用ではなく専用アプリを選んだ理由

最初はCapCutを使う案も考えました。数本を手作業で作るなら、とても便利です。

しかし、写真アーカイブを何十本、何百本と作る場合、毎回同じ作業が発生します。

作業 汎用動画編集ソフト 今回の専用アプリ
写真の読み込み 毎回操作 固定手順
横型と縦型 別々に編集しやすい 同じデータから生成
テキスト配置 手動調整が中心 固定テンプレート
再生成 プロジェクト依存 project.jsonから再生成
大量運用 操作が積み重なる ルーティン化しやすい

そこで、「何でもできる動画編集ソフト」ではなく、写真スライド動画だけを速く作る小さな専用アプリに絞りました。

いきなり実装せず、まず仕様を文章にした

開発の最初に行ったのはコーディングではありません。以下をMarkdownで決めていきました。

  1. 写真をどう管理するか
  2. カードの種類をどう分けるか
  3. 横型と縦型の関係をどうするか
  4. 元写真をどう守るか
  5. どこまでをMVPにするか

動画は次の4種類のカードで構成します。

カード 役割
リード タイトルと導入文
写真 写真、見出し、本文
基本情報 住所や営業時間など(MVPではGUI未実装)
エンディング 終了メッセージと注意書き

カードの並び順は、保存データ内の cards 配列を唯一の正本にしました。

{
  "schema_version": 1,
  "photos": [],
  "cards": [
    { "card_type": "lead" },
    { "card_type": "photo" },
    { "card_type": "photo" },
    { "card_type": "ending" }
  ]
}

実際の保存データにはID、表示時間、文章、写真への相対パスなどが入ります。ここでは構造だけを簡略化しています。

AIとの役割分担

今回うまく機能したのは、AIに全部を一度に頼まず、役割を分けたことでした。

人間が担当したのは、「何を作りたいか」「どこまで必要か」「実際に使えるか」の判断です。

CursorにはIssue単位で実装範囲を限定して依頼し、作業後には変更ファイル、テスト結果、コミットハッシュ、未解決事項を報告してもらいました。Codexには、その報告をうのみにせず、コード差分と実写真で再確認してもらいました。

この往復により、非エンジニアでも「何が終わり、何がまだなのか」を見失いにくくなりました。

MVPの技術構成

技術はできるだけ小さくしました。

役割 採用技術
GUI PySide6 / Qt Widgets
画像読み込み・描画 Pillow
HEIC / HEIF pillow-heif
動画生成 FFmpeg
保存 JSON
テスト pytest

アプリ内では、GUI、保存、写真取り込み、描画、FFmpeg実行を分離しています。

app/
├── main.py        # GUI起動
├── cli.py         # コマンドライン再生成
├── gui/           # 画面操作
└── core/          # 保存・取り込み・描画・FFmpeg

出力形式は、現時点で次のとおりです。

用途 解像度 形式
YouTube長尺 1920×1080 H.264 High / yuv420p / 30fps
SNSショート 1080×1920 H.264 High / yuv420p / 30fps

元写真を絶対に壊さない設計

写真アーカイブで最も怖いのは、元写真を上書きしたり、移動したりすることです。

そこで、読み込んだ写真はプロジェクト内へ作業用コピーを作り、元ファイルは変更しない設計にしました。保存データには元写真の絶対パスを残さず、プロジェクト内の相対パスを保存します。

動画生成の前後でSHA-256を比較し、元写真と作業用コピーが一致することも確認しました。

実写真で初めて見つかった「iPhone JPEGなのに読めない」問題

自動テストが47件通った段階で、実際のiPhone 16の写真を読み込ませました。すると、拡張子は .jpeg なのに「未対応形式」として拒否されました。

原因は、最近のiPhone写真が深度情報用の補助画像を含むことでした。Pillowで開くと、通常の JPEG ではなく MPO と判定される写真があります。

ファイル名: IMG_7813.jpeg
Pillowの判定: MPO
フレーム数: 2
撮影機種: iPhone 16

生成画像だけを使ったテストでは、この問題を発見できませんでした。

修正では、次の条件を満たす場合だけMPOをJPEGとして受け入れました。

  • 拡張子が .jpg または .jpeg
  • ファイル先頭がJPEGのSOIシグネチャ FF D8
  • 主画像(第1フレーム)だけを表示・動画生成に使う
  • 補助画像を別カードにしない
  • .mpo ファイルを無条件には許可しない

実写真3枚で再検証した結果は次のとおりです。

確認項目 結果
写真取り込み 3枚成功
保存・再読込 成功
横型MP4 1920×1080で生成成功
縦型MP4 1080×1920で生成成功
EXIF回転 正立表示
元写真のSHA-256 前後一致
自動テスト 50 passed

この経験から、テストが全部通ることと、実際に使えることは別だと実感しました。自分が普段使う写真で試す工程は欠かせません。

現在の操作方法

現時点では、リポジトリを開いて次のコマンドで起動します。

cd /Users/NakazonoShingo/Cursor/photo-story-video
python3 -m app.main

起動後の流れはシンプルです。

  1. 新規プロジェクト用の空フォルダを選ぶ
  2. Finderから写真をドロップする
  3. タイトル、導入文、写真ごとの文章を入力する
  4. 写真をドラッグして並べ替える
  5. 保存する
  6. 横型動画、縦型動画を書き出す

次はmacOSの .app ランチャーを用意し、ターミナルを開かなくても起動できるようにする予定です。

まだ完成していないこと

MVPなので、以下は未完成です。

  • BGMとナレーション
  • トランジション
  • 基本情報カードのGUI編集
  • 複数のデザインテンプレート
  • 15〜60秒への自動尺調整
  • YouTube・SNSへの自動投稿
  • AIによる文章生成

ただし、最も大事な「写真を選び、文章を書き、同じデータから横型と縦型を生成する」ところまでは動いています。

非エンジニアとして学んだこと

1. AIには完成品ではなく、次の小さなゴールを渡す

「動画アプリを全部作って」ではなく、「写真データモデルだけ」「横型出力だけ」「実写真の不具合だけ」のように範囲を区切ると、結果を確認しやすくなりました。

2. 作業報告にコミットハッシュと未実施事項を含める

AIが何をしたかだけでなく、何をしていないかも毎回明記すると、勝手に範囲が広がるのを防げます。

3. 実素材テストを早めに行う

今回のMPO問題は、生成JPEGでは見つかりませんでした。iPhone写真を使うアプリなら、iPhone写真で確認する必要があります。

4. 人間は「使えるかどうか」の責任を持つ

コードを書けなくても、「この操作は面倒」「この写真が読めないなら使えない」という判断はできます。むしろ、それこそがプロダクトを前に進める重要な役割でした。

まとめ

今回作ったのは、派手な万能動画編集ソフトではありません。写真アーカイブを継続的に動画へ変えるための、小さな専用道具です。

非エンジニアでも、目的を言葉にし、仕様を小さく分け、AIに実装とレビューを分担させ、実素材で検証すれば、動くデスクトップアプリまで到達できました。

AIがコードを書く時代でも、最後に必要なのは「何を作るか」と「本当に使えるか」を判断する人間です。

これからは、起動方法の簡略化、BGM、テンプレート追加、実運用10本を目標に改善していきます。


開発時点の環境

  • macOS
  • Python 3.11
  • PySide6
  • Pillow / pillow-heif
  • FFmpeg
  • Cursor
  • Codex
  • pytest: 50 tests passed

写真から横型・縦型動画を作るイメージ

はじめに

手元には、ブログ取材で撮りためた大量の写真があります。

これをブログだけに眠らせず、YouTubeの長尺動画やSNSのショート動画として残せないか。そこから始まったのが、今回の Photo Story Video(写真アーカイブ動画制作OS) です。

私はプログラマーではありません。最初からコードを書けたわけでも、動画生成の仕組みに詳しかったわけでもありません。それでも、AIと会話しながら仕様を決め、Cursorに実装してもらい、Codexにレビューと実写真テストを任せることで、次のところまで到達できました。

  • 写真をFinderからドラッグ&ドロップ
  • タイトル、導入文、写真ごとの文章を編集
  • 並び順をドラッグで変更
  • プロジェクトを保存・再読込
  • 同じ編集データからYouTube用の横型MP4を生成
  • 同じ編集データからSNS用の縦型MP4を生成
  • iPhoneのJPEG・HEICにも対応
  • 元写真を変更しない

この記事では、完成した機能だけでなく、どうやって非エンジニアが開発を前へ進めたか、そして実写真テストで見つかった失敗も含めてまとめます。

最初の目的は「数万枚の写真を検索資産にする」こと

当初は、iCloudにある写真をスライドショーにしてYouTubeへ保存したい、という素朴なアイデアでした。

ただ写真を流すだけではなく、1話題につき1本の動画にして、タイトルや短い説明を添える。そうすれば過去の写真が、ブログ記事とは別の入口を持つ検索資産になります。

考えた運用は次のようなものです。

ここで重要だったのは、横型動画を作った後に切り抜いて縦型にするのではなく、同じ編集データから、それぞれの画面サイズに合わせて再描画することでした。

CapCut運用ではなく専用アプリを選んだ理由

最初はCapCutを使う案も考えました。数本を手作業で作るなら、とても便利です。

しかし、写真アーカイブを何十本、何百本と作る場合、毎回同じ作業が発生します。

作業 汎用動画編集ソフト 今回の専用アプリ
写真の読み込み 毎回操作 固定手順
横型と縦型 別々に編集しやすい 同じデータから生成
テキスト配置 手動調整が中心 固定テンプレート
再生成 プロジェクト依存 project.jsonから再生成
大量運用 操作が積み重なる ルーティン化しやすい

そこで、「何でもできる動画編集ソフト」ではなく、写真スライド動画だけを速く作る小さな専用アプリに絞りました。

いきなり実装せず、まず仕様を文章にした

開発の最初に行ったのはコーディングではありません。以下をMarkdownで決めていきました。

  1. 写真をどう管理するか
  2. カードの種類をどう分けるか
  3. 横型と縦型の関係をどうするか
  4. 元写真をどう守るか
  5. どこまでをMVPにするか

動画は次の4種類のカードで構成します。

カード 役割
リード タイトルと導入文
写真 写真、見出し、本文
基本情報 住所や営業時間など(MVPではGUI未実装)
エンディング 終了メッセージと注意書き

カードの並び順は、保存データ内の cards 配列を唯一の正本にしました。

{
  "schema_version": 1,
  "photos": [],
  "cards": [
    { "card_type": "lead" },
    { "card_type": "photo" },
    { "card_type": "photo" },
    { "card_type": "ending" }
  ]
}

実際の保存データにはID、表示時間、文章、写真への相対パスなどが入ります。ここでは構造だけを簡略化しています。

AIとの役割分担

今回うまく機能したのは、AIに全部を一度に頼まず、役割を分けたことでした。

人間が担当したのは、「何を作りたいか」「どこまで必要か」「実際に使えるか」の判断です。

CursorにはIssue単位で実装範囲を限定して依頼し、作業後には変更ファイル、テスト結果、コミットハッシュ、未解決事項を報告してもらいました。Codexには、その報告をうのみにせず、コード差分と実写真で再確認してもらいました。

この往復により、非エンジニアでも「何が終わり、何がまだなのか」を見失いにくくなりました。

MVPの技術構成

技術はできるだけ小さくしました。

役割 採用技術
GUI PySide6 / Qt Widgets
画像読み込み・描画 Pillow
HEIC / HEIF pillow-heif
動画生成 FFmpeg
保存 JSON
テスト pytest

アプリ内では、GUI、保存、写真取り込み、描画、FFmpeg実行を分離しています。

app/
├── main.py        # GUI起動
├── cli.py         # コマンドライン再生成
├── gui/           # 画面操作
└── core/          # 保存・取り込み・描画・FFmpeg

出力形式は、現時点で次のとおりです。

用途 解像度 形式
YouTube長尺 1920×1080 H.264 High / yuv420p / 30fps
SNSショート 1080×1920 H.264 High / yuv420p / 30fps

元写真を絶対に壊さない設計

写真アーカイブで最も怖いのは、元写真を上書きしたり、移動したりすることです。

そこで、読み込んだ写真はプロジェクト内へ作業用コピーを作り、元ファイルは変更しない設計にしました。保存データには元写真の絶対パスを残さず、プロジェクト内の相対パスを保存します。

動画生成の前後でSHA-256を比較し、元写真と作業用コピーが一致することも確認しました。

実写真で初めて見つかった「iPhone JPEGなのに読めない」問題

自動テストが47件通った段階で、実際のiPhone 16の写真を読み込ませました。すると、拡張子は .jpeg なのに「未対応形式」として拒否されました。

原因は、最近のiPhone写真が深度情報用の補助画像を含むことでした。Pillowで開くと、通常の JPEG ではなく MPO と判定される写真があります。

ファイル名: IMG_7813.jpeg
Pillowの判定: MPO
フレーム数: 2
撮影機種: iPhone 16

生成画像だけを使ったテストでは、この問題を発見できませんでした。

修正では、次の条件を満たす場合だけMPOをJPEGとして受け入れました。

  • 拡張子が .jpg または .jpeg
  • ファイル先頭がJPEGのSOIシグネチャ FF D8
  • 主画像(第1フレーム)だけを表示・動画生成に使う
  • 補助画像を別カードにしない
  • .mpo ファイルを無条件には許可しない

実写真3枚で再検証した結果は次のとおりです。

確認項目 結果
写真取り込み 3枚成功
保存・再読込 成功
横型MP4 1920×1080で生成成功
縦型MP4 1080×1920で生成成功
EXIF回転 正立表示
元写真のSHA-256 前後一致
自動テスト 50 passed

この経験から、テストが全部通ることと、実際に使えることは別だと実感しました。自分が普段使う写真で試す工程は欠かせません。

現在の操作方法

現時点では、リポジトリを開いて次のコマンドで起動します。

cd ~/Cursor/photo-story-video
python3 -m app.main

起動後の流れはシンプルです。

  1. 新規プロジェクト用の空フォルダを選ぶ
  2. Finderから写真をドロップする
  3. タイトル、導入文、写真ごとの文章を入力する
  4. 写真をドラッグして並べ替える
  5. 保存する
  6. 横型動画、縦型動画を書き出す

次はmacOSの .app ランチャーを用意し、ターミナルを開かなくても起動できるようにする予定です。

まだ完成していないこと

MVPなので、以下は未完成です。

  • BGMとナレーション
  • トランジション
  • 基本情報カードのGUI編集
  • 複数のデザインテンプレート
  • 15〜60秒への自動尺調整
  • YouTube・SNSへの自動投稿
  • AIによる文章生成

ただし、最も大事な「写真を選び、文章を書き、同じデータから横型と縦型を生成する」ところまでは動いています。

非エンジニアとして学んだこと

1. AIには完成品ではなく、次の小さなゴールを渡す

「動画アプリを全部作って」ではなく、「写真データモデルだけ」「横型出力だけ」「実写真の不具合だけ」のように範囲を区切ると、結果を確認しやすくなりました。

2. 作業報告にコミットハッシュと未実施事項を含める

AIが何をしたかだけでなく、何をしていないかも毎回明記すると、勝手に範囲が広がるのを防げます。

3. 実素材テストを早めに行う

今回のMPO問題は、生成JPEGでは見つかりませんでした。iPhone写真を使うアプリなら、iPhone写真で確認する必要があります。

4. 人間は「使えるかどうか」の責任を持つ

コードを書けなくても、「この操作は面倒」「この写真が読めないなら使えない」という判断はできます。むしろ、それこそがプロダクトを前に進める重要な役割でした。

まとめ

今回作ったのは、派手な万能動画編集ソフトではありません。写真アーカイブを継続的に動画へ変えるための、小さな専用道具です。

非エンジニアでも、目的を言葉にし、仕様を小さく分け、AIに実装とレビューを分担させ、実素材で検証すれば、動くデスクトップアプリまで到達できました。

AIがコードを書く時代でも、最後に必要なのは「何を作るか」と「本当に使えるか」を判断する人間です。

これからは、起動方法の簡略化、BGM、テンプレート追加、実運用10本を目標に改善していきます。


開発時点の環境

  • macOS
  • Python 3.11
  • PySide6
  • Pillow / pillow-heif
  • FFmpeg
  • Cursor
  • Codex
  • pytest: 50 tests passed
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?