Cv2.EqualizeHist / CLAHE の使い方【OpenCV/C#(OpenCvSharp)】〜ヒストグラム平坦化で画像のコントラストを改善する〜

OpenCV for C#
📌 準備: OpenCV の環境構築がまだの方はこちら → C++ 環境構築ガイド / C#(OpenCvSharp)セットアップ

Cv2.EqualizeHist / CLAHE の使い方【OpenCV/C#(OpenCvSharp)】〜ヒストグラム平坦化で画像のコントラストを改善する〜

Cv2.EqualizeHist はグレースケール画像のコントラストをヒストグラム均等化によって自動改善する関数です。さらに局所領域ごとに均等化を行う CLAHE(Contrast Limited Adaptive Histogram Equalization)を使うと、全体をつぶすことなく細部のコントラストを引き出せます。まず最小コードだけ先に見ておきます。

// EqualizeHist(グローバル)
Cv2.EqualizeHist(gray, dst);

// CLAHE(局所適応)
using var clahe = Cv2.CreateCLAHE(clipLimit: 2.0, tileGridSize: new Size(8, 8));
clahe.Apply(gray, dst);

動作環境

  • OpenCV 4.x(OpenCvSharp4)
  • .NET 8 コンソールアプリ
  • NuGet: OpenCvSharp4 + OpenCvSharp4.runtime.win(Windows 実行時)

環境構築がまだの方は環境構築ガイドを先にどうぞ。

基本の使い方

以下は EqualizeHist と CLAHE の両方を実行してファイルに保存する完全プログラムです。

using OpenCvSharp;

// --- 画像の読み込みとグレースケール変換 ---
using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (src.Empty()) throw new Exception("画像を読み込めませんでした。");

using var gray = new Mat();
Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);

// --- EqualizeHist(グローバルなヒストグラム均等化)---
using var dstGlobal = new Mat();
Cv2.EqualizeHist(gray, dstGlobal);
Cv2.ImWrite("output_equalize.png", dstGlobal);

// --- CLAHE(局所適応ヒストグラム均等化)---
using var dstClahe = new Mat();
// clipLimit: コントラスト制限値(大きいほど強調が強い)
// tileGridSize: 分割タイルサイズ(8x8 が一般的な初期値)
using var clahe = Cv2.CreateCLAHE(clipLimit: 2.0, tileGridSize: new Size(8, 8));
clahe.Apply(gray, dstClahe);
Cv2.ImWrite("output_clahe.png", dstClahe);

Console.WriteLine("完了: output_equalize.png / output_clahe.png を保存しました。");

実行すると以下のように表示されます。

完了: output_equalize.png / output_clahe.png を保存しました。

コードの要点:

行 説明
Cv2.CvtColor(..., BGR2GRAY) どちらの関数もグレースケール(8ビット)入力が必須
Cv2.EqualizeHist(gray, dst) 画像全体のヒストグラムを均等に引き伸ばす
Cv2.CreateCLAHE(...) CLAHE オブジェクトを生成。IDisposable なので using 必須
clahe.Apply(gray, dst) CLAHE を適用。タイル単位で局所的に均等化する

引数と戻り値

Cv2.EqualizeHist

引数 型 説明
src Mat 入力画像(8ビットグレースケール必須)
dst Mat 出力画像(src と同サイズ・同型)

戻り値: なし(void)


Cv2.CreateCLAHE

引数 型 説明
clipLimit double コントラスト制限の閾値。デフォルト 40.0。小さいほど強調を抑制
tileGridSize Size 局所ヒストグラムを計算するタイルの分割数。デフォルト 8x8

戻り値: CLAHE(IDisposable)

CLAHE.Apply

引数 型 説明
src Mat 入力画像(8ビットまたは16ビットグレースケール)
dst Mat 出力画像

実践例

実践例1:カラー画像に CLAHE を適用する(YUV変換経由)

カラー画像に直接ヒストグラム均等化を RGB チャンネルに適用すると色が崩れます。YUV(または LAB)の輝度チャンネルだけに適用するのが実務の定石です。

using OpenCvSharp;

using var src = Cv2.ImRead("input.jpg", ImreadModes.Color);
if (src.Empty()) throw new Exception("画像を読み込めませんでした。");

// BGR → YUV 変換
using var yuv = new Mat();
Cv2.CvtColor(src, yuv, ColorConversionCodes.BGR2YUV);

// チャンネル分割
Mat[] channels = Cv2.Split(yuv);
// Y チャンネル(輝度)にのみ CLAHE を適用
using var clahe = Cv2.CreateCLAHE(clipLimit: 3.0, tileGridSize: new Size(8, 8));
using var yEqualized = new Mat();
clahe.Apply(channels[0], yEqualized);

// Y チャンネルを差し替えてマージ
yEqualized.CopyTo(channels[0]);
using var yuvOut = new Mat();
Cv2.Merge(channels, yuvOut);

// YUV → BGR に戻す
using var dst = new Mat();
Cv2.CvtColor(yuvOut, dst, ColorConversionCodes.YUV2BGR);
Cv2.ImWrite("output_clahe_color.png", dst);

// チャンネル Mat を解放
foreach (var ch in channels) ch.Dispose();

Console.WriteLine("完了: output_clahe_color.png を保存しました。");

実践例2:EqualizeHist と CLAHE を数値で比較する

均等化の効果をピクセル平均値で簡易確認します。

using OpenCvSharp;

using var src = Cv2.ImRead("input.jpg", ImreadModes.Grayscale);
if (src.Empty()) throw new Exception("画像を読み込めませんでした。");

using var dstEq = new Mat();
Cv2.EqualizeHist(src, dstEq);

using var dstClahe = new Mat();
using var clahe = Cv2.CreateCLAHE(clipLimit: 2.0, tileGridSize: new Size(8, 8));
clahe.Apply(src, dstClahe);

// 標準偏差でコントラスト強度を比較
Cv2.MeanStdDev(src,     out _, out Scalar stdOrig);
Cv2.MeanStdDev(dstEq,   out _, out Scalar stdEq);
Cv2.MeanStdDev(dstClahe, out _, out Scalar stdCl);

Console.WriteLine($"元画像    標準偏差: {stdOrig.Val0:F2}");
Console.WriteLine($"EqualizeHist 標準偏差: {stdEq.Val0:F2}");
Console.WriteLine($"CLAHE      標準偏差: {stdCl.Val0:F2}");

実行するとコントラストの強さを標準偏差で確認できます。

元画像    標準偏差: 42.15
EqualizeHist 標準偏差: 73.88
CLAHE      標準偏差: 58.31

低コントラスト画像では EqualizeHist のほうが標準偏差を大きく引き上げ、CLAHE は過剰強調を抑えながらコントラストを改善します。

つまずきポイント

⚠️ CLAHE オブジェクトの Dispose 漏れ

Cv2.CreateCLAHE() は CLAHE オブジェクト(ネイティブリソースを保持)を返します。using を付け忘れるとネイティブメモリがリークします。

// NG: Dispose されない
var clahe = Cv2.CreateCLAHE(2.0, new Size(8, 8));
clahe.Apply(gray, dst);

// OK: using で確実に解放
using var clahe = Cv2.CreateCLAHE(2.0, new Size(8, 8));
clahe.Apply(gray, dst);

Cv2.Split が返す Mat[] も同様に各要素を Dispose() する必要があります(実践例1を参照)。

⚠️ 入力が 8ビットグレースケール以外だと例外が出る

Cv2.EqualizeHist は 8ビットシングルチャンネルのみ対応です。カラー Mat や 16ビット Mat をそのまま渡すと OpenCvSharpException が発生します。CLAHE は 16ビットにも対応しますが、カラーは不可。必ず CvtColor でグレースケール変換してから渡してください。

⚠️ clipLimit のデフォルト値が大きい

Cv2.CreateCLAHE() を引数なしで呼ぶと clipLimit = 40.0 になります。これは強調が非常に強く、ノイズも増幅されるため、実務では 2.0〜4.0 程度から始めて調整するのが無難です。

関連する関数

まとめ

  • Cv2.EqualizeHist は手軽で高速なグローバル均等化。コントラストが全体的に低い画像に有効。
  • CLAHE は局所適応型で過剰強調を抑えながら細部を引き出せる。clipLimit と tileGridSize のチューニングが品質を左右する。
  • カラー画像への適用は YUV/LAB の輝度チャンネルだけに行うのが実務の基本。

🛠 画像処理のプロが開発するSDK/API

本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。

→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

タイトルとURLをコピーしました