C#实现图片曲线调整效果
另外按业务逻辑,应该在每加入一个新的曲线上的点,就更新原始图片和曲线图片,所以可以使用图片容器的鼠标事件。本文在求得曲线的X-Y关系时,采用了指定X查找该列上颜色点对应的Y的值的方法,这种方法依赖于先绘制好图像后才可以使用。如果不依赖这种方式还可以使用插值法等方式,因为X-Y关系是个曲线,因此插值不是简单的线性插值,计算会更加复杂。除了RGB通道可以这样用曲线操作,将图像转为HSV(HSL)图像后
项目背景
最近好友分享了OpenCV实现Photoshop算法-曲线调整的文章,然后就有人在问是否可以通过C#实现。在此分享一下如何使用纯C#代码,不依赖第三方库如何实现。
基本效果如下
基本思路
使用曲线控制图像的效果的原理,可以参考用OpenCV实现Photoshop算法(三): 曲线调整,本文就不在过多赘述。本文主要提供如何通过C#实现。
本项目主要分成两个部分:1、曲线绘制和X-Y对应值求法;2、X-Y对应关系如何作用于原图片。
主要模块——Curve
本模块主要的作用是绘制曲线和存储X-Y的对应关系。为了能够快速使用这个关系,可以生成一个数组保存这个关系,这样加快整个图像的生成。
代码如下:其中Bitmap用于返回绘制好的曲线,Result用于存储曲线上X-Y的对应关系。绘制曲线使用了Graphics,这种方法为C#自带的,不需要引入第三方依赖。
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace Curves
{
public class Curve
{
private List<Point> points = new List<Point>();
private int[] result = new int[256];
private Bitmap bitmap = new Bitmap(256, 256);
public int[] Result
{
get
{
return result;
}
}
public Bitmap Bitmap
{
get
{
return bitmap;
}
}
public Curve()
{
points.Add(new Point(0, 0));
points.Add(new Point(255, 255));
DrawCurve();
GetResult();
}
public void AddPoint(Point point)
{
points.Add(point);
points = points.OrderBy(p => p.X).ToList();
DrawCurve();
GetResult();
}
private int GetYValue(Bitmap bitmap, int x)
{
for (int i = 0; i < bitmap.Height; i++)
{
Color color = bitmap.GetPixel(x, i);
if (color.B == 255)
{
return i;
}
}
return 0;
}
private void GetResult()
{
for (int i = 0; i < 256; i++)
{
result[i] = GetYValue(bitmap, i);
}
result[255] = 255;
}
public void DrawCurve()
{
bitmap = new Bitmap(256, 256);
using (Graphics g = Graphics.FromImage(bitmap))
{
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
Pen pen = new Pen(Color.Blue, 2);
g.DrawCurve(pen, points.ToArray());
g.Save();
}
}
}
}
曲线图片控制模块
图片控制部分的思路是将Bitmap图片转为数组,对数组中的元素进行操作,以此加快处理速度。数组存储颜色信息时排布为RGB形式。因此处理不同的颜色通道,只需要操作对应的部分即可。另外按业务逻辑,应该在每加入一个新的曲线上的点,就更新原始图片和曲线图片,所以可以使用图片容器的鼠标事件。核心代码如下:
private void pictureBox2_MouseUp(object sender, MouseEventArgs e)
{
curve.AddPoint(e.Location);
pictureBox2.Image = curve.Bitmap;
Bitmap bmp = pictureBox1.Image as Bitmap;
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
byte[] data = new byte[bitmapData.Stride * bitmapData.Height];
Marshal.Copy(bitmapData.Scan0, data, 0, data.Length);
for (int i = 0; i < data.Length; i = i + 3)
{
data[i] = (byte)curve.Result[data[i]];
}
Marshal.Copy(data, 0, bitmapData.Scan0, data.Length);
bmp.UnlockBits(bitmapData);
pictureBox1.Image = bmp;
}
功能拓展
除了RGB通道可以这样用曲线操作,将图像转为HSV(HSL)图像后,也可以对图像的色相、明度、饱和度进行调整,实现更多类似Photoshop的功能。
功能不足
本文在求得曲线的X-Y关系时,采用了指定X查找该列上颜色点对应的Y的值的方法,这种方法依赖于先绘制好图像后才可以使用。如果不依赖这种方式还可以使用插值法等方式,因为X-Y关系是个曲线,因此插值不是简单的线性插值,计算会更加复杂。
项目下载链接
更多推荐
所有评论(0)