2016-11-06 4 views
2

Я пытаюсь реализовать функцию размытия, которую я нашел в Интернете, но по какой-то причине она рисует изображение полностью белым. Я почти уверен, что исходный фрагмент был не совсем функциональным для начала, поэтому ошибка.C# Функция размытия не работает

Вот простейший вид кода:

 public void Blur(int blurSize) 
     { 
      // look at every pixel in the blur rectangle 
      for (int xx = 0; xx < this.Width; xx++) 
      { 
       for (int yy = 0; yy < this.Height; yy++) 
       { 
        float avgR = 0; 
        float avgG = 0; 
        float avgB = 0; 
        float avgA = 0; 
        int blurPixelCount = 0; 
        // average the color of the red, green and blue for each pixel in the 
        // blur size while making sure you don't go outside the image bounds 
        for (int x = xx; (x < xx + blurSize && x < this.Width); x++) 
        { 
         for (int y = yy; (y < yy + blurSize && y < this.Height); y++) 
         { 
          Color pixel = this.GetPixel(x, y); 
          avgR += pixel.R; 
          avgG += pixel.G; 
          avgB += pixel.B; 
          avgA += pixel.A; 
          blurPixelCount++; 
         } 
        } 
        avgR = avgR/blurPixelCount; 
        avgG = avgG/blurPixelCount; 
        avgB = avgB/blurPixelCount; 
        avgA = avgA/blurPixelCount; 
        // now that we know the average for the blur size, set each pixel to that color 
        for (int x = xx; x < xx + blurSize && x < this.Width; x++) 
        { 
         for (int y = yy; y < yy + blurSize && y < this.Height; y++) 
         { 
          SetPixel(x, y, new Color(avgR, avgG, avgB, avgA)); 
         } 
        } 
       } 
      } 
     } 

В качестве примера, вот это изображение, прежде чем размытости: enter image description here

и здесь после «попытки» размытия (я изменил черный фон из-за Stackoverflow быть белым): enter image description here

Я заметил, что если blurSize что-нибудь больше, чем 1, то изображение просто белое пятно, как это (используя blurSize 2 и backg круглый прозрачность сделал черный мной):.

enter image description here

Как вы можете себе представить, что-либо выше 2 создает чистое белое изображение. Только в случае, если это не очевидно, это эффект, который я стремлюсь:

enter image description here

Мой вопрос довольно прост, кто может определить, что случилось с этой размытости функции?

Update:

В соответствии с просьбой, вот мой собственный класс растровый:

using System; 
using System.Collections.Generic; 
using System.Drawing; 
using System.Drawing.Imaging; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Security.Cryptography.X509Certificates; 
using System.Text; 
using System.Threading.Tasks; 
using GrimoireEngine.Framework.Maths; 
using Point = GrimoireEngine.Framework.Maths.Point; 
using Rectangle = GrimoireEngine.Framework.Maths.Rectangle; 

namespace GrimoireEngine.Framework.Utilities 
{ 
    public class GrimoireBitmap 
    { 
     public Bitmap Source; 
     private IntPtr _iptr = IntPtr.Zero; 
     public BitmapData BitmapData; 

     public byte[] Pixels { get; set; } 
     public int Depth { get; private set; } 
     public int Width { get; private set; } 
     public int Height { get; private set; } 

     public Color this[int x, int y] 
     { 
      get { return GetPixel(x, y); } 
      set { SetPixel(x, y, value); } 
     } 

     public Color this[Point point] 
     { 
      get { return GetPixel(point); } 
      set { SetPixel(point, value); } 
     } 

     public bool IsLocked { get; private set; } 

     public GrimoireBitmap(int width, int height) 
     { 
      this.Source = new Bitmap(width, height); 
     } 

     public GrimoireBitmap(int width, int height, PixelFormat format) 
     { 
      this.Source = new Bitmap(width, height, format); 
     } 

     public GrimoireBitmap(Bitmap image) 
     { 
      this.Source = image; 
     } 

     public GrimoireBitmap(string file) 
     { 
      this.Source = new Bitmap(file); 
     } 

     /// <summary> 
     /// Lock bitmap data 
     /// </summary> 
     public void LockBits() 
     { 
      Width = Source.Width; 
      Height = Source.Height; 
      int pixelCount = Width * Height; 
      System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, Width, Height); 
      Depth = Bitmap.GetPixelFormatSize(Source.PixelFormat); 
      if (Depth != 8 && Depth != 24 && Depth != 32) 
      { 
       throw new ArgumentException("Only 8, 24 and 32 bpp images are supported."); 
      } 
      BitmapData = Source.LockBits(rect, ImageLockMode.ReadWrite, Source.PixelFormat); 
      int step = Depth/8; 
      Pixels = new byte[pixelCount * step]; 
      _iptr = BitmapData.Scan0; 
      Marshal.Copy(_iptr, Pixels, 0, Pixels.Length); 
      this.IsLocked = true; 
     } 

     /// <summary> 
     /// Unlock bitmap data 
     /// </summary> 
     public void UnlockBits() 
     { 
      Marshal.Copy(Pixels, 0, _iptr, Pixels.Length); 
      Source.UnlockBits(BitmapData); 
      this.IsLocked = false; 
     } 

     /// <summary> 
     /// Get the color of the specified pixel 
     /// </summary> 
     /// <param name="x"></param> 
     /// <param name="y"></param> 
     /// <returns></returns> 
     public Color GetPixel(int x, int y) 
     { 
      Color clr = Color.Transparent; 
      int cCount = Depth/8; 
      int i = ((y * Width) + x) * cCount; 

      if (i > Pixels.Length - cCount) 
       throw new IndexOutOfRangeException(); 

      if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha 
      { 
       byte b = Pixels[i]; 
       byte g = Pixels[i + 1]; 
       byte r = Pixels[i + 2]; 
       byte a = Pixels[i + 3]; // a 
       clr = Color.FromNonPremultiplied(a, r, g, b); 
      } 
      if (Depth == 24) // For 24 bpp get Red, Green and Blue 
      { 
       byte b = Pixels[i]; 
       byte g = Pixels[i + 1]; 
       byte r = Pixels[i + 2]; 
       clr = Color.FromNonPremultiplied(r, g, b); 
      } 
      if (Depth == 8) // For 8 bpp get color value (Red, Green and Blue values are the same) 
      { 
       byte c = Pixels[i]; 
       clr = Color.FromNonPremultiplied(c, c, c); 
      } 
      return clr; 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="point"></param> 
     /// <returns></returns> 
     public Color GetPixel(Point point) 
     { 
      return GetPixel(point.X, point.Y); 
     } 

     /// <summary> 
     /// Set the color of the specified pixel 
     /// </summary> 
     /// <param name="x"></param> 
     /// <param name="y"></param> 
     /// <param name="color"></param> 
     public void SetPixel(int x, int y, Color color) 
     { 
      int i = (((y * Width) + x) * (Depth/8)); 
      if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha 
      { 
       Pixels[i] = color.B; 
       Pixels[i + 1] = color.G; 
       Pixels[i + 2] = color.R; 
       Pixels[i + 3] = color.A; 
      } 
      if (Depth == 24) // For 24 bpp set Red, Green and Blue 
      { 
       Pixels[i] = color.B; 
       Pixels[i + 1] = color.G; 
       Pixels[i + 2] = color.R; 
      } 
      if (Depth == 8) // For 8 bpp set color value (Red, Green and Blue values are the same) 
      { 
       Pixels[i] = color.B; 
      } 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="point"></param> 
     /// <param name="color"></param> 
     public void SetPixel(Point point, Color color) 
     { 
      SetPixel(point.X, point.Y, color); 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="x"></param> 
     /// <param name="y"></param> 
     /// <param name="width"></param> 
     /// <param name="height"></param> 
     /// <param name="color"></param> 
     public void FillRectangle(int x, int y, int width, int height, Color color) 
     { 
      for (int i = 0; i < width; i++) 
      { 
       for (int j = 0; j < height; j++) 
       { 
        SetPixel(i + x, j + y, color); 
       } 
      } 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="rectangle"></param> 
     /// <param name="color"></param> 
     public void FillRectangle(Rectangle rectangle, Color color) 
     { 
      FillRectangle(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, color); 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="x"></param> 
     /// <param name="y"></param> 
     /// <param name="bitmap"></param> 
     public void DrawBitmap(int x, int y, GrimoireBitmap bitmap) 
     { 
      for (int i = 0; i < bitmap.Width; i++) 
      { 
       for (int j = 0; j < bitmap.Height; j++) 
       { 
        SetPixel(x + i, y + j, bitmap.GetPixel(i, j)); 
       } 
      } 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="color"></param> 
     public void Fill(Color color) 
     { 
      FillRectangle(0, 0, this.Width, this.Height, color); 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="x"></param> 
     /// <param name="y"></param> 
     /// <param name="width"></param> 
     /// <param name="height"></param> 
     /// <returns></returns> 
     public GrimoireBitmap CopyRegion(int x, int y, int width, int height) 
     { 
      GrimoireBitmap bitmap = new GrimoireBitmap(width, height); 
      bitmap.LockBits(); 
      for (int i = 0; i < width; i++) 
      { 
       for (int j = 0; j < height; j++) 
       { 
        bitmap.SetPixel(i, j, this.GetPixel(x + i, y + j)); 
       } 
      } 
      bitmap.UnlockBits(); 
      return bitmap; 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="rectangle"></param> 
     /// <returns></returns> 
     public GrimoireBitmap CopyRegion(Rectangle rectangle) 
     { 
      return CopyRegion(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     public void Clear() 
     { 
      for (int i = 0; i < this.Width; i++) 
      { 
       for (int j = 0; j < this.Height; j++) 
       { 
        SetPixel(i, j, Color.Transparent); 
       } 
      } 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="fileName"></param> 
     public void Save(string fileName) 
     { 
      this.Source.Save(fileName); 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="fileName"></param> 
     public void Load(string fileName) 
     { 
      this.Source = new Bitmap(fileName); 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <returns></returns> 
     public Bitmap ToBitmap() 
     { 
      return this.Source; 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="image"></param> 
     public void FromBitmap(Bitmap image) 
     { 
      this.Source = image; 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="x"></param> 
     /// <param name="y"></param> 
     /// <param name="width"></param> 
     /// <param name="height"></param> 
     /// <param name="color"></param> 
     /// <param name="amount"></param> 
     public void Blend(int x, int y, int width, int height, Color color, float amount) 
     { 
      for (int i = 0; i < width; i++) 
      { 
       for (int j = 0; j < height; j++) 
       { 
        SetPixel(i + x, j + y, Color.Blend(GetPixel(i + x, j + y), color, amount)); 
       } 
      } 
     } 

     /// <summary> 
     /// 
     /// </summary> 
     /// <param name="rectangle"></param> 
     /// <param name="color"></param> 
     /// <param name="amount"></param> 
     public void Blend(Rectangle rectangle, Color color, float amount) 
     { 
      Blend(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height, color, amount); 
     } 

     public void Blur(int blurSize) 
     { 
      // look at every pixel in the blur rectangle 
      for (int xx = 0; xx < this.Width; xx++) 
      { 
       for (int yy = 0; yy < this.Height; yy++) 
       { 
        float avgR = 0; 
        float avgG = 0; 
        float avgB = 0; 
        float avgA = 0; 
        int blurPixelCount = 0; 
        // average the color of the red, green and blue for each pixel in the 
        // blur size while making sure you don't go outside the image bounds 
        for (int x = xx; (x < xx + blurSize && x < this.Width); x++) 
        { 
         for (int y = yy; (y < yy + blurSize && y < this.Height); y++) 
         { 
          Color pixel = this.GetPixel(x, y); 
          avgR += pixel.R; 
          avgG += pixel.G; 
          avgB += pixel.B; 
          avgA += pixel.A; 
          blurPixelCount++; 
         } 
        } 
        avgR = avgR/blurPixelCount; 
        avgG = avgG/blurPixelCount; 
        avgB = avgB/blurPixelCount; 
        avgA = avgA/blurPixelCount; 
        // now that we know the average for the blur size, set each pixel to that color 
        for (int x = xx; x < xx + blurSize && x < this.Width; x++) 
        { 
         for (int y = yy; y < yy + blurSize && y < this.Height; y++) 
         { 
          SetPixel(x, y, new Color(avgR, avgG, avgB, avgA)); 
         } 
        } 
       } 
      } 
     } 
    } 
} 
+0

Как именно вы используете этот код? Я имею в виду, например, что System.Drawing.Color не имеет конструктора, который принимает 4 аргумента, поэтому вы используете что-то отличное от простого растрового изображения? Что касается самого алгоритма, он отлично работает. – Evk

+0

У меня есть пользовательский класс цвета. Пять секунд. – Krythic

+0

@Evk My Color class, основанный на Monogame: http://pastebin.com/2BuzKjVW – Krythic

ответ

1

Edit: Я изменил код, чтобы использовать System.Drawing.Bitmap. Он отлично работает, как это, вот результат с Размытие = 5:

enter image description here

Вот код:

public void Blur(int blurSize, Bitmap input) 
    { 
     // look at every pixel in the blur rectangle 
     for (int xx = 0; xx < input.Width; xx++) 
     { 
      for (int yy = 0; yy < input.Height; yy++) 
      { 
       float avgR = 0; 
       float avgG = 0; 
       float avgB = 0; 
       float avgA = 0; 
       int blurPixelCount = 0; 
       // average the color of the red, green and blue for each pixel in the 
       // blur size while making sure you don't go outside the image bounds 
       for (int x = xx; (x < xx + blurSize && x < input.Width); x++) 
       { 
        for (int y = yy; (y < yy + blurSize && y < input.Height); y++) 
        { 
         Color pixel = input.GetPixel(x, y); 
         avgR += pixel.R; 
         avgG += pixel.G; 
         avgB += pixel.B; 
         avgA += pixel.A; 
         blurPixelCount++; 
        } 
       } 
       avgR = avgR/blurPixelCount; 
       avgG = avgG/blurPixelCount; 
       avgB = avgB/blurPixelCount; 
       avgA = avgA/blurPixelCount; 
       // now that we know the average for the blur size, set each pixel to that color 
       for (int x = xx; x < xx + blurSize && x < input.Width; x++) 
       { 
        for (int y = yy; y < yy + blurSize && y < input.Height; y++) 
        { 
         input.SetPixel(x, y, Color.FromArgb((int)avgA, (int)avgR, (int)avgG, (int)avgB)); 
        } 
       } 
      } 
     } 
    } 

Так один из таких методов, как SetPixel или GetPixel или новый цвет не работает должным образом.

+0

@ Krythic См. Править – Nathan

+0

Благодарим за подтверждение этого; Я вернусь и загляну в рамки. – Krythic

+0

Я понял, что проблема действительно связана с конструктором Color. Он умножился на 255 при задании поплавка. Я исправил это, отправив байт. Алгоритм работает безупречно. – Krythic