2009-05-24 11 views
13

Quiero poner un filtro de nitidez en una imagen. Encontré una web with short tutorial. Intenté hacerlo en C# así que aquí está mi código. De todos modos, traté de averiguar por qué no está funcionando. No sé si estoy haciendo algo mal, si es así, por favor avísenme qué hacer para que funcione como debería ser. GraciasAfilar en un mapa de bits usando C#

 public static Bitmap sharpen(Bitmap image) 
    { 
     Bitmap sharpenImage = new Bitmap(image.Width, image.Height); 

     int filterWidth = 3; 
     int filterHeight = 3; 
     int w = image.Width; 
     int h = image.Height; 

     double[,] filter = new double[filterWidth, filterHeight]; 

     filter[0, 0] = filter[0, 1] = filter[0, 2] = filter[1, 0] = filter[1, 2] = filter[2, 0] = filter[2, 1] = filter[2, 2] = -1; 
     filter[1, 1] = 9; 

     double factor = 1.0; 
     double bias = 0.0; 

     Color[,] result = new Color[image.Width, image.Height]; 

     for (int x = 0; x < w; ++x) 
     { 
      for (int y = 0; y < h; ++y) 
      { 
       double red = 0.0, green = 0.0, blue = 0.0; 
       Color imageColor = image.GetPixel(x, y); 

       for (int filterX = 0; filterX < filterWidth; filterX++) 
       { 
        for (int filterY = 0; filterY < filterHeight; filterY++) 
        { 
         int imageX = (x - filterWidth/2 + filterX + w) % w; 
         int imageY = (y - filterHeight/2 + filterY + h) % h; 
         red += imageColor.R * filter[filterX, filterY]; 
         green += imageColor.G * filter[filterX, filterY]; 
         blue += imageColor.B * filter[filterX, filterY]; 
        } 
        int r = Math.Min(Math.Max((int)(factor * red + bias), 0), 255); 
        int g = Math.Min(Math.Max((int)(factor * green + bias), 0), 255); 
        int b = Math.Min(Math.Max((int)(factor * blue + bias), 0), 255); 

        result[x, y] = Color.FromArgb(r, g, b); 
       } 
      } 
     } 
     for (int i = 0; i < w; ++i) 
     { 
      for (int j = 0; j < h; ++j) 
      { 
       sharpenImage.SetPixel(i, j, result[i, j]); 
      } 
     } 
     return sharpenImage; 
    } 
+0

No es interesante capítulo de "código Hermosa" escrito por Charles Petzold llamado "Generación de código on-the-fly para procesamiento de imágenes". Puede encontrarlo muy útil. – okutane

Respuesta

25
public static Bitmap sharpen(Bitmap image) 
{ 
    Bitmap sharpenImage = new Bitmap(image.Width, image.Height); 

    int filterWidth = 3; 
    int filterHeight = 3; 
    int w = image.Width; 
    int h = image.Height; 

    double[,] filter = new double[filterWidth, filterHeight]; 

    filter[0, 0] = filter[0, 1] = filter[0, 2] = filter[1, 0] = filter[1, 2] = filter[2, 0] = filter[2, 1] = filter[2, 2] = -1; 
    filter[1, 1] = 9; 

    double factor = 1.0; 
    double bias = 0.0; 

    Color[,] result = new Color[image.Width, image.Height]; 

    for (int x = 0; x < w; ++x) 
    { 
     for (int y = 0; y < h; ++y) 
     { 
      double red = 0.0, green = 0.0, blue = 0.0; 

//=====[REMOVE LINES]======================================================== 
// Color must be read per filter entry, not per image pixel. 
      Color imageColor = image.GetPixel(x, y); 
//=========================================================================== 

      for (int filterX = 0; filterX < filterWidth; filterX++) 
      { 
       for (int filterY = 0; filterY < filterHeight; filterY++) 
       { 
        int imageX = (x - filterWidth/2 + filterX + w) % w; 
        int imageY = (y - filterHeight/2 + filterY + h) % h; 

//=====[INSERT LINES]======================================================== 
// Get the color here - once per fiter entry and image pixel. 
        Color imageColor = image.GetPixel(imageX, imageY); 
//=========================================================================== 

        red += imageColor.R * filter[filterX, filterY]; 
        green += imageColor.G * filter[filterX, filterY]; 
        blue += imageColor.B * filter[filterX, filterY]; 
       } 
       int r = Math.Min(Math.Max((int)(factor * red + bias), 0), 255); 
       int g = Math.Min(Math.Max((int)(factor * green + bias), 0), 255); 
       int b = Math.Min(Math.Max((int)(factor * blue + bias), 0), 255); 

       result[x, y] = Color.FromArgb(r, g, b); 
      } 
     } 
    } 
    for (int i = 0; i < w; ++i) 
    { 
     for (int j = 0; j < h; ++j) 
     { 
      sharpenImage.SetPixel(i, j, result[i, j]); 
     } 
    } 
    return sharpenImage; 
} 
+1

Gracias, su respuesta fue realmente útil – Allek

23

Tomé la respuesta de Daniel y lo modificó para el rendimiento, mediante el uso de la clase BitmapData, ya que el uso GetPixel/SetPixel es muy caro e inadecuado para sistemas de rendimiento-hambre. Funciona exactamente igual que la solución anterior y se puede usar en su lugar.

public static Bitmap Sharpen(Bitmap image) 
    { 
     Bitmap sharpenImage = (Bitmap)image.Clone(); 

     int filterWidth = 3; 
     int filterHeight = 3; 
     int width = image.Width; 
     int height = image.Height; 

     // Create sharpening filter. 
     double[,] filter = new double[filterWidth, filterHeight]; 
     filter[0, 0] = filter[0, 1] = filter[0, 2] = filter[1, 0] = filter[1, 2] = filter[2, 0] = filter[2, 1] = filter[2, 2] = -1; 
     filter[1, 1] = 9; 

     double factor = 1.0; 
     double bias = 0.0; 

     Color[,] result = new Color[image.Width, image.Height]; 

     // Lock image bits for read/write. 
     BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 

     // Declare an array to hold the bytes of the bitmap. 
     int bytes = pbits.Stride * height; 
     byte[] rgbValues = new byte[bytes]; 

     // Copy the RGB values into the array. 
     System.Runtime.InteropServices.Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes); 

     int rgb; 
     // Fill the color array with the new sharpened color values. 
     for (int x = 0; x < width; ++x) 
     { 
      for (int y = 0; y < height; ++y) 
      { 
       double red = 0.0, green = 0.0, blue = 0.0; 

       for (int filterX = 0; filterX < filterWidth; filterX++) 
       { 
        for (int filterY = 0; filterY < filterHeight; filterY++) 
        { 
         int imageX = (x - filterWidth/2 + filterX + width) % width; 
         int imageY = (y - filterHeight/2 + filterY + height) % height; 

         rgb = imageY * pbits.Stride + 3 * imageX; 

         red += rgbValues[rgb + 2] * filter[filterX, filterY]; 
         green += rgbValues[rgb + 1] * filter[filterX, filterY]; 
         blue += rgbValues[rgb + 0] * filter[filterX, filterY]; 
        } 
        int r = Math.Min(Math.Max((int)(factor * red + bias), 0), 255); 
        int g = Math.Min(Math.Max((int)(factor * green + bias), 0), 255); 
        int b = Math.Min(Math.Max((int)(factor * blue + bias), 0), 255); 

        result[x, y] = Color.FromArgb(r, g, b); 
       } 
      } 
     } 

     // Update the image with the sharpened pixels. 
     for (int x = 0; x < width; ++x) 
     { 
      for (int y = 0; y < height; ++y) 
      { 
       rgb = y * pbits.Stride + 3 * x; 

       rgbValues[rgb + 2] = result[x, y].R; 
       rgbValues[rgb + 1] = result[x, y].G; 
       rgbValues[rgb + 0] = result[x, y].B; 
      } 
     } 

     // Copy the RGB values back to the bitmap. 
     System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes); 
     // Release image bits. 
     sharpenImage.UnlockBits(pbits); 

     return sharpenImage; 
    } 
7

Esto creará un efecto de nitidez más suave. Puede expandir la matriz de filtros si es necesario o cambiar la 16 a algo más grande, pero descubrí que no es tan dura como la que tiene.

const int filterWidth = 5; 
const int filterHeight = 5; 

double[,] filter = new double[filterWidth,filterHeight] { 
    { -1, -1, -1, -1, -1 }, 
    { -1, 2, 2, 2, -1 }, 
    { -1, 2, 16, 2, -1 }, 
    { -1, 2, 2, 2, -1 }, 
    { -1, -1, -1, -1, -1 } 
}; 

double factor = 1.0/16.0; 
3

Combiné la respuesta de niaher y David y fijé la propiedad "bias". Ahora puede pasar una "fuerza" entre 0.0 y 1.0 a la función Sharpen().

/// <summary> 
///  Sharpens the specified image. 
/// </summary> 
/// <param name="image">The image.</param> 
/// <param name="strength">The strength between 0.0 and 1.0.</param> 
/// <returns></returns> 
public static Bitmap Sharpen(Image image, double strength) 
{ 
    using (var bitmap = image as Bitmap) 
    { 
     if (bitmap != null) 
     { 
      var sharpenImage = bitmap.Clone() as Bitmap; 

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

      // Create sharpening filter. 
      const int filterWidth = 5; 
      const int filterHeight = 5; 

      var filter = new double[,] 
       { 
        {-1, -1, -1, -1, -1}, 
        {-1, 2, 2, 2, -1}, 
        {-1, 2, 16, 2, -1}, 
        {-1, 2, 2, 2, -1}, 
        {-1, -1, -1, -1, -1} 
       }; 

      double bias = 1.0 - strength; 
      double factor = strength/16.0; 

      var result = new Color[image.Width,image.Height]; 

      // Lock image bits for read/write. 
      if (sharpenImage != null) 
      { 
       BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height), 
                  ImageLockMode.ReadWrite, 
                  PixelFormat.Format24bppRgb); 

       // Declare an array to hold the bytes of the bitmap. 
       int bytes = pbits.Stride*height; 
       var rgbValues = new byte[bytes]; 

       // Copy the RGB values into the array. 
       Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes); 

       int rgb; 
       // Fill the color array with the new sharpened color values. 
       for (int x = 0; x < width; ++x) 
       { 
        for (int y = 0; y < height; ++y) 
        { 
         double red = 0.0, green = 0.0, blue = 0.0; 

         for (int filterX = 0; filterX < filterWidth; filterX++) 
         { 
          for (int filterY = 0; filterY < filterHeight; filterY++) 
          { 
           int imageX = (x - filterWidth/2 + filterX + width)%width; 
           int imageY = (y - filterHeight/2 + filterY + height)%height; 

           rgb = imageY*pbits.Stride + 3*imageX; 

           red += rgbValues[rgb + 2]*filter[filterX, filterY]; 
           green += rgbValues[rgb + 1]*filter[filterX, filterY]; 
           blue += rgbValues[rgb + 0]*filter[filterX, filterY]; 
          } 

          rgb = y*pbits.Stride + 3*x; 

          int r = Math.Min(Math.Max((int) (factor*red + (bias*rgbValues[rgb + 2])), 0), 255); 
          int g = Math.Min(Math.Max((int) (factor*green + (bias*rgbValues[rgb + 1])), 0), 255); 
          int b = Math.Min(Math.Max((int) (factor*blue + (bias*rgbValues[rgb + 0])), 0), 255); 

          result[x, y] = Color.FromArgb(r, g, b); 
         } 
        } 
       } 

       // Update the image with the sharpened pixels. 
       for (int x = 0; x < width; ++x) 
       { 
        for (int y = 0; y < height; ++y) 
        { 
         rgb = y*pbits.Stride + 3*x; 

         rgbValues[rgb + 2] = result[x, y].R; 
         rgbValues[rgb + 1] = result[x, y].G; 
         rgbValues[rgb + 0] = result[x, y].B; 
        } 
       } 

       // Copy the RGB values back to the bitmap. 
       Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes); 
       // Release image bits. 
       sharpenImage.UnlockBits(pbits); 
      } 

      return sharpenImage; 
     } 
    } 
    return null; 
} 
3

Bien, solucionado el problema con los bordes desordenados. Actualizan tope aquí tienes uno:

/// <summary> 
/// Sharpens the specified image. 
/// </summary> 
/// <param name="image">The image.</param> 
/// <param name="strength">The strength.</param> 
/// <returns></returns> 
public static Bitmap Sharpen(Image image, double strength) 
{ 
    using (var bitmap = image as Bitmap) 
    { 
     if (bitmap != null) 
     { 
      var sharpenImage = bitmap.Clone() as Bitmap; 

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

      // Create sharpening filter. 
      const int filterSize = 5; 

      var filter = new double[,] 
       { 
        {-1, -1, -1, -1, -1}, 
        {-1, 2, 2, 2, -1}, 
        {-1, 2, 16, 2, -1}, 
        {-1, 2, 2, 2, -1}, 
        {-1, -1, -1, -1, -1} 
       }; 

      double bias = 1.0 - strength; 
      double factor = strength/16.0; 

      const int s = filterSize/2; 

      var result = new Color[image.Width,image.Height]; 

      // Lock image bits for read/write. 
      if (sharpenImage != null) 
      { 
       BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height), 
                  ImageLockMode.ReadWrite, 
                  PixelFormat.Format24bppRgb); 

       // Declare an array to hold the bytes of the bitmap. 
       int bytes = pbits.Stride*height; 
       var rgbValues = new byte[bytes]; 

       // Copy the RGB values into the array. 
       Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes); 

       int rgb; 
       // Fill the color array with the new sharpened color values. 
       for (int x = s; x < width - s; x++) 
       { 
        for (int y = s; y < height - s; y++) 
        { 
         double red = 0.0, green = 0.0, blue = 0.0; 

         for (int filterX = 0; filterX < filterSize; filterX++) 
         { 
          for (int filterY = 0; filterY < filterSize; filterY++) 
          { 
           int imageX = (x - s + filterX + width)%width; 
           int imageY = (y - s + filterY + height)%height; 

           rgb = imageY*pbits.Stride + 3*imageX; 

           red += rgbValues[rgb + 2]*filter[filterX, filterY]; 
           green += rgbValues[rgb + 1]*filter[filterX, filterY]; 
           blue += rgbValues[rgb + 0]*filter[filterX, filterY]; 
          } 

          rgb = y * pbits.Stride + 3 * x; 

          int r = Math.Min(Math.Max((int)(factor * red + (bias * rgbValues[rgb + 2])), 0), 255); 
          int g = Math.Min(Math.Max((int)(factor * green + (bias * rgbValues[rgb + 1])), 0), 255); 
          int b = Math.Min(Math.Max((int)(factor * blue + (bias * rgbValues[rgb + 0])), 0), 255); 

          result[x, y] = Color.FromArgb(r, g, b); 
         } 
        } 
       } 

       // Update the image with the sharpened pixels. 
       for (int x = s; x < width - s; x++) 
       { 
        for (int y = s; y < height - s; y++) 
        { 
         rgb = y*pbits.Stride + 3*x; 

         rgbValues[rgb + 2] = result[x, y].R; 
         rgbValues[rgb + 1] = result[x, y].G; 
         rgbValues[rgb + 0] = result[x, y].B; 
        } 
       } 

       // Copy the RGB values back to the bitmap. 
       Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes); 
       // Release image bits. 
       sharpenImage.UnlockBits(pbits); 
      } 

      return sharpenImage; 
     } 
    } 
    return null; 
} 
1

hi i editar el código un poco corta y añadir otras dos matrices para mí esto funciona ahora perfecta

/// <summary> 
    /// Sharpens the specified image. 
    /// </summary> 
    /// <param name="image">The image.</param> 
    /// <param name="strength">strength erwartet werte zwische 0 - 99</param> 
    /// <returns></returns> 
    public Bitmap Sharpen(Image image, whichMatrix welcheMatrix , double strength) 
    { 
     double FaktorKorrekturWert = 0; 

     //strenght muß für den jeweiligen filter angepasst werden 
     switch (welcheMatrix) 
     { 
      case whichMatrix.Gaussian3x3: 
       //diese Matrix benötigt einen strenght Wert von 0 bis -9.9 default ist -2.5 
       //und einen korekturwert von 16 
       strength = (strength * -1)/10; 
       FaktorKorrekturWert = 16; 
       break; 

      case whichMatrix.Mean3x3: 
       //diese Matrix benötigt einen strenght Wert von 0 bis -9 default ist -2.25 
       //und einen Korrekturwert von 10 
       strength = strength * -9/100; 
       FaktorKorrekturWert = 10; 
       break; 

      case whichMatrix.Gaussian5x5Type1: 
       //diese Matrix benötigt einen strenght Wert von 0 bis 2.5 default ist 1.25 
       //und einen Korrekturwert von 12 
       strength = strength * 2.5/100; 
       FaktorKorrekturWert = 12; 
       break; 

      default: 
       break; 
     } 

     using (var bitmap = image as Bitmap) 
     { 
      if (bitmap != null) 
      { 
       var sharpenImage = bitmap.Clone() as Bitmap; 

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

       // Create sharpening filter. 
       var filter = Matrix(welcheMatrix); 

       //const int filterSize = 3; // wenn die Matrix 3 Zeilen und 3 Spalten besitzt dann 3 bei 4 = 4 usw.      
       int filterSize = filter.GetLength(0);     

       double bias = 1.0 - strength; 
       double factor = strength/FaktorKorrekturWert; 

       //const int s = filterSize/2; 
       int s = filterSize/2; // Filtersize ist keine Constante mehr darum wurde der befehl const entfernt 


       var result = new Color[image.Width, image.Height]; 

       // Lock image bits for read/write. 
       if (sharpenImage != null) 
       { 
        BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); 

        // Declare an array to hold the bytes of the bitmap. 
        int bytes = pbits.Stride * height; 
        var rgbValues = new byte[bytes]; 

        // Copy the RGB values into the array. 
        Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes); 

        int rgb; 
        // Fill the color array with the new sharpened color values. 
        for (int x = s; x < width - s; x++) 
        { 
         for (int y = s; y < height - s; y++) 
         { 
          double red = 0.0, green = 0.0, blue = 0.0; 

          for (int filterX = 0; filterX < filterSize; filterX++) 
          { 
           for (int filterY = 0; filterY < filterSize; filterY++) 
           { 
            int imageX = (x - s + filterX + width) % width; 
            int imageY = (y - s + filterY + height) % height; 

            rgb = imageY * pbits.Stride + 3 * imageX; 

            red += rgbValues[rgb + 2] * filter[filterX, filterY]; 
            green += rgbValues[rgb + 1] * filter[filterX, filterY]; 
            blue += rgbValues[rgb + 0] * filter[filterX, filterY]; 
           } 

           rgb = y * pbits.Stride + 3 * x; 

           int r = Math.Min(Math.Max((int)(factor * red + (bias * rgbValues[rgb + 2])), 0), 255); 
           int g = Math.Min(Math.Max((int)(factor * green + (bias * rgbValues[rgb + 1])), 0), 255); 
           int b = Math.Min(Math.Max((int)(factor * blue + (bias * rgbValues[rgb + 0])), 0), 255); 

           result[x, y] = System.Drawing.Color.FromArgb(r, g, b); 
          } 
         } 
        } 

        // Update the image with the sharpened pixels. 
        for (int x = s; x < width - s; x++) 
        { 
         for (int y = s; y < height - s; y++) 
         { 
          rgb = y * pbits.Stride + 3 * x; 

          rgbValues[rgb + 2] = result[x, y].R; 
          rgbValues[rgb + 1] = result[x, y].G; 
          rgbValues[rgb + 0] = result[x, y].B; 
         } 
        } 

        // Copy the RGB values back to the bitmap. 
        Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes); 
        // Release image bits. 
        sharpenImage.UnlockBits(pbits); 
       } 

       return sharpenImage; 
      } 
     } 
     return null; 
    } 


    public enum whichMatrix 
    { 
     Gaussian3x3, 
     Mean3x3, 
     Gaussian5x5Type1 
    } 


    private double[,] Matrix(whichMatrix welcheMatrix) 
    { 
     double[,] selectedMatrix = null; 

     switch (welcheMatrix) 
     { 
      case whichMatrix.Gaussian3x3: 
       selectedMatrix = new double[,] 
       { 
        { 1, 2, 1, }, 
        { 2, 4, 2, }, 
        { 1, 2, 1, }, 
       }; 
       break; 

      case whichMatrix.Gaussian5x5Type1: 
       selectedMatrix = new double[,] 
       { 
        {-1, -1, -1, -1, -1}, 
        {-1, 2, 2, 2, -1}, 
        {-1, 2, 16, 2, -1}, 
        {-1, 2, -1, 2, -1}, 
        {-1, -1, -1, -1, -1} 
       }; 
       break; 

      case whichMatrix.Mean3x3: 
       selectedMatrix =new double[,] 
       { 
        { 1, 1, 1, }, 
        { 1, 1, 1, }, 
        { 1, 1, 1, }, 
       }; 
       break; 
     } 

     return selectedMatrix; 
    } 
+0

aaalter edit coden in deutsch und englisch gleichezitig? schlechte idee ^^ –

Cuestiones relacionadas