Attachment 'daltonize.py'
Download 1 # -*- coding: iso-8859-1 -*-
2 """
3 MoinMoin - Daltonize ImageCorrection - Effect
4
5 Daltonize image correction algorithm implemented according to
6 http://scien.stanford.edu/class/psych221/projects/05/ofidaner/colorblindness_project.htm
7
8 Many thanks to Onur Fidaner, Poliang Lin and Nevran Ozguven for their work
9 on this topic and for releasing their complete research results to the public
10 (unlike the guys from http://www.vischeck.com/). This is of great help for a
11 lot of people!
12
13 Please note:
14 Daltonize ImageCorrection needs
15 * Python Image Library (PIL) from http://www.pythonware.com/products/pil/
16 * NumPy from http://numpy.scipy.org/
17
18 You can call Daltonize from the command-line with
19 "daltonize.py C:\image.png"
20
21 Explanations:
22 * Normally this module is called from Moin.AttachFile.get_file
23 * @param filename, fpath is the filename/fullpath to an image in the attachment
24 dir of a page.
25 * @param color_deficit can either be
26 - 'd' for Deuteranope image correction
27 - 'p' for Protanope image correction
28 - 't' for Tritanope image correct
29 Idea:
30 * Since daltonizing an image takes quite some time and we don't want visually
31 impaired users to wait so long until the page is loaded, this module has a
32 command-line option built-in which could be called as a separate process
33 after a file upload of a non visually impaired user in "AttachFile", e.g
34 "spawnlp(os.NO_WAIT...)"
35 * "AttachFile": If an image attachment is deleted or overwritten by a new version
36 please make sure to delete the daltonized images and redaltonize them.
37 * But all in all: Concrete implementation of ImageCorrection needs further
38 thinking and discussion. This is only a first prototype as proof of concept.
39
40 @copyright: 2007 by Oliver Siemoneit
41 @license: GNU GPL, see COPYING for details.
42 """
43
44 import os.path
45
46 def execute(filename, fpath, color_deficit='d'):
47 modified_filename = "%s-%s-%s" % ('daltonize', color_deficit, filename)
48 head, tail = os.path.split(fpath)
49 # Save transformed image to the cache dir
50 #head = head.replace('attachments', 'cache')
51 modified_fpath = os.path.join(head, modified_filename)
52
53 # Look if requested image is already available
54 if os.path.isfile(modified_fpath):
55 return (modified_filename, modified_fpath)
56
57 helpers_available = True
58 try:
59 import numpy
60 from PIL import Image
61 except:
62 helpers_available = False
63 if not helpers_available:
64 return (filename, fpath)
65
66 # Get image data
67 im = Image.open(fpath)
68 if im.mode in ['1', 'L']: # Don't process black/white or grayscale images
69 return (filename, fpath)
70 im = im.copy()
71 im = im.convert('RGB')
72 RGB = numpy.asarray(im, dtype=float)
73
74 # Transformation matrix for Deuteranope (a form of red/green color deficit)
75 lms2lmsd = numpy.array([[1,0,0],[0.494207,0,1.24827],[0,0,1]])
76 # Transformation matrix for Protanope (another form of red/green color deficit)
77 lms2lmsp = numpy.array([[0,2.02344,-2.52581],[0,1,0],[0,0,1]])
78 # Transformation matrix for Tritanope (a blue/yellow deficit - very rare)
79 lms2lmst = numpy.array([[1,0,0],[0,1,0],[-0.395913,0.801109,0]])
80 # Colorspace transformation matrices
81 rgb2lms = numpy.array([[17.8824,43.5161,4.11935],[3.45565,27.1554,3.86714],[0.0299566,0.184309,1.46709]])
82 lms2rgb = numpy.linalg.inv(rgb2lms)
83 # Daltonize image correction matrix
84 err2mod = numpy.array([[0,0,0],[0.7,1,0],[0.7,0,1]])
85
86 # Get the requested image correction
87 if color_deficit == 'd':
88 lms2lms_deficit = lms2lmsd
89 elif color_deficit == 'p':
90 lms2lms_deficit = lms2lmsp
91 elif color_deficit == 't':
92 lms2lms_deficit = lms2lmst
93 else:
94 return (filename, fpath)
95
96 # Transform to LMS space
97 LMS = numpy.zeros_like(RGB)
98 for i in range(RGB.shape[0]):
99 for j in range(RGB.shape[1]):
100 rgb = RGB[i,j,:3]
101 LMS[i,j,:3] = numpy.dot(rgb2lms, rgb)
102
103 # Calculate image as seen by the color blind
104 _LMS = numpy.zeros_like(RGB)
105 for i in range(RGB.shape[0]):
106 for j in range(RGB.shape[1]):
107 lms = LMS[i,j,:3]
108 _LMS[i,j,:3] = numpy.dot(lms2lms_deficit, lms)
109
110 _RGB = numpy.zeros_like(RGB)
111 for i in range(RGB.shape[0]):
112 for j in range(RGB.shape[1]):
113 _lms = _LMS[i,j,:3]
114 _RGB[i,j,:3] = numpy.dot(lms2rgb, _lms)
115
116 ## # Save simulation how image is perceived by a color blind
117 ## for i in range(RGB.shape[0]):
118 ## for j in range(RGB.shape[1]):
119 ## _RGB[i,j,0] = max(0, _RGB[i,j,0])
120 ## _RGB[i,j,0] = min(255, _RGB[i,j,0])
121 ## _RGB[i,j,1] = max(0, _RGB[i,j,1])
122 ## _RGB[i,j,1] = min(255, _RGB[i,j,1])
123 ## _RGB[i,j,2] = max(0, _RGB[i,j,2])
124 ## _RGB[i,j,2] = min(255, _RGB[i,j,2])
125 ## simulation = _RGB.astype('uint8')
126 ## im_simulation = Image.fromarray(simulation, mode='RGB')
127 ## simulation_filename = "%s-%s-%s" % ('daltonize-simulation', color_deficit, filename)
128 ## simulation_fpath = os.path.join(head, simulation_filename)
129 ## im_simulation.save(simulation_fpath)
130
131 # Calculate error between images
132 error = (RGB-_RGB)
133
134 # Daltonize
135 ERR = numpy.zeros_like(RGB)
136 for i in range(RGB.shape[0]):
137 for j in range(RGB.shape[1]):
138 err = error[i,j,:3]
139 ERR[i,j,:3] = numpy.dot(err2mod, err)
140
141 dtpn = ERR + RGB
142
143 for i in range(RGB.shape[0]):
144 for j in range(RGB.shape[1]):
145 dtpn[i,j,0] = max(0, dtpn[i,j,0])
146 dtpn[i,j,0] = min(255, dtpn[i,j,0])
147 dtpn[i,j,1] = max(0, dtpn[i,j,1])
148 dtpn[i,j,1] = min(255, dtpn[i,j,1])
149 dtpn[i,j,2] = max(0, dtpn[i,j,2])
150 dtpn[i,j,2] = min(255, dtpn[i,j,2])
151
152 result = dtpn.astype('uint8')
153
154 # Save daltonized image
155 im_converted = Image.fromarray(result, mode='RGB')
156 im_converted.save(modified_fpath)
157 return (modified_filename, modified_fpath)
158
159
160 if __name__ == '__main__':
161 import sys
162 print "Daltonize image correction for color blind users"
163
164 if len(sys.argv) != 2:
165 print "Calling syntax: daltonize.py [fullpath to image file]"
166 print "Example: daltonize.py C:/wikiinstance/data/pages/PageName/attachments/pic.png"
167 sys.exit(1)
168
169 if not (os.path.isfile(sys.argv[1])):
170 print "Given file does not exist"
171 sys.exit(1)
172
173 extpos = sys.argv[1].rfind(".")
174 if not (extpos > 0 and sys.argv[1][extpos:].lower() in ['.gif', '.jpg', '.jpeg', '.png', '.bmp', '.ico', ]):
175 print "Given file is not an image"
176 sys.exit(1)
177
178 path, fname = os.path.split(sys.argv[1])
179 print "Please wait. Daltonizing in progress..."
180
181 colorblindness = { 'd': 'Deuteranope',
182 'p': 'Protanope',
183 't': 'Tritanope',}
184
185 for col_deficit in ['d', 'p', 't']:
186 print "Creating %s corrected version" % colorblindness[col_deficit]
187 modified_filename, modified_fpath = execute(fname, sys.argv[1], col_deficit)
188 if modified_fpath == sys.argv[1]:
189 print "Error while processing image: PIL/NumPy missing and/or source file is a grayscale image."
190 else:
191 print "Image successfully daltonized"
192
193
Attached Files
To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.You are not allowed to attach a file to this page.