2015年8月26日水曜日

C#で熱画像っぽい色合いを作る



昔の熱画像風ではなく、FLIRの熱画像風の色合いになってる。また上半分は結構のっぺりした感じになってる。これは赤と緑が早々と飽和してしまうため。
ウインドウ内、上は0-1の熱画像風、下は各色の割合を表示している。また下のウインドウは上のそれをPaint.netで白黒化したものとなる。それとデコボコしながら右肩上がりになっているグラフはRGBを輝度に近似したグラフとなっている。デコボコして入るが、一応右肩上がりになっているので白黒化してもBk-Whで変化しているのがわかると思う。
この熱画像風化では内部でサインテーブルを使用している(Math.Sinを使用)。そのために計算コストはかなり高いものとなっている。また画像を見てもわかるとおりに青は綺麗に増加させているわけではないため、多数の浮動小数点演算が行われる。今回はPCでちょっと使いたかったのでこのようになっているが、マイコンで使うにはかなり大変だろう。



using System;
using System.Drawing;
using System.Windows.Forms;

namespace ThermalColor
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            MaximumSize = MinimumSize = Size;

            Bitmap bmp = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            pictureBox1.Image = bmp;

            using (Graphics gra = Graphics.FromImage(bmp))
            {
                for (int x = 0; x < bmp.Width; x++)
                {
                    double Value = (double)x / bmp.Width;
                    Color clr = ThermalColor(Value);

                    using (Pen pen = new Pen(clr))
                    { gra.DrawLine(pen, x, 0, x, bmp.Height); }
                }
            }

            bmp = new Bitmap(pictureBox2.Width, pictureBox2.Height);
            pictureBox2.Image = bmp;

            DrawGraph();
        }

        private void DrawGraph()
        {
            Bitmap bmp = (Bitmap)pictureBox2.Image;

            using (Graphics gra = Graphics.FromImage(bmp))
            { gra.Clear(Color.Black); }

            double d = 255.0 / bmp.Height;

            for (int x = 0; x < bmp.Width; x++)
            {
                double Value = (double)x / bmp.Width;
                Color clr = ThermalColor(Value);
                int y;

                y = bmp.Height - (int)(clr.R / d);
                if (y < 0) { y = 0; }
                if (y >= bmp.Height) { y = bmp.Height - 1; }
                bmp.SetPixel(x, y, Color.Red);


                y = bmp.Height - (int)(clr.G / d);
                if (y < 0) { y = 0; }
                if (y >= bmp.Height) { y = bmp.Height - 1; }
                bmp.SetPixel(x, y, Color.Green);


                y = bmp.Height - (int)(clr.B / d);
                if (y < 0) { y = 0; }
                if (y >= bmp.Height) { y = bmp.Height - 1; }
                bmp.SetPixel(x, y, Color.Blue);

                y = bmp.Height - (int)((clr.R * 0.3 + clr.G * 0.6 + clr.B * 0.1) / d);
                if (y < 0) { y = 0; }
                if (y >= bmp.Height) { y = bmp.Height - 1; }
                bmp.SetPixel(x, y, Color.Wheat);
            }

            pictureBox2.Refresh();
        }

        Color ThermalColor(double Value)
        {
            double Rf = 0, Gf = 0, Bf = 0;

            Rf = Value * 2;
            Gf = (Value - 0.25) * 2;

            if (Value <= 0.5)
            {
                if (Value < 0.25)
                {
                    Bf = Value * 4;
                }
                else
                {
                    Bf = 2 - Value * 4;
                }
            }
            else
            {
                Bf = (Value - 0.75) * 4;
            }

            if (Rf >= 0 && Rf <= 1) { Rf = Math.Sin(Rf * Math.PI / 2); }
            if (Gf >= 0 && Gf <= 1) { Gf = Math.Sin(Gf * Math.PI / 2); }
            if (Bf >= 0 && Bf <= 1) { Bf = Math.Sin(Bf * Math.PI / 2); }

            int R = (int)(Rf * 255);
            int G = (int)(Gf * 255);
            int B = (int)(Bf * 255);

            if (R < 0) { R = 0; }
            if (R > 255) { R = 255; }

            if (G < 0) { G = 0; }
            if (G > 255) { G = 255; }

            if (B < 0) { B = 0; }
            if (B > 255) { B = 255; }

            return (Color.FromArgb(R, G, B));
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            Point cp = pictureBox1.PointToClient(Cursor.Position);

            Color clr = ((Bitmap)pictureBox1.Image).GetPixel(cp.X, cp.Y);

            using (Graphics gra = Graphics.FromImage((Bitmap)pictureBox2.Image))
            { gra.Clear(clr); }

            Text =
                clr.R.ToString("000") + "," +
                clr.G.ToString("000") + "," +
                clr.B.ToString("000") +
                ((double)cp.X / pictureBox1.Width).ToString(" @ 0.000");

            pictureBox2.Refresh();
        }

        private void pictureBox1_MouseLeave(object sender, EventArgs e)
        {
            DrawGraph();
        }
    }
}

0 件のコメント:

コメントを投稿