C#のWinFormsで画像加工アプリ6「LUTによるガンマ補正」

コンピュータ

LUTを使ってガンマ補正を行います。

ソースコード

ファイル名:Form1.cs(前回の記事のソースコードに追加)

    // ガンマ補正(Form1のメンバーとして追加)
    readonly ToolStripMenuItem gammaMenuItem = new()
    {
        Text = "ガンマ補正",
    };
        // ガンマ補正(Form1のコンストラクタに追加)
        filterMenuItem.DropDownItems.Add(gammaMenuItem);
        gammaMenuItem.Click += (s, e) =>
        {
            if (_buffBmp is null) return;
            Bitmap? bmp = GammaDialog(_buffBmp);
            if (bmp is not null)
            {
                this.Bmp = bmp;
                mainPicbox.Image = this.Bmp;
            }
        };

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

using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace GazouKakou01;
public partial class Form1 : Form
{
    public static Bitmap? GammaDialog(Bitmap src)
    {
        const string filterName = "ガンマ補正";

        Form frm = new Form
        {
            FormBorderStyle = FormBorderStyle.FixedDialog,
            ClientSize = new System.Drawing.Size(640, 480),
            Text = filterName,
        };
        Label lbl = new Label
        {
            Size = new System.Drawing.Size(600, 60),
            Location = new System.Drawing.Point(10, 10),
            Text = filterName,
        };
        lbl.Parent = frm;
        PictureBox picbox = new()
        {
            Size = new System.Drawing.Size(600, 320),
            Location = new System.Drawing.Point(10, 70),
            Parent = frm,
        };
        Button okBtn = new Button
        {
            Size = new System.Drawing.Size(80,40),
            Location = new System.Drawing.Point(10, 410),
            Text = "OK",
            DialogResult = DialogResult.OK,
        };
        okBtn.Parent = frm;
        Button cancelBtn = new Button
        {
            Size = new System.Drawing.Size(80,40),
            Location = new System.Drawing.Point(100, 410),
            Text = "Cancel",
            DialogResult = DialogResult.Cancel,
        };
        cancelBtn.Parent = frm;

        frm.AcceptButton = okBtn;
        frm.CancelButton = cancelBtn;

        Label label1 = new()
        {
            Size = new System.Drawing.Size(120,40),
            Location = new System.Drawing.Point(190, 410),
            Parent = frm,
        };
        TrackBar track1 = new()
        {
            Minimum = 0,
            Maximum = 100,
            Value = 0,
            TickFrequency = 1,
            SmallChange = 1,
            LargeChange = 10,
            Size = new System.Drawing.Size(100,40),
            Location = new System.Drawing.Point(320, 410),
            Parent = frm,
        };

        // mat変換
        var srcMat = BitmapConverter.ToMat(src);


        // ガンマ補正
        bool filterExecFlag = false;
        Func<Mat, double, Mat> filter = new((src, gamma)=>
        {
            filterExecFlag = true;
            Mat dst = new();

            byte[] lut = new byte[256];
            for(int i=0; i < lut.Length; i++)
            {
                if (gamma == 0.0d)
                    lut[i] = (byte)i;
                else
                    lut[i] = (byte)(System.Math.Pow((double)(i / 255.0d), 1.0d / gamma) * 255.0d);
            }
            Cv2.LUT(src, lut, dst);

            filterExecFlag = false;
            return dst;
        });
        track1.ValueChanged += async (s, e) =>
        {
            Mat? dstMat = null;
            double gamma = (double)track1.Value / 10.0d;
            label1.Text = String.Format("ガンマ{0}", gamma);

            if (filterExecFlag) return;

            double backupValue;
            do {
                backupValue = gamma;
                dstMat?.Dispose();
                dstMat = await Task.Run(()=> filter(srcMat, gamma));
                gamma = (double)track1.Value / 10.0d;
            } while (backupValue != gamma);
            
            picbox.Image?.Dispose();
            picbox.Image = BitmapConverter.ToBitmap(dstMat);
            dstMat?.Dispose();
        };
        
        frm.Load += (s, e) =>
        {
            track1.Value = 6;
        };

        if (frm.ShowDialog() == DialogResult.Cancel)
        {
            return null;
        } else {
            return (Bitmap)picbox.Image;
        }
    }
}

実行

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

コメント