⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 effect.extend.cs

📁 一个C#开发的类似PHOTOSHOP的软件,用到了很多图形算法.
💻 CS
📖 第 1 页 / 共 4 页
字号:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

namespace PhotoSprite.ImageProcessing
{
  partial class Effect
  {
    /************************************************************
     * 
     * 剪纸、铅笔画、素描、连环画
     * 碧绿、棕褐、渲染
     * 冰冻、熔铸
     * 暗调、对调、怪调
     * 
     ************************************************************/


    /// <summary>
    /// 剪纸
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="threshold">阈值[0, 255]</param>
    /// <param name="bgColor">背景色</param>
    /// <param name="fgColor">前景色</param>
    /// <returns></returns>
    public Bitmap PaperCut(Bitmap b, byte threshold, Color bgColor, Color fgColor)
    {
      GrayProcessing gp = new GrayProcessing();

      // 对图像按指定阈值进行二值化
      byte[,] GrayArray = gp.BinaryArray(b, threshold);

      // 对图像进行上色
      return gp.BinaryImage(GrayArray, bgColor, fgColor);
    } // end of PaperCut


    /// <summary>
    /// 铅笔画
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="threshold">颜色阈值[0, 100]</param>
    /// <returns></returns>
    public Bitmap Pencil(Bitmap b, int threshold)
    {
      if (threshold < 0) threshold = 0;
      if (threshold > 100) threshold = 100;

      int width = b.Width;
      int height = b.Height;

      Bitmap dstImage = new Bitmap(width, height);

      BitmapData srcData = b.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
      BitmapData dstData = dstImage.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

      // 图像实际处理区域
      // 图像最外围一圈不处理
      int rectTop = 1;
      int rectBottom = height - 1;
      int rectLeft = 1;
      int rectRight = width - 1;

      unsafe
      {
        byte* src = (byte*)srcData.Scan0;
        byte* dst = (byte*)dstData.Scan0;

        int stride = srcData.Stride;
        int offset = stride - width * BPP;

        // 源图像周围八点指针
        byte* nw; byte* n; byte* ne;
        byte* w; byte* e;
        byte* sw; byte* s; byte* se;

        int R, G, B;

        // 移向第一行
        src += stride;
        dst += stride;
        for (int y = rectTop; y < rectBottom; y++)
        {
          // 移向每行第 1 列
          src += BPP;
          dst += BPP;

          for (int x = rectLeft; x < rectRight; x++)
          {
            // 取周围八个点的颜色值
            nw = src - stride - BPP;   // (x-1, y-1)
            n = src - stride;          // (x  , y-1)
            ne = src - stride + BPP;   // (x+1, y-1)

            w = src - BPP;             // (x-1, y)
            e = src + BPP;             // (x+1, y)

            sw = src + stride - BPP;   // (x-1, y+1)
            s = src + stride;          // (x  , y+1)
            se = src + stride + BPP;   // (x+1, y+1)

            // 计算当前像素点与周围八点平均值的差
            R = nw[2] + n[2] + ne[2] + w[2] + e[2] + sw[2] + s[2] + se[2];
            R = src[2] - R / 8;
            G = nw[1] + n[1] + ne[1] + w[1] + e[1] + sw[1] + s[1] + se[1];
            G = src[1] - G / 8;
            B = nw[0] + n[0] + ne[0] + w[0] + e[0] + sw[0] + s[0] + se[0];
            B = src[0] - B / 8;

            // 取差值的绝对值
            if (R < 0) R = -R;
            if (G < 0) G = -G;
            if (B < 0) B = -B;

            // 如果差值大于指定阈值,则在当前位置描点
            if (R >= threshold || G >= threshold || B >= threshold)
            {
              dst[0] = dst[1] = dst[2] = 0;
            }
            else
            {
              dst[0] = dst[1] = dst[2] = 255;
            }

            dst[3] = src[3];  // A

            // 向后移一像素
            src += BPP;
            dst += BPP;
          } // x

          // 移向下一行
          // 这里得注意要多移 1 列,因最右列不必处理
          src += offset + BPP;
          dst += offset + BPP;
        } // y
      }

      b.UnlockBits(srcData);
      dstImage.UnlockBits(dstData);

      b.Dispose();

      return dstImage;
    } // end of Pencil


    /// <summary>
    /// 素描
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="threshold">颜色阈值[0, 100]</param>
    /// <returns></returns>
    public Bitmap Sketch(Bitmap b, int threshold)
    {
      if (threshold < 0) threshold = 0;
      if (threshold > 100) threshold = 100;

      // 先求灰度
      GrayProcessing gp = new GrayProcessing();
      b = gp.Gray(b, GrayProcessing.GrayMethod.WeightAveraging);

      int width = b.Width;
      int height = b.Height;

      BitmapData srcData = b.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

      // 图像实际处理区域
      int rectTop = 0;
      int rectBottom = height - 1;
      int rectLeft = 0;
      int rectRight = width - 1;

      unsafe
      {
        byte* dst = (byte*)srcData.Scan0;
        // 取当前像素点右下角像素
        byte* src = dst + srcData.Stride + BPP;

        int offset = srcData.Stride - width * BPP;

        int diff;

        for (int y = rectTop; y < rectBottom; y++)
        {
          for (int x = rectLeft; x < rectRight; x++)
          {
            // 计算相邻两点的灰度差
            diff = dst[0] - src[0];
            if (diff < 0)
              diff = -diff;

            // 如果灰度差大于指定阈值,则颜色跳变严重,需描下轮廓,
            // 即把该点置为黑色,否则置为白色
            if (diff >= threshold)
              dst[0] = dst[1] = dst[2] = 0;
            else
              dst[0] = dst[1] = dst[2] = 255;

            // 向后移一像素
            src += BPP;
            dst += BPP;
          } // x

          // 移向下一行
          // 这里得注意要多移 1 列,因最右列不必处理
          src += offset + BPP;
          dst += offset + BPP;
        } // y
      }

      b.UnlockBits(srcData);

      return b;
    } // end of Sketch


    /// <summary>
    /// 连环画
    /// </summary>
    /// <param name="b">位图流</param>
    /// <returns></returns>
    public Bitmap Comic(Bitmap b)
    {
      int width = b.Width;
      int height = b.Height;

      BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

      unsafe
      {
        byte* p = (byte*)data.Scan0;
        int offset = data.Stride - width * BPP;

        int R, G, B, pixel;

        for (int y = 0; y < height; y++)
        {
          for (int x = 0; x < width; x++)
          {
            R = p[2];
            G = p[1];
            B = p[0];

            // R = |g – b + g + r| * r / 256;
            pixel = G - B + G + R;
            if (pixel < 0) pixel = -pixel;
            pixel = pixel * R / 256;
            if (pixel > 255) pixel = 255;
            p[2] = (byte)pixel;

            // G = |b – g + b + r| * r / 256;
            pixel = B - G + B + R;
            if (pixel < 0) pixel = -pixel;
            pixel = pixel * R / 256;
            if (pixel > 255) pixel = 255;
            p[1] = (byte)pixel;

            // B = |b – g + b + r| * g / 256;
            pixel = B - G + B + R;
            if (pixel < 0) pixel = -pixel;
            pixel = pixel * G / 256;
            if (pixel > 255) pixel = 255;
            p[0] = (byte)pixel;

            p += BPP;
          } // x

          p += offset;
        } // y
      }

      b.UnlockBits(data);

      // 对图像进行灰度化
      GrayProcessing gp = new GrayProcessing();
      return gp.Gray(b, GrayProcessing.GrayMethod.WeightAveraging);
    } // end of Comic


    /// <summary>
    /// 碧绿
    /// </summary>
    /// <param name="b">位图流</param>
    /// <returns></returns>
    public Bitmap Aqua(Bitmap b)
    {
      int width = b.Width;
      int height = b.Height;

      BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

      unsafe
      {
        byte* p = (byte*)data.Scan0;
        int offset = data.Stride - width * BPP;

        int R, G, B, pixel;

        for (int y = 0; y < height; y++)
        {
          for (int x = 0; x < width; x++)
          {
            // R = (g - b) * (g - b) / 128;
            // G = (r - b) * (r - b) / 128;
            // B = (r - g) * (r - g) / 128;

            R = p[2];
            G = p[1];
            B = p[0];

            pixel = (G - B) * (G - B) / 128;
            if (pixel > 255) pixel = 255;
            p[2] = (byte)pixel;

            pixel = (R - B) * (R - B) / 128;
            if (pixel > 255) pixel = 255;
            p[1] = (byte)pixel;

            pixel = (R - G) * (R - G) / 128;
            if (pixel > 255) pixel = 255;
            p[0] = (byte)pixel;

            p += BPP;
          }  // x

          p += offset;
        } // y
      }

      b.UnlockBits(data);

      return b;
    } // end of Aqua


    /// <summary>
    /// 棕褐色、旧相片
    /// </summary>
    /// <param name="b">位图流</param>
    /// <returns></returns>
    public Bitmap Sepia(Bitmap b)
    {
      int width = b.Width;
      int height = b.Height;

      BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

      unsafe
      {
        byte* p = (byte*)data.Scan0;
        int offset = data.Stride - width * BPP;

        int R, G, B;

        for (int y = 0; y < height; y++)
        {
          for (int x = 0; x < width; x++)
          {
            // R = 0.393 * r + 0.769 * g + 0.189 * b;
            // G = 0.349 * r + 0.686 * g + 0.168 * b;
            // B = 0.272 * r + 0.534 * g + 0.131 * b;
            R = (25756 * p[2] + 50397 * p[1] + 12386 * p[0]) >> 16;
            G = (22872 * p[2] + 44958 * p[1] + 11010 * p[0]) >> 16;
            B = (17826 * p[2] + 34996 * p[1] + 8585 * p[0]) >> 16;

            if (R < 0) R = 0;
            if (R > 255) R = 255;

            if (G < 0) G = 0;
            if (G > 255) G = 255;

            if (B < 0) B = 0;
            if (B > 255) B = 255;

            p[2] = (byte)R;
            p[1] = (byte)G;
            p[0] = (byte)B;

            p += BPP;
          } // x
          p += offset;
        } // y
      }

      b.UnlockBits(data);

      return b;
    } // end of Sepia


    /// <summary>
    /// 颜色渲染
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="red">红色分量[0, 255]</param>
    /// <param name="green">绿色分量[0, 255]</param>
    /// <param name="blue">蓝色分量[0, 255]</param>
    /// <returns></returns>
    public Bitmap Colorize(Bitmap b, int red, int green, int blue)
    {
      if (red < 0) red = 0;
      if (red > 255) red = 255;
      if (green < 0) green = 0;
      if (green > 255) green = 255;
      if (blue < 0) blue = 0;
      if (blue > 255) blue = 255;

      // 灰度化
      GrayProcessing gp = new GrayProcessing();
      b = gp.Gray(b, GrayProcessing.GrayMethod.WeightAveraging);

      int width = b.Width;
      int height = b.Height;

      BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

      unsafe
      {
        byte* p = (byte*)data.Scan0;
        int offset = data.Stride - width * BPP;

        int R, G, B;

        for (int y = 0; y < height; y++)
        {
          for (int x = 0; x < width; x++)
          {
            R = p[2] * red / 255;
            G = p[1] * green / 255;
            B = p[0] * blue / 255;

            p[2] = (byte)R;
            p[1] = (byte)G;
            p[0] = (byte)B;

            p += BPP;
          } // x

          p += offset;
        } // y
      }

      b.UnlockBits(data);

      return b;
    } // end of Colorize


    /// <summary>
    /// 冰冻
    /// </summary>
    /// <param name="b">位图流</param>
    /// <returns></returns>
    public Bitmap Ice(Bitmap b)
    {
      int width = b.Width;
      int height = b.Height;

      BitmapData data = b.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

      unsafe
      {
        byte* p = (byte*)data.Scan0;
        int offset = data.Stride - width * BPP;

        int R, G, B, pixel;

        for (int y = 0; y < height; y++)
        {
          for (int x = 0; x < width; x++)
          {
            R = p[2];
            G = p[1];
            B = p[0];

            // R = |r - g - b| * 3 / 2;
            pixel = R - G - B;
            pixel = pixel * 3 / 2;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -