Welcome, guest | Sign In | My Account | Store | Cart

Code to generate degraded letter stimuli, as used in the paper "The remarkable inefficiency of word recognition" (Pelli et al. 2003). Utilizes the Python Imaging Library, and is an example of the usage of this library.

Python, 67 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
"""This contains routines to generate degraded letter stimuli"""

import Image #The PIL
import ImageDraw
import ImageFont

import numpy

def generate_letter(contrast_energy = .01, #michelson contrast energy
                   noise = 30.,
                   bg_luminance = 128.,
                   letter = "a",
                   letter_size = 400):
 N = 300 #size of image in pixels

 #first figure out what is the ink-area of the letter

 font = ImageFont.truetype("Data/arial.ttf", letter_size)
 #we copy the .ttf file to the local directory to avoid problems

 im_temp = Image.new("1", (1,1), 0)
 draw = ImageDraw.Draw(im_temp)
 #now we can draw on this

 sz = draw.textsize(letter, font=font)
 #this tells us the size of the letter

 im_temp = Image.new("1", sz, 0)
 #this is a temporary binary image created solely for the purpose of computing
 #the ink-area of the letter
 draw = ImageDraw.Draw(im_temp)
 #now we can draw on this
 draw.text((0,0), letter, font=font, fill=1)
 pix = im_temp.load()
 #pix is now an addressable array of pixel values
 area_in_pixels = 0.
 for row in xrange(sz[0]):
   for col in xrange(sz[1]):
     area_in_pixels += pix[row,col]

 #since contrast_energy = contrast^2 * pixel_area
 contrast = (contrast_energy/area_in_pixels)**0.5
 fg_luminance = bg_luminance*(1+contrast)/(1-contrast)
 print area_in_pixels
 print contrast
 print fg_luminance


 im = Image.new("L", (N,N), bg_luminance)
 #im is now a NxN luminance image with luminance set to bg_luminance

 draw = ImageDraw.Draw(im)
 #now we can draw on this

 draw.text(((N-sz[0])/2, (N-sz[1])/2), letter, font=font, fill=fg_luminance)
 #this centers the letter

 if noise > 0:
   pix = im.load()
   #pix is now an addressable array of pixel values
  
   rd = numpy.random.normal(scale=noise, size=(N,N))
   for row in xrange(N):
     for col in xrange(N):
       pix[row,col] += rd[row,col]

 im.show()

2 comments

greg p 13 years, 2 months ago  # | flag

I made this into a an online utility here.

But I could only get PIL's default font to work, could you tell me if I'm getting the right result? It doesn't look like anything.

Kaushik Ghose (author) 10 years, 7 months ago  # | flag

Woops, I just saw this greg. I only got an error from the online utility, unfortunately.