+3  A: 

It is quite simple: divide the image with a grid, compute average color (or luminosity or hue, etc.) of the pixels found on each grid cell, create an image of same size, draw the letter corresponding to the grid cell with the found color.

PhiLho
That would be assuming a fixed-width font?
digitala
If you're being adventurous, you could also weight different characters be the amount of space they take up when printed (So you might make 'i' artificially lighter than 'I' to achieve the same luminosity in the result)
Rowland Shaw
@Phillip: yes, the simple solution (used in the question itself too) requires a fixed-width font
orip
@Phillip: I posted the second answer before seeing your comment... As I wrote, a fixed font gives better results, but since I position each char individually, a proportional font is OK. Can play with dingbat fonts too...
PhiLho
A: 

There are two drivers for mplayer that address this, one is BW called "libaa" / ascii-art, the other "libcaca":

Sources are available to both, I don't remember under which license.

See this for screenshots of both libs in action: http://liquidweather.net/howto/index.php?id=74

diciu
A: 

I was a bit buzzy, but I finally hacked a little Processing sketch to demonstrate my algorithm.

final int GRID_SIZE_H = 9;
final int GRID_SIZE_V = 9;
final int GRID_SIZE = GRID_SIZE_H * GRID_SIZE_V;
final String TEXT_TO_DISPLAY = "Picture yourself in a boat on a river With tangerine trees and marmalade skies";

void setup()
{
  size(600, 600);
  smooth();
  noStroke();
  background(0);

  PImage niceImage = loadImage("SomeImage.png");
  int niW  = niceImage.width;
  int niH = niceImage.height;
  int imgW = niW + 10;
  image(niceImage, 0, 0);

  PFont f = loadFont("Arial-Black-12.vlw");
  textFont(f);
  textAlign(CENTER);
  String textToDisplay = TEXT_TO_DISPLAY.toUpperCase().replaceAll("\\s", "");

  int pos = 0;
  niceImage.loadPixels();
  for (int j = 0; j < niH - GRID_SIZE_V; j += GRID_SIZE_V)
  {
    for (int i = 0; i < niW - GRID_SIZE_H; i += GRID_SIZE_H)
    {
      long avgR = 0, avgG = 0, avgB = 0;
      for (int x = 0; x < GRID_SIZE_H; x++)
      {
        for (int y = 0; y < GRID_SIZE_V; y++)
        {
          int c = niceImage.pixels[i + x + (j + y) * niW];
          avgR += (c >> 16) & 0xFF;
          avgG += (c >>  8) & 0xFF;
          avgB +=  c        & 0xFF;
        }
      }
      color clr = color(avgR / GRID_SIZE, avgG / GRID_SIZE, avgB / GRID_SIZE);
      fill(clr);
      char chr = textToDisplay.charAt(pos++);
      pos = pos % textToDisplay.length();
      text(chr, i + imgW, j + 12);
    }
  }
}

Should work better with a fat (bold) monospaced font.

PhiLho