Changeset 1930Tweet

Ignore:
Timestamp:
11/11/07 13:27:40 (6 years ago)
Message:
• Introducing dither matrices.
Location:
www/study
Files:
5 edited

Unmodified
Removed
• www/study/index.html

 r1926

Still not very good. Obviously something better is needed.

Choosing the best thresholding value for a given image is called average dithering. But even with the best value, the results will not improve tremendously.

1.2. Grayscale thresholding

2.3. Introducing gamma

More importantly, if you are reading this document on a computer

Obviously the middle pattern looks far better to the human eye on a computer screen. Optimising patterns so that they look good to the human eye and don't create artifacts is a crucial element of a dithering algorithm. Here is another example of two patterns that approximate to the same shade of gray but may look slightly different from a distance:

2.3. Ordered dither

A generalisation of the dithering technique we just saw that uses a certain family of patterns is called ordered dither. It is based on a dither matrix such as the following one:

This matrix is then repeated all over the image, and the cells are used as threshold values. In this case, pixels (0,0), (0,2), (0,4) etc. will be thresholded with a value of 0.2. Pixels (0,1), (0, 3), (0, 4) etc. will be thresholded with a value of 0.8, and so on, resulting in the image seen in 2.1.

Different matrices can give very different results. This is a 4×4 Bayer ordered dither matrix:

This 4×4 cluster dot matrix creates dot patterns that mimic the halftoning techniques used by newspapers:

This unusual 5×3 matrix creates artistic vertical line artifacts:

• www/study/study.py

 r1927 for y in range(256): gradient256bw.setGray(x, 255 - y, y / 255.) gradient256bw.writePng("gradient256bw.png") # Output 1: 50% threshold dest.setGray(x, y, c) dest.writePng("pat003.png") # Pattern 4: two different 25% patterns dest = Image((320, 80)) for y in range(80): for x in range(80): c = (x / 2 & 1) and (y / 2 & 1) dest.setGray(x, y, c) for x in range(80, 160): c = (x & 1) and (y & 1) dest.setGray(x, y, c) for x in range(160, 240): c = (x & 1) and ((y + x / 2) & 1) dest.setGray(x, y, c) for x in range(240, 320): c = (x / 2 & 1) and ((y / 2 + x / 4) & 1) dest.setGray(x, y, c) dest.writePng("pat004.png") # Output 7: 4x4 Bayer dithering def test4(src, mat, name): (w, h) = src.size() dest = Image((w, h)) dx = len(mat[0]) dy = len(mat) for y in range(h): for x in range(w): c = src.getGray(x, y) threshold = (1. + mat[y % dy][x % dx]) / (dx * dy + 1) c = c > threshold dest.setGray(x, y, c) dest.writePng(name) mat = [[  0,  8,  3, 11], [ 15,  4, 12,  7], [  2, 10,  1,  9], [ 13,  6, 14,  5]] test4(lenna256bw, mat, "out007.png") test4(gradient256bw, mat, "grad007.png") mat = [[ 12,  5,  6, 13], [  4,  0,  1,  7], [ 11,  3,  2,  8], [ 15, 10,  9, 14]] test4(lenna256bw, mat, "out008.png") test4(gradient256bw, mat, "grad008.png") mat = [[ 13,  7,  0,  4, 10], [  9,  3,  1,  8, 14], [ 11,  5,  2,  6, 12],] test4(lenna256bw, mat, "out009.png") test4(gradient256bw, mat, "grad009.png") ############################################################################## # Only temporary cruft below this import sys sys.exit(0) # Pattern 4: gamma-corrected 50% gray, black-white halftone, 50% gray ############################################################################## # Only temporary cruft below this src = lenna256bw src = gradient256bw [  2, 10,  1,  9], [ 13,  6, 14,  5]] mat = [[  6,  7,  8,  9], [  5,  0,  1, 10], [  4,  3,  2, 11], [ 15, 14, 13, 12]] mat = [[ 12,  5,  9, 13], [  8,  0,  1,  6], [  4,  3,  2, 10], [ 15, 11,  7, 14]] mat = [[ 35, 24, 13, 14, 25, 32], [ 31, 12,  5,  6, 15, 26], [ 23,  4,  0,  1,  7, 16], [ 22, 11,  3,  2,  8, 17], [ 30, 21, 10,  9, 18, 27], [ 34, 29, 20, 19, 28, 33]] mat = [[  0, 20, 30,  3, 23, 29], [ 12, 32, 18, 15, 35, 17], [ 27,  8,  4, 24, 11,  7], [  2, 22, 28,  1, 21, 31], [ 14, 34, 16, 13, 33, 19], [ 25, 10,  6, 26,  9,  5]] #mat = [[  6,  7,  8,  9], #       [  5,  0,  1, 10], #       [  4,  3,  2, 11], #       [ 15, 14, 13, 12]] #mat = [[ 12,  5,  9, 13], #       [  8,  0,  1,  6], #       [  4,  3,  2, 10], #       [ 15, 11,  7, 14]] size = 4 #mat = [[ 35, 24, 13, 14, 25, 32], #       [ 31, 12,  5,  6, 15, 26], #       [ 23,  4,  0,  1,  7, 16], #       [ 22, 11,  3,  2,  8, 17], #       [ 30, 21, 10,  9, 18, 27], #       [ 34, 29, 20, 19, 28, 33]] #mat = [[  0, 20, 30,  3, 23, 29], #       [ 12, 32, 18, 15, 35, 17], #       [ 27,  8,  4, 24, 11,  7], #       [  2, 22, 28,  1, 21, 31], #       [ 14, 34, 16, 13, 33, 19], #       [ 25, 10,  6, 26,  9,  5]] #size = 6 dest = Image((w, h)) for y in range(h): c = src.getGray(x, y) i = Gamma.CtoI(c) threshold = mat[x % 6][y % 6] c = math.floor(i * 35.999) > threshold threshold = mat[x % size][y % size] d = math.floor(i * (size * size + .9999)) > threshold if c > 0.95: print c, i, i * (size * size + .9999) c = d dest.setGray(x, y, c) dest.writePng("out008.png") import sys sys.exit(0) # Create a dot-matrix pattern
Note: See TracChangeset for help on using the changeset viewer.