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.CalcHist — ヒストグラムを計算する。均等化前後の分布確認に使える
- Cv2.MeanStdDev — コントラスト改善の効果検証に活用(実践例2参照)
- Cv2.MatchTemplate の使い方【OpenCV/C#(OpenCvSharp)】〜テンプレートマッチングで部分画像を検索する〜 — 前処理にヒストグラム均等化を組み合わせることでマッチング精度が向上するケースがある
まとめ
Cv2.EqualizeHistは手軽で高速なグローバル均等化。コントラストが全体的に低い画像に有効。- CLAHE は局所適応型で過剰強調を抑えながら細部を引き出せる。
clipLimitとtileGridSizeのチューニングが品質を左右する。 - カラー画像への適用は YUV/LAB の輝度チャンネルだけに行うのが実務の基本。
🛠 画像処理のプロが開発するSDK/API
本ブログを運営するスワローインキュベートは、OpenCV ベースのなりすまし判定SDK/APIを開発しています。SDK は C#/.NET 8 に正式対応しており、OpenCvSharp を使うプロジェクトからそのまま組み込めます。
→ 顔認証のなりすまし対策 設計チェックリスト(当ブログ)
→ なりすまし判定SDK/APIの詳細を見る
→ API仕様書・サンプルコード

