OpenCVSharp「膨張・収縮フィルタ(dilate, erode)」を試す。

コンピュータ
膨張・収縮フィルタのサンプル

実行環境構築

プロジェクトの作成

mkdir プロジェクト名
cd プロジェクト名
dotnet new winforms
dotnet add package OpenCvSharp4.Windows -v 4.6.0.20220608
dotnet add package OpenCvSharp4.Extensions -v 4.6.0.20220608
code .

ソースプログラム

namespace DilateErodeSample;

using OpenCvSharp;
using OpenCvSharp.Extensions;
public partial class Form1 : Form
{
    Mat? _view = null;

    public Form1()
    {
        InitializeComponent();

        Text = "膨張・収縮フィルタ";
        Size = new System.Drawing.Size(850, 800);

        // ベース画像
        var fnt = new Font("MS UI Gothic", 24);
        var bmp = new Bitmap(800, 600);
        using (var g = Graphics.FromImage(bmp))
        {
            g.FillRectangle(Brushes.White, 0, 0, bmp.Width, bmp.Height);
            g.DrawString("こちらにD&D", fnt,  Brushes.Green, 0.0f, 0.0f);
        }
        // スプリットコンテナ(上下)
        var ud = new SplitContainer
        {
            Dock = DockStyle.Fill,
            Orientation = Orientation.Horizontal,   // 上下
            Panel1MinSize = 120,
        };
        // ピクチャボックス
        var picbox = new PictureBox
        {
            SizeMode = PictureBoxSizeMode.Zoom,
            Dock = DockStyle.Fill,
            AllowDrop = true,
            Image = bmp,
        };
        // 実行ボタン
        var execBtn = new RadioButton
        {
            Text = "フィルターOFF",
            Appearance = Appearance.Button,
            AutoCheck = false,
            Size = new System.Drawing.Size(180, 50),
        };
        // 収縮フィルタ回数
        var dilateNLabel = new Label
        {
            Text = "収縮回数:1"
        };
        var dilateN = new TrackBar
        {
            Value = 1,
            Minimum = 0,
            Maximum = 5,
        };
        // 膨張フィルタ回数
        var erodeNLabel = new Label
        {
            Text = "膨張回数:1"
        };
        var erodeN = new TrackBar
        {
            Value = 1,
            Minimum = 0,
            Maximum = 5,
        };
        // パネル
        var flowPanel = new FlowLayoutPanel
        {
            Dock = DockStyle.Fill,
        };
        // ドラッグエンターイベント
        picbox.DragEnter += (sender, e) =>
        {
            if (e.Data == null) return;
            if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return;
            e.Effect = DragDropEffects.Copy;
        };
        // ドラッグアンドドロップイベント
        picbox.DragDrop += (sender, e) =>
        {
            if (e.Data == null) return;
            var fd = e.Data.GetData(DataFormats.FileDrop);
            if (fd == null) return;
            string? path = ((string[])fd)[0];
            _view?.Dispose();
            _view = Cv2.ImRead(path);
            picbox.Image?.Dispose();
            picbox.Image = BitmapConverter.ToBitmap(_view);
            execBtn.Checked = false;
        };
        // ボタンクリックイベント
        execBtn.Click += (sender, e) =>
        {
            if (_view is null) return;
            picbox.Image?.Dispose();
            if (execBtn.Checked == true)
            {
                picbox.Image = BitmapConverter.ToBitmap(_view);
                execBtn.Text = "フィルターOff";
                execBtn.Checked = false;
            } else {
                using (var img = new Mat()) 
                using (var element = Cv2.GetStructuringElement(MorphShapes.Ellipse, new OpenCvSharp.Size(3,3)))
                {
                    // RGB=>グレースケール
                    Cv2.CvtColor(_view, img, ColorConversionCodes.RGB2GRAY);
                    // 2値化
                    Cv2.Threshold(img, img, 127.0, 255.0, ThresholdTypes.Binary);
                    // 収縮
                    for(int i = 0; i < dilateN.Value; i++)
                        Cv2.Dilate(img, img, element);
                    // 膨張
                    for(int i = 0; i < erodeN.Value; i++)
                        Cv2.Erode(img, img, element);

                    picbox.Image = BitmapConverter.ToBitmap(img);
                }

                execBtn.Text = "フィルターOn";
                execBtn.Checked = true;
            }
        };
        // 収縮フィルタ回数変更イベント
        dilateN.ValueChanged += (s, e) =>
        {
            dilateNLabel.Text = string.Format("収縮回数:{0}", dilateN.Value);
        };
        // 膨張フィルタ回数変更イベント
        erodeN.ValueChanged += (s, e) =>
        {
            erodeNLabel.Text = string.Format("膨張回数:{0}", erodeN.Value);
        };
        // コントロールの追加
        ud.Panel1.Controls.Add(picbox);
        flowPanel.Controls.AddRange(new Control[]
        {
            execBtn,
            dilateNLabel,
            dilateN,
            erodeNLabel,
            erodeN,
        });
        ud.Panel2.Controls.Add(flowPanel);
        Controls.Add(ud);
    }
}

実行

dotnet run

画像ファイルをドラックアンドドロップ

フィルター実行:収縮0回膨張0回、グレースケール→2値化のみ

フィルター実行:収縮1回膨張1回、面積の小さな黒部分が白に置き換わっている。

フィルター実行:収縮1回膨張0回、黒部分が小さくなっている

フィルター実行:収縮0回膨張1回、黒部分が大きくなっている

コメント