rewrote colormaps to use classes

This commit is contained in:
Martin Diehl 2013-01-08 18:47:44 +00:00
parent 19d86ca06a
commit fd0e096256
2 changed files with 326 additions and 201 deletions

View File

@ -4,8 +4,8 @@ import sys
from .environment import Environment # only one class
from .asciitable import ASCIItable # only one class
from .config import Material # will be extended to debug and numerics
from .colormaps import Colormaps # only one class
#from .block import Block # only one class
from .colormaps import Colormap, Color
#from .block import Block # only one class
from .result import Result # one class with subclasses
from .geometry import Geometry # one class with subclasses
from .solver import Solver # one class with subclasses

View File

@ -1,8 +1,329 @@
#!/usr/bin/env python
# suggestion to have class Color and class ColorMap, both use numpy arrays...
# Color has properties:
# .model
# .color
# and methods
# .as/toOTHER (which checks own model and does appropriate conversion)
class Color():
'''
There should be a doc string here :)
'''
import numpy
__slots__ = ['model',
'color',
]
# convert H(ue) S(aturation) L(uminance) to R(red) G(reen) B(lue)
# with S,L,H,R,G,B running from 0 to 1
# from http://en.wikipedia.org/wiki/HSL_and_HSV
def _HSL2RGB(self):
import numpy
if self.model != 'HSL': return
sextant = int(self.color[0]*6.0)
c = (1.0 - abs(2.0 * self.color[2] - 1.0))*self.color[1]
x = c*(1.0 - abs(sextant%2 - 1.0))
m = self.color[2] - 0.5*c
converted = Color('RGB',numpy.array([
[c+m, x+m, m],
[x+m, c+m, m],
[m, c+m, x+m],
[m, x+m, c+m],
[x+m, m, c+m],
[c+m, m, x+m],
][sextant],'d'))
self.model = converted.model
self.color = converted.color
# convert R(ed) G(reen) B(lue) to H(ue) S(aturation) L(uminance)
# with S,L,H,R,G,B running from 0 to 1
# from http://130.113.54.154/~monger/hsl-rgb.html
def _RGB2HSL(self):
import numpy
if self.model != 'RGB': return
HSL = numpy.zeros(3,'d')
maxcolor = self.color.max()
mincolor = self.color.min()
HSL[2] = (maxcolor + mincolor)/2.0
if(mincolor == maxcolor):
HSL[0] = 0.0
HSL[1] = 0.0
else:
if (HSL[2]<0.5):
HSL[1] = (maxcolor - mincolor)/(maxcolor + mincolor)
else:
HSL[1] = (maxcolor - mincolor)/(2.0 -maxcolor -mincolor)
if (maxcolor == self.color[0]):
HSL[0] = 0.0 + (self.color[1] - self.color[2])/(maxcolor - mincolor)
elif (maxcolor == self.color[1]):
HSL[0] = 2.0 + (self.color[2] - self.color[0])/(maxcolor - mincolor)
elif (maxcolor == self.color[2]):
HSL[0] = 4.0 + (self.color[0] - self.color[1])/(maxcolor - mincolor)
HSL[0] = HSL[0]*60.0
if (HSL[0] < 0.0):
HSL[0] = HSL[0] + 360.0
for i in xrange(2):
HSL[i+1] = min(HSL[i+1],1.0)
HSL[i+1] = max(HSL[i+1],0.0)
converted = Color('HSL', HSL)
self.model = converted.model
self.color = converted.color
# convert R(ed) G(reen) B(lue) to CIE XYZ
# with all values in the range of 0 to 1
# from http://www.cs.rit.edu/~ncs/color/t_convert.html
def _RGB2XYZ(self):
import numpy
if self.model != 'RGB': return
XYZ = numpy.zeros(3,'d')
RGB_lin = numpy.zeros(3,'d')
for i in xrange(3):
if (self.color[i] > 0.04045):
RGB_lin[i] = ((self.color[i]+0.0555)/1.0555)**2.4
else:
RGB_lin[i] = self.color[i]/12.92
convert = numpy.array([[0.412453,0.357580,0.180423],
[0.212671,0.715160,0.072169],
[0.019334,0.119193,0.950227]])
XYZ = numpy.dot(convert,RGB_lin)
for i in xrange(3):
XYZ[i] = min(XYZ[i],1.0)
XYZ[i] = max(XYZ[i],0.0)
converted = Color('XYZ', XYZ)
self.model = converted.model
self.color = converted.color
# convert CIE XYZ R(ed) G(reen) B(lue)
# with all values in the range of 0 to 1
# from http://www.cs.rit.edu/~ncs/color/t_convert.html
def _XYZ2RGB(self):
import numpy
if self.model != 'XYZ': return
RGB = numpy.zeros(3,'d')
RGB_lin = numpy.zeros(3,'d')
convert = numpy.array([[ 3.240479,-1.537150,-0.498535],
[-0.969256, 1.875992, 0.041556],
[ 0.055648,-0.204043, 1.057311]])
RGB_lin = numpy.dot(convert,self.color)
for i in xrange(3):
if (RGB_lin[i] > 0.0031308):
RGB[i] = ((RGB_lin[i])**(1.0/2.4))*1.0555-0.0555
else:
RGB[i] = RGB_lin[i]*12.92
for i in xrange(3):
RGB[i] = min(RGB[i],1.0)
RGB[i] = max(RGB[i],0.0)
maxVal = max(RGB) # clipping colors according to the display gamut
if (maxVal > 1.0):
RGB /= maxVal
converted = Color('RGB', RGB)
self.model = converted.model
self.color = converted.color
# convert CIE Lab to CIE XYZ
# with XYZ in the range of 0 to 1
# from http://www.easyrgb.com/index.php?X=MATH&H=07#text7
def _CIELAB2XYZ(self):
import numpy
if self.model != 'CIELAB': return
ref_white = numpy.array([.95047, 1.00000, 1.08883],'d') # Observer = 2, Illuminant = D65
XYZ = numpy.zeros(3,'d')
XYZ[1] = (self.color[0] + 16 ) / 116
XYZ[0] = XYZ[1] + self.color[1] / 500
XYZ[2] = XYZ[1] - self.color[2] / 200
for i in xrange(len(XYZ)):
if (XYZ[i] > 6./29. ):
XYZ[i] = XYZ[i]**3.
else:
XYZ[i] = 108./2523.*(XYZ[i]-4./29.)
converted = Color('XYZ', XYZ*ref_white)
self.model = converted.model
self.color = converted.color
# convert CIE XYZ to CIE Lab
# with XYZ in the range of 0 to 1
# from http://en.wikipedia.org/wiki/Lab_color_space, http://www.cs.rit.edu/~ncs/color/t_convert.html
def _XYZ2CIELAB(self):
import numpy
if self.model != 'XYZ': return
ref_white = numpy.array([.95047, 1.00000, 1.08883],'d') # Observer = 2, Illuminant = D65
XYZ = self.color/ref_white
for i in xrange(len(XYZ)):
if (XYZ[i] > 216./24389 ):
XYZ[i] = XYZ[i]**(1.0/3.0)
else:
XYZ[i] = ( 24389./27. * XYZ[i] + 16.0 ) / 116.0
converted = Color('CIELAB', numpy.array([ 116.0 * XYZ[1] - 16.0,
500.0 * (XYZ[0] - XYZ[1]),
200.0 * (XYZ[1] - XYZ[2]) ]))
self.model = converted.model
self.color = converted.color
# convert Cie Lab to msh colorspace
# from http://www.cs.unm.edu/~kmorel/documents/ColorMaps/DivergingColorMapWorkshop.xls
def _CIELAB2MSH(self):
import numpy, math
if self.model != 'CIELAB': return
Msh = numpy.zeros(3,'d')
Msh[0] = math.sqrt(numpy.dot(self.color,self.color))
if (Msh[0] != 0.0) and (Msh[0] > 0.001):
Msh[1] = math.acos(self.color[0]/Msh[0])
if (self.color[1] != 0.0) and (Msh[1] > 0.001):
Msh[2] = math.atan2(self.color[2],self.color[1])
converted = Color('MSH', Msh)
self.model = converted.model
self.color = converted.color
# convert msh colorspace to Cie Lab
# from http://www.cs.unm.edu/~kmorel/documents/ColorMaps/DivergingColorMapWorkshop.xls
def _MSH2CIELAB(self):
import numpy, math
if self.model != 'MSH': return
Lab = numpy.zeros(3,'d')
Lab[0] = self.color[0] * math.cos(self.color[1])
Lab[1] = self.color[0] * math.sin(self.color[1]) * math.cos(self.color[2])
Lab[2] = self.color[0] * math.sin(self.color[1]) * math.sin(self.color[2])
converted = Color('CIELAB', Lab)
self.model = converted.model
self.color = converted.color
# ------------------------------------------------------------------
def __init__(self,
model = 'RGB',
color = numpy.zeros(3,'d')):
import numpy
self.__transforms__ = \
{'HSL': {'index': 0, 'next': self._HSL2RGB},
'RGB': {'index': 1, 'next': self._RGB2XYZ, 'prev': self._RGB2HSL},
'XYZ': {'index': 2, 'next': self._XYZ2CIELAB, 'prev': self._XYZ2RGB},
'CIELAB': {'index': 3, 'next': self._CIELAB2MSH, 'prev': self._CIELAB2XYZ},
'MSH': {'index': 4, 'prev': self._MSH2CIELAB},
}
model = model.upper()
if model not in self.__transforms__.keys(): model = 'RGB'
if model == 'RGB' and max(color) > 1.0: # are we RGB255 ?
color /= 255.0 # rescale to RGB
if model == 'HSL': # are we HSL ?
if abs(color[0]) > 1.0: color[0] /= 360.0 # with angular hue?
while color[0] >= 1.0: color[0] -= 1.0 # rewind to proper range
while color[0] < 0.0: color[0] += 1.0 # rewind to proper range
self.model = model
self.color = numpy.array(color,'d')
def __repr__(self):
return 'Model: %s Color: %s'%(self.model,str(self.color))
def __str__(self):
return self.__repr__()
# ------------------------------------------------------------------
def to(self,toModel = 'RGB'):
toModel = toModel.upper()
if toModel not in self.__transforms__.keys(): return
sourcePos = self.__transforms__[self.model]['index']
targetPos = self.__transforms__[toModel]['index']
while sourcePos < targetPos:
self.__transforms__[self.model]['next']()
sourcePos += 1
while sourcePos > targetPos:
self.__transforms__[self.model]['prev']()
sourcePos -= 1
return self
# ------------------------------------------------------------------
def asModel(self,toModel = 'RGB'):
return self.__class__(self.model,self.color).to(toModel)
# lorMap has properties
# .type (seq, div)
# .len
# .colors (.len of class Color)
# and methods
# .export(type) (switches internally to output desired format)
class Colormap():
__slots__ = ['type',
'left',
'right',
]
__formats__ = ['sequential','diverging']
def __init__(self,
style = 'sequential',
left = Color('RGB',[1,1,1]),
right = Color('RGB',[0,0,0]),
):
style = style.lower()
if style not in self.__formats__:
style = self.__formats__[0]
if left.__class__.__name__ != 'Color':
left = Color()
if right.__class__.__name__ != 'Color':
right = Color()
self.style = style
self.left = left.asModel('MSH')
self.right = right.asModel('MSH')
class Colormaps():
'''
Funtionality to create colormaps
Funtionality to manipulate colormaps
'''
# from http://code.activestate.com/recipes/121574-matrix-vector-multiplication/
@ -13,208 +334,12 @@ class Colormaps():
w[row] = reduce(lambda x,y: x+y, map(lambda x,y: x*y, m[row], v))
return w
# convert H(ue) S(aturation) L(uminance) to R(ot) G(elb) B(lau)
# with S,L,R,G,B running from 0 to 1, H running from 0 to 360
# from http://en.wikipedia.org/wiki/HSL_and_HSV
def HSL2RGB(self,HSL):
RGB = [0.0,0.0,0.0]
H_strich = HSL[0]/60.0
c = (1.0- abs(2.0 * HSL[2] - 1.0))*HSL[1]
x = c*(1.0- abs(H_strich%2-1.0))
m = HSL[2] -.5*c
if (0.0 <= H_strich)and(H_strich<1.0):
RGB[0] = c + m
RGB[1] = x + m
RGB[2] = 0.0 + m
elif (1.0 <= H_strich)and(H_strich<2.0):
RGB[0] = x + m
RGB[1] = c + m
RGB[2] = 0.0 + m
elif (2.0 <= H_strich)and(H_strich<3.0):
RGB[0] = 0.0 + m
RGB[1] = c + m
RGB[2] = x + m
elif (3.0 <= H_strich)and(H_strich<4.0):
RGB[0] = 0.0 + m
RGB[1] = x + m
RGB[2] = c + m
elif (4.0 <= H_strich)and(H_strich<5.0):
RGB[0] = x + m
RGB[1] = 0.0 + m
RGB[2] = c + m
elif (5.0 <= H_strich)and(H_strich<=6.0):
RGB[0] = c + m
RGB[1] = 0.0 + m
RGB[2] = x + m
for i in range(3):
RGB[i] = min(RGB[i],1.0)
RGB[i] = max(RGB[i],0.0)
return RGB
# convert R(ot) G(elb) B(lau) to H(ue) S(aturation) L(uminance)
# with S,L,R,G,B running from 0 to 1, H running from 0 to 360
# from http://130.113.54.154/~monger/hsl-rgb.html
def RGB2HSL(self,RGB):
HSL = [0.0,0.0,0.0]
maxcolor = max(RGB)
mincolor = min(RGB)
HSL[2] = (maxcolor + mincolor)/2.0
if(mincolor == maxcolor):
HSL[0] = 0.0
HSL[1] = 0.0
else:
if (HSL[2]<0.5):
HSL[1] = (maxcolor - mincolor)/(maxcolor + mincolor)
else:
HSL[1] = (maxcolor - mincolor)/(2.0 -maxcolor -mincolor)
if (maxcolor == RGB[0]):
HSL[0] = 0.0 + (RGB[1] - RGB[2])/(maxcolor - mincolor)
elif (maxcolor == RGB[1]):
HSL[0] = 2.0 + (RGB[2] - RGB[0])/(maxcolor - mincolor)
elif (maxcolor == RGB[2]):
HSL[0] = 4.0 + (RGB[0] - RGB[1])/(maxcolor - mincolor)
HSL[0] = HSL[0]*60.0
if (HSL[0] < 0.0):
HSL[0] = HSL[0] + 360.0
for i in range(2):
HSL[i+1] = min(HSL[i+1],1.0)
HSL[i+1] = max(HSL[i+1],0.0)
return HSL
# convert R(ot) G(elb) B(lau) to CIE XYZ
# with all values in the range of 0 to 1
# from http://www.cs.rit.edu/~ncs/color/t_convert.html
def RGB2XYZ(self,RGB):
XYZ = [0.0,0.0,0.0]
RGB_lin = [0.0,0.0,0.0]
for i in range(3):
if (RGB[i] > 0.04045):
RGB_lin[i] = ((RGB[i]+0.0555)/1.0555)**2.4
else:
RGB_lin[i] = RGB[i]/12.92
convert =[[0.412453,0.357580,0.180423],[0.212671,0.715160,0.072169],[0.019334,0.119193,0.950227]]
XYZ = self.matmult(convert,RGB_lin)
for i in range(3):
XYZ[i] = min(XYZ[i],1.0)
XYZ[i] = max(XYZ[i],0.0)
return XYZ
# convert CIE XYZ R(ot) G(elb) B(lau)
# with all values in the range of 0 to 1
# from http://www.cs.rit.edu/~ncs/color/t_convert.html
def XYZ2RGB(self,XYZ):
RGB_lin = [0.0,0.0,0.0]
RGB = [0.0,0.0,0.0]
convert =[[3.240479,-1.537150,-0.498535],[-0.969256,1.875992,0.041556],[0.055648,-0.204043,1.057311]]
RGB_lin = self.matmult(convert,XYZ)
for i in range(3):
if (RGB_lin[i] > 0.0031308):
RGB[i] = ((RGB_lin[i])**(1.0/2.4))*1.0555-0.0555
else:
RGB[i] = RGB_lin[i]*12.92
for i in range(3):
RGB[i] = min(RGB[i],1.0)
RGB[i] = max(RGB[i],0.0)
maxVal = RGB[0] # clipping clolors according to the display gamut
if (maxVal < RGB[1]): maxVal = RGB[1]
if (maxVal < RGB[2]): maxVal = RGB[2]
if (maxVal > 1.0):
RGB[0] = RGB[0]/maxVal
RGB[1] = RGB[1]/maxVal
RGB[2] = RGB[2]/maxVal
return RGB
# convert CIE Lab to CIE XYZ
# with XYZ in the range of 0 to 1
# from http://www.easyrgb.com/index.php?X=MATH&H=07#text7
def CIELab2XYZ(self,Lab,white):
# ref_white_XYZ = [.95047, 1.00000, 1.08883] # Observer = 2, Illuminant = D65
XYZ = [0.0,0.0,0.0]
var_Y = ( Lab[0] + 16 ) / 116
var_X = Lab[1] / 500 + var_Y
var_Z = var_Y - Lab[2] / 200
if ( var_Y**3 > 0.008856 ):
var_Y = var_Y**3
else:
var_Y = ( var_Y-16/116) / 7.787
if ( var_X**3 > 0.008856 ):
var_X = var_X**3
else:
var_X = ( var_X-16/116) / 7.787
if ( var_Z**3 > 0.008856 ):
var_Z = var_Z**3
else:
var_Z = ( var_Z-16/116) / 7.787
XYZ[0] = white[0]*var_X
XYZ[1] = white[1]*var_Y
XYZ[2] = white[2]*var_Z
return XYZ
# convert CIE XYZ to CIE Lab
# with XYZ in the range of 0 to 1
# from http://en.wikipedia.org/wiki/Lab_color_space, http://www.cs.rit.edu/~ncs/color/t_convert.html
def XYZ2CIELab(self,XYZ,white):
# ref_white_XYZ = [.95047, 1.00000, 1.08883] # Observer = 2, Illuminant = D65
Lab = [0.0,0.0,0.0]
var_X = XYZ[0]/white[0]
var_Y = XYZ[1]/white[1]
var_Z = XYZ[2]/white[2]
if ( var_X > 0.008856 ):
var_X = var_X**(1.0/3.0)
else:
var_X = ( 7.787 * var_X ) + (16.0/116.0)
if ( var_Y > 0.008856 ):
var_Y = var_Y**(1.0/3.0)
else:
var_Y = ( 7.787 * var_Y ) + (16.0/116.0)
if ( var_Z > 0.008856 ):
var_Z = var_Z**(1.0/3.0)
else:
var_Z = (7.787*var_Z)+(16.0/116.0)
Lab[0] = (116.0 * var_Y) - 16.0
Lab[1] = 500.0 * (var_X - var_Y)
Lab[2] = 200.0 * (var_Y - var_Z)
return Lab
# convert Cie Lab to msh colorspace
# from http://www.cs.unm.edu/~kmorel/documents/ColorMaps/DivergingColorMapWorkshop.xls
def CIELab2Msh(self,Lab):
import math
Msh = [0.0,0.0,0.0]
Msh[0] = math.sqrt(Lab[0]**2.0 + Lab[1]**2.0 + Lab[2]**2.0)
if (Msh[0] != 0.0) and (Msh[0] > 0.001):
Msh[1] = math.acos(Lab[0]/Msh[0])
if (Lab[1] != 0.0) and (Msh[1] > 0.001):
Msh[2] = math.atan2(Lab[2],Lab[1])
return Msh
# convert msh colorspace to Cie Lab
# from http://www.cs.unm.edu/~kmorel/documents/ColorMaps/DivergingColorMapWorkshop.xls
def Msh2CIELab(self,Msh):
import math
Lab = [0.0,0.0,0.0]
Lab[0] = Msh[0] * math.cos(Msh[1])
Lab[1] = Msh[0] * math.sin(Msh[1]) * math.cos(Msh[2])
Lab[2] = Msh[0] * math.sin(Msh[1]) * math.sin(Msh[2])
return Lab
def write_gsmh(self,RGB_vector,name):
colormap = open(str(name) + '.map',"w")
colormap.write('View.ColorTable = {\n')
for i in range(len(RGB_vector)-1):
colormap.write('{'+str((RGB_vector[0][i])*255.0)+','+str((RGB_vector[0][i])*255.0)+','+str((RGB_vector[0][i])*255.0)+'},\n')
colormap.write('{'+str((RGB_vector[0][-1])*255.0)+','+str((RGB_vector[0][-1])*255.0)+','+str((RGB_vector[0][-1])*255.0)+'}}')
colormap.write('{'+str((RGB_vector[0][i])*255.0)+','+str((RGB_vector[1][i])*255.0)+','+str((RGB_vector[2][i])*255.0)+'},\n')
colormap.write('{'+str((RGB_vector[0][-1])*255.0)+','+str((RGB_vector[1][-1])*255.0)+','+str((RGB_vector[2][-1])*255.0)+'}}')
file.close(colormap)
def write_paraview(self,RGB_vector,name):