source: www/study/study.py @ 1930

Last change on this file since 1930 was 1930, checked in by Sam Hocevar, 13 years ago
  • Introducing dither matrices.
  • Property svn:executable set to *
File size: 8.9 KB
Line 
1#!/usr/bin/env python
2
3import math, gd
4
5# Tiny image class to make examples short and readable
6class Image(gd.image):
7    def __new__(args, truecolor = False):
8        gd.gdMaxColors = 256 * 256 * 256
9        if truecolor:
10            return gd.image.__new__(args, True)
11        else:
12            return gd.image.__new__(args)
13    def getGray(self, x, y):
14        p = self.getPixel((x, y))
15        c = self.colorComponents(p)[0] / 255.0
16        return c
17    def getRgb(self, x, y):
18        p = self.getPixel((x, y))
19        rgb = self.colorComponents(p)
20        return [rgb[0] / 255.0, rgb[1] / 255.0, rgb[2] / 255.0]
21    def setGray(self, x, y, t):
22        p = (int)(t * 255.999)
23        c = self.colorResolve((p, p, p))
24        self.setPixel((x, y), c)
25    def setRgb(self, x, y, r, g, b):
26        r = (int)(r * 255.999)
27        g = (int)(g * 255.999)
28        b = (int)(b * 255.999)
29        c = self.colorResolve((r, g, b))
30        self.setPixel((x, y), c)
31
32# Manipulate gamma values
33class Gamma:
34    def CtoI(x):
35        return math.pow(x, 2.2)
36    def ItoC(x):
37        return math.pow(x, 1 / 2.2)
38    CtoI = staticmethod(CtoI)
39    ItoC = staticmethod(ItoC)
40
41# Load the 256x256 grayscale Lenna image
42lenna256bw = Image("lenna256bw.png")
43
44# Create a 32x256 grayscale gradient
45gradient256bw = Image((32, 256))
46for x in range(32):
47    for y in range(256):
48        gradient256bw.setGray(x, 255 - y, y / 255.)
49gradient256bw.writePng("gradient256bw.png")
50
51# Output 1: 50% threshold
52# Output 2: 40% threshold
53# Output 3: 60% threshold
54def test1(src, threshold, name):
55    (w, h) = src.size()
56    dest = Image((w, h))
57    for y in range(h):
58        for x in range(w):
59            c = src.getGray(x, y) > threshold
60            dest.setGray(x, y, c)
61    dest.writePng(name)
62
63test1(lenna256bw, 0.5, "out001.png")
64test1(lenna256bw, 0.4, "out002.png")
65test1(lenna256bw, 0.6, "out003.png")
66test1(gradient256bw, 0.5, "grad001.png")
67test1(gradient256bw, 0.4, "grad002.png")
68test1(gradient256bw, 0.6, "grad003.png")
69
70# Output 4: 3-colour threshold
71# Output 5: 5-colour threshold
72def test2(src, colors, name):
73    (w, h) = src.size()
74    dest = Image((w, h))
75    p = -0.0001 + colors
76    q = colors - 1
77    for y in range(h):
78        for x in range(w):
79            c = src.getGray(x, y)
80            c = math.floor(c * p) / q
81            dest.setGray(x, y, c)
82    dest.writePng(name)
83
84test2(lenna256bw, 3, "out004.png")
85test2(lenna256bw, 5, "out005.png")
86test2(gradient256bw, 3, "grad004.png")
87test2(gradient256bw, 5, "grad005.png")
88
89# Pattern 1: a 50% halftone pattern with various block sizes
90dest = Image((320, 80))
91for x in range(320):
92    d = 8 >> (x / 80)
93    for y in range(80):
94        c = (x / d + y / d) & 1
95        dest.setGray(x, y, c)
96dest.writePng("pat001.png")
97
98# Pattern 2: 25% and 75% halftone patterns with various block sizes
99dest = Image((320, 80))
100for x in range(320):
101    d = 8 >> (x / 80)
102    for y in range(40):
103        c = ((x / d + y / d) & 1) or (y / d & 1)
104        dest.setGray(x, y, c)
105    for y in range(40, 80):
106        c = ((x / d + y / d) & 1) and (y / d & 1)
107        dest.setGray(x, y, c)
108dest.writePng("pat002.png")
109
110# Output 6: 20/40/60/80% threshold with 25/50/75% halftone patterns inbetween:
111def test3(src, name):
112    (w, h) = src.size()
113    dest = Image((w, h))
114    for y in range(h):
115        for x in range(w):
116            c = src.getGray(x, y)
117            if c < 0.2:
118                c = 0.
119            elif c < 0.4:
120                c = ((x + y) & 1) and (y & 1)
121            elif c < 0.6:
122                c = (x + y) & 1
123            elif c < 0.8:
124                c = ((x + y) & 1) or (y & 1)
125            else:
126                c = 1.
127            dest.setGray(x, y, c)
128    dest.writePng(name)
129
130test3(lenna256bw, "out006.png")
131test3(gradient256bw, "grad006.png")
132
133# Pattern 3: vertical, mixed and horizontal black-white halftones
134dest = Image((240, 80))
135for y in range(80):
136    for x in range(80):
137        c = x & 1
138        dest.setGray(x, y, c)
139    for x in range(80, 160):
140        c = (x / d + y / d) & 1
141        dest.setGray(x, y, c)
142    for x in range(160, 240):
143        c = y & 1
144        dest.setGray(x, y, c)
145dest.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
205
206# Pattern 4: gamma-corrected 50% gray, black-white halftone, 50% gray
207dest = Image((240, 80))
208for y in range(80):
209    for x in range(80):
210        dest.setGray(x, y, Gamma.ItoC(0.5))
211    for x in range(80, 160):
212        c = (x + y) & 1
213        dest.setGray(x, y, c)
214    for x in range(160, 240):
215        dest.setGray(x, y, 0.5)
216dest.writePng("pat004.png")
217
218# Pattern 5: gamma-corrected 50% gray, black-white halftone, 50% gray
219dest = Image((400, 240))
220for y in range(80):
221    for x in range(400):
222        if x < 80:
223            c = 0.
224        elif x < 160:
225            c = ((x + y) & 1) and (y & 1)
226        elif x < 240:
227            c = (x + y) & 1
228        elif x < 320:
229            c = ((x + y) & 1) or (y & 1)
230        else:
231            c = 1.
232        dest.setGray(x, y, c)
233for y in range(80, 160):
234    for x in range(400):
235        dest.setGray(x, y, x / 80 / 4.)
236for y in range(160, 240):
237    for x in range(400):
238        if x < 80:
239            c = 0.
240        elif x < 160:
241            c = (((x + y) & 3) == 1) and ((y & 3) == 1)
242        elif x < 240:
243            c = ((x + y) & 1) and (y & 1)
244        elif x < 320:
245            c = (x + y) & 1
246        else:
247            c = 1.
248        dest.setGray(x, y, c)
249dest.writePng("pat005.png")
250
251# Output 6: gamma-aware 20/40/60/80% threshold:
252def test4(src, name):
253    (w, h) = src.size()
254    dest = Image((w, h))
255    for y in range(h):
256        for x in range(w):
257            c = src.getGray(x, y)
258            if c < 0.2:
259                c = 0.
260            elif c < 0.4:
261                c = (((x + y) & 3) == 1) and ((y & 3) == 1)
262            elif c < 0.6:
263                c = ((x + y) & 1) and (y & 1)
264            elif c < 0.8:
265                c = (x + y) & 1
266            else:
267                c = 1.
268            dest.setGray(x, y, c)
269    dest.writePng(name)
270
271test4(lenna256bw, "out007.png")
272test4(gradient256bw, "grad007.png")
273
274
275src = lenna256bw
276src = gradient256bw
277(w, h) = src.size()
278
279mat = [[  0,  8,  3, 11],
280       [ 15,  4, 12,  7],
281       [  2, 10,  1,  9],
282       [ 13,  6, 14,  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
305dest = Image((w, h))
306for y in range(h):
307    for x in range(w):
308        c = src.getGray(x, y)
309        i = Gamma.CtoI(c)
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
315        dest.setGray(x, y, c)
316dest.writePng("out008.png")
317
318# Create a dot-matrix pattern
319mat = [[0, 2, 2, 3, 1],
320       [2, 2, 0, 2, 3],
321       [2, 0, 1, 1, 3],
322       [3, 2, 1, 0, 3],
323       [1, 3, 3, 3, 3]]
324dest = Image((320, 64))
325for x in range(320):
326    d = x / 64
327    for y in range(64):
328        c = mat[y % 5][x % 5] >= d
329        dest.setGray(x, y, c)
330dest.writePng("pat003.png")
331
Note: See TracBrowser for help on using the repository browser.