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

日本語対応 LLMランキング2026 ~ベンチマーク分析レポート~(7月10日版)

日本語対応 LLMランキング2026 ~ベンチマーク分析レポート~(7月10日版)

はじめに 本レポートは、Nejumi Leaderboard 4のベンチマークデータ(2026/7/10版)に基づいて、日本語対応LLMの性能を総合的に分析したものです。 前回は 2026/3/6 版の分析レポート を公開しましたが、 約4か月ぶりとなる今回も、上位勢の顔ぶれが大きく入れ替わる激動の回となりました! (定期的に最新LLMランキングを更新してまいります。当社のX(旧Twitter)をフォローいただくことで更新情報を受け取り可能です) Nejumi Leaderboard 4は、日本語タスクにおけるLLMの性能を多角的に評価する信頼性の高いベンチマークとして知られています。汎用的言語性能(GLP)とアラインメント(ALT)の2軸で構成され、翻訳・要約・推論・コーディングから毒性・バイアス・真実性まで、幅広い観点をカバーしているのが特徴です。 本分析では、商用APIモデルとオープンモデルの両方を対象に、それぞれの特徴や傾向を詳しく見ていきます。まず、今回の3大トピックを先にご紹介します。 * Claude Opus 4.8がリーダーボード史上初の総合スコア0.8

By Qualiteg プロダクト開発部
Claude Fable5 完全ガイド — 公式ドキュメントから読み解くモデル仕様とClaude Code運用ポイント

Claude Fable5 完全ガイド — 公式ドキュメントから読み解くモデル仕様とClaude Code運用ポイント

こんにちは! 2026年6月に登場した Claude Fable 5 は、公開直後の輸出規制による一時停止、グローバル再展開、そしてサブスクリプション枠からの離脱と、わずか1か月でめまぐるしい動きを見せています。 当ブログでもその時々の状況を追ってきました。 まず全体像は ついに一般公開、Claude Mythos 5 / Fable 5 を実務視点で読み解く で、公開直後の停止騒動は 公開から3日で停止──Fable 5/Mythos 5 をめぐる米政府指令が示した、AI の新しい可用性リスク で、料金と今後の見通しは Claude Fable 5 はこれからどうなる? 経緯・コスト・今後の見通し で扱っています。 本記事は、それらを踏まえた「実務で使うための決定版ガイド」です。 とくに 2026年7月12日(日本時間7月13日)を境にサブスクリプション枠から外れ、使用クレジットを有効化しないと使えなくなる (この期限は当初2026年7月7日とされていましたが、のちに5日間延長されて7月12日になりました。

By Qualiteg プロダクト開発部
AI時代のデータ漏洩防止の要諦とテクノロジー:第2回 従来型DLPを超えて、AI-DLPが解決すべき本質的課題

AI時代のデータ漏洩防止の要諦とテクノロジー:第2回 従来型DLPを超えて、AI-DLPが解決すべき本質的課題

こんにちは! 前回の記事では、AI時代のデータ漏洩防止における技術的な基礎として、HTTPSインターセプトの仕組みと限界について詳しく解説しました。プロキシサーバーによるSSL/TLS通信の復号化、中間CA証明書の運用、そして証明書ピンニングという技術的制約まで、企業がWeb通信を監視する際の技術的な現実を明らかにしました。 しかし、これらのプロキシ技術は、実は既存のDLP製品でも広く採用されている一般的な手法です。メール監視、ファイル転送の制御、Webアクセスの監査など、従来型のデータ漏洩防止においても、HTTPSインターセプトは中核的な役割を果たしてきました。 では、なぜAI時代において新たにDLPを考え直す必要があるのでしょうか。 前回にひきつづき、従来型DLPでは対応できないAI固有の課題と、AI-DLPとして新たに考慮すべき要素に焦点を当て、より本質的な議論を展開していきます。 1. AI時代が要求する新たなDLP要件 従来のDLP製品は、クレジットカード番号や社会保障番号といった定型的なパターンの検出において優れた実績を持っています。これらの技術は今後も重要な

By Qualiteg プロダクト開発部, Qualiteg コンサルティング
Claude Fable 5はこれからどうなる? 経緯・コスト・今後の見通しをファクトベースで整理する

Claude Fable 5はこれからどうなる? 経緯・コスト・今後の見通しをファクトベースで整理する

こんにちは! 2026年7月2日(日本時間)、日本からもClaude Fable 5が再び利用できるようになりました。 2026年6月に大きな注目を集めて登場し、わずか3日で米政府の指令により停止、そして7月1日(米国時間)に復活したAnthropicの最上位モデル「Claude Fable 5」。 復活と同時に 「サブスクで使えるのは7月7日まで」 という条件が付いたことで、利用者の間ではコストへの懸念の声も見られます。 本記事では、憶測と事実を切り分けながら、 (1)これまでの経緯、 (2)確定している料金体系、 (3)実際のコスト試算、 (4)今後の見通し、 の4点を整理します。確定情報(ファクト)と筆者の推測は明確に区別して書きます。 ※本記事の日付は、特記のない限りAnthropicの発表に基づく米国時間を基準としています。 なお当ブログでは、Fable 5 / Mythos 5についてリリース直後の技術解説、米政府指令による停止が示した可用性リスクの考察、Fable 5の安全分類器がClaude Code上で実際にどう振る舞ったかの体験記を公開してきました。

By Qualiteg コンサルティング