Other Posts in Image Editing

  1. Perlin Noise
  2. Fault Formation
  3. Cellular Textures
  4. Resizing an Image in C#
  5. Box Blur and Gaussian Blur... Sort of...
  6. Thermal Erosion
  7. Using Mid Point Displacement to Create Cracks
  8. Fluvial Erosion
  9. Creating Marble Like Textures Procedurally
  10. Procedural Textures and Dilation
  11. Converting Image to Black and White in C#
  12. Getting an HTML Based Color Palette from an Image in C#
  13. Adding Noise/Jitter to an Image in C#
  14. Creating Pixelated Images in C#
  15. Edge detection in C#
  16. Using Sin to Get What You Want... In C#...
  17. Noise Reduction of an Image in C# using Median Filters
  18. Image Dilation in C#
  19. Sepia Tone in C#
  20. Kuwahara Filter in C#
  21. Matrix Convolution Filters in C#
  22. Symmetric Nearest Neighbor in C#
  23. Bump Map Creation Using C#
  24. Normal Map Creation Using C#
  25. Creating Negative Images using C#
  26. Red, Blue, and Green Filters in C#
  27. Converting an Image to ASCII Art in C#
  28. Adjusting Brightness of an Image in C#
  29. Adding Noise to an Image in C#
  30. Adjusting the Gamma of an Image Using C#
  31. Adjusting Contrast of an Image in C#
  32. Drawing a Box With Rounded Corners in C#
  33. Anding Two Images Together Using C#
  34. Motion Detection in C#
  35. Creating Thermometer Chart in C#
  36. Colorizing a Black and White Image in C#
  37. Extracting an Icon From a File
  38. Setting the Pixel Format and Image Format of an Image in .Net
  39. Using Unsafe Code for Faster Image Manipulation
  40. Sobel Edge Detection and Laplace Edge Detection in C#

Converting an Image to ASCII Art in C#

4/14/2009

I'm not sure if I have to tell you what ASCII art is or not... I might as well talk about what it is just in case. ASCII art is a graphic design technique where you use ASCII characters to represent something. I'm fairly sure that if you're on my site you know what the heck it is and you've seen it numerous times... Anyway, there is a technique of taking existing images and converting them to ASCII art.

The way this technique works, is we figure out the brightness of an individual pixel and insert the correct ASCII character that corresponds with that brightness (obviously looping through the image doing this for each pixel. This is done in only a couple of steps:

  1. Figure out the ASCII characters we want to use
  2. Convert the image to black and white
  3. Loop over the image and insert ASCII characters for pixels...

So there really isn't much to it... But lets look at each step:

What ASCII Characters Should I Use

Generally speaking you want a range of characters with each one having a slightly different brightness and weight. For example:

   1: "#", "@", "%", "=", "+", "*", ":", "-", ".", " "

The characters above go from dark to light. Each of those characters will represent a range within the pixels. For example, if we used the characters above in that order, we'd have each character taking up a range of 28.333. The more characters, the tighter the range but figuring out where each character ranks in terms of brightness can be difficult.

Convert The Image To Black And White

I've covered this before here. If you really wanted to, you could add up the values and divide by 3 (considering accuracy isn't really needed in ASCII art conversion) but you might as well use the ColorMatrix. Another thing you may want to do on this step is resize the image. ASCII art tends to stretch the image's height so scrunching it vertically can be done at this stage to help fight that (or you can just ignore every other line like I'm going to do).

Loop Over The Image

   1: /*
   2: Copyright (c) 2010 <a href="http://www.gutgames.com">James Craig</a>
   3: 
   4: Permission is hereby granted, free of charge, to any person obtaining a copy
   5: of this software and associated documentation files (the "Software"), to deal
   6: in the Software without restriction, including without limitation the rights
   7: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   8: copies of the Software, and to permit persons to whom the Software is
   9: furnished to do so, subject to the following conditions:
  10: 
  11: The above copyright notice and this permission notice shall be included in
  12: all copies or substantial portions of the Software.
  13: 
  14: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20: THE SOFTWARE.*/
  21:  
  22: #region Usings
  23: using System.Drawing;
  24: using System.Drawing.Imaging;
  25: using System.Text;
  26: #endregion
  27:  
  28: namespace Utilities.Media.Image
  29: {
  30:     /// <summary>
  31:     /// Used to create ASCII art
  32:     /// </summary>
  33:     public class ASCIIArt
  34:     {
  35:         #region Public Static Functions
  36:  
  37:         /// <summary>
  38:         /// Converts an image to ASCII art
  39:         /// </summary>
  40:         /// <param name="Input">The image you wish to convert</param>
  41:         /// <returns>A string containing the art</returns>
  42:         public static string ConvertToASCII(Bitmap Input)
  43:         {
  44:             bool ShowLine = true;
  45:             using (Bitmap TempImage = Image.ConvertBlackAndWhite(Input))
  46:             {
  47:                 BitmapData OldData = Image.LockImage(TempImage);
  48:                 int OldPixelSize = Image.GetPixelSize(OldData);
  49:                 StringBuilder Builder = new StringBuilder();
  50:                 for (int x = 0; x < TempImage.Height; ++x)
  51:                 {
  52:                     for (int y = 0; y < TempImage.Width; ++y)
  53:                     {
  54:                         if (ShowLine)
  55:                         {
  56:                             Color CurrentPixel = Image.GetPixel(OldData, y, x, OldPixelSize);
  57:                             Builder.Append(_ASCIICharacters[((CurrentPixel.R * _ASCIICharacters.Length) / 255)]);
  58:                         }
  59:  
  60:                     }
  61:                     if (ShowLine)
  62:                     {
  63:                         Builder.Append(System.Environment.NewLine);
  64:                         ShowLine = false;
  65:                     }
  66:                     else
  67:                     {
  68:                         ShowLine = true;
  69:                     }
  70:                 }
  71:                 Image.UnlockImage(TempImage, OldData);
  72:                 return Builder.ToString();
  73:             }
  74:         }
  75:  
  76:         #endregion
  77:  
  78:         #region Private Variables
  79:  
  80:         private static string[] _ASCIICharacters = { "#", "#", "@", "%", "=", "+", "*", ":", "-", ".", " " };
  81:  
  82:         #endregion
  83:     }
  84: }

The code above uses a couple of functions from my utility library, mainly Image.LockImage, UnlockImage, etc. These functions are there to speed things up a bit but can be removed/replaced with the built in GetPixel function (or you can simply download my utility library and get access to pretty much everything that I've ever posted on my site). Anyway, the code above loops through the image, takes each pixel and multiplies the R value (although G or B would work as well since this is greyscale) by the number of entries in our ASCII character array, then dividing it by 255. This in turn gets us the character that we're going to use. You'll notice that it toggles on and off for every other line (it's the cheap way of fighting the vertical stretching that ASCII art tends to do to an image). Also, you'll notice that it uses my utility library for converting the image to black and white.

Anyway, that's all there is to it really. Converting an image to ASCII art, as you can see above, is incredibly simple. The only difficult portion is figuring out the brightness of an individual character but the characters I use above work fairly well. So try it out, leave feedback, and happy coding.



Comments