Changeset 2127Tweet

Ignore:
Timestamp:
Dec 6, 2007, 11:47:14 PM (12 years ago)
Message:
• Shiau-Fan patented dithering.
• Ostromoukhov's variable coefficient error diffusion.
Location:
www/study
Files:
2 edited

Unmodified
Removed
• www/study/part3.html

 r2125

3.2. Floyd-Steinberg derivatives

Fan dithering is a slight modification of Floyd-Steinberg with a very similar matrix:

Zhigang Fan came up with several Floyd-Steinberg derivatives. Fan dithering just moves one coefficient around:

class="inline" alt="Fan error diffusion gradient" />

Shiau-Fan dithering use a family of matrices supposed to reduce the apparition of artifacts usually seen with Floyd-Steinberg:

By the way, these matrices are covered by Shiau’s and Fan’s U.S. patent 5353127.

Jarvis, Judice and Ninke dithering uses a much more complex -->

3.3. Image parsing

3.3. Image parsing direction

While image parsing order does not matter with ordered dithering, it can class="inline" alt="serpentine Floyd-Steinberg" /> class="inline" alt="serpentine Floyd-Steinberg gradient" />

3.4. Variable coefficients error diffusion

Ostromoukhov’s variable coefficients error diffusion uses a small matrix, which usually causes a lot of artifacts to appear. However, the coefficients here vary according to the input value, and the list of 256 discrete value triplets for d1, d2 and d3 provided by Ostromoukhov give pretty good results:

• www/study/study.py

 r2126 # FIXME: serpentine only works if rows == offset * 2 + 1 # Output 3.2.1: Fan (modified Floyd-Steinberg) # Output 3.2.1b: Shiau-Fan 1 # Output 3.2.1c: Shiau-Fan 2 # Output 3.2.2: Jarvis, Judice and Ninke # Output 3-2-3: Stucki [[    0.,    0.,    -1, 7./16], [ 1./16, 3./16, 5./16,    0.]] ERROR_SHIAUFAN = \ [[    0.,    0.,    -1, 8./16], [ 2./16, 2./16, 4./16,    0.]] ERROR_SHIAUFAN2 = \ [[    0.,    0.,    0.,    -1, 8./16], [ 1./16, 1./16, 2./16, 4./16,    0.]] ERROR_JAJUNI = \ [[    0.,    0.,    -1, 7./48, 5./48], test3xx(lenna256bw, ERROR_FAN, False).save("out3-2-1.png") test3xx(gradient256bw, ERROR_FAN, False).save("grad3-2-1.png") test3xx(lenna256bw, ERROR_SHIAUFAN, False).save("out3-2-1b.png") test3xx(gradient256bw, ERROR_SHIAUFAN, False).save("grad3-2-1b.png") test3xx(lenna256bw, ERROR_SHIAUFAN2, False).save("out3-2-1c.png") test3xx(gradient256bw, ERROR_SHIAUFAN2, False).save("grad3-2-1c.png") test3xx(lenna256bw, ERROR_JAJUNI, False).save("out3-2-2.png") test3xx(tmp, ERROR_FSTEIN, False).getZoom(2).save("out3-3-1.png") test3xx(tmp, ERROR_FSTEIN, True).getZoom(2).save("out3-3-2.png") # Output 3-4-1: Ostromoukhov’s variable error diffusion def test341(src, serpentine): m = [[13, 0, 5], [13, 0, 5], [21, 0, 10], [7, 0, 4], [8, 0, 5], [47, 3, 28], [23, 3, 13], [15, 3, 8], [22, 6, 11], [43, 15, 20], [7, 3, 3], [501, 224, 211], [249, 116, 103], [165, 80, 67], [123, 62, 49], [489, 256, 191], [81, 44, 31], [483, 272, 181], [60, 35, 22], [53, 32, 19], [237, 148, 83], [471, 304, 161], [3, 2, 1], [481, 314, 185], [354, 226, 155], [1389, 866, 685], [227, 138, 125], [267, 158, 163], [327, 188, 220], [61, 34, 45], [627, 338, 505], [1227, 638, 1075], [20, 10, 19], [1937, 1000, 1767], [977, 520, 855], [657, 360, 551], [71, 40, 57], [2005, 1160, 1539], [337, 200, 247], [2039, 1240, 1425], [257, 160, 171], [691, 440, 437], [1045, 680, 627], [301, 200, 171], [177, 120, 95], [2141, 1480, 1083], [1079, 760, 513], [725, 520, 323], [137, 100, 57], [2209, 1640, 855], [53, 40, 19], [2243, 1720, 741], [565, 440, 171], [759, 600, 209], [1147, 920, 285], [2311, 1880, 513], [97, 80, 19], [335, 280, 57], [1181, 1000, 171], [793, 680, 95], [599, 520, 57], [2413, 2120, 171], [405, 360, 19], [2447, 2200, 57], [11, 10, 0], [158, 151, 3], [178, 179, 7], [1030, 1091, 63], [248, 277, 21], [318, 375, 35], [458, 571, 63], [878, 1159, 147], [5, 7, 1], [172, 181, 37], [97, 76, 22], [72, 41, 17], [119, 47, 29], [4, 1, 1], [4, 1, 1], [4, 1, 1], [4, 1, 1], [4, 1, 1], [4, 1, 1], [4, 1, 1], [4, 1, 1], [4, 1, 1], [65, 18, 17], [95, 29, 26], [185, 62, 53], [30, 11, 9], [35, 14, 11], [85, 37, 28], [55, 26, 19], [80, 41, 29], [155, 86, 59], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [5, 3, 2], [305, 176, 119], [155, 86, 59], [105, 56, 39], [80, 41, 29], [65, 32, 23], [55, 26, 19], [335, 152, 113], [85, 37, 28], [115, 48, 37], [35, 14, 11], [355, 136, 109], [30, 11, 9], [365, 128, 107], [185, 62, 53], [25, 8, 7], [95, 29, 26], [385, 112, 103], [65, 18, 17], [395, 104, 101], [4, 1, 1]] (w, h) = src.size() dest = Image((w, h)) ey = [0.] * (w + 2) for y in range(h): ex = 0 newey = [0.] * (w + 2) if serpentine and y & 1: xrange = range(w - 1, -1, -1) else: xrange = range(w) for x in xrange: # Set pixel c = src.getGray(x, y) + ex + ey[x + 1] d = c > 0.5 dest.setGray(x, y, d) error = c - d i = (int)(c * 255.9999) if i > 127: i = 255 - i (d1, d2, d3) = m[i] t = d1 + d2 + d3 # Propagate error ex = error * d1 / t if serpentine and y & 1: newey[x + 2] += error * d3 / t newey[x + 1] += error * d2 / t else: newey[x] += error * d2 / t newey[x + 1] += error * d3 / t ey = newey return dest if chapter(3): test341(lenna256bw, True).save("out3-4-1.png") test341(gradient256bw, True).save("grad3-4-1.png") ##############################################################################
Note: See TracChangeset for help on using the changeset viewer.