.NET で画像を比較する方法 – サマリーページをスキップ

.NET アプリケーションでプログラム的に 画像を比較する方法 が必要なとき、時間とストレージを無駄にする余計なサマリーページは避けたいものです。品質管理ライン、コンテンツ管理パイプライン、または自動化されたビジュアルリグレッションテストスイートを構築している場合でも、サマリーページをスキップすることで各実行の秒数を削減し、ディスク使用量を抑えることができます。

このチュートリアルでは、GroupDocs.Comparison for .NET を使用して 2 つの画像を効率的に比較し、サマリーページの生成を抑制するようライブラリを設定し、ベストプラクティスのパフォーマンス技術を適用する方法を学びます。また、なぜこれが重要なのか、いつ使用すべきか、一般的な落とし穴を回避する方法も解説します。

クイック回答

  • サマリーページなしで画像を比較する最速の方法は何ですか? ComparerCompareOptions を使用し、GenerateSummaryPage = false を設定します。
  • この機能を標準でサポートしているライブラリはどれですか? GroupDocs.Comparison for .NET (v25.4.0 以上)。
  • ライセンスは必要ですか? はい、商用環境では商用ライセンスが必要です。開発用には無料トライアルが利用できます。
  • 一度に2枚以上の画像を比較できますか? もちろんです – Compare() の前に Add() を複数回呼び出します。
  • このアプローチは大規模バッチジョブに適していますか? はい、バッチ処理と適切なメモリ管理を組み合わせれば問題ありません。

GroupDocs.Comparison とは何ですか?

GroupDocs.Comparison は、ドキュメントや画像間の視覚的差分を検出し、並列表示またはオーバーレイ結果を生成する .NET ライブラリです。JPEG、PNG、BMP、TIFF、GIF など 50 以上の入力・出力形式 をサポートし、ファイル全体をメモリに読み込むことなく数百ページのファイルを処理できます。

サマリーページをスキップする理由は?

サマリーページを無効にすると、画像のみの比較で I/O が最大 70 % 削減され、平均で処理時間が約 30 % 短縮されます(ライブラリのベンチマークスイートによる)。差分画像だけが必要な自動テストや QC の合否判定の場合、余分な HTML レポートは価値がなく、ディスク容量だけを消費します。

前提条件と環境設定

必要なもの

  • GroupDocs.Comparison for .NET バージョン 25.4.0 以上
  • Visual Studio 2019 以上、または任意の .NET 対応 IDE
  • .NET Framework 4.6.1 以上 または .NET Core 2.0 以上
  • 基本的な C# の知識とファイル I/O の経験

推奨追加項目

  • サンプル画像のペア(例: source.pngtarget.png)を含む小規模テストプロジェクト。
  • オプション: サービス指向アーキテクチャを好む場合は依存性注入の設定。

これらの前提条件が重要な理由

指定されたライブラリバージョンには GenerateSummaryPage フラグとパフォーマンス改善が含まれており、旧バージョンにはありません。最新の IDE を使用することで NuGet パッケージ管理が利用でき、コンパイル時警告を早期に確認できます。

GroupDocs.Comparison のインストール方法

GroupDocs.Comparison は NuGet を通じて任意の .NET プロジェクトに追加でき、バイナリのダウンロードとプロジェクトファイルの更新を自動で行います。Visual Studio のパッケージマネージャコンソールまたは .NET CLI のいずれかの方法を選択してください。どちらのコマンドも依存関係を自動で解決し、正しいバージョンが参照されます。

Install-Package GroupDocs.Comparison -Version 25.4.0

25.4.0 をロックする正確なバージョンに置き換えてください。)

dotnet add package GroupDocs.Comparison --version 25.4.0

両方のコマンドはライブラリをプロジェクトファイルに追加し、必要なバイナリを復元します。

Pro Tip: .csproj にバージョンを固定しておくと、API の挙動が変わる偶発的なアップグレードを防げます。

ライセンスに関する考慮事項

GroupDocs.Comparison は本番環境での使用にライセンスが必要です。無料トライアル でフル機能を試した後、一時ライセンスで拡張テストを行い、最終的に 本格商用ライセンス を取得してください。GroupDocs.Comparison.lic ファイルをアプリケーションのルートに配置するか、プログラムでパスを指定します。

基本的なプロジェクト設定

新しいコンソールアプリ(または既存サービス)を作成し、以下のボイラープレートコードを追加します。このスニペットは比較ロジックに入る前に必要な最小設定を示しています。

using System;
using System.IO;
using GroupDocs.Comparison;

// Define directory paths for input images and output results
string documentDirectory = "YOUR_DOCUMENT_DIRECTORY";
string outputDirectory = "YOUR_OUTPUT_DIRECTORY";

// Initialize paths to your source and target images
string sourceImagePath = Path.Combine(documentDirectory, "sourceImage.jpg");
string targetImagePath = Path.Combine(documentDirectory, "targetImage.jpg");

// Output image path for comparison result
string resultImagePath = Path.Combine(outputDirectory, "resultImage.jpg");

重要: ファイルパスには必ず Path.Combine() を使用してください。OS 固有のパス区切り文字を自動で処理し、Windows と Linux コンテナ間での微妙なバグを回避できます。

ステップバイステップ実装ガイド

サマリーページなしで画像を比較するにはどうすればよいですか?

Comparer は GroupDocs.Comparison の中心クラスで、ドキュメントや画像の比較操作を統括します。CompareOptions で比較時の設定を行い、サマリーページの生成可否を制御します。ソース画像を読み込み、サマリーページを無効にした CompareOptions を設定し、ターゲット画像を追加して Compare() を呼び出します。メソッドは ComparisonResult を返し、差分画像ストリームが含まれるため、ディスクへ書き出したりネットワーク経由で送信したり、UI コンポーネントに埋め込んだりできます。このアプローチにより余分な HTML や PDF のサマリーレポートが生成されません。

using (Comparer comparer = new Comparer())
{
    // Load source image
    comparer.Add(sourcePath);

    // Configure options – this is where we turn off the summary page
    CompareOptions options = new CompareOptions
    {
        GenerateSummaryPage = false,
        // You can also tweak sensitivity here if needed
        Sensitivity = 0.5
    };

    // Add the target image for comparison
    comparer.Add(targetPath, options);

    // Execute comparison and retrieve the result image stream
    ComparisonResult result = comparer.Compare();

    // Save the diff image
    using (FileStream outStream = new FileStream(outputPath, FileMode.Create))
    {
        result.Save(outStream);
    }
}

上記コードは 4 つの論理ステップ で比較を実行し、差分画像のみを書き出し、HTML や PDF のサマリは出力しません。

ステップ 1: Comparer オブジェクトの初期化

Comparer クラスはすべての比較操作へのゲートウェイです。IDisposable を実装しているため、using ブロックでラップすると例外が発生してもファイルハンドルやアンマネージドメモリが速やかに解放されます。

ステップ 2: サマリなしのために CompareOptions を設定

CompareOptions インスタンスの GenerateSummaryPage = false を設定します。このフラグにより、画像のみのシナリオで余計な I/O の主因となるデフォルト HTML レポートの生成がスキップされます。

ステップ 3: 比較対象の画像を追加

Add() を複数回呼び出すことで、1 つのソースに対して複数のターゲットをバッチで比較できます。必要に応じて各呼び出しごとに個別の CompareOptions を渡すことも可能です。

ステップ 4: 比較を実行し結果を保存

Comparer.Compare() が実際の比較処理を行い、ComparisonResult を返します。結果には差分画像の Stream が含まれ、直接ディスクに保存したり、ネットワーク経由で送信したり、UI に埋め込んだりできます。

完全な本番対応メソッド

以下は任意の .NET サービスに組み込める、パス検証、例外処理、オプションのロギングフックを備えたメソッドです。

public static void CompareImagesWithoutSummary(string sourcePath, string targetPath, string outputPath)
{
    try
    {
        using (Comparer comparer = new Comparer(sourcePath))
        {
            // Configure options to skip summary generation
            CompareOptions options = new CompareOptions
            {
                GenerateSummaryPage = false
            };
            
            // Add target image and execute comparison
            comparer.Add(targetPath);
            comparer.Compare(outputPath, options);
            
            Console.WriteLine($"Comparison completed successfully. Result saved to: {outputPath}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Error during image comparison: {ex.Message}");
        throw; // Re-throw for proper error handling upstream
    }
}

一般的な実装上の落とし穴(回避方法)

  • Path Issues: File.Exists() でソースとターゲットの両方が存在するか必ず確認してください。ファイルが見つからないと FileNotFoundException がスローされ、早期に捕捉できます。
  • Memory Pressure: 10 MB 超の大きな画像はかなりの RAM を消費します。バッチ処理で分割し、ピクセル単位の完全精度が不要な場合はダウンサンプリングを検討してください。
  • File Locks: 他のプロセスが画像ファイルに排他ロックを保持していないことを確認します。特にマルチスレッドやコンテナ環境では重要です。

実用的な適用例とユースケース

製造業における品質管理

生産ラインで各製品の画像を取得し、ゴールデンリファレンスと比較します。サマリーページを省くことで「合格」か「不合格」かをミリ秒単位で判断でき、ラインの高速稼働を維持できます。

コンテンツ管理システム

ユーザーがアセットをアップロードした際に、即座に重複または類似画像を検出し、ストレージ肥大化を防ぎ、検索関連性を向上させます。差分画像はサムネイルとして保存し、迅速な視覚的検査に利用できます。

自動 UI テスト(ビジュアルリグレッション)

Selenium や Playwright が取得したスクリーンショットをこの比較ルーチンに渡します。差分画像が UI の変化をハイライトし、サマリーページが生成されないため CI パイプラインは高速かつ軽量に保たれます。

医療画像(監査付き)

放射線診断のワークフローでは、連続スキャン間の変化をフラグ付けする必要があります。詳細な監査ログは別途生成しつつ、差分画像自体はサマリーページなしで生成できるため、DICOM 変換後の PNG など大容量画像の処理時間が短縮されます。

パフォーマンスの考慮事項と最適化

メモリ管理のベストプラクティス

サーバーの RAM に応じて 20〜50 枚 のバッチで画像を処理します。Comparer インスタンスは速やかに破棄し、長時間ジョブでメモリスパイクが見られる場合のみ GC.Collect() を呼び出します。

foreach (var batch in imageBatches)
{
    using (Comparer comparer = new Comparer())
    {
        // batch processing logic here
    }
}

ディスク I/O の最適化

入力・出力・一時ディレクトリは同一の高速 SSD ボリューム上に配置します。差分画像保存後は一時ファイルを即座に削除し、不要なディスク使用を防ぎます。

スレッドと非同期の考慮事項

GroupDocs.Comparison は読み取り専用操作に対してスレッドセーフですが、単一の Comparer インスタンスをスレッド間で共有しないでください。代わりに独立したタスクを起動します:

var tasks = images.Select(pair => Task.Run(() => ComparePair(pair)));
await Task.WhenAll(tasks);

一般的な問題のトラブルシューティング

ファイルパスと権限エラー

  • Symptom: FileNotFoundException または UnauthorizedAccessException が発生。
  • Solution: Path.GetFullPath() で解決されたパスをデバッグし、アプリケーションプールの ID(または Docker コンテナユーザー)に読み書き権限があることを確認し、環境変数でパスが切り詰められていないか再チェックします。

メモリとパフォーマンスのボトルネック

  • Symptom: 実行が遅い、または OutOfMemoryException が発生。
  • Solution: 正確なピクセル比較が不要な場合は画像を共通解像度(例: 1024 × 768)にリサイズします。dotMemory や組み込みの Performance Profiler でメモリ使用状況を監視します。

ライセンス問題

  • Symptom: 差分画像に透かしが入る、または LicenseException がスロー。
  • Solution: GroupDocs.Comparison.lic が実行ファイルディレクトリにあることを確認するか、License license = new License(); license.SetLicense("path/to/license.file"); で明示的にロードします。

高度な構成オプション

比較感度のカスタマイズ

CompareOptionsSensitivity プロパティを調整することで、圧縮アーティファクトなどの微細なピクセル変動の扱い方を微調整できます。

CompareOptions options = new CompareOptions
{
    GenerateSummaryPage = false,
    DetectStyleChanges = false,  // Focus on content changes only
    DetalisationLevel = DetalisationLevel.Low  // Faster processing
};

出力形式の最適化

差分画像を特定の形式(PNG と JPEG など)で取得したい場合は、OutputFormat プロパティを設定します:

options.OutputFormat = ImageSaveOptions.SaveFormat.Png;
CompareOptions options = new CompareOptions
{
    GenerateSummaryPage = false,
    ShowDeletedContent = true,
    ShowInsertedContent = true,
    // Customize highlighting colors if needed
    DeletedItemStyle = new StyleSettings
    {
        HighlightColor = Color.Red,
        FontColor = Color.DarkRed
    }
};

一般的な .NET フレームワークとの統合

ASP.NET Core サービス例

2 つの画像ストリームを受け取り、比較を実行し、差分画像を FileResult として返す軽量 HTTP エンドポイントを公開します。

public interface IImageComparisonService
{
    Task<string> CompareImagesAsync(string sourceImage, string targetImage);
}

public class ImageComparisonService : IImageComparisonService
{
    private readonly ILogger<ImageComparisonService> _logger;
    private readonly string _outputDirectory;

    public ImageComparisonService(ILogger<ImageComparisonService> logger, IConfiguration config)
    {
        _logger = logger;
        _outputDirectory = config.GetValue<string>("ImageComparison:OutputDirectory");
    }

    public async Task<string> CompareImagesAsync(string sourceImage, string targetImage)
    {
        // Your implementation here
        return await Task.FromResult("comparisonResult.jpg");
    }
}

依存性注入の登録

Program.cs または Startup.cs で比較機能をスコープドサービスとして追加します:

services.AddScoped<IImageComparisonService, ImageComparisonService>();

よくある質問

Q: サマリーページをスキップする主な利点は何ですか?
A: 画像のみの比較で処理時間が最大 30 % 短縮され、ディスク使用量が約 70 % 削減されます。高スループットパイプラインではこれが重要です。

Q: サマリーページなしでも詳細な変更メタデータを取得できますか?
A: はい。ComparisonResult オブジェクトは Changes コレクションを公開しており、検出された各差分に関するプログラム的情報を取得できます。

Q: サポートされている画像形式は何ですか?
A: JPEG、PNG、BMP、TIFF、GIF など、合計で 50 以上の形式をサポートしています。

Q: 非常に大きな画像(例: 20 MB 超)をどのように扱うべきですか?
A: 小さなバッチに分割して処理し、必要に応じてダウンサンプリングを行い、メモリ使用量を監視してください。using ブロックで Comparer を囲むことでリソースは速やかに解放されます。

Q: このアプローチはマルチスレッドアプリケーションで安全ですか?
A: はい、各スレッドが独自の Comparer インスタンスを作成すれば安全です。単一インスタンスの共有はレースコンディションを引き起こす可能性があります。

追加リソース


最終更新日: 2026-05-31
テスト環境: GroupDocs.Comparison 25.4.0 for .NET
作者: GroupDocs

Install-Package GroupDocs.Comparison -Version 25.4.0
dotnet add package GroupDocs.Comparison --version 25.4.0
// Create a Comparer object with the source image path
using (Comparer comparer = new Comparer(sourceImagePath))
{
    // Configuration will follow in subsequent steps
}
// Set up compare options to avoid generating a summary page
CompareOptions options = new CompareOptions();
options.GenerateSummaryPage = false;
// Add the target image to the comparison
comparer.Add(targetImagePath);
// Execute comparison with configured options and save to result path
comparer.Compare(resultImagePath, options);
public static void ProcessImageBatch(List<string> imagePairs, int batchSize = 10)
{
    for (int i = 0; i < imagePairs.Count; i += batchSize)
    {
        var batch = imagePairs.Skip(i).Take(batchSize);
        // Process batch and allow garbage collection between batches
        foreach (var pair in batch)
        {
            // Your comparison logic here
        }
        
        // Explicit garbage collection after each batch (use sparingly)
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}
public static async Task<bool> CompareImagesAsync(string source, string target, string output)
{
    return await Task.Run(() =>
    {
        try
        {
            CompareImagesWithoutSummary(source, target, output);
            return true;
        }
        catch
        {
            return false;
        }
    });
}

関連チュートリアル