[C#] 濾鏡筆記 – 漣漪效果
2012-12-04
最近一些需求我要用到漣漪效果,讓文字變得讓機器人看不懂..
就是要歪七扭八,也就是要將圖片給液態化..
其中會用到比較多的數學跟演算方法
關於相關數學範例可以參考:
http://marlongrech.wordpress.com/2009/08/27/playing-with-shaders-creating-a-water-effect/
http://www.codeproject.com/Articles/2812/A-C-water-effect-picture-control
http://www.aforgenet.com/framework/docs/html/6f6ba0e1-cc41-0277-c856-598089b4ed02.htm
http://www.codeproject.com/Articles/3419/Image-Processing-for-Dummies-with-C-and-GDI-Part-5
整理過上述網站的Code 寫成一隻function 給有需要的人..
/// <summary>
/// 水波紋效果
/// </summary>
/// <param name="src"></param>
/// <param name="nWave">坡度</param>
/// <returns></returns>
public Bitmap AdjustRippleEffect(Bitmap src, short nWave)
{
int nWidth = src.Width;
int nHeight = src.Height;
// 透過公式進行水波紋的採樣
FloatPoint[,] fp = new FloatPoint[nWidth, nHeight];
Point[,] pt = new Point[nWidth, nHeight];
Point mid = new Point();
mid.X = nWidth / 2;
mid.Y = nHeight / 2;
double newX, newY;
double xo, yo;
//先取樣將水波紋座標跟RGB取出
for (int x = 0; x < nWidth; ++x)
for (int y = 0; y < nHeight; ++y)
{
xo = ((double)nWave * Math.Sin(2.0 * 3.1415 * (float)y / 128.0));
yo = ((double)nWave * Math.Cos(2.0 * 3.1415 * (float)x / 128.0));
newX = (x + xo);
newY = (y + yo);
if (newX > 0 && newX < nWidth)
{
fp[x, y].X = newX;
pt[x, y].X = (int)newX;
}
else
{
fp[x, y].X = 0.0;
pt[x, y].X = 0;
}
if (newY > 0 && newY < nHeight)
{
fp[x, y].Y = newY;
pt[x, y].Y = (int)newY;
}
else
{
fp[x, y].Y = 0.0;
pt[x, y].Y = 0;
}
}
//進行合成
Bitmap bSrc = (Bitmap)src.Clone();
// 依照 Format24bppRgb 每三個表示一 Pixel 0: 藍 1: 綠 2: 紅
BitmapData bitmapData = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);
BitmapData bmSrc = bSrc.LockBits(new Rectangle(0, 0, bSrc.Width, bSrc.Height), ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);
int scanline = bitmapData.Stride;
IntPtr Scan0 = bitmapData.Scan0;
IntPtr SrcScan0 = bmSrc.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
byte* pSrc = (byte*)(void*)SrcScan0;
int nOffset = bitmapData.Stride - src.Width * 3;
int xOffset, yOffset;
for (int y = 0; y < nHeight; ++y)
{
for (int x = 0; x < nWidth; ++x)
{
xOffset = pt[x, y].X;
yOffset = pt[x, y].Y;
if (yOffset >= 0 && yOffset < nHeight && xOffset >= 0 && xOffset < nWidth)
{
p[0] = pSrc[(yOffset * scanline) + (xOffset * 3)];
p[1] = pSrc[(yOffset * scanline) + (xOffset * 3) + 1];
p[2] = pSrc[(yOffset * scanline) + (xOffset * 3) + 2];
}
p += 3;
}
p += nOffset;
}
}
src.UnlockBits(bitmapData);
bSrc.UnlockBits(bmSrc);
return src;
}
public struct FloatPoint
{
public double X;
public double Y;
}
原圖:
效果:
Bitmap bmpSrc = new Bitmap(Server.MapPath("sample.png"));
var result = AdjustRippleEffect(bmpSrc, 5);
Bitmap bmpSrc = new Bitmap(Server.MapPath("sample.png"));
var result = AdjustRippleEffect(bmpSrc, 10);