Skip to content

Instantly share code, notes, and snippets.

@rossant
Last active December 15, 2015 01:19
Show Gist options
  • Save rossant/5178730 to your computer and use it in GitHub Desktop.
Save rossant/5178730 to your computer and use it in GitHub Desktop.
ASCII art in the IPython notebook.
{
"metadata": {
"name": "ascimage"
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ASCII art in the IPython notebook\n",
"=================================\n",
"\n",
"We're going to write a script in Python for generating an ASCII image from a picture."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, we need a few imports. We'll use NumPy, SciPy, PIL and Matplotlib here."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from pylab import *\n",
"import scipy.misc\n",
"from PIL import Image"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will download images directly from the Internet. Here is a function which takes a picture URL as an argument, and returns a NumPy array."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import cStringIO\n",
"import urllib\n",
"\n",
"def download_image(url):\n",
" return array(Image.open(cStringIO.StringIO(urllib.urlopen(url).read())))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here is how the generation is going to work. We will:\n",
" \n",
" * Reduce the image size so that each pixel corresponds to a single character\n",
" * Convert the image in grayscale, so that each pixel corresponds to a single luminance value\n",
" * Discretize the luminance values regularly between 0 and 1\n",
" * Associate each discretized luminance value to a character, with dark pixels corresponding to rich characters like `@`, and light pixels corresponding to small characters like `.`. To improve the quality of the ASCII art, we can randomly sample a character among several ones for a single luminance value.\n",
" * Render the ASCII art in an HTML tag with specific CSS properties like a monospace font.\n",
" \n",
"Here, we first specify the list of characters to use, where the `|` character separates the different luminance values"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"characters = '@|ARE|CLI|+|/|-|.| '.split('|')\n",
"nbins = len(characters)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We also specify the size, in characters, of the final text."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"asciisize = 100"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, we download a picture and convert it into an array."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"url = \"http://cyrille.rossant.net/wp-content/uploads/2011/09/photo.jpg\"\n",
"image = download_image(url)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We resize the image using SciPy (we could also use PIL)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"h, w = image.shape[:2]\n",
"w, h = asciisize, int(h / float(w) * asciisize)\n",
"image = scipy.misc.imresize(image, (w, h))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We convert the picture into a grayscale image."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"bins = linspace(0, 1., nbins)\n",
"grey = image.mean(axis=2)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 7
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To take discrete luminance values of each pixel, we use the NumPy `digitize` function, so that `digitized` contains integer values between 0 and K - 1, where K is the total number of different luminance values."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"m, M = grey.min(), grey.max()\n",
"grey = (grey - m) / (M - m)\n",
"digitized = digitize(grey.ravel(), bins).reshape((w, h))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 8
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The ASCII generation happens here: we replace every luminance index by a text character, according to the characters list specified above."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"ascii = zeros(digitized.shape, dtype='a1')\n",
"for i in xrange(nbins):\n",
" ind = digitized == i\n",
" ascii[ind] = array(list(characters[i]))[randint(low=0, high=len(characters[i]), size=ind.sum())]\n",
"asciistr = '\\n'.join([''.join(row) for row in ascii])"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 9
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, we render the ASCII art in a `<pre>` tag and we specify some CSS styles. Playing with the CSS parameters might be a good idea, especially when using different pictures."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"fontsize = 5\n",
"lineheight = 4\n",
"letterspacing = 1\n",
"\n",
"class Ascii(object):\n",
" def __init__(self, asciistr):\n",
" self.asciistr = asciistr\n",
" \n",
" def _repr_html_(self):\n",
" return \"\"\"<pre style=\"font-size: {0:.1f}pt; font-family: monospace;\n",
" line-height: {1:.1f}pt; letter-spacing: {2:.1f}pt;\">{3:s}</pre>\"\"\".format(\n",
" fontsize, lineheight, letterspacing, self.asciistr)\n",
"Ascii(asciistr)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<pre style=\"font-size: 5.0pt; font-family: monospace;\n",
" line-height: 4.0pt; letter-spacing: 1.0pt;\">RCLLICIECCLLLEICCLCICAERRAAREAAERRAAL++++IREA+//++++CRARRARAEI++++++EEARERRLEERILCLCEEERCCIICCCLCCIL\n",
"LILLILCRIIICAERR+CCIIEAEAEERAEEAEEEAAICAREERR//++++IEEREEEAAEI+++++LIRREEAREEARLLICAAREARARRARRRREAR\n",
"ILCICIIRCIEAAEEEARLIIEAAAEAERREARERERAARAREAE+//C/CEEEEREEEERE++++++LEREAAAEREREAEREERARAAEEEAEERAIE\n",
"ICIIICIIAEARARARERALRREAREEEEERARERRAEEAEAAAAREALC/EEREARARRA+L/++++AERRERERARAAARAEREAEEAAAARRRALCR\n",
"CIICCCCCAAREARERRAALEREAEERAAAREAEEAARRAAEREERAAAE++ECREEAEL/EEL++++CAARAEARRRRRREEAERRAREERERAER+IC\n",
"CLIICCILILLCRRAAAAECRERRARREEEEAEAERREEEERAAERARRAE/+EREAEL+IEALLL+++ERRRERRRRAEEAEEEARRRRAREARIC+/L\n",
"IIIIIIICLICLLLLL+CCLARRARAEARRRAEERAERAAARRAAREAARLA/ARAARC+CAIEIC+++ERIAREAAEEREAAEARRERRAALAE++++C\n",
"LLLCCALIAIICL/+LCC+IIAERAEARRARE+CEAAAEAEEEEREEREAC++AAACCEALCERACI+CAERERRRAEAEEERERAAAEERALRRLI++L\n",
"EERECIIILI++/+CLILCC+IRRCCRAIL+LACEAAEREEAAAEAEEERCRL+EILCECLREREAILAAAEEAEELCCEARRAEARRARRAECEER+IL\n",
"ICICILIL++++LIILCII+CL++C+L+IILAAIERREEAAAAREEAAAECCRC/CEACARRERARLICREERARLCALAAREEERARRREAAEARAEAA\n",
"ICICACC+++++CC+IIILARLLRRCLLLIEIAALIRRERARREAAEREI++IC+EERAAEERRAERIIEERAEEEAIAIREEAERRRARERAAAERERA\n",
"LI++IR+//++++LCCC+RCEELLCRCRRECL+I+CCRREARRRARRLLCC+LRL/ICCCEIARRREEEIRERREAAIRACRERERARRREERRRAREER\n",
"C+++++/+L+++LILIIICEARLLCRLEREAAL++C/IARAEEARRCLL+CLIAC/+IEARAEARARRCCLLEAARRARAAERRRRRARRARRAAEAERA\n",
"L++C++EACILCICAALCCAAILRELACRREAL+++//ERRAEARRIAAILCEA++IIAEERAERRARCIICARRRERRREREAEEERAEEAEAAEARER\n",
"I++CCCAREILL+LRECAEA++IRRLARRERAL+++//LAREELILCILCLLAEILEIEEEEEAAAAECILLLREAEAEARRAEEERRRREERREAEEEA\n",
"E++CICAAEREICEREAAAE++IEAEAEREAL+//+++CECCII+++//++++IILARAAERRAREAEACILLAEAAERERARRAERARAAAAERAAERR\n",
"AC+CCAAARERRIARRRRRA+IACRAERRERI+//IRAI++++///////////++CRRRRACLERRERCLLIRREAREAARRRREERREEAAAEREEAR\n",
"EEIIRARARRAAAERLAEEE+ALCREERAERC++LEC++///-//--/////////+IIAEAREIEREACLLREREAEEAEAAERAAEEEEARRAREEAE\n",
"RLRCAARRRRAARAERAEAA+ACIEAAEEAECCREI+//////--------------/+LIAAEIERRACCRRERARAEAAEERAEARRARREAEAAERA\n",
"ILERAAERRRRAERIIRRERAAILCCARRREEAI+///////---..-.----------/+IEEREERRIIEEREAERREEREAEERRARRARREAAAAR\n",
"CCRRREAEERRRELIICARILRI++IIEARRAI+///////---..............--/+CAAALARILLERREAEAEEAAREEERRERAARRRARER\n",
"CLARREAREEAAACLLRELIAEL++++CAAEI+////-----.. . ......--/LLRALIARAEERRAERARREAREAAEAEREREEERAA\n",
"LEARAEEAERRRERLCEEEAREC+///LAAR+///--... . ......-+ILRREERERERERRAEAEEARRAAREREERERRAII\n",
"AREAREAAEECIILIIERAAEEC+//+AERI//--... ....../+CIEARERAICRRREREAEAREREARAERRAEALCC\n",
"ERAEERRARRLCIIILICICEEL++RAERL/---.. ......-++LARARAEILLAAEERAEAEAAAERAAEARIRCII\n",
"REREAEARRCCCLLLIILLCEEL/+LERE+--..... ......//+IAAAERCLLERAEEEEAERAAAERAILLLLCCE\n",
"RRAAAEARICIILCIC+L+AER++IEAEC-...... .......-/+CLRE+CCREARRAEEEAEERREALIIILICCLR\n",
"AEARRAAALLCCLL+L+++AIA++EAEI/........ ..........-+ICAAILL+EAAAAARRARREERAECCLIIIICL\n",
"AAEARAARLICCLL+++++ICA++AARL-........ ..........-/+LIALAECREARAARRRRRRREAEICLCIRRCI\n",
"RARRARACICCIII+LICCILLLLRRC+-........ .........../+ILELRECERAEERRAREEEERRRICLEAALIL\n",
"CRAAEEAILCCCICLIIALLREIIRLL+-.--.... .........-..-+CCIAACCAEAAEAEEEEREERRAARRAARILC\n",
"ECRRALILICLCICILIECRRIECLCC/----..... ........----/+LLIALICARERRRREAAREEAEREEEACCLL\n",
"ICRAELILCILLILLCIICRECICCI+-----...... ........----/+CLCRIIIREREEAAREEERARRERRRACLLL\n",
"CIEELLIICCCCLLIICRERAECICL+-----..... ........----/+ILICIICAAAAREIRERAREAEAEARAILCI\n",
"LIRCIILLIICCCCIAEERAAAELIL+-----...... . ......----+LLIICIILERAAERIARRAEERAAEEEECCCI\n",
"ILCLCCLLLIILLLREAARAAARRIL+-----...... . .....-----/LCICCICLAEAARRALEAAEEAEEEAAALILL\n",
"IILLLCLIIICCAREEAAEAEEEEAI+/----...... . ...-----+CLICLLIIREAEAARCEARAERAEAEARCICI\n",
"CIIILIIICILIRRRERRAEAEREACC+/---..... ..... .....----/LIILICIIREREEARLCIEARARERAEALCLC\n",
"CCCCLIICIICCRRRAERARAEREERL+/---..... . . .............---------/ICCIIILLAEAARAAICCICERRERREREICL\n",
"CLLILLCLLLCLAAARERRAAERCERII/----.....................//++++++///---ICLCCLCIERARARRECLILIREEREERRLCR\n",
"CLERIIICCCIIAAARAREAAELCAECC/-/--.-............-.----+LICIC++++++/--+CLC+/LIARRERRELREELIIAREAEEALAA\n",
"++LCLICRIEREEAAREEAALIILRACC/-/-.--//////---------//CLIL+/////+++/--/III.-/IRERRERCCLALCIICRACAAEEEE\n",
"++I+II++IEAREAAAAEERL+LIRAII/-/--+++ILIIC++//----/++LC++//////////---LI-.+++CCRARRRLCCCCILEEAAAIAAER\n",
"IERELRERA+ERREAEEAEAREELLRLC/-//+L++//+ICCCI+/-..-++C+L++/---/////---CC-/++/LLCLRAARICLLCREARRLLEEAE\n",
"CAREIAAEACAEEAAAEERAARALLARI///++/----//++IL+/...-/+LIC+++IL+++++//-+LI//-//CLLIRACRAREAEAECEELLIRRA\n",
"CECRERCCERAEEAEAAERRCCL+-IRI/-////-////++LCIC/. ./LIL++LLAL+I+//-LLC+I/--/-AIICCIARAERERRAAEELLLLCC\n",
"CEREREACLRCAI++LAEARIII/--CL/-//+++/+ILLC++C++--/+C++++-+LI+/++/--+/--+//-/-ACCCIAEERRERREARRACLCCIL\n",
"CLAERAALAELCAERICLIC+AL++-+R+//-/+++LRAI++I/-++---/+////////++/---/---/+//-/AIILLLREAAEEEARREELCCCIE\n",
"EREERECIRECILLCRRARRCCI++//LCC+-/+LI/LIL///--L- -++++++++++/----+---/+/--+EELIIERAEAAELREAARILLLAA\n",
"ACREERRC+ICCEERERRRLILI//-/I//+//+++////+++//C. .+///++++++/-.../---///--LCEECILIIIEECRERAAAACIILE\n",
"AARRERAECERLEARRCCCCCCL-/-/+--+///////++++/-.+. .-----//----....----/+-.-LEEEILLLLLRRRACLLCICIRIIE\n",
"LIEAEAERAEERCCICAAICIIC+/-/+--/---///++++/-.-/.. .-/.....-------.---//+-..ARERILILCCCERCCCLLCCIILAE\n",
"EAEAEILEIC+LLICEEALCEAEE--/+/---.----///-...--.. ..-//-----......---//+-..RAAAIIILIAAERCCCCLCCILRAE\n",
"AREAEIAAIAIELRREEAEEELRR/--+/-------------///-.. ..-//--........---//++-.-RREALIEAREACLLRCLIIIICERC\n",
"ERRIIEAARRRRLREAEAERIICCC-.+----.........--//-.. ....-//--.......---//+C.-/LCEIILERECLCCLICIIILLILCI\n",
"ECAICREEEERRRARAARAR++IIA..+/--..........----......--.-/---......---//++--LCEEERILLIILLLILICLLLILICC\n",
"ACEILEEARAARRAEIAAEELCCRA/.+/--.........----..--.--//--------------///++--ARRRRICCLCLICICICELLCIICRL\n",
"RLAECAAARALILEALIRAALICREL.///--........-----/C+///IE+/-----------///+++-LAERERCCLCCILLCEREEELILIRRR\n",
"RRERCCARALCLCRAE+EEIIICLEE//+/---.....---.../+C+/+++++/-------//////+++++EEEARALCCCLIICRRAAEACCIELRA\n",
"ARRELCRRAARILARRIIACCCLREEI/+/------..--....-+//++++///----/////////+++CERAARAERLLLLICEEAERAEAAIAERE\n",
"AAERACLEARECIREAICCCCILAAAR/C//---------....---//+++////--///+///+///++RERREREERCCLARAEAEEEEERAAAAAA\n",
"ERRERCLLARACILRRLILLACCEEERCC+//---------.---------------//++++//+++/++EREAAAEAERLIERRRAAERERRAARARL\n",
"ARAAAECCAERIILARLIIIAARRAERAI+////-/-/-//----...----------/++++/+++//+IREAREEREARREERAAREEAEAAREEERL\n",
"RREEEACLRAAREEAALICLAARERREAE++////////++/--.--/--//++++++CC++/////+++IIEEAERAERERERARRAAREARREAAEAC\n",
"RREERRAICEREAARA+++ERRRREREAAL+++/////+++/////////++++++++//++///+//++AIAEARAEREAAEAEERRARREAERRREAE\n",
"REREAREALCRAEEEE+CLRARRRAEEERC+///////+++IC+++++++C+///////////+++//+LLIIEAEAEAAEEEAEERERRREEAREARRA\n",
"RAEEEARAACEEEELELEERAEEARAEAEL+///////++////--.......-///////+/++++/+LEAEEEAEREARRAERRAAAEREEAERREEE\n",
"EARREEERALCEAACELREARAAEARRAEIL/////////---///------/+++////+++++++++REERARAREAAAREARRERERLCAAEEEAAA\n",
"EERAAREAEEELERCAIAREEARRARRARIC+//////-//--////////++++/////++++++++LAAREERARAERAERAAALEIELREEAERRRR\n",
"EREAEEREEAAAEAAILEAEAREAEEERRLCL+//////////////++++++++///+++++ILL+LIRARRRREARAEEEERARARLCREAERAEEAE\n",
"RERRRAEEREACICI++EREAEARAEAEALII+++++/+///-////+++++//////+++CLCICIL+ERRERREREERARAERCRELAEAAEARRAEA\n",
"AEARALARAEEAI+++LRAAEAEEAERARCIACC+++++++//---/---------//++IILIIILL/RRRRAEEEEAERAAAARILAREAICERRLRR\n",
"AEAAAERAEREI+++IAAEREARAEREEILLELI++LI++++/--------/---///++LLILCRL+/IARRREARAREARRERACAAAALLIEAEICA\n",
"RRRRARRREC+C++LIRAAERAEEAREAICLE+LLCCC++++//----/--//////++LIIIIEL+//CREAAAAEEARRREAAIRACLEILCAAIILI\n",
"ARRRAAAIEAALICAERARAEEEAARAECLEAC/LLILC+++//----////////+++LIICERL+//AARARREARRAERAARLRACCLICLERLLII\n",
"REREEEEAIRRERAAARAEEREERAAAALCRAA/+CEIIL+++///////++/+++++LICEERC+///REEAAEREAAEEREEIEEEIEIEIEREACIC\n",
"AEERREREAEEAAEERREEARREAEEARLCERE//+IECIII++/++++++++++ILIILAARLC+///RARAARRRERRARRAAARILILIILARRLLC\n",
"AEREAERREAREAAAREERRRAAEEEERICAEC///+IAALCCI+L+LLLC+ICCIILEARELCI+///AARRAAEREEEEARRRARLCACILIARAICL\n",
"EEREAREREEILAEEEARRERACEAEACLAARR+///+CERRELLCCIICCLLEREEAAEILCI+////RREAAEERAAARAERRILLAEICCAREILII\n",
"+++CLEEREEAELEARAAREECCREEEIEEERRI/-//+LIRERERLLRRREREAREERIICL++////EAREARERRAERREAEIIILRLILRRILLLC\n",
"REERL+IEREEEIEARARRARLILRRRARREEER+--//+LIERREERAERRRERRRAILCC++////+AAEARRREERRERAARACICLCLICRRACLI\n",
"AARAEILC+LARALRERIERAAREAAAEARARRE+/--//+CCCREAAARERRRREIIICI++/////LRRARRAERRAARRRERREACLLCLLRARCCL\n",
"ERRRRAEEILLARAIIAILAARAEEAREAAEREAL/---//++CLLIAEAEARECCCL++L++/////ARAERAAAARAEAARRRRRRERRRICAEEILI\n",
"RERARACEEEELRRCRACCEAAEEREEEREAERAA/---//++++IILCCLCIIILCC++C++////+AAREEARREAAEEEEAEARRREECLLEALEII\n",
"RAEEARREERRRLICALLLERAAEARRRARARAER+-----//+++LIIIICCI++++++++/////+RAAEAARRRREAERAERRRAAEAECARREAIL\n",
"RARAAAAREEAECRLIERAAAEARRRRRAERRAEEA/----///+++++++LCL+++++++//////CERERAERRREAAEERERAREEEAAEARRACCL\n",
"RRRRAAEEARERERRRREAAAEREAAEEEAAERRAR/-------///++++++IIIC++++/////+AREAARAERREEARREARAEREERREERIEILC\n",
"AEAARERRICLICEAEEREEAARREAEARRARAAERL--------////++/++++++////////IAREREEEEARERARREEERERARRRERAAAICI\n",
"AAAEEELERCAEEERAEAERREREEAAAAAEAAAREA/--------///////+++/+///////+CERARRAERRAAARRAEAEEEEEAERAAARACLL\n",
"REREERLIREEREEAEAAAARRRAAEAEEREAEREEE/-----------///////////////++LRERREAAARAERERERERRRAEEAACEEARRAC\n",
"RRERERRRERRRAREAEEERAAERAAEREEEEAEERR+------------/////////////+++CEAARRRERRREAAAEEARARAIEERAEEAAAAA\n",
"AAAARRAEERRRRERRAARRREEAAEEEEAEAEEAEEL/-----------/////////////++CREEAAEAAEEEAAEEREAEEEAEEEEERRRREAE\n",
"EAEEEAEEAEEREERREEARREERARRERAAARREAAE+/--------/////////++///+++IEEREERARAAEAEARERREARRRAAEEERERERA\n",
"AEEEERAAARRERREEEEEEEERARERREAEAEAAERA+/---------//////++++++++++CEEEAAERRAERREERREAERERAEIREEEAEARR\n",
"RRARRRERRRREEERRRREEAARAEEEARAEERRRAEE+/----------///++++++///+++AAAAARRAAAREEAEREEEARELERRAEAAEERAR\n",
"RARREERAEEEERRAERARRARARAAAREEERERAEAA+/----------////++++////+++RRARARRAREAERAAERARAAERERAEEAAEEARA\n",
"EAAREERARRRREAREARRRREREEAEEEERREAARAEC/-----------////+////////+RAARARAARRARRRAAEAAEAEEAAEEARRRREER\n",
"RERAEEEREAAAAAEEAEAAARREEERRAEEERRAARRA/-......----///////////-/ARARAARAAAEEEAAEAAAERAERERRAARRREAAE\n",
"ARRAEEAREERARREAAAAAARERAARRRARAAREEAER/--.......-------/------+AAAERRERRREEAERAERREERCAAEARRRAAARRR\n",
"REERARRRERRRRRERRRREAERARAERERREERAARER/-...........-----------AEERRRRRARAARARAEERERAARERAEAEEAAERRA</pre>"
],
"output_type": "pyout",
"prompt_number": 10,
"text": [
"<__main__.Ascii at 0x58d59b0>"
]
}
],
"prompt_number": 10
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment