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.
  • [get | view] (2008-04-13 11:47:21, 246.4 KB) [[attachment:color2gray.png]]
  • [get | view] (2008-09-07 18:50:15, 5.3 KB) [[attachment:color2gray.py]]
  • [get | view] (2008-04-13 11:46:22, 7.3 KB) [[attachment:daltonize.py]]
  • [get | view] (2008-04-12 20:27:43, 125.1 KB) [[attachment:diff.zip]]
  • [get | view] (2007-04-14 16:44:45, 230.5 KB) [[attachment:ishihara_plates.png]]
  • [get | view] (2007-04-14 21:53:13, 564.1 KB) [[attachment:landscape.png]]
  • [get | view] (2015-02-14 18:46:03, 31.5 KB) [[attachment:test]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.