当前位置:   article > 正文

C# OpenCvSharp 实现Reinhard颜色迁移算法

C# OpenCvSharp 实现Reinhard颜色迁移算法

C# OpenCvSharp 实现Reinhard颜色迁移算法

目录

效果

项目

代码

下载


效果

项目

Reinhard颜色迁移算法的步骤:
1、将参考图片和目标图片转换到LAB空间下
2、得到参考图片和目标图片的均值和标准差
3、对目标图片的每一个像素值,减去目标图像均值然后乘上参考图片和目标图片标准差的比值,再加上参考图像均值
4、将目标图片转换到RGB空间

代码

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 = "";

            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 mat3 = new Mat<Vec3b>(sc);
            var indexer = mat3.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";
            pictureBox2.Image = new Bitmap(sc.ToMemoryStream());

        }

        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);
            }
        }

    }
}
/*
Reinhard颜色迁移算法的过程
1、将参考图片和目标图片转换到LAB空间下
2、得到参考图片和目标图片的均值和标准差
3、对目标图片的每一个像素值,减去目标图像均值然后乘上参考图片和目标图片标准差的比值,再加上参考图像均值
4、将目标图片转换到RGB空间
 */

  1. using OpenCvSharp;
  2. using System;
  3. using System.Diagnostics;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.Windows.Forms;
  7. namespace OpenCvSharp_Demo
  8. {
  9. public partial class Form1 : Form
  10. {
  11. public Form1()
  12. {
  13. InitializeComponent();
  14. }
  15. string fileFilter = "选择图片|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
  16. string sc_image_path;
  17. string dc_image_path;
  18. Stopwatch stopwatch = new Stopwatch();
  19. private void Form1_Load(object sender, EventArgs e)
  20. {
  21. sc_image_path = "1.jpg";
  22. dc_image_path = "2.jpg";
  23. pictureBox1.Image = new Bitmap(sc_image_path);
  24. pictureBox3.Image = new Bitmap(dc_image_path);
  25. }
  26. private void button1_Click(object sender, EventArgs e)
  27. {
  28. OpenFileDialog ofd = new OpenFileDialog();
  29. ofd.Filter = fileFilter;
  30. if (ofd.ShowDialog() != DialogResult.OK) return;
  31. pictureBox1.Image = null;
  32. pictureBox2.Image = null;
  33. textBox1.Text = "";
  34. sc_image_path = ofd.FileName;
  35. pictureBox1.Image = new Bitmap(sc_image_path);
  36. }
  37. private void button4_Click(object sender, EventArgs e)
  38. {
  39. OpenFileDialog ofd = new OpenFileDialog();
  40. ofd.Filter = fileFilter;
  41. if (ofd.ShowDialog() != DialogResult.OK) return;
  42. pictureBox3.Image = null;
  43. pictureBox2.Image = null;
  44. textBox1.Text = "";
  45. dc_image_path = ofd.FileName;
  46. pictureBox3.Image = new Bitmap(dc_image_path);
  47. }
  48. private void button2_Click(object sender, EventArgs e)
  49. {
  50. if (sc_image_path == "")
  51. {
  52. return;
  53. }
  54. if (dc_image_path == "")
  55. {
  56. return;
  57. }
  58. stopwatch.Restart();
  59. Mat sc = Cv2.ImRead(sc_image_path, ImreadModes.Color);
  60. Cv2.CvtColor(sc, sc, ColorConversionCodes.BGR2Lab);
  61. Mat sc_m = new Mat();
  62. Mat sc_sd = new Mat();
  63. Cv2.MeanStdDev(sc, sc_m, sc_sd);
  64. Mat dc = Cv2.ImRead(dc_image_path, ImreadModes.Color);
  65. Cv2.CvtColor(dc, dc, ColorConversionCodes.BGR2Lab);
  66. Mat dc_m = new Mat();
  67. Mat dc_sd = new Mat();
  68. Cv2.MeanStdDev(dc, dc_m, dc_sd);
  69. var mat3 = new Mat<Vec3b>(sc);
  70. var indexer = mat3.GetIndexer();
  71. for (int y = 0; y < sc.Height; y++)
  72. {
  73. for (int x = 0; x < sc.Width; x++)
  74. {
  75. Vec3b color = indexer[y, x];
  76. byte temp = color.Item0;
  77. 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);
  78. dtemp = Math.Round(dtemp);
  79. if (dtemp < 0)
  80. {
  81. dtemp = 0;
  82. }
  83. else if (dtemp > 255)
  84. {
  85. dtemp = 255;
  86. }
  87. byte temp1 = color.Item1;
  88. 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)));
  89. dtemp1 = Math.Round(dtemp1);
  90. if (dtemp1 < 0)
  91. {
  92. dtemp1 = 0;
  93. }
  94. else if (dtemp1 > 255)
  95. {
  96. dtemp1 = 255;
  97. }
  98. byte temp2 = color.Item2;
  99. 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)));
  100. dtemp2 = Math.Round(dtemp2);
  101. if (dtemp2 < 0)
  102. {
  103. dtemp2 = 0;
  104. }
  105. else if (dtemp2 > 255)
  106. {
  107. dtemp2 = 255;
  108. }
  109. color.Item0 = (byte)dtemp;
  110. color.Item1 = (byte)dtemp1;
  111. color.Item2 = (byte)dtemp2;
  112. indexer[y, x] = color;
  113. }
  114. }
  115. Cv2.CvtColor(sc, sc, ColorConversionCodes.Lab2BGR);
  116. double costTime = stopwatch.Elapsed.TotalMilliseconds;
  117. textBox1.Text = $"耗时:{costTime:F2}ms";
  118. pictureBox2.Image = new Bitmap(sc.ToMemoryStream());
  119. }
  120. private void button3_Click(object sender, EventArgs e)
  121. {
  122. if (pictureBox2.Image == null)
  123. {
  124. return;
  125. }
  126. Bitmap output = new Bitmap(pictureBox2.Image);
  127. var sdf = new SaveFileDialog();
  128. sdf.Title = "保存";
  129. sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp";
  130. if (sdf.ShowDialog() == DialogResult.OK)
  131. {
  132. switch (sdf.FilterIndex)
  133. {
  134. case 1:
  135. {
  136. output.Save(sdf.FileName, ImageFormat.Jpeg);
  137. break;
  138. }
  139. case 2:
  140. {
  141. output.Save(sdf.FileName, ImageFormat.Png);
  142. break;
  143. }
  144. case 3:
  145. {
  146. output.Save(sdf.FileName, ImageFormat.Bmp);
  147. break;
  148. }
  149. }
  150. MessageBox.Show("保存成功,位置:" + sdf.FileName);
  151. }
  152. }
  153. }
  154. }
  155. /*
  156. Reinhard颜色迁移算法的过程
  157. 1、将参考图片和目标图片转换到LAB空间下
  158. 2、得到参考图片和目标图片的均值和标准差
  159. 3、对目标图片的每一个像素值,减去目标图像均值然后乘上参考图片和目标图片标准差的比值,再加上参考图像均值
  160. 4、将目标图片转换到RGB空间
  161. */

下载

源码下载

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/817037
推荐阅读
相关标签
  

闽ICP备14008679号