Changeset 2029


Ignore:
Timestamp:
Nov 19, 2007, 1:40:43 AM (13 years ago)
Author:
Sam Hocevar
Message:
  • Refactored study.py so that it can be called with the list of chapters to run. That will save me some time.
  • Merged lenna.py into study.py.
Location:
www/study
Files:
1 deleted
2 edited

Legend:

Unmodified
Added
Removed
  • www/study/index.html

    r2027 r2029  
    6868the <tt><a href="study.py">study.py</a></tt> Python program. Just install
    6969the <tt>python-gd</tt> package on your favourite operating system and
    70 run the script. The original Lenna images were generated with the
    71 <tt><a href="lenna.py">lenna.py</a></tt> program from the original colour
    72 512×512 image. </p>
     70run the script. The different Lenna images were generated with the same
     71script from the <a href="http://www.cs.cmu.edu/~chuck/lennapg/">original
     72colour 512×512 image</a>. </p>
    7373
    7474<h3> Sections </h3>
  • www/study/study.py

    r2028 r2029  
    11#!/usr/bin/env python
    22
    3 import math, gd, random
     3import math, gd, random, sys
     4
     5# Select which chapters to run
     6def chapter(n):
     7    if len(sys.argv) == 1:
     8        return True
     9    return str(n) in sys.argv
     10
     11##############################################################################
    412
    513# Tiny image class to make examples short and readable
    614class Image(gd.image):
    7     def __new__(args, truecolor = False):
     15    def __init__(self, *args):
    816        gd.gdMaxColors = 256 * 256 * 256
    9         if truecolor:
    10             return gd.image.__new__(args, True)
    11         else:
    12             return gd.image.__new__(args)
     17        if args[0].__class__ == str:
     18            print " * loading %s" % (args[0],)
     19        gd.image.__init__(self, *args)
    1320    def save(self, name):
    1421        print " * saving %s" % (name,)
     
    3340        self.setPixel((x, y), c)
    3441
    35 ##############################################################################
    36 print "Initialisation"
    37 
    3842# Manipulate gamma values
    3943class Gamma:
     
    4650    CtoI = staticmethod(CtoI)
    4751    ItoC = staticmethod(ItoC)
    48 
    49 # Load the 256x256 grayscale Lenna image
    50 lenna256bw = Image("lenna256bw.png")
     52    def Cto2(x):
     53        if x < Gamma.CtoI(0.50):
     54            return 0.
     55        return 1.
     56    def Cto3(x):
     57        if x < Gamma.CtoI(0.25):
     58            return 0.
     59        elif x < Gamma.CtoI(0.75):
     60            return Gamma.CtoI(0.5)
     61        return 1.
     62    def Cto4(x):
     63        if x < Gamma.CtoI(0.17):
     64            return 0.
     65        elif x < Gamma.CtoI(0.50):
     66            return Gamma.CtoI(0.3333)
     67        elif x < Gamma.CtoI(0.83):
     68            return Gamma.CtoI(0.6666)
     69        return 1.
     70    Cto2 = staticmethod(Cto2)
     71    Cto3 = staticmethod(Cto3)
     72    Cto4 = staticmethod(Cto4)
     73
     74##############################################################################
     75print "Initialisation"
     76
     77# Load the original Lenna image
     78lenna512 = Image("lenna512.png")
     79(w, h) = lenna512.size()
     80
     81# Image 1: grayscale conversion
     82# Read the compression FAQ [55] for the rationale behind using the green
     83# channel (http://www.faqs.org/faqs/compression-faq/part1/section-30.html)
     84if chapter(0):
     85    (w, h) = lenna512.size()
     86    lenna512bw = Image((w, h))
     87    for y in range(h):
     88        for x in range(w):
     89            rgb = lenna512.getRgb(x, y)
     90            c = rgb[1]
     91            lenna512bw.setGray(x, y, c)
     92    lenna512bw.save("lenna512bw.png")
     93else:
     94    lenna512bw = Image("lenna512bw.png")
     95   
     96# Image 2: 50% grayscale
     97# Image 3: 50% scaling
     98if chapter(0):
     99    (w, h) = lenna512.size()
     100    lenna256bw = Image((w / 2, h / 2))
     101    lenna256 = Image((w / 2, h / 2), True)
     102    for y in range(h / 2):
     103        for x in range(w / 2):
     104            r = g = b = 0.
     105            for j in range(2):
     106                for i in range(2):
     107                    rgb = lenna512.getRgb(x * 2 + i, y * 2 + j)
     108                    r += Gamma.CtoI(rgb[0])
     109                    g += Gamma.CtoI(rgb[1])
     110                    b += Gamma.CtoI(rgb[2])
     111            r = Gamma.ItoC(r / 4)
     112            g = Gamma.ItoC(g / 4)
     113            b = Gamma.ItoC(b / 4)
     114            lenna256bw.setGray(x, y, g)
     115            lenna256.setRgb(x, y, r, g, b)
     116    lenna256bw.save("lenna256bw.png")
     117    lenna256.save("lenna256.png")
     118else:
     119    lenna256bw = Image("lenna256bw.png")
     120    lenna256 = Image("lenna256.png")
    51121
    52122# Create a 32x256 grayscale gradient
    53 gradient256bw = Image((32, 256))
    54 for x in range(32):
    55     for y in range(256):
    56         gradient256bw.setGray(x, 255 - y, y / 255.)
    57 gradient256bw.save("gradient256bw.png")
     123if chapter(0):
     124    gradient256bw = Image((32, 256))
     125    for x in range(32):
     126        for y in range(256):
     127            gradient256bw.setGray(x, 255 - y, y / 255.)
     128    gradient256bw.save("gradient256bw.png")
     129else:
     130    gradient256bw = Image("gradient256bw.png")
    58131
    59132##############################################################################
    60 print "Chapter 1. Colour quantisation"
     133if chapter(1):
     134    print "Chapter 1. Colour quantisation"
    61135
    62136# Output 1.1.1: 50% threshold
     
    72146    return dest
    73147
    74 test11x(lenna256bw, 0.5).save("out1-1-1.png")
    75 test11x(lenna256bw, 0.4).save("out1-1-2.png")
    76 test11x(lenna256bw, 0.6).save("out1-1-3.png")
    77 test11x(gradient256bw, 0.5).save("grad1-1-1.png")
    78 test11x(gradient256bw, 0.4).save("grad1-1-2.png")
    79 test11x(gradient256bw, 0.6).save("grad1-1-3.png")
     148if chapter(1):
     149    test11x(lenna256bw, 0.5).save("out1-1-1.png")
     150    test11x(lenna256bw, 0.4).save("out1-1-2.png")
     151    test11x(lenna256bw, 0.6).save("out1-1-3.png")
     152    test11x(gradient256bw, 0.5).save("grad1-1-1.png")
     153    test11x(gradient256bw, 0.4).save("grad1-1-2.png")
     154    test11x(gradient256bw, 0.6).save("grad1-1-3.png")
    80155
    81156# Output 1.2.1: 3-colour threshold
     
    93168    return dest
    94169
    95 test12x(lenna256bw, 3).save("out1-2-1.png")
    96 test12x(lenna256bw, 5).save("out1-2-2.png")
    97 test12x(gradient256bw, 3).save("grad1-2-1.png")
    98 test12x(gradient256bw, 5).save("grad1-2-2.png")
     170if chapter(1):
     171    test12x(lenna256bw, 3).save("out1-2-1.png")
     172    test12x(lenna256bw, 5).save("out1-2-2.png")
     173    test12x(gradient256bw, 3).save("grad1-2-1.png")
     174    test12x(gradient256bw, 5).save("grad1-2-2.png")
    99175
    100176# Output 1.2.3: 3-colour threshold, minimal error
     
    112188    return dest
    113189
    114 test12y(lenna256bw, 3).save("out1-2-3.png")
    115 test12y(lenna256bw, 5).save("out1-2-4.png")
    116 test12y(gradient256bw, 3).save("grad1-2-3.png")
    117 test12y(gradient256bw, 5).save("grad1-2-4.png")
     190if chapter(1):
     191    test12y(lenna256bw, 3).save("out1-2-3.png")
     192    test12y(lenna256bw, 5).save("out1-2-4.png")
     193    test12y(gradient256bw, 3).save("grad1-2-3.png")
     194    test12y(gradient256bw, 5).save("grad1-2-4.png")
    118195
    119196##############################################################################
    120 print "Chapter 2. Halftoning patterns"
     197if chapter(2):
     198    print "Chapter 2. Halftoning patterns"
    121199
    122200# Pattern 2.1.1: a 50% halftone pattern with various block sizes
    123 dest = Image((320, 80))
    124 for x in range(320):
    125     d = 8 >> (x / 80)
    126     for y in range(80):
    127         c = (x / d + y / d) & 1
    128         dest.setGray(x, y, c)
    129 dest.save("pat2-1-1.png")
    130 
    131201# Pattern 2.1.2: 25% and 75% halftone patterns with various block sizes
    132 dest = Image((320, 80))
    133 for x in range(320):
    134     d = 8 >> (x / 80)
    135     for y in range(40):
    136         c = ((x / d + y / d) & 1) or (y / d & 1)
    137         dest.setGray(x, y, c)
    138     for y in range(40, 80):
    139         c = ((x / d + y / d) & 1) and (y / d & 1)
    140         dest.setGray(x, y, c)
    141 dest.save("pat2-1-2.png")
     202if chapter(2):
     203    dest = Image((320, 80))
     204    for x in range(320):
     205        d = 8 >> (x / 80)
     206        for y in range(80):
     207            c = (x / d + y / d) & 1
     208            dest.setGray(x, y, c)
     209    dest.save("pat2-1-1.png")
     210
     211    dest = Image((320, 80))
     212    for x in range(320):
     213        d = 8 >> (x / 80)
     214        for y in range(40):
     215            c = ((x / d + y / d) & 1) or (y / d & 1)
     216            dest.setGray(x, y, c)
     217        for y in range(40, 80):
     218            c = ((x / d + y / d) & 1) and (y / d & 1)
     219            dest.setGray(x, y, c)
     220    dest.save("pat2-1-2.png")
    142221
    143222# Output 2.1.1: 20/40/60/80% threshold with 25/50/75% patterns inbetween:
     
    161240    return dest
    162241
    163 test211(lenna256bw).save("out2-1-1.png")
    164 test211(gradient256bw).save("grad2-1-1.png")
     242if chapter(2):
     243    test211(lenna256bw).save("out2-1-1.png")
     244    test211(gradient256bw).save("grad2-1-1.png")
    165245
    166246# Pattern 2.2.1: vertical, mixed and horizontal black-white halftones
    167 dest = Image((240, 80))
    168 for y in range(80):
    169     for x in range(80):
    170         c = x & 1
    171         dest.setGray(x, y, c)
    172     for x in range(80, 160):
    173         c = (x / d + y / d) & 1
    174         dest.setGray(x, y, c)
    175     for x in range(160, 240):
    176         c = y & 1
    177         dest.setGray(x, y, c)
    178 dest.save("pat2-2-1.png")
    179 
    180247# Pattern 2.2.2: two different 25% patterns
    181 dest = Image((320, 80))
    182 for y in range(80):
    183     for x in range(80):
    184         c = (x / 2 & 1) and (y / 2 & 1)
    185         dest.setGray(x, y, c)
    186     for x in range(80, 160):
    187         c = (x & 1) and (y & 1)
    188         dest.setGray(x, y, c)
    189     for x in range(160, 240):
    190         c = (x & 1) and ((y + x / 2) & 1)
    191         dest.setGray(x, y, c)
    192     for x in range(240, 320):
    193         c = (x / 2 & 1) and ((y / 2 + x / 4) & 1)
    194         dest.setGray(x, y, c)
    195 dest.save("pat2-2-2.png")
     248if chapter(2):
     249    dest = Image((240, 80))
     250    for y in range(80):
     251        for x in range(80):
     252            c = x & 1
     253            dest.setGray(x, y, c)
     254        for x in range(80, 160):
     255            c = (x / d + y / d) & 1
     256            dest.setGray(x, y, c)
     257        for x in range(160, 240):
     258            c = y & 1
     259            dest.setGray(x, y, c)
     260    dest.save("pat2-2-1.png")
     261
     262    dest = Image((320, 80))
     263    for y in range(80):
     264        for x in range(80):
     265            c = (x / 2 & 1) and (y / 2 & 1)
     266            dest.setGray(x, y, c)
     267        for x in range(80, 160):
     268            c = (x & 1) and (y & 1)
     269            dest.setGray(x, y, c)
     270        for x in range(160, 240):
     271            c = (x & 1) and ((y + x / 2) & 1)
     272            dest.setGray(x, y, c)
     273        for x in range(240, 320):
     274            c = (x / 2 & 1) and ((y / 2 + x / 4) & 1)
     275            dest.setGray(x, y, c)
     276    dest.save("pat2-2-2.png")
    196277
    197278# Output 2.3.1: 4x4 Bayer dithering
    198279# Output 2.3.2: 4x4 cluster dot
    199280# Output 2.3.3: 5x3 line dithering
     281def test23x(src, mat):
     282    (w, h) = src.size()
     283    dest = Image((w, h))
     284    dx = len(mat[0])
     285    dy = len(mat)
     286    for y in range(h):
     287        for x in range(w):
     288            c = src.getGray(x, y)
     289            threshold = (1. + mat[y % dy][x % dx]) / (dx * dy + 1)
     290            c = c > threshold
     291            dest.setGray(x, y, c)
     292    return dest
     293
    200294DITHER_BAYER44 = \
    201295    [[  0, 12,  3, 15],
     
    231325     [ 11,  5,  2,  6, 12],]
    232326
    233 def test23x(src, mat):
    234     (w, h) = src.size()
    235     dest = Image((w, h))
    236     dx = len(mat[0])
    237     dy = len(mat)
    238     for y in range(h):
    239         for x in range(w):
    240             c = src.getGray(x, y)
    241             threshold = (1. + mat[y % dy][x % dx]) / (dx * dy + 1)
    242             c = c > threshold
    243             dest.setGray(x, y, c)
    244     return dest
    245 
    246 test23x(lenna256bw, DITHER_BAYER44).save("out2-3-1.png")
    247 test23x(gradient256bw, DITHER_BAYER44).save("grad2-3-1.png")
    248 
    249 test23x(lenna256bw, DITHER_BAYER88).save("out2-3-1b.png")
    250 test23x(gradient256bw, DITHER_BAYER88).save("grad2-3-1b.png")
    251 
    252 test23x(lenna256bw, DITHER_CLUSTER44).save("out2-3-2.png")
    253 test23x(gradient256bw, DITHER_CLUSTER44).save("grad2-3-2.png")
    254 
    255 test23x(lenna256bw, DITHER_CLUSTER88).save("out2-3-2b.png")
    256 test23x(gradient256bw, DITHER_CLUSTER88).save("grad2-3-2b.png")
    257 
    258 test23x(lenna256bw, DITHER_LINE53).save("out2-3-3.png")
    259 test23x(gradient256bw, DITHER_LINE53).save("grad2-3-3.png")
     327if chapter(2):
     328    test23x(lenna256bw, DITHER_BAYER44).save("out2-3-1.png")
     329    test23x(gradient256bw, DITHER_BAYER44).save("grad2-3-1.png")
     330
     331    test23x(lenna256bw, DITHER_BAYER88).save("out2-3-1b.png")
     332    test23x(gradient256bw, DITHER_BAYER88).save("grad2-3-1b.png")
     333
     334    test23x(lenna256bw, DITHER_CLUSTER44).save("out2-3-2.png")
     335    test23x(gradient256bw, DITHER_CLUSTER44).save("grad2-3-2.png")
     336
     337    test23x(lenna256bw, DITHER_CLUSTER88).save("out2-3-2b.png")
     338    test23x(gradient256bw, DITHER_CLUSTER88).save("grad2-3-2b.png")
     339
     340    test23x(lenna256bw, DITHER_LINE53).save("out2-3-3.png")
     341    test23x(gradient256bw, DITHER_LINE53).save("grad2-3-3.png")
    260342
    261343# Output 2.4.1: uniform random dithering
     
    271353    return dest
    272354
    273 test241(lenna256bw).save("out2-4-1.png")
    274 test241(gradient256bw).save("grad2-4-1.png")
     355if chapter(2):
     356    test241(lenna256bw).save("out2-4-1.png")
     357    test241(gradient256bw).save("grad2-4-1.png")
    275358
    276359# Output 2.4.2: gaussian random dithering
     
    286369    return dest
    287370
    288 test242(lenna256bw).save("out2-4-2.png")
    289 test242(gradient256bw).save("grad2-4-2.png")
     371if chapter(2):
     372    test242(lenna256bw).save("out2-4-2.png")
     373    test242(gradient256bw).save("grad2-4-2.png")
    290374
    291375# Output 2.4.3: 4x4 Bayer dithering with gaussian perturbation
     
    305389    return dest
    306390
    307 test243(lenna256bw, DITHER_BAYER88).save("out2-4-3.png")
    308 test243(gradient256bw, DITHER_BAYER88).save("grad2-4-3.png")
     391if chapter(2):
     392    test243(lenna256bw, DITHER_BAYER88).save("out2-4-3.png")
     393    test243(gradient256bw, DITHER_BAYER88).save("grad2-4-3.png")
    309394
    310395# Output 2.4.4: random dither matrice selection
     
    326411    return dest
    327412
    328 m1 = [[1, 4, 7],
    329       [6, 0, 2],
    330       [3, 8, 5]]
    331 m2 = [[4, 6, 3],
    332       [8, 1, 5],
    333       [0, 3, 7]]
    334 m3 = [[5, 0, 3],
    335       [2, 8, 6],
    336       [7, 4, 1]]
    337 m4 = [[8, 2, 5],
    338       [6, 4, 0],
    339       [1, 7, 3]]
    340 m5 = [[2, 5, 8],
    341       [0, 7, 3],
    342       [4, 1, 6]]
    343 m6 = [[7, 4, 1],
    344       [3, 6, 8],
    345       [2, 0, 5]]
    346 mlist = [m1, m2, m3, m4, m5, m6]
    347 test244(lenna256bw, mlist).save("out2-4-4.png")
    348 test244(gradient256bw, mlist).save("grad2-4-4.png")
     413if chapter(2):
     414    m1 = [[1, 4, 7],
     415          [6, 0, 2],
     416          [3, 8, 5]]
     417    m2 = [[4, 6, 3],
     418          [8, 1, 5],
     419          [0, 3, 7]]
     420    m3 = [[5, 0, 3],
     421          [2, 8, 6],
     422          [7, 4, 1]]
     423    m4 = [[8, 2, 5],
     424          [6, 4, 0],
     425          [1, 7, 3]]
     426    m5 = [[2, 5, 8],
     427          [0, 7, 3],
     428          [4, 1, 6]]
     429    m6 = [[7, 4, 1],
     430          [3, 6, 8],
     431          [2, 0, 5]]
     432    mlist = [m1, m2, m3, m4, m5, m6]
     433    test244(lenna256bw, mlist).save("out2-4-4.png")
     434    test244(gradient256bw, mlist).save("grad2-4-4.png")
    349435
    350436##############################################################################
    351 print "Chapter 3. Error diffusion"
     437if chapter(3):
     438    print "Chapter 3. Error diffusion"
    352439
    353440# Output 3.0.1: naive error diffusion
     
    363450# Output 3.2.7: Sierra's Filter Lite
    364451# Output 3-2-8: Atkinson
     452def test3xx(src, mat, serpentine):
     453    (w, h) = src.size()
     454    dest = Image((w, h))
     455    lines = len(mat)
     456    rows = len(mat[0])
     457    offset = mat[0].index(-1)
     458    ey = [[0.] * (w + rows - 1) for x in range(lines)]
     459    for y in range(h):
     460        ex = [0.] * (rows - offset)
     461        if serpentine and y & 1:
     462            xrange = range(w - 1, -1, -1)
     463        else:
     464            xrange = range(w)
     465        for x in xrange:
     466            # Set pixel
     467            c = src.getGray(x, y) + ex[0] + ey[0][x + offset]
     468            d = c > 0.5
     469            dest.setGray(x, y, d)
     470            error = c - d
     471            # Propagate first line of error
     472            for dx in range(rows - offset - 2):
     473                ex[dx] = ex[dx + 1] + error * mat[0][offset + 1 + dx]
     474            ex[rows - offset - 2] = error * mat[0][rows - 1]
     475            # Propagate next lines
     476            if serpentine and y & 1:
     477                for dy in range(1, lines):
     478                    for dx in range(rows):
     479                        ey[dy][x + dx] += error * mat[dy][rows - 1 - dx]
     480            else:
     481                for dy in range(1, lines):
     482                    for dx in range(rows):
     483                        ey[dy][x + dx] += error * mat[dy][dx]
     484        for dy in range(lines - 1):
     485            ey[dy] = ey[dy + 1]
     486        ey[lines - 1] = [0.] * (w + rows - 1)
     487    return dest
     488
    365489ERROR_NAIVE = \
    366490    [[ -1, 1]]
     
    409533#     [  2./200,  9./200, 12./200,  9./200,  2./200]]
    410534
    411 def test3xx(src, mat, serpentine):
    412     (w, h) = src.size()
    413     dest = Image((w, h))
    414     lines = len(mat)
    415     rows = len(mat[0])
    416     offset = mat[0].index(-1)
    417     ey = [[0.] * (w + rows - 1) for x in range(lines)]
    418     for y in range(h):
    419         ex = [0.] * (rows - offset)
    420         if serpentine and y & 1:
    421             xrange = range(w - 1, -1, -1)
    422         else:
    423             xrange = range(w)
    424         for x in xrange:
    425             # Set pixel
    426             c = src.getGray(x, y) + ex[0] + ey[0][x + offset]
    427             d = c > 0.5
    428             dest.setGray(x, y, d)
    429             error = c - d
    430             # Propagate first line of error
    431             for dx in range(rows - offset - 2):
    432                 ex[dx] = ex[dx + 1] + error * mat[0][offset + 1 + dx]
    433             ex[rows - offset - 2] = error * mat[0][rows - 1]
    434             # Propagate next lines
    435             if serpentine and y & 1:
    436                 for dy in range(1, lines):
    437                     for dx in range(rows):
    438                         ey[dy][x + dx] += error * mat[dy][rows - 1 - dx]
    439             else:
    440                 for dy in range(1, lines):
    441                     for dx in range(rows):
    442                         ey[dy][x + dx] += error * mat[dy][dx]
    443         for dy in range(lines - 1):
    444             ey[dy] = ey[dy + 1]
    445         ey[lines - 1] = [0.] * (w + rows - 1)
    446     return dest
    447 
    448 test3xx(lenna256bw, ERROR_NAIVE, False).save("out3-0-1.png")
    449 test3xx(gradient256bw, ERROR_NAIVE, False).save("grad3-0-1.png")
    450 
    451 test3xx(lenna256bw, ERROR_FSTEIN, False).save("out3-1-1.png")
    452 test3xx(gradient256bw, ERROR_FSTEIN, False).save("grad3-1-1.png")
    453 test3xx(lenna256bw, ERROR_FSTEIN, True).save("out3-1-2.png")
    454 test3xx(gradient256bw, ERROR_FSTEIN, True).save("grad3-1-2.png")
    455 
    456 test3xx(lenna256bw, ERROR_FAN, False).save("out3-2-1.png")
    457 test3xx(gradient256bw, ERROR_FAN, False).save("grad3-2-1.png")
    458 
    459 test3xx(lenna256bw, ERROR_JAJUNI, False).save("out3-2-2.png")
    460 test3xx(gradient256bw, ERROR_JAJUNI, False).save("grad3-2-2.png")
    461 
    462 test3xx(lenna256bw, ERROR_STUCKI, False).save("out3-2-3.png")
    463 test3xx(gradient256bw, ERROR_STUCKI, False).save("grad3-2-3.png")
    464 
    465 test3xx(lenna256bw, ERROR_BURKES, False).save("out3-2-4.png")
    466 test3xx(gradient256bw, ERROR_BURKES, False).save("grad3-2-4.png")
    467 
    468 test3xx(lenna256bw, ERROR_SIERRA, False).save("out3-2-5.png")
    469 test3xx(gradient256bw, ERROR_SIERRA, False).save("grad3-2-5.png")
    470 
    471 test3xx(lenna256bw, ERROR_SIERRA2, False).save("out3-2-6.png")
    472 test3xx(gradient256bw, ERROR_SIERRA2, False).save("grad3-2-6.png")
    473 
    474 test3xx(lenna256bw, ERROR_FILTERLITE, False).save("out3-2-7.png")
    475 test3xx(gradient256bw, ERROR_FILTERLITE, False).save("grad3-2-7.png")
    476 
    477 test3xx(lenna256bw, ERROR_ATKINSON, False).save("out3-2-8.png")
    478 test3xx(gradient256bw, ERROR_ATKINSON, False).save("grad3-2-8.png")
    479 
    480 #test3xx(lenna256bw, ERROR_STAR, False).save("out3-2-9.png")
    481 #test3xx(gradient256bw, ERROR_STAR, False).save("grad3-2-9.png")
    482 
    483 #test3xx(lenna256bw, ERROR_STAR, False).save("out3-2-9.png")
    484 #test3xx(gradient256bw, ERROR_STAR, False).save("grad3-2-9.png")
     535if chapter(3):
     536    test3xx(lenna256bw, ERROR_NAIVE, False).save("out3-0-1.png")
     537    test3xx(gradient256bw, ERROR_NAIVE, False).save("grad3-0-1.png")
     538
     539    test3xx(lenna256bw, ERROR_FSTEIN, False).save("out3-1-1.png")
     540    test3xx(gradient256bw, ERROR_FSTEIN, False).save("grad3-1-1.png")
     541    test3xx(lenna256bw, ERROR_FSTEIN, True).save("out3-1-2.png")
     542    test3xx(gradient256bw, ERROR_FSTEIN, True).save("grad3-1-2.png")
     543
     544    test3xx(lenna256bw, ERROR_FAN, False).save("out3-2-1.png")
     545    test3xx(gradient256bw, ERROR_FAN, False).save("grad3-2-1.png")
     546
     547    test3xx(lenna256bw, ERROR_JAJUNI, False).save("out3-2-2.png")
     548    test3xx(gradient256bw, ERROR_JAJUNI, False).save("grad3-2-2.png")
     549
     550    test3xx(lenna256bw, ERROR_STUCKI, False).save("out3-2-3.png")
     551    test3xx(gradient256bw, ERROR_STUCKI, False).save("grad3-2-3.png")
     552
     553    test3xx(lenna256bw, ERROR_BURKES, False).save("out3-2-4.png")
     554    test3xx(gradient256bw, ERROR_BURKES, False).save("grad3-2-4.png")
     555
     556    test3xx(lenna256bw, ERROR_SIERRA, False).save("out3-2-5.png")
     557    test3xx(gradient256bw, ERROR_SIERRA, False).save("grad3-2-5.png")
     558
     559    test3xx(lenna256bw, ERROR_SIERRA2, False).save("out3-2-6.png")
     560    test3xx(gradient256bw, ERROR_SIERRA2, False).save("grad3-2-6.png")
     561
     562    test3xx(lenna256bw, ERROR_FILTERLITE, False).save("out3-2-7.png")
     563    test3xx(gradient256bw, ERROR_FILTERLITE, False).save("grad3-2-7.png")
     564
     565    test3xx(lenna256bw, ERROR_ATKINSON, False).save("out3-2-8.png")
     566    test3xx(gradient256bw, ERROR_ATKINSON, False).save("grad3-2-8.png")
     567
     568    #test3xx(lenna256bw, ERROR_STAR, False).save("out3-2-9.png")
     569    #test3xx(gradient256bw, ERROR_STAR, False).save("grad3-2-9.png")
     570
     571    #test3xx(lenna256bw, ERROR_STAR, False).save("out3-2-9.png")
     572    #test3xx(gradient256bw, ERROR_STAR, False).save("grad3-2-9.png")
    485573
    486574##############################################################################
    487 print "Chapter 4. Grayscale dithering"
     575if chapter(4):
     576    print "Chapter 4. Grayscale dithering"
    488577
    489578# Output 4.0.1: 4x4 Bayer dithering, 3 colours
     
    504593    return dest
    505594
    506 test401(lenna256bw, DITHER_BAYER44).save("out4-0-1.png")
    507 test401(gradient256bw, DITHER_BAYER44).save("grad4-0-1.png")
     595if chapter(4):
     596    test401(lenna256bw, DITHER_BAYER44).save("out4-0-1.png")
     597    test401(gradient256bw, DITHER_BAYER44).save("grad4-0-1.png")
    508598
    509599# Output 4.0.2: standard Floyd-Steinberg, 3 colours
     
    545635    return dest
    546636
    547 test402(lenna256bw, ERROR_FSTEIN, False).save("out4-0-2.png")
    548 test402(gradient256bw, ERROR_FSTEIN, False).save("grad4-0-2.png")
     637    test402(lenna256bw, ERROR_FSTEIN, False).save("out4-0-2.png")
     638    test402(gradient256bw, ERROR_FSTEIN, False).save("grad4-0-2.png")
    549639
    550640# Pattern 4.1.1: gamma-corrected 50% gray, black-white halftone, 50% gray
    551 dest = Image((240, 80))
    552 for y in range(80):
    553     for x in range(80):
    554         dest.setGray(x, y, Gamma.ItoC(0.5))
    555     for x in range(80, 160):
    556         c = (x + y) & 1
    557         dest.setGray(x, y, c)
    558     for x in range(160, 240):
    559         dest.setGray(x, y, 0.5)
    560 dest.save("pat4-1-1.png")
     641if chapter(4):
     642    dest = Image((240, 80))
     643    for y in range(80):
     644        for x in range(80):
     645            dest.setGray(x, y, Gamma.ItoC(0.5))
     646        for x in range(80, 160):
     647            c = (x + y) & 1
     648            dest.setGray(x, y, c)
     649        for x in range(160, 240):
     650            dest.setGray(x, y, 0.5)
     651    dest.save("pat4-1-1.png")
    561652
    562653# Output 4.2.1: gamma-corrected 2-colour Floyd-Steinberg
     
    591682    return dest
    592683
    593 def threshold_2(x):
    594     if x < Gamma.CtoI(0.50):
    595         return 0.
    596     return 1.
    597 
    598 def threshold_3(x):
    599     if x < Gamma.CtoI(0.25):
    600         return 0.
    601     elif x < Gamma.CtoI(0.75):
    602         return Gamma.CtoI(0.5)
    603     return 1.
    604 
    605 def threshold_4(x):
    606     if x < Gamma.CtoI(0.17):
    607         return 0.
    608     elif x < Gamma.CtoI(0.50):
    609         return Gamma.CtoI(0.3333)
    610     elif x < Gamma.CtoI(0.83):
    611         return Gamma.CtoI(0.6666)
    612     return 1.
    613 
    614 test42x(lenna256bw, ERROR_FSTEIN, threshold_2).save("out4-2-1.png")
    615 test42x(gradient256bw, ERROR_FSTEIN, threshold_2).save("grad4-2-1.png")
    616 test42x(lenna256bw, ERROR_FSTEIN, threshold_3).save("out4-2-2.png")
    617 test42x(gradient256bw, ERROR_FSTEIN, threshold_3).save("grad4-2-2.png")
    618 test42x(lenna256bw, ERROR_FSTEIN, threshold_4).save("out4-2-3.png")
    619 test42x(gradient256bw, ERROR_FSTEIN, threshold_4).save("grad4-2-3.png")
     684if chapter(4):
     685    test42x(lenna256bw, ERROR_FSTEIN, Gamma.Cto2).save("out4-2-1.png")
     686    test42x(gradient256bw, ERROR_FSTEIN, Gamma.Cto2).save("grad4-2-1.png")
     687    test42x(lenna256bw, ERROR_FSTEIN, Gamma.Cto3).save("out4-2-2.png")
     688    test42x(gradient256bw, ERROR_FSTEIN, Gamma.Cto3).save("grad4-2-2.png")
     689    test42x(lenna256bw, ERROR_FSTEIN, Gamma.Cto4).save("out4-2-3.png")
     690    test42x(gradient256bw, ERROR_FSTEIN, Gamma.Cto4).save("grad4-2-3.png")
    620691
    621692##############################################################################
    622 print "Chapter 5. Colour dithering"
     693if chapter(5):
     694    print "Chapter 5. Colour dithering"
    623695
    624696# Pattern 5.1.1: 8-colour palette
    625 dest = Image((512, 64))
    626 for x in range(512):
    627     d = x / 64
    628     r = (d & 2) >> 1
    629     g = (d & 4) >> 2
    630     b = d & 1
    631     for y in range(64):
    632         dest.setRgb(x, y, r, g, b)
    633 dest.save("pat5-1-1.png")
    634 
    635 # Load the 256x256 colour Lenna image
    636 lenna256 = Image("lenna256.png")
     697if chapter(5):
     698    dest = Image((512, 64))
     699    for x in range(512):
     700        d = x / 64
     701        r = (d & 2) >> 1
     702        g = (d & 4) >> 2
     703        b = d & 1
     704        for y in range(64):
     705            dest.setRgb(x, y, r, g, b)
     706    dest.save("pat5-1-1.png")
    637707
    638708# Output 5.1.1: 8-colour Floyd-Steinberg RGB dithering
     
    648718                tmp[i].setGray(x, y, rgb[i])
    649719    for i in range(3):
    650         tmp[i] = func(tmp[i], mat, threshold_2)
     720        tmp[i] = func(tmp[i], mat, Gamma.Cto2)
    651721    for y in range(h):
    652722        for x in range(w):
     
    655725    return dest
    656726
    657 test51x(lenna256, ERROR_FSTEIN, test3xx).save("out5-1-1.png")
    658 out512 = test51x(lenna256, ERROR_FSTEIN, test42x)
    659 out512.save("out5-1-2.png")
     727if chapter(5):
     728    test51x(lenna256, ERROR_FSTEIN, test3xx).save("out5-1-1.png")
     729    out512 = test51x(lenna256, ERROR_FSTEIN, test42x)
     730    out512.save("out5-1-2.png")
    660731
    661732# Pattern 5.2.1: different colours give the same result
    662 dest = Image((320, 160))
    663 for x in range(80):
    664     for y in range(80):
    665         r = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 7
    666         g = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 13
    667         b = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 13
    668         dest.setRgb(x, y, b, g, r)
    669     for y in range(80, 160):
    670         r = DITHER_BAYER44[y % 4][x % 4] > 7
    671         g = DITHER_BAYER44[y % 4][x % 4] > 13
    672         b = DITHER_BAYER44[y % 4][x % 4] > 13
    673         dest.setRgb(x, y, b, g, r)
    674 for x in range(80, 160):
    675     for y in range(80):
    676         r = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 7
    677         g = DITHER_BAYER44[(y / 8) % 4][(x / 8 + 1) % 4] > 13
    678         b = DITHER_BAYER44[(y / 8) % 4][(x / 8 + 1) % 4] > 13
    679         dest.setRgb(x, y, b, g, r)
    680     for y in range(80, 160):
    681         r = DITHER_BAYER44[y % 4][x % 4] > 7
    682         g = DITHER_BAYER44[y % 4][(x + 1) % 4] > 13
    683         b = DITHER_BAYER44[y % 4][(x + 1) % 4] > 13
    684         dest.setRgb(x, y, b, g, r)
    685 for x in range(160, 240):
    686     for y in range(80):
    687         r = DITHER_BAYER44[(y / 8 + 1) % 4][(x / 8 + 1) % 4] > 7
    688         g = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 13
    689         b = DITHER_BAYER44[(y / 8 + 1) % 4][(x / 8) % 4] > 13
    690         dest.setRgb(x, y, b, g, r)
    691     for y in range(80, 160):
    692         r = DITHER_BAYER44[(y + 1) % 4][(x + 1) % 4] > 7
    693         g = DITHER_BAYER44[y % 4][x % 4] > 13
    694         b = DITHER_BAYER44[(y + 1) % 4][x % 4] > 13
    695         dest.setRgb(x, y, b, g, r)
    696 for x in range(240, 320):
    697     for y in range(80):
    698         r = DITHER_BAYER44[(y / 8 + 1) % 4][(x / 8) % 4] > 7
    699         g = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 13
    700         b = DITHER_BAYER44[(y / 8) % 4][(x / 8 + 2) % 4] > 13
    701         dest.setRgb(x, y, b, g, r)
    702     for y in range(80, 160):
    703         r = DITHER_BAYER44[(y + 1) % 4][x % 4] > 7
    704         g = DITHER_BAYER44[y % 4][x % 4] > 13
    705         b = DITHER_BAYER44[y % 4][(x + 2) % 4] > 13
    706         dest.setRgb(x, y, b, g, r)
    707 dest.save("pat5-2-1.png")
     733def chapter5():
     734    dest = Image((320, 160))
     735    for x in range(80):
     736        for y in range(80):
     737            r = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 7
     738            g = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 13
     739            b = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 13
     740            dest.setRgb(x, y, b, g, r)
     741        for y in range(80, 160):
     742            r = DITHER_BAYER44[y % 4][x % 4] > 7
     743            g = DITHER_BAYER44[y % 4][x % 4] > 13
     744            b = DITHER_BAYER44[y % 4][x % 4] > 13
     745            dest.setRgb(x, y, b, g, r)
     746    for x in range(80, 160):
     747        for y in range(80):
     748            r = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 7
     749            g = DITHER_BAYER44[(y / 8) % 4][(x / 8 + 1) % 4] > 13
     750            b = DITHER_BAYER44[(y / 8) % 4][(x / 8 + 1) % 4] > 13
     751            dest.setRgb(x, y, b, g, r)
     752        for y in range(80, 160):
     753            r = DITHER_BAYER44[y % 4][x % 4] > 7
     754            g = DITHER_BAYER44[y % 4][(x + 1) % 4] > 13
     755            b = DITHER_BAYER44[y % 4][(x + 1) % 4] > 13
     756            dest.setRgb(x, y, b, g, r)
     757    for x in range(160, 240):
     758        for y in range(80):
     759            r = DITHER_BAYER44[(y / 8 + 1) % 4][(x / 8 + 1) % 4] > 7
     760            g = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 13
     761            b = DITHER_BAYER44[(y / 8 + 1) % 4][(x / 8) % 4] > 13
     762            dest.setRgb(x, y, b, g, r)
     763        for y in range(80, 160):
     764            r = DITHER_BAYER44[(y + 1) % 4][(x + 1) % 4] > 7
     765            g = DITHER_BAYER44[y % 4][x % 4] > 13
     766            b = DITHER_BAYER44[(y + 1) % 4][x % 4] > 13
     767            dest.setRgb(x, y, b, g, r)
     768    for x in range(240, 320):
     769        for y in range(80):
     770            r = DITHER_BAYER44[(y / 8 + 1) % 4][(x / 8) % 4] > 7
     771            g = DITHER_BAYER44[(y / 8) % 4][(x / 8) % 4] > 13
     772            b = DITHER_BAYER44[(y / 8) % 4][(x / 8 + 2) % 4] > 13
     773            dest.setRgb(x, y, b, g, r)
     774        for y in range(80, 160):
     775            r = DITHER_BAYER44[(y + 1) % 4][x % 4] > 7
     776            g = DITHER_BAYER44[y % 4][x % 4] > 13
     777            b = DITHER_BAYER44[y % 4][(x + 2) % 4] > 13
     778            dest.setRgb(x, y, b, g, r)
     779    dest.save("pat5-2-1.png")
    708780
    709781# Output 5.2.1: cropped 5.1.2
     
    719791    return dest
    720792
    721 test52x(out512, 20, 70, 32, 32, 1).save("out5-2-1.png")
    722 test52x(out512, 20, 70, 32, 32, 6).save("out5-2-2.png")
    723 
    724 out523 = test51x(lenna256, ERROR_STUCKI, test42x)
    725 out523.save("out5-2-3.png")
    726 test52x(out523, 20, 70, 32, 32, 1).save("out5-2-4.png")
    727 test52x(out523, 20, 70, 32, 32, 6).save("out5-2-5.png")
     793if chapter(5):
     794    test52x(out512, 20, 70, 32, 32, 1).save("out5-2-1.png")
     795    test52x(out512, 20, 70, 32, 32, 6).save("out5-2-2.png")
     796
     797    out523 = test51x(lenna256, ERROR_STUCKI, test42x)
     798    out523.save("out5-2-3.png")
     799    test52x(out523, 20, 70, 32, 32, 1).save("out5-2-4.png")
     800    test52x(out523, 20, 70, 32, 32, 6).save("out5-2-5.png")
     801
     802##############################################################################
     803if chapter(6):
     804    print "Chapter 6. Photographic mosaics"
    728805
    729806##############################################################################
     
    731808
    732809# Place temporary cruft below this
    733 import sys; sys.exit(0)
    734 
     810sys.exit(0)
     811
Note: See TracChangeset for help on using the changeset viewer.