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

📄 effect.extend.cs

📁 一个C#开发的类似PHOTOSHOP的软件,用到了很多图形算法.
💻 CS
📖 第 1 页 / 共 4 页
字号:
      b.UnlockBits(srcData);
      dstImage.UnlockBits(dstData);

      b.Dispose();

      return dstImage;
    } // end of Mosaic


    /// <summary>
    /// 油画
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="brushSize">画刷尺寸[1, 8]</param>
    /// <param name="coarseness">粗糙度[1, 255]</param>
    /// <returns></returns>
    public Bitmap OilPainting(Bitmap b, int brushSize, byte coarseness)
    {
      if (brushSize < 1) brushSize = 1;
      if (brushSize > 8) brushSize = 8;

      if (coarseness < 1) coarseness = 1;
      if (coarseness > 255) coarseness = 255;

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

      int lenArray = coarseness + 1;
      int[] CountIntensity = new int[lenArray];
      uint[] RedAverage = new uint[lenArray];
      uint[] GreenAverage = new uint[lenArray];
      uint[] BlueAverage = new uint[lenArray];
      uint[] AlphaAverage = new uint[lenArray];

      // 产生灰度数组
      GrayProcessing gp = new GrayProcessing();
      Bitmap grayImage = gp.Gray( (Bitmap)b.Clone(), GrayProcessing.GrayMethod.WeightAveraging );
      byte[,] Gray = gp.Image2Array(grayImage);
      grayImage.Dispose();

      // 目标图像
      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.ReadWrite, PixelFormat.Format32bppArgb);

      int stride = srcData.Stride;
      System.IntPtr srcScan0 = srcData.Scan0;
      System.IntPtr dstScan0 = dstData.Scan0;
      int offset = stride - width * BPP;

      unsafe
      {
        byte* src = (byte*)srcScan0;
        byte* dst = (byte*)dstScan0;

        for (int y = 0; y < height; y++)
        {
          // 油画渲染范围上下边界
          int top = y - brushSize;
          int bottom = y + brushSize + 1;

          if (top < 0) top = 0;
          if (bottom >= height) bottom = height - 1;

          for (int x = 0; x < width; x++)
          {
            // 油画渲染范围左右边界
            int left = x - brushSize;
            int right = x + brushSize + 1;

            if (left < 0) left = 0;
            if (right >= width) right = width - 1;

            // 初始化数组
            for (int i = 0; i < lenArray; i++)
            {
              CountIntensity[i] = 0;
              RedAverage[i] = 0;
              GreenAverage[i] = 0;
              BlueAverage[i] = 0;
              AlphaAverage[i] = 0;
            } // i


            // 下面这个内循环类似于外面的大循环
            // 也是油画特效处理的关键部分
            src = (byte*)srcScan0 + top * stride + left * BPP;
            int offsetBlock = stride - (right - left) * BPP;

            for (int j = top; j < bottom; j++)
            {
              for (int i = left; i < right; i++)
              {
                byte intensity = (byte)(coarseness * Gray[i, j] / 255);
                CountIntensity[intensity]++;

                AlphaAverage[intensity] += src[3];
                RedAverage[intensity] += src[2];
                GreenAverage[intensity] += src[1];
                BlueAverage[intensity] += src[0];

                src += BPP;
              } // i

              src += offsetBlock;
            } // j

            // 求最大值,并记录下数组索引
            byte chosenIntensity = 0;
            int maxInstance = CountIntensity[0];
            for (int i = 1; i < lenArray; i++)
            {
              if (CountIntensity[i] > maxInstance)
              {
                chosenIntensity = (byte)i;
                maxInstance = CountIntensity[i];
              }
            } // i

            dst[3] = (byte)(AlphaAverage[chosenIntensity] / maxInstance);
            dst[2] = (byte)(RedAverage[chosenIntensity] / maxInstance);
            dst[1] = (byte)(GreenAverage[chosenIntensity] / maxInstance);
            dst[0] = (byte)(BlueAverage[chosenIntensity] / maxInstance);

            dst += BPP;
          } // x

          dst += offset;
        } // y
      }

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

      b.Dispose();

      return dstImage;
    } // end of OilPainting


    /// <summary>
    /// 曝光
    /// </summary>
    /// <param name="b">位图流</param>
    /// <returns></returns>
    public Bitmap Solarize(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;

        for (int y = 0; y < height; y++)
        {
          for (int x = 0; x < width; x++)
          {
            if (p[0] < 128) p[0] = (byte)(p[0] ^ 0xFF); // B
            if (p[1] < 128) p[1] = (byte)(p[1] ^ 0xFF); // G
            if (p[2] < 128) p[2] = (byte)(p[2] ^ 0xFF); // R

            p += BPP;
          }// x

          p += offset;
        } // y
      }

      b.UnlockBits(data);

      return b;
    } // end of Solarize


    /************************************************************
     * 
     * 图像融合
     * 
     ************************************************************/


    /// <summary>
    /// 图像融合
    /// </summary>
    /// <param name="bgImage">背景图像</param>
    /// <param name="fgImage">前景图像</param>
    /// <param name="transparency">前景透明度[0, 255]</param>
    /// <returns></returns>
    public Bitmap Inosculate(Bitmap bgImage, Bitmap fgImage, byte transparency)
    {
      int width = bgImage.Width;
      int height = bgImage.Height;

      BitmapData bgData = bgImage.LockBits(new Rectangle(0, 0, width, height),
        ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
      BitmapData fgData = fgImage.LockBits(new Rectangle(0, 0, width, height), 
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

      unsafe
      {
        byte* bg = (byte*)bgData.Scan0;
        byte* fg = (byte*)fgData.Scan0;
        
        int offset = bgData.Stride - width * BPP;

        for (int y = 0; y < height; y++)
        {
          for (int x = 0; x < width; x++)
          {
            if (fg[3] != 0)
            {
              // pixel = FG * transparency / 255 + BG * (255 - transparency) / 255
              bg[0] = (byte)((fg[0] - bg[0]) * transparency / 255 + bg[0]);
              bg[1] = (byte)((fg[1] - bg[1]) * transparency / 255 + bg[1]);
              bg[2] = (byte)((fg[2] - bg[2]) * transparency / 255 + bg[2]);
            }

            bg += BPP;
            fg += BPP;
          } // x

          bg += offset;
          fg += offset;
        } // y
      }

      bgImage.UnlockBits(bgData);
      fgImage.UnlockBits(fgData);

      Bitmap dstImage = (Bitmap)bgImage.Clone();

      bgImage.Dispose();
      fgImage.Dispose();

      return dstImage;
    } // end of Inosculate


    /// <summary>
    /// 将两张图像合成为魔术图
    /// </summary>
    /// <param name="bgImage">背景图像</param>
    /// <param name="fgImage">前景图像</param>
    /// <param name="transparency">透明度[0, 255],即隐藏状况</param>
    /// <param name="contrast">前景图与背景图的对比度[-100, 100]</param>
    public Bitmap Magic(Bitmap bgImage, Bitmap fgImage, byte transparency, int contrast)
    {
      Adjustment a = new Adjustment();
      Effect e = new Effect();

      // 按像素交错翻转
      bgImage = a.Interleaving(bgImage);

      // 处理对比度
      bgImage = a.Contrast(bgImage, contrast);

      // 前景和背景进行混合处理
      Bitmap dstImage = e.Inosculate(bgImage, fgImage, transparency);

      bgImage.Dispose();
      fgImage.Dispose();

      return dstImage;
    } // end of Magic


    /************************************************************
     * 
     * 自定义、去红眼、艺术字符
     * 
     ************************************************************/


    /// <summary>
    /// 自定义
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="sequence">卷积核元素序列</param>
    /// <returns></returns>
    public Bitmap Custom(Bitmap b, int[] sequence)
    {
      MatrixNxN m = new MatrixNxN();
      m.Sequence = sequence;

      return m.Convolute(b);
    } // end of Custom


    /// <summary>
    /// 自定义
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="kernel">卷积核</param>
    /// <param name="scale">缩放比例</param>
    /// <param name="offset">偏移量</param>
    /// <returns></returns>
    public Bitmap Custom(Bitmap b, int[,] kernel, int scale, int offset)
    {
      MatrixNxN m = new MatrixNxN();
      m.Kernel = kernel;
      m.Scale = scale;
      m.Offset = offset;

      return m.Convolute(b);
    } // end of Custom


    /// <summary>
    /// 去除红眼
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="tolerence">容差[0, 100]</param>
    /// <param name="red">红色分量[0, 255]</param>
    /// <param name="green">绿色分量[0, 255]</param>
    /// <param name="blue">蓝色分量[0, 255]</param>
    /// <returns></returns>
    public Bitmap RedEyeRemoval(Bitmap b, int tolerence, int red, int green, int blue)
    {
      if (tolerence < 0) tolerence = 0;
      if (tolerence > 100) tolerence = 100;

      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;

      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;

        byte R, G, B;
        int gray;

        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 两分量差距越大,则红色成分越多
            int difference = R - (G > B ? G : B);

            // 如果当前像素颜色分量差距在指定容差范围内,并且红色成份足够高
            // 则认为当前像素需要进行红眼去除处理
            if ((difference > tolerence) && (R > 100))
            {
              // 求灰度
              gray = (19661 * R + 38666 * G + 7209 * B) >> 16;

              // 用指定的颜色替换掉红色
              p[2] = (byte)(gray * red / 255);
              p[1] = (byte)(gray * green / 255);
              p[0] = (byte)(gray * blue / 255);
            }

            p += BPP;
          } // x

          p += offset;
        } // y
      }

      b.UnlockBits(data);

      return b;
    } // end of RedEyeRemoval


    /// <summary>
    /// 艺术文字,将图片转换为字符
    /// </summary>
    /// <param name="b">位图流</param>
    /// <param name="text">待显示的文字</param>
    /// <param name="blockWidth">块宽</param>
    /// <param name="blockHeight">块高</param>
    /// <returns></returns>
    public string Image2Text(Bitmap b, string text, int blockWidth, int blockHeight)
    {
      int width = b.Width;
      int height = b.Height;

      // 首先将图像灰度化
      GrayProcessing gp = new GrayProcessing();
      b = gp.Gray(b, GrayProcessing.GrayMethod.WeightAveraging);
      byte[,] Gray = gp.Image2Array(b);

      // 用于显示的灰度字符
      char[] ArtChar = text.ToCharArray();
      int len = ArtChar.Length;

      // 统计每个字符的点数
      int[] CharDots = new int[len];
      Watermark w = new Watermark();
      for (int i = 0; i < len; i++)
      {
        CharDots[i] = w.CountTextDots(ArtChar[i]);
      } // i

      // 对字符点数进行冒泡法排序
      for (int i = 0; i < len - 1; i++)
      {
        for (int j = i + 1; j < len; j++)
        {
          if (CharDots[j] < CharDots[i])
          {
            // 交换点数
            int t = CharDots[j];
            CharDots[j] = CharDots[i];
            CharDots[i] = t;

            // 交换字符
            char c = ArtChar[j];
            ArtChar[j] = ArtChar[i];
            ArtChar[i] = c;
          }
        } // j
      } // i

      // 最大点数
      int maxGray = CharDots[len - 1];

      // 累加块灰度
      int sum = 0;

      // 块积
      double product = maxGray / (double)(blockWidth * blockHeight * 255);

      // 图案化后的字符串,即返回字符串
      string artString = "";

      for (int y = 0; y < height; y += blockHeight)
      {
        for (int x = 0; x < width; x += blockWidth)
        {
          sum = 0;

          for (int yB = 0; yB < blockHeight && (y + yB) < height; yB++)
          {
            for (int xB = 0; xB < blockWidth && (x + xB) < width; xB++)
            {
              // 累加小块内的灰度
              sum += Gray[x + xB, y + yB];
            } // xB
          } // yB

          // gray = maxGray * (sum / (blockWidth * blockHeight)) / 255
          int gray = (int)(sum * product);

          // 寻找灰度最接近的字符
          int k = 0;
          while (CharDots[k] < (maxGray - gray))
            k++;

          // 进行灰度映射
          artString += ArtChar[k];
        } // x

        artString += "\r\n";
      } // y

      return artString;
    } // end of Image2Text


  }
}

⌨️ 快捷键说明

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