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     

New Attachment

File to upload
Rename to
Overwrite existing attachment of same name
Which programming language does the MoinMoin project mainly use?

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.