Changeset 1930 for www


Ignore:
Timestamp:
Nov 11, 2007, 1:27:40 PM (13 years ago)
Author:
Sam Hocevar
Message:
  • Introducing dither matrices.
Location:
www/study
Files:
13 added
5 edited

Legend:

Unmodified
Added
Removed
  • www/study/index.html

    r1926 r1930  
    4040  <img src="lenna256bw.png" width="256" height="256"
    4141       class="inline" alt="Lenna (256x256BW)" />
     42  <img src="gradient256bw.png" width="32" height="256"
     43       class="inline" alt="gradient" />
    4244</p>
    4345
     
    106108</p>
    107109
    108 <p> Still not very good. Obviously something better is needed. </p>
     110<p> Choosing the best thresholding value for a given image is called
     111<b>average dithering</b>. But even with the best value, the results will
     112not improve tremendously. </p>
    109113
    110114<h3> 1.2. Grayscale thresholding </h3>
     
    172176</p>
    173177
    174 <!--<p> Even if the shades -->
    175 
    176 <h3> 2.3. Introducing gamma </h3>
    177 
    178 <p> More importantly, if you are reading this document on a computer
     178<p> Obviously the middle pattern looks far better to the human eye on a
     179computer screen. Optimising patterns so that they look good to the human
     180eye and don't create artifacts is a crucial element of a dithering
     181algorithm. Here is another example of two patterns that approximate to
     182the same shade of gray but may look slightly different from a distance: </p>
     183
     184<p style="text-align: center;">
     185  <img src="pat004.png" width="320" height="80"
     186       class="inline" alt="two different 25% patterns" />
     187</p>
     188
     189<h3> 2.3. Ordered dither </h3>
     190
     191<p> A generalisation of the dithering technique we just saw that uses a
     192certain family of patterns is called <b>ordered dither</b>. It is based on
     193a <b>dither matrix</b> such as the following one: </p>
     194
     195<p style="text-align: center;">
     196  <img src="fig001.png" width="128" height="128" alt="2x2 dither matrix" />
     197</p>
     198
     199<p> This matrix is then repeated all over the image, and the cells are used
     200as threshold values. In this case, pixels (0,0), (0,2), (0,4) etc. will be
     201thresholded with a value of 0.2. Pixels (0,1), (0, 3), (0, 4) etc. will be
     202thresholded with a value of 0.8, and so on, resulting in the image seen
     203in 2.1. </p>
     204
     205<p> Different matrices can give very different results. This is a 4×4
     206Bayer ordered dither matrix: </p>
     207
     208<p style="text-align: center;">
     209  <img src="fig002.png" width="160" height="160"
     210       style="margin-right: 30px;" alt="4x4 Bayer matrix" />
     211  <img src="out007.png" width="256" height="256"
     212       class="inline" alt="4x4 Bayer dithering" />
     213  <img src="grad007.png" width="32" height="256"
     214       class="inline" alt="4x4 Bayer dithering gradient" />
     215</p>
     216
     217<p> This 4×4 cluster dot matrix creates dot patterns that mimic the
     218halftoning techniques used by newspapers: </p>
     219
     220<p style="text-align: center;">
     221  <img src="fig003.png" width="160" height="160"
     222       style="margin-right: 30px;" alt="4x4 cluster dot matrix" />
     223  <img src="out008.png" width="256" height="256"
     224       class="inline" alt="4x4 cluster dot dithering" />
     225  <img src="grad008.png" width="32" height="256"
     226       class="inline" alt="4x4 cluster dot dithering gradient" />
     227</p>
     228
     229<p> This unusual 5×3 matrix creates artistic vertical line artifacts: </p>
     230
     231<p style="text-align: center;">
     232  <img src="fig004.png" width="200" height="120"
     233       style="margin-right: 30px;" alt="4x4 cluster dot matrix" />
     234  <img src="out009.png" width="256" height="256"
     235       class="inline" alt="4x4 cluster dot dithering" />
     236  <img src="grad009.png" width="32" height="256"
     237       class="inline" alt="4x4 cluster dot dithering gradient" />
     238</p>
     239
     240<!--
     241<h3> 3. Introducing gamma </h3>
     242
     243<p> If you are reading this document on a computer
    179244screen, you may have noticed that the above 50% pattern was closer to a 0.73
    180245grayscale (left) than to the intuitively expected 0.5 value (right). If you
     
    195260
    196261<p style="text-align: center;">
    197   <img src="fig001.png" width="256" height="230" alt="introducing gamma" />
     262  <img src="fig001.png" width="300" height="240" alt="introducing gamma" />
    198263</p>
    199264
     
    227292  <img src="grad007.png" width="32" height="256"
    228293       class="inline" alt="gamma-aware 3-pattern halftoning gradient" />
    229   <img src="out008.png" width="32" height="256"
    230        class="inline" alt="gamma-aware 6.25%, 25% and 50% halftoning" />
    231 </p>
     294</p>
     295-->
    232296
    233297<!--
     298<h3> Gamma with more gray levels </h3>
     299
     300<p> As seen above, the smoothest dithering pattern that can be created with
     301black and white is by uniformly alterning the two colours. However, the
     302resulting colour (0.73) it is not evenly situated on the gray scale. </p>
     303
    234304  <img src="out008.png" width="256" height="256"
    235305       class="inline" alt="gamma-aware 6.25%, 25% and 50% halftoning" />
  • www/study/study.py

    r1927 r1930  
    4747    for y in range(256):
    4848        gradient256bw.setGray(x, 255 - y, y / 255.)
     49gradient256bw.writePng("gradient256bw.png")
    4950
    5051# Output 1: 50% threshold
     
    143144        dest.setGray(x, y, c)
    144145dest.writePng("pat003.png")
     146
     147# Pattern 4: two different 25% patterns
     148dest = Image((320, 80))
     149for y in range(80):
     150    for x in range(80):
     151        c = (x / 2 & 1) and (y / 2 & 1)
     152        dest.setGray(x, y, c)
     153    for x in range(80, 160):
     154        c = (x & 1) and (y & 1)
     155        dest.setGray(x, y, c)
     156    for x in range(160, 240):
     157        c = (x & 1) and ((y + x / 2) & 1)
     158        dest.setGray(x, y, c)
     159    for x in range(240, 320):
     160        c = (x / 2 & 1) and ((y / 2 + x / 4) & 1)
     161        dest.setGray(x, y, c)
     162dest.writePng("pat004.png")
     163
     164# Output 7: 4x4 Bayer dithering
     165def test4(src, mat, name):
     166    (w, h) = src.size()
     167    dest = Image((w, h))
     168    dx = len(mat[0])
     169    dy = len(mat)
     170    for y in range(h):
     171        for x in range(w):
     172            c = src.getGray(x, y)
     173            threshold = (1. + mat[y % dy][x % dx]) / (dx * dy + 1)
     174            c = c > threshold
     175            dest.setGray(x, y, c)
     176    dest.writePng(name)
     177
     178mat = [[  0,  8,  3, 11],
     179       [ 15,  4, 12,  7],
     180       [  2, 10,  1,  9],
     181       [ 13,  6, 14,  5]]
     182test4(lenna256bw, mat, "out007.png")
     183test4(gradient256bw, mat, "grad007.png")
     184
     185mat = [[ 12,  5,  6, 13],
     186       [  4,  0,  1,  7],
     187       [ 11,  3,  2,  8],
     188       [ 15, 10,  9, 14]]
     189test4(lenna256bw, mat, "out008.png")
     190test4(gradient256bw, mat, "grad008.png")
     191
     192mat = [[ 13,  7,  0,  4, 10],
     193       [  9,  3,  1,  8, 14],
     194       [ 11,  5,  2,  6, 12],]
     195test4(lenna256bw, mat, "out009.png")
     196test4(gradient256bw, mat, "grad009.png")
     197
     198##############################################################################
     199# Only temporary cruft below this
     200import sys
     201sys.exit(0)
     202
     203
     204
    145205
    146206# Pattern 4: gamma-corrected 50% gray, black-white halftone, 50% gray
     
    213273
    214274
    215 ##############################################################################
    216 # Only temporary cruft below this
    217 
    218275src = lenna256bw
    219276src = gradient256bw
     
    224281       [  2, 10,  1,  9],
    225282       [ 13,  6, 14,  5]]
    226 mat = [[  6,  7,  8,  9],
    227        [  5,  0,  1, 10],
    228        [  4,  3,  2, 11],
    229        [ 15, 14, 13, 12]]
    230 mat = [[ 12,  5,  9, 13],
    231        [  8,  0,  1,  6],
    232        [  4,  3,  2, 10],
    233        [ 15, 11,  7, 14]]
    234 mat = [[ 35, 24, 13, 14, 25, 32],
    235        [ 31, 12,  5,  6, 15, 26],
    236        [ 23,  4,  0,  1,  7, 16],
    237        [ 22, 11,  3,  2,  8, 17],
    238        [ 30, 21, 10,  9, 18, 27],
    239        [ 34, 29, 20, 19, 28, 33]]
    240 mat = [[  0, 20, 30,  3, 23, 29],
    241        [ 12, 32, 18, 15, 35, 17],
    242        [ 27,  8,  4, 24, 11,  7],
    243        [  2, 22, 28,  1, 21, 31],
    244        [ 14, 34, 16, 13, 33, 19],
    245        [ 25, 10,  6, 26,  9,  5]]
     283#mat = [[  6,  7,  8,  9],
     284#       [  5,  0,  1, 10],
     285#       [  4,  3,  2, 11],
     286#       [ 15, 14, 13, 12]]
     287#mat = [[ 12,  5,  9, 13],
     288#       [  8,  0,  1,  6],
     289#       [  4,  3,  2, 10],
     290#       [ 15, 11,  7, 14]]
     291size = 4
     292#mat = [[ 35, 24, 13, 14, 25, 32],
     293#       [ 31, 12,  5,  6, 15, 26],
     294#       [ 23,  4,  0,  1,  7, 16],
     295#       [ 22, 11,  3,  2,  8, 17],
     296#       [ 30, 21, 10,  9, 18, 27],
     297#       [ 34, 29, 20, 19, 28, 33]]
     298#mat = [[  0, 20, 30,  3, 23, 29],
     299#       [ 12, 32, 18, 15, 35, 17],
     300#       [ 27,  8,  4, 24, 11,  7],
     301#       [  2, 22, 28,  1, 21, 31],
     302#       [ 14, 34, 16, 13, 33, 19],
     303#       [ 25, 10,  6, 26,  9,  5]]
     304#size = 6
    246305dest = Image((w, h))
    247306for y in range(h):
     
    249308        c = src.getGray(x, y)
    250309        i = Gamma.CtoI(c)
    251         threshold = mat[x % 6][y % 6]
    252         c = math.floor(i * 35.999) > threshold
     310        threshold = mat[x % size][y % size]
     311        d = math.floor(i * (size * size + .9999)) > threshold
     312        if c > 0.95:
     313            print c, i, i * (size * size + .9999)
     314        c = d
    253315        dest.setGray(x, y, c)
    254316dest.writePng("out008.png")
    255 
    256 import sys
    257 sys.exit(0)
    258317
    259318# Create a dot-matrix pattern
Note: See TracChangeset for help on using the changeset viewer.