OpenCV cv2.imwrite で発生する「_img.empty()」エラーと「動画安定化」による解決法

OpenCV cv2.imwrite で発生する「_img.empty()」エラーと「動画安定化」による解決法

こんにちは!

画像処理や動画解析の現場で広く利用されている OpenCV。

しかし実務で動画処理を行っていると、時折以下のようなエラーに遭遇することがあります。

cv2.error: OpenCV(4.11.0) /io/opencv/modules/imgcodecs/src/loadsave.cpp:929:
error: (-215:Assertion failed) !_img.empty() in function 'imwrite'

このエラーは、cv2.imwrite() に渡された画像が空(None またはサイズ0) の場合に発生します。 一見単純に見える問題ですが、背後には「入力動画の不安定さ」や「並列処理の競合」といった要因が潜んでいることが少なくありません。

本記事では、このエラーの発生原因を掘り下げ、実務で効果のある解決策として 「動画の安定化(正規化)」 を紹介します。

TL;DR

OpenCVの動画処理で頻発する !_img.empty() エラーは、入力動画(mp4)の不安定さが根本原因であることがけっこう多い

不安定な動画→安定化するためのffmpegコマンドは

ffmpeg で動画を安定化

ffmpeg -y -fflags +genpts -i INPUT.mp4 \
  -vf "fps=30,format=yuv420p" \
  -c:v libx264 -preset slow -crf 20 -g 90 -sc_threshold 0 \
  -movflags +faststart -an OUTPUT_stable.mp4

最終手段
それでもダメなら、 連番画像に展開してから処理

目次

  • なぜ「空画像」が紛れ込むのか?
  • エラーを防ぐ基本的な工夫
  • 動画を「安定化」してから処理する
  • さらに堅牢にするレシピ
  • 実務で役立つ環境上の注意点
  • デバッグ方法
  • まとめ

なぜ動画に「空画像」が紛れ込むのか?

1. 入力動画の不安定さ

  • 可変フレームレート(VFR) 一部のカメラやスマートフォンは VFR で撮影しており、処理パイプラインによっては「抜けフレーム」や「タイムスタンプ不整合」が発生します。
  • 特殊なピクセルフォーマット 10bit、4:2:2、4:4:4 など、標準的でないフォーマットはライブラリによって扱いが不安定。
  • GOP 構造の揺らぎ I/P/B フレームの参照構造が複雑な動画は、特定フレームだけ取り出しに失敗するケースがあります。

2. 中間処理での破損

  • 一時的に PNG などへ展開して並列処理を行うと、I/O が競合し libpng error: IDAT: CRC error が出ることがあります
  • たとえば、 Windows + WSL 環境で /mnt/c を経由すると、I/O レイテンシが大きく、破損の可能性が増したりします

3. アルゴリズム側の仕様

  • 顔検出やセグメンテーションなどの処理で「対象が見つからない場合に None を返す」実装になっていると、そのまま imwrite に渡されて落ちます。

4. 環境要因

  • ディスクの空き容量不足やメモリ不足による一時的なフレーム生成失敗。
  • 並列度が高すぎて一時ファイルの読み書きが衝突するケース。

エラーを防ぐ基本的な工夫

imwrite 前のチェック

まずは cv2.imwrite を呼ぶ前に、画像が空でないか確認するのが基本です。

if img is None or getattr(img, "size", 0) == 0:
    # 空の場合はスキップやフォールバック処理を行う
    continue
cv2.imwrite(path, img)

安全なラッパー関数の例

リトライやフォールバックコピーを組み合わせるとさらに堅牢になります。

import cv2, os, shutil, time

def safe_imwrite(path, img, retries=2, sleep=0.05):
    if img is None or getattr(img, "size", 0) == 0:
        return False
    for _ in range(retries + 1):
        try:
            if cv2.imwrite(path, img):
                return True
        except cv2.error:
            pass
        time.sleep(sleep)
    return False

def write_with_fallback(out_path, img, src_path_for_fallback=None):
    os.makedirs(os.path.dirname(out_path), exist_ok=True)
    if safe_imwrite(out_path, img):
        return True
    if src_path_for_fallback and os.path.exists(src_path_for_fallback):
        shutil.copy2(src_path_for_fallback, out_path)
        return True
    return False

動画を「安定化」してから処理する

根本的な解決策として有効なのが、

入力動画を事前に正規化(安定化)すること

です。

これがけっこう効きます

具体的には以下のような ffmpeg コマンドを利用します。

標準的な安定化(最初に試すべきレシピ)

ffmpeg -y -fflags +genpts -i INPUT.mp4 \
  -vf "fps=30,format=yuv420p" \
  -c:v libx264 -preset slow -crf 20 -g 90 -sc_threshold 0 \
  -movflags +faststart \
  -an \
  OUTPUT_stable.mp4

オプションの詳細説明

オプション 説明 効果
-fflags +genpts タイムスタンプ生成 欠損したPTSを補完
-vf fps=30 FPS固定 VFR→CFR変換で安定化
-vf format=yuv420p ピクセルフォーマット統一 最も互換性の高い8bit 4:2:0に
-g 90 GOPサイズ指定 30fpsなら3秒ごとにIフレーム
-sc_threshold 0 シーンチェンジ無効化 GOP構造の完全な安定化
-crf 20 品質設定 品質とファイルサイズのバランス
-movflags +faststart メタデータ配置最適化 ストリーミング再生の高速化
-an 音声除去 映像処理に特化

さらに堅牢にするレシピ

I フレームのみ(All-I)

ffmpeg -i INPUT.mp4 \
  -vf "fps=30,format=yuv420p" \
  -c:v libx264 -crf 18 -g 1 \
  -an \
  OUTPUT_allI.mp4

→ すべて I フレーム化するため、ランダムアクセス時の不具合が激減。ただしファイルサイズは増加。

ProRes 422HQ(中間コーデック)

ffmpeg -i INPUT.mp4 \
  -vf "fps=30,format=yuv422p10le" \
  -c:v prores_ks -profile:v 3 \
  -an \
  OUTPUT_prores422hq.mov

→ 編集用途でもよく使われる高品質・高安定コーデック。

MJPEG(軽量で堅牢)

ffmpeg -i INPUT.mp4 \
  -vf "fps=30,format=yuvj420p" \
  -c:v mjpeg -q:v 3 \
  -an \
  OUTPUT_mjpeg.avi

→ I フレームのみ、デコードも軽い。検証・実験用に便利。

画像連番に展開(最強の安定策)

mkdir -p frames
ffmpeg -i INPUT.mp4 -vf "fps=30" -qscale:v 2 frames/%06d.jpg

→ PNG より JPG の方が CRC エラーを避けやすく、大量並列処理に強い。


実務で役立つ環境上の注意点

  • WSL を使う場合 一時ファイルは /mnt/c ではなく /home/... 側(ext4)に置く方が安定。
  • ディスクの空き容量 df -h で確認し、余裕を持たせる。容量不足は破損の温床。
  • 並列度の調整 ワーカー数を減らすと I/O 衝突や PNG CRC エラーを減らせる。
  • "未検出=原画返し"の仕様に統一 処理関数が None を返さず、検出できなければ元のフレームを返す設計にする。

デバッグ方法

問題の切り分けには、どのフレームで失敗しているかを特定することが重要です。

フレーム読み込みの検証

def debug_frame_read(video_path):
    """どのフレームで読み込みに失敗しているか特定"""
    cap = cv2.VideoCapture(video_path)
    frame_count = 0
    failed_frames = []
    
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        if frame is None or frame.size == 0:
            failed_frames.append(frame_count)
            print(f"Frame {frame_count}: Empty or corrupted")
        frame_count += 1
    
    cap.release()
    
    if failed_frames:
        print(f"\n問題のあるフレーム数: {len(failed_frames)}")
        print(f"最初の10個: {failed_frames[:10]}")
    else:
        print(f"全 {frame_count} フレーム正常に読み込み可能")
    
    return failed_frames

動画の整合性チェック

def verify_video_integrity(video_path):
    """動画ファイルの基本情報と整合性を確認"""
    cap = cv2.VideoCapture(video_path)
    
    if not cap.isOpened():
        print(f"エラー: {video_path} を開けません")
        return False
    
    fps = cap.get(cv2.CAP_PROP_FPS)
    frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    
    print(f"動画情報:")
    print(f"  FPS: {fps}")
    print(f"  フレーム数: {frame_count}")
    print(f"  解像度: {width}x{height}")
    
    # 実際に読み込めるフレーム数をカウント
    actual_count = 0
    while True:
        ret, _ = cap.read()
        if not ret:
            break
        actual_count += 1
    
    cap.release()
    
    if actual_count != frame_count:
        print(f"警告: メタデータのフレーム数({frame_count})と")
        print(f"      実際のフレーム数({actual_count})が一致しません")
        return False
    
    return True

まとめ

  • cv2.imwrite_img.empty() エラーは 空画像が渡された結果 であり、背景には 入力動画の不安定さや I/O の揺らぎ がある。
  • 解決にはの二段構えが効果的。
    1. ガード処理を入れる(空画像をスキップ or フォールバック)
    2. 動画を ffmpeg で安定化する(CFR化・ピクセルフォーマット統一・GOP安定化)
  • さらに堅牢化するなら、All-I / ProRes / MJPEG / 画像連番 といった手段も検討可能。
  • デバッグ時は、問題のあるフレームを特定することで原因の切り分けが容易になる。

こうした工夫により、実務の動画処理パイプラインはより堅牢で信頼性の高いものになります。

なにはともあれ、
まずは後段で泣かないために入力となる動画の品質をあげましょう!

それでは、お読みいただきありがとうございました!

Read more

発話音声からリアルなリップシンクを生成する技術 第5回(前編):Transformerの実装と実践的な技術選択

発話音声からリアルなリップシンクを生成する技術 第5回(前編):Transformerの実装と実践的な技術選択

こんにちは!リップシンク技術シリーズもいよいよ終盤となりました。 前回(第4回)では、LSTMの学習プロセスと限界について詳しく解説しました。限られたデータでも効果的に学習できるLSTMの強みを理解する一方で、長距離依存の処理に限界があることも明らかになりました。そして、この問題を解決する革新的なアプローチとして、すべての位置の情報を同時に参照できるTransformerのSelf-Attention機構を紹介しました。 第5回の今回は、 Transformerの具体的なネットワーク設計から始め、その実装上の課題を明らかにします。(前編※) そして、LSTMとTransformerの長所を組み合わせたハイブリッドアプローチを紹介し、実際の製品開発における技術選択の指針を示します。最後に、感情表現への拡張という次なる挑戦についても触れていきます。(後編※) ※Transformerの仕組みは複雑であるため、第5回は前編と後編に分けて解説させていただく予定です。 1. Transformerベースのネットワーク設計 1.1 全体アーキテクチャ図 では、さっそく、Tran

By Qualiteg 研究部, Qualiteg コンサルティング
大企業のAIセキュリティを支える基盤技術 - 今こそ理解するActive Directory 第2回 ドメイン環境の構築

大企業のAIセキュリティを支える基盤技術 - 今こそ理解するActive Directory 第2回 ドメイン環境の構築

こんにちは、今回はシリーズ第2回ドメイン環境の構築 - 検証環境の構築手順について解説いたします! 連載の構成 第1章:基本概念の理解 - Active DirectoryとKerberos/NTLM認証の基礎 【★今回です★】第2章:ドメイン環境の構築 - 検証環境の構築手順 第3章:クライアントとサーバーのドメイン参加 - ドメイン参加の詳細手順 第4章:プロキシサーバーと統合Windows認証 第5章:ブラウザ設定と認証 - 各ブラウザでの設定方法 第6章:トラブルシューティング - よくある問題と解決方法 第7章:セキュリティとベストプラクティス - 本番環境での考慮事項 第8章:実践的な構成例 - AIセキュリティツールとの統合事例 第2章:ドメイン環境の構築 2.1 ドメイン名の設計 2.1.1 ドメイン名の命名規則 Active Directoryを構築する際、

By Qualiteg コンサルティング
AIがよく間違える「クロージャ問題」の本質と対策

AIがよく間違える「クロージャ問題」の本質と対策

こんにちは! 本日は「クロージャ問題」に関する話題となります。 Pythonでループ内に関数を定義したことはありますか? もしあるなら、あれれ?な挙動に遭遇したことがあるかもしれません。 本稿では、Pythonプログラマーなら一度は経験する「クロージャ問題」について、初心者にもわかりやすく解説してみたいとおもいます クロージャとは何か? そもそも ”クロージャ” とは何でしょうか。 クロージャ(closure)とは、関数が自分の定義されたスコープの変数を覚えて持ち運ぶ仕組み のことです。 もう少し分解すると、次の2つがポイントとなります 1. 内側の関数が、外側の関数の変数を使える 2. 外側の関数が終了しても、その変数は生き続ける 普通の関数とクロージャ―を使った関数を比較してみましょう 普通の関数との比較 まずは普通の関数から、 def add(x, y): return x + y print(add(3, 5)) # 8 print(add(3, 7)

By Qualiteg プロダクト開発部
フリーランスHub様にQualiteg Blogをご紹介いただきました

フリーランスHub様にQualiteg Blogをご紹介いただきました

この度、フリーランス向け案件検索サービス「フリーランスHub」様の特集記事「トレンドをキャッチアップ!AIに関する情報が得られるメディア・ブログまとめ」にて、弊社が運営する「Qualiteg Blog」をご紹介いただきました。 掲載記事について フリーランスHub様の記事では、AI技術の最前線で活躍するエンジニアや開発者の方々に向けて、価値ある情報源となるメディア・ブログが厳選して紹介されています。 その中で、Qualiteg Blogを「AI技術の専門知識を実践的なビジネス活用につなげる貴重な情報源」として取り上げていただきました。 特に以下の点を評価いただいております * 実践的なビジネス活用事例の提供 AI新規事業創出や事業選定方法など、経営者やビジネスリーダーが直面する課題への具体的な解決策 * 技術的な深掘りコンテンツ リップシンク技術など、実際のサービスで使用されている技術の開発現場目線での詳細な解説 * 多様な情報発信 代表執筆記事、AIトピックス、講演会動画など、幅広いフォーマットでの情報提供 今後も価値ある情報発

By Qualiteg ニュース