• C#如何实现Reinhard颜色迁移算法
  • 发布于 2个月前
  • 269 热度
    0 评论
介绍
代码实现参考:https://github.com/chia56028/Color-Transfer-between-Images
论文地址:https://www.cs.tau.ac.il/~turkel/imagepapers/ColorTransfer.pdf
Reinhard颜色迁移算法的过程:
1、将参考图片和目标图片转换到LAB空间下。
2、得到参考图片和目标图片的均值和标准差。
3、对目标图片的每一个像素值,减去目标图像均值然后乘上参考图片和目标图片标准差的比值,再加上参考图像均值。
4、将目标图片转换到RGB空间。

效果

开发环境
VS2022
.net framework 4.8
OpenCvSharp 4.8

代码
using OpenCvSharp;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

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

        string fileFilter = "选择图片|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
        string sc_image_path;
        string dc_image_path;

        Stopwatch stopwatch = new Stopwatch();

        private void Form1_Load(object sender, EventArgs e)
        {
            sc_image_path = "1.jpg";
            dc_image_path = "2.jpg";

            pictureBox1.Image = new Bitmap(sc_image_path);
            pictureBox3.Image = new Bitmap(dc_image_path);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;

            pictureBox1.Image = null;
            pictureBox2.Image = null;
            textBox1.Text = "";

            sc_image_path = ofd.FileName;
            pictureBox1.Image = new Bitmap(sc_image_path);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = fileFilter;
            if (ofd.ShowDialog() != DialogResult.OK) return;

            pictureBox3.Image = null;
            pictureBox2.Image = null;
            textBox1.Text = "";
            // 堆代码 duidaima.com
            dc_image_path = ofd.FileName;
            pictureBox3.Image = new Bitmap(dc_image_path);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (sc_image_path == "")
            {
                return;
            }

            if (dc_image_path == "")
            {
                return;
            }

            stopwatch.Restart();

            Mat sc = Cv2.ImRead(sc_image_path, ImreadModes.Color);
            Cv2.CvtColor(sc, sc, ColorConversionCodes.BGR2Lab);
            Mat sc_m = new Mat();
            Mat sc_sd = new Mat();
            Cv2.MeanStdDev(sc, sc_m, sc_sd);

            Mat dc = Cv2.ImRead(dc_image_path, ImreadModes.Color);
            Cv2.CvtColor(dc, dc, ColorConversionCodes.BGR2Lab);
            Mat dc_m = new Mat();
            Mat dc_sd = new Mat();
            Cv2.MeanStdDev(dc, dc_m, dc_sd);

            var matTemp = new Mat<Vec3b>(sc);
            var indexer = matTemp.GetIndexer();

            for (int y = 0; y < sc.Height; y++)
            {
                for (int x = 0; x < sc.Width; x++)
                {
                    Vec3b color = indexer[y, x];

                    byte temp = color.Item0;
                    double dtemp = (temp - sc_m.At<double>(0, 0)) * (dc_sd.At<double>(0, 0) / sc_sd.At<double>(0, 0)) + dc_m.At<double>(0, 0);
                    dtemp = Math.Round(dtemp);
                    if (dtemp < 0)
                    {
                        dtemp = 0;
                    }
                    else if (dtemp > 255)
                    {
                        dtemp = 255;
                    }

                    byte temp1 = color.Item1;
                    double dtemp1 = ((byte)((temp1 - sc_m.At<double>(0, 1)) * (dc_sd.At<double>(0, 1) / sc_sd.At<double>(0, 1)) + dc_m.At<double>(0, 1)));
                    dtemp1 = Math.Round(dtemp1);
                    if (dtemp1 < 0)
                    {
                        dtemp1 = 0;
                    }
                    else if (dtemp1 > 255)
                    {
                        dtemp1 = 255;
                    }

                    byte temp2 = color.Item2;
                    double dtemp2 = ((byte)((temp2 - sc_m.At<double>(0, 2)) * (dc_sd.At<double>(0, 2) / sc_sd.At<double>(0, 2)) + dc_m.At<double>(0, 2)));
                    dtemp2 = Math.Round(dtemp2);
                    if (dtemp2 < 0)
                    {
                        dtemp2 = 0;
                    }
                    else if (dtemp2 > 255)
                    {
                        dtemp2 = 255;
                    }

                    color.Item0 = (byte)dtemp;
                    color.Item1 = (byte)dtemp1;
                    color.Item2 = (byte)dtemp2;

                    indexer[y, x] = color;
                }
            }

            Cv2.CvtColor(sc, sc, ColorConversionCodes.Lab2BGR);

            double costTime = stopwatch.Elapsed.TotalMilliseconds;

            textBox1.Text = $"耗时:{costTime:F2}ms";
            if (pictureBox2.Image != null)
            {
                pictureBox2.Image.Dispose();
            }
            pictureBox2.Image = new Bitmap(sc.ToMemoryStream());

            sc.Dispose();
            matTemp.Dispose();
            dc_m.Dispose();
            dc_sd.Dispose();
            dc.Dispose();
            sc_m.Dispose();
            sc_sd.Dispose();
            sc.Dispose();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (pictureBox2.Image == null)
            {
                return;
            }
            Bitmap output = new Bitmap(pictureBox2.Image);
            var sdf = new SaveFileDialog();
            sdf.Title = "保存";
            sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp";
            if (sdf.ShowDialog() == DialogResult.OK)
            {
                switch (sdf.FilterIndex)
                {
                    case 1:
                        {
                            output.Save(sdf.FileName, ImageFormat.Jpeg);
                            break;
                        }
                    case 2:
                        {
                            output.Save(sdf.FileName, ImageFormat.Png);
                            break;
                        }
                    case 3:
                        {
                            output.Save(sdf.FileName, ImageFormat.Bmp);
                            break;
                        }
                }
                MessageBox.Show("保存成功,位置:" + sdf.FileName);
            }
        }

    }
}

用户评论