C#图形处理系列(三)——霓虹处理、浮雕处理
霓虹处理与浮雕处理算法有共同之处,都是像素及邻近像素直接关系运算,因此放到一起写。
霓虹处理
关于霓虹灯的效果,不知道的可以baidu图片里面看看。
霓虹处理算法:同样以3*3的点阵为例,目标像素g(i,j)应当以f(i,j)与f(i,j+1),f(i,j)与f(i+1,j)的梯度作为R,G,B分量,我们不妨设f(i,j)的RGB分量为(r1, g1, b1), f(i,j+1)为(r2, g2, b2), f(i+1,j)为(r3, g3, b3), g(i, j)为(r, g, b),那么结果应该为
r = 2 * sqrt( (r1 - r2)^2 + (r1 - r3)^2 )
g = 2 * sqrt( (g1 - g2)^2 + (g1 - g3)^2 )
b = 2 * sqrt( (b1 - b2)^2 + (b1 - b3)^2 )
f(i,j)=2*sqrt[(f(i,j)-f(i+1,j))^2+(f(i,j)-f(,j+1))^2]
/// <summary>
/// 霓虹处理
/// </summary>
public class NeonImage : IImageProcessable
{
public void ProcessBitmap(Bitmap bmp)
{
int width = bmp.Width;
int height = bmp.Height;
for (int i = 0; i < width - 1; i++)//注意边界的控制
{
for (int j = 0; j < height - 1; j++)
{
Color cc1 = bmp.GetPixel(i, j);
Color cc2 = bmp.GetPixel(i, j + 1);
Color cc3 = bmp.GetPixel(i + 1, j);
int rr = 2 * (int)Math.Sqrt((cc3.R - cc1.R) * (cc3.R - cc1.R) + (cc2.R - cc1.R) * (cc2.R - cc1.R));
int gg = 2 * (int)Math.Sqrt((cc3.G - cc1.G) * (cc3.G - cc1.G) + (cc2.G - cc1.G) * (cc2.G - cc1.G));
int bb = 2 * (int)Math.Sqrt((cc3.B - cc1.B) * (cc3.B - cc1.B) + (cc2.B - cc1.B) * (cc2.B - cc1.B));
if (rr > 255) rr = 255;
if (gg > 255) gg = 255;
if (bb > 255) bb = 255;
bmp.SetPixel(i, j, Color.FromArgb(rr, gg, bb));
}
}
}
#region IImageProcessable 成员
public unsafe void UnsafeProcessBitmap(Bitmap bmp)
{
int width = bmp.Width;
int height = bmp.Height;
Rectangle rect = new Rectangle(0, 0, width, height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
byte* ptr = (byte*)(bmpData.Scan0);
for (int i = 0; i < height-1; i++)
{
for (int j = 0; j < width-1; j++)
{
byte bb=(byte)(2 * Math.Sqrt((ptr[4]-ptr[0])*(ptr[4]-ptr[0]))+(ptr[bmpData.Stride]-ptr[0])*(ptr[bmpData.Stride]-ptr[0]));//b;
byte gg = (byte)(2 * Math.Sqrt((ptr[5] - ptr[1]) * (ptr[5] - ptr[1])) + (ptr[bmpData.Stride+1] - ptr[1]) * (ptr[bmpData.Stride+1] - ptr[1]));//g
byte rr = (byte)(2 * Math.Sqrt((ptr[6] - ptr[2]) * (ptr[6] - ptr[2])) + (ptr[bmpData.Stride+2] - ptr[2]) * (ptr[bmpData.Stride+2] - ptr[2]));//r
if (rr > 255) rr = 255;
if (gg > 255) gg = 255;
if (bb > 255) bb = 255;
ptr[0] = bb;
ptr[1] = gg;
ptr[2] = rr;
ptr += 4;
}
ptr += bmpData.Stride - width * 4;
}
bmp.UnlockBits(bmpData);
}
#endregion
}
浮雕处理
浮雕处理原理: 通过对图像像素点的像素值与相邻像素点的像素值相减后加上一个常数(一般为128), 然后作为新的像素点的值.
/********************************************************************
*
* 浮雕处理原理:通过对图像像素点的像素值与相邻像素点的像素值相减后加上128, 然后作为新的像素点的值...
* g(i,j)=f(i,i)-f(i+1,j)+128
*
* ******************************************************************/
/// <summary>
/// 浮雕处理
/// </summary>
public class ReliefImage:IImageProcessable
{
public void ProcessBitmap(System.Drawing.Bitmap bmp)
{
int width = bmp.Width;
int height = bmp.Height;
for (int i = 0; i < width-1; i++)//注意控制边界 相邻元素 i+1=width
{
for (int j = 0; j < height; j++)
{
Color c1 = bmp.GetPixel(i, j);
Color c2 = bmp.GetPixel(i + 1, j);//相邻的像素
int rr = c1.R - c2.R + 128;
int gg = c1.G - c2.G + 128;
int bb = c1.B - c2.B + 128;
//处理溢出
if (rr > 255) rr = 255;
if (rr < 0) rr = 0;
if (gg > 255) gg = 255;
if (gg < 0) gg = 0;
if (bb > 255) bb = 255;
if (bb < 0) bb = 0;
bmp.SetPixel(i,j,Color.FromArgb(rr,gg,bb));
}
}
}
#region IImageProcessable 成员
public unsafe void UnsafeProcessBitmap(Bitmap bmp)
{
int width = bmp.Width;
int height = bmp.Height;
Rectangle rect = new Rectangle(0, 0, width, height);
BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
byte* ptr = (byte*)(bmpData.Scan0);
int rr = 0,gg=0,bb=0;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width-1; j++)
{
bb =(ptr[0] - ptr[4] + 128);//B
gg = (ptr[1] - ptr[5] + 128);//G
rr = (ptr[2] - ptr[6] +128); ;//R
//处理溢出
if (rr > 255) rr = 255;
if (rr < 0) rr = 0;
if (gg > 255) gg = 255;
if (gg < 0) gg = 0;
if (bb > 255) bb = 255;
if (bb < 0) bb = 0;
ptr[0] = (byte)bb;
ptr[1] = (byte)gg;
ptr[2] = (byte)rr;
ptr += 4;
}
ptr += bmpData.Stride - width * 4;
}
bmp.UnlockBits(bmpData);
}
#endregion
}
从图里面可以看出,浮雕处理并没有让图片“失真”,尽管处理成浮雕了,浮雕仍然很清晰。公式中为什么是128,可以用其他常数试试就知道了,如果过小,则图片偏黑色,如果
过大,则图片偏白色,128刚好。