WPFヘルパー:OpenCvHelper.cs – OpenCVSharp関連ヘルパー「グレースケール読み込み・2値化・範囲指定マスク生成」

コンピュータ

helpers/OpenCvHelper.cs

using OpenCvSharp;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace Maywork.WPF.Helpers;

public static partial class OpenCvHelper
{
    /// <summary>
    /// グレースケールで画像を読み込む
    /// </summary>
    public static Mat LoadGrayscale(string path)
        => Cv2.ImRead(path, ImreadModes.Grayscale);

    /// <summary>
    /// OpenCV Mat を WPF BitmapSource に変換
    /// </summary>
    public static BitmapSource ToBitmapSource(Mat mat)
    {
        if (mat.Empty())
            throw new ArgumentException("Mat is empty.");

        Mat converted = mat;

        // BGR → BGRA(WPFはBGRA推奨)
        if (mat.Type() == MatType.CV_8UC3)
        {
            converted = new Mat();
            Cv2.CvtColor(mat, converted, ColorConversionCodes.BGR2BGRA);
        }
        // Gray → BGRA
        else if (mat.Type() == MatType.CV_8UC1)
        {
            converted = new Mat();
            Cv2.CvtColor(mat, converted, ColorConversionCodes.GRAY2BGRA);
        }
        // すでにBGRAならそのまま
        else if (mat.Type() != MatType.CV_8UC4)
        {
            throw new NotSupportedException($"Unsupported Mat type: {mat.Type()}");
        }

        var bmp = BitmapSource.Create(
            converted.Width,
            converted.Height,
            96,
            96,
            PixelFormats.Bgra32,
            null,
            converted.Data,
            (int)converted.Step() * converted.Rows,
            (int)converted.Step());

        bmp.Freeze(); // UIスレッド外安全化

        if (!ReferenceEquals(converted, mat))
            converted.Dispose();

        return bmp;
    }
    /// <summary>
    /// 固定閾値で2値化する
    /// </summary>
    /// <param name="src">入力画像(グレースケール推奨)</param>
    /// <param name="threshold">閾値(0~255)</param>
    /// <param name="maxValue">白側の値(通常255)</param>
    public static Mat ThresholdBinary(Mat src, double threshold, double maxValue = 255)
    {
        if (src.Empty())
            throw new ArgumentException("Source image is empty.");

        // カラーならグレースケールに変換
        Mat gray = src;
        if (src.Channels() > 1)
        {
            gray = new Mat();
            Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
        }

        var dst = new Mat();
        Cv2.Threshold(gray, dst, threshold, maxValue, ThresholdTypes.Binary);

        if (!ReferenceEquals(gray, src))
            gray.Dispose();

        return dst;
    }

    /// <summary>
    /// 指定範囲の輝度を白(255)、それ以外を黒(0)にする
    /// </summary>
    /// <param name="src">入力画像(カラー可)</param>
    /// <param name="minValue">下限(0~255)</param>
    /// <param name="maxValue">上限(0~255)</param>
    public static Mat ThresholdRange(Mat src, byte minValue, byte maxValue)
    {
        if (src.Empty())
            throw new ArgumentException("Source image is empty.");

        if (minValue > maxValue)
            throw new ArgumentException("minValue must be <= maxValue.");

        // カラーならグレースケールへ
        Mat gray = src;
        if (src.Channels() > 1)
        {
            gray = new Mat();
            Cv2.CvtColor(src, gray, ColorConversionCodes.BGR2GRAY);
        }

        var mask = new Mat();

        // 指定範囲を255にする
        Cv2.InRange(gray, new Scalar(minValue), new Scalar(maxValue), mask);

        if (!ReferenceEquals(gray, src))
            gray.Dispose();

        return mask;
    }

}

/*
 // パッケージ導入
 dotnet add package OpenCvSharp4
 dotnet add package OpenCvSharp4.runtime.win

 // 使用例
using System.Windows.Media.Imaging;
using Maywork.WPF.Helpers;
using OpenCvSharp;

...

var path = @"C:\temp\test.jpg";

var result = await Task.Run(() =>
{
    // ① グレースケールで読み込み
    var mat = OpenCvHelper.LoadGrayscale(path);

    // ② 固定閾値2値化
    var binary = OpenCvHelper.ThresholdBinary(mat, 128);

    // ③ 範囲指定2値化
    var range = OpenCvHelper.ThresholdRange(mat, 100, 180);

    // WPF用に変換
    var bmpOriginal = OpenCvHelper.ToBitmapSource(mat);
    var bmpBinary   = OpenCvHelper.ToBitmapSource(binary);
    var bmpRange    = OpenCvHelper.ToBitmapSource(range);

    // 後始末
    mat.Dispose();
    binary.Dispose();
    range.Dispose();

    return (bmpOriginal, bmpBinary, bmpRange);
}); 

*/
Download

コメント