C#のWinFormsで画像加工アプリ5「LUTによる減色」

コンピュータ

LUTを使って減色処理を行います。

ソースコード

ファイル名:Form1.DietColor.cs(新規追加)

using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace GazouKakou02;
public partial class Form1 : Form
{
    // メニュー項目
    readonly ToolStripMenuItem dietColorMenuItem = new()
    {
        Text = "減色",
    };
    
    /// <summary>
    /// 減色の初期化
    /// </summary>
    public void Init_DietColor()
    {
        // メニューの登録
        filterMenuItem.DropDownItems.Add(dietColorMenuItem);

        // フィルター(減色)
        Func<Bitmap, int, Task<Bitmap>> filter = new(async (src, n) =>
        {
            return await Task.Run(()=>
            {
                using Mat srcMat = BitmapConverter.ToMat(src);
                using Mat dstMat = new();

                byte[] lut = new byte[256];
                int x = lut.Length;
                int div = x / n;
                int min = 0;
                int max = x - 1;
                int center = x / 2;
                for(int i=0; i < lut.Length; i++)
                {
                    int a = i / div;
                    int b;

                    if (i < center)
                    {
                        b = a * div - 1;
                    } else {
                        b = (a + 1) * div - 1;
                    }
                    b = (b < min) ? min : b;
                    b = (b > max) ? max : b;

                    lut[i] = (byte)b;
                }
                Cv2.LUT(srcMat, lut, dstMat);

                return BitmapConverter.ToBitmap(dstMat);
            });
        });

        // メニューアイテムのクリックイベント
        dietColorMenuItem.Click += (s, e) =>
        {
            if (_buffBmp is null) return;

            var dialog = new FilterDialog();

            dialog.Load += (s, e) =>
            {
                dialog.Track1.Value = 8;
                dialog.Track1.Maximum = 256;
                dialog.Track1.Minimum = 1;
            };

            bool filterFlag = false;
            Bitmap? bmp = null;
            dialog.Track1.ValueChanged += async (s, e) =>
            {
                dialog.Track1Label.Text = string.Format("n:{0}", dialog.Track1.Value);
                if (filterFlag)
                {
                    // フィルター実行中につきキャンセル
                    return;
                }

                filterFlag = true;
                dialog.OkBtn.Enabled = !filterFlag;
                var backupValue = dialog.Track1.Value;
                var currentValue = backupValue;
                do
                {
                    backupValue = currentValue;

                    int n = currentValue;
                    bmp = await filter(_buffBmp, n);
                    dialog.Picbox.Image?.Dispose();
                    dialog.Picbox.Image = bmp;

                    currentValue = dialog.Track1.Value;
                } while( currentValue != backupValue);

                filterFlag = false;
                dialog.OkBtn.Enabled = !filterFlag;
            };

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                // OK
                this.Bmp = bmp;
            } else {
                // Cancel
                bmp?.Dispose();
            }
        };
    }
}

実行

画像が表示されている状態でメインメニュー「フィルター」→「減色」を選ぶ

注)グレースケールでの動作を想定してるのでカラー画像での場合動作は未確認

解説

OpenCVにはk-means法を使った減色用のメソッドがあるのですが、OpenCVSharpでの使い方を筆者は理解していません。
ということで、今回はLUTを使い減色処理を行ってみました。LUTで色を置き換えるテーブルを減色されるように値をセットしてあります。
アルゴリズムとしては0~255の数字に対して減色したい色数を割り算して求めています。ただし、最小値が0最大値が255になるように調整しており、指定の色数を超える可能性があります。

コメント