Image to Characters Converter using Intensity






4.60/5 (9 votes)
This article shows how you can display a picture in digits 1 and 0.
Introduction
The main idea is about reading the intensity value of every group of the picture. (The mentioned group is a matrix formed from the adjacent pixels.) Then writing a digit either 1 or 0 and its color value is the average intensity value of the source group.
Background
First of all we have to distinguish between how the intensity is obtained, in this article I'll going to show two methods either:
- 1st intensity method (gives better visual results): in this method, intensity is obtained from the first pixel of the group.
- Average intensity method: while here we calculate the average intensity value of each group.
In both methods, after we get the intensity value we write a digit either 1 or 0 and its color value is the value which we got.
The previous mechanism is applied to the image by reading it as a matrix (2D array). Noticing that traversing through the array is "for each row of the image, visit each pixel".
The next figuures show the differences between the two methods:
![]() |
Original picture |
![]() |
![]() |
1st intensity method | Average intensity method |
Using the Code
Tools
class:
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
namespace Image2Characters
{
public static class Tools
{
/// <summary>
/// folder names both input and output folder
/// </summary>
static String strImagesFolderName = "images";
static String strHtmlFolderName = "pages";
/// <summary>
/// Result html file content
/// </summary>
static String strHtmlFileHeader = "<html><head><title>{0} Image - {1}</title></head><body><pre><font><font style=\"font-size: 9px;\">";
static String strHtmlFileFooter = "</font></font></pre></body></html>";
/// <summary>
/// How many pixels fit in each group
/// here the group size is 12 * 5
/// </summary>
static int iWidthRatio = 5, iHeightRatio = 12;
/// <summary>
/// Make sure program needed directories is exists
/// </summary>
public static void InitEnviroment()
{
Directory.CreateDirectory(strImagesFolderName);
Directory.CreateDirectory(strHtmlFolderName);
}
/// <summary>
/// Calculates the Intensity of each given pixel
/// </summary>
/// <param name="color">the image pixel</param>
/// <returns>the Intensity</returns>
public static int GetIntensity(Color color)
{
return (int)(0.3f * color.R + 0.59f * color.G + 0.11f * color.B);
}
/// <summary>
/// Retrieves the available images that should be converted
/// </summary>
/// <returns></returns>
public static String[] GetImages()
{
return Directory.GetFiles(strImagesFolderName + @"\", "*.jpg");
}
/// <summary>
/// Converts a given image file to its matching html file
/// in "pages" folder using "1st Intensity" value
/// </summary>
/// <param name="strImageName">Image to be converted path</param>
public static void ConvertImageToCharacter1stIntensity(String strImageName)
{
Bitmap img = (Bitmap)Image.FromFile(strImageName);
String strDigit = ""
, strImageNameWithoutExtension = Path.GetFileNameWithoutExtension(strImageName);
StringBuilder createdFileContent = new StringBuilder();
int k = 0; // for switching between 1 and 0
createdFileContent.AppendFormat(strHtmlFileHeader, strImageNameWithoutExtension, System.Windows.Forms.Application.ProductName);
// looping through the image
for (int i = 0; i < img.Height - 1; i += iHeightRatio)
{
for (int j = 0; j < img.Width - 1; j += iWidthRatio)
{
strDigit = (k % 2 == 0) ? "0" : "1";
k++;
createdFileContent.AppendFormat("<font color=\"#{0:x2}{0:x2}{0:x2}\">{1}</font>", Tools.GetIntensity(img.GetPixel(j, i)), strDigit);
}
createdFileContent.Append("<br/>");
}
createdFileContent.Append(strHtmlFileFooter);
// save html output file in "pages" folder
File.WriteAllText(String.Format(@"{0}\{1}.html", strHtmlFolderName, strImageNameWithoutExtension), createdFileContent.ToString());
}
/// <summary>
/// Converts a given image file to its matching html file
/// in "pages" folder using "Average Intensity" value
/// </summary>
/// <param name="strImageName">Image to be converted path</param>
public static void ConvertImageToCharacterAverageIntensity(String strImageName)
{
Bitmap img = (Bitmap)Image.FromFile(strImageName);
String strDigit = ""
, strImageNameWithoutExtension = Path.GetFileNameWithoutExtension(strImageName);
StringBuilder createdFileContent = new StringBuilder();
int iAverageValue // intensity average value for each group
, k = 0 // for switching between 1 and 0
, iItemsCountInSubMatrix = iWidthRatio * iHeightRatio // the count of elements in group
, iSubMatrixElementsSum; // the total value of group elements
createdFileContent.AppendFormat(strHtmlFileHeader, strImageNameWithoutExtension, System.Windows.Forms.Application.ProductName);
// looping through the image
for (int i = 0; i < img.Height - 1; i += iHeightRatio)
{
for (int j = 0; j < img.Width - 1; j += iWidthRatio)
{
iSubMatrixElementsSum = 0;
// looping inside the group
for (int i2 = 0; i2 < iHeightRatio - 1; i2++)
{
if (i + i2 < img.Height)
{
for (int j2 = 0; j2 < iWidthRatio - 1; j2++)
{
if (j + j2 < img.Width)
{
iSubMatrixElementsSum += Tools.GetIntensity(img.GetPixel(j + j2, i + i2));
}
}
}
}
// calculating the average intensity value
iAverageValue = iSubMatrixElementsSum / iItemsCountInSubMatrix;
strDigit = (k % 2 == 0) ? "0" : "1";
k++;
createdFileContent.AppendFormat("<font color=\"#{0:x2}{0:x2}{0:x2}\">{1}</font>", iAverageValue, strDigit);
}
createdFileContent.Append("<br/>");
}
createdFileContent.Append(strHtmlFileFooter);
// save html output file in "pages" folder
File.WriteAllText(String.Format(@"{0}\{1}.html", strHtmlFolderName, strImageNameWithoutExtension), createdFileContent.ToString());
}
}
}
History
- v1.0 15/10/08
Notices
- The only accepted images are the ones that end with the "jpg" extension due to the implementation of my code.
- I chose the size of the group to be 12 rows and 5 columns. You can change these values if you didn't get the desired result. Either you can set them to 1 row and 1 column, this will map each pixel to a digit; of course this will give a bigger picture.
- This project is using C# 2.0 but was coded in Visual Studio 2008.
- I write "1st intensity method" from my practical tries, meaning this is not a referential contrary to "Average intensity method" that is a simple well known method. But I prefered to write "1st intensity method" because it showed better results.
Improvements
- Change the group size to be related to the size of the source image. This improvement will reduce the bad results when the source image is small. For example: width = 80~110px.