fenfire-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[ff-cvs] libvob/vob color/spaces.py paper/colors.py


From: Janne V. Kujala
Subject: [ff-cvs] libvob/vob color/spaces.py paper/colors.py
Date: Sun, 14 Sep 2003 06:46:53 -0400

CVSROOT:        /cvsroot/libvob
Module name:    libvob
Branch:         
Changes by:     Janne V. Kujala <address@hidden>        03/09/14 06:46:53

Modified files:
        vob/color      : spaces.py 
        vob/paper      : colors.py 

Log message:
        do gamma corrections explicitly and use proper per-component 
gamma-corrections in libpaper; implement special cases in the CIELAB formulas

CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/libvob/libvob/vob/color/spaces.py.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/libvob/libvob/vob/paper/colors.py.diff?tr1=1.2&tr2=1.3&r1=text&r2=text

Patches:
Index: libvob/vob/color/spaces.py
diff -u libvob/vob/color/spaces.py:1.3 libvob/vob/color/spaces.py:1.4
--- libvob/vob/color/spaces.py:1.3      Thu Sep  4 08:47:04 2003
+++ libvob/vob/color/spaces.py  Sun Sep 14 06:46:53 2003
@@ -25,23 +25,36 @@
 
 import math
 
-# Gamma correction used with the perceptual non-linearity in
-# CIE XYZ and YtoL and LtoY conversion functions.
-#
+# The gamma used for converting linear RGB to monitor RGB
+
 gamma = 2.2
-#
+
 # The uncorrected display gamma of PC's is typically 2.2, i.e.,
 # RGB values map to physical intensities with an exponent of 2.2.
-# So, gamma correction of 2.2 here should result in linear
-# intensity. (The CIE L* / Y computation assumes linear intensity).
+# So, gamma correction of 2.2 here should result in linear intensity.
+
+# These may later be changed to use the sRGB standard
+# (which is almost the same as the simple 2.2 gamma).
+
+def linear_to_monitor(rgb):
+    def f(x):
+        if x < 0: return 0
+        return x**(1.0/gamma)
+    return (f(rgb[0]), f(rgb[1]), f(rgb[2]))
+
+def monitor_to_linear(rgb):
+    def f(x):
+        if x < 0: return 0
+        return x**gamma
+    return (f(rgb[0]), f(rgb[1]), f(rgb[2]))
+
+# RGB709 <-> CIE XYZ conversions
 
 def RGBtoXYZ(v):
     mat = [[ 0.412453, 0.35758 , 0.180423],
            [ 0.212671, 0.71516 , 0.072169],
            [ 0.019334, 0.119193, 0.950227]];
 
-    v = ( v[0]**gamma, v[1]**gamma, v[2]**gamma )
-    
     return [ mat[0][0] * v[0] + mat[0][1] * v[1] + mat[0][2] * v[2],
              mat[1][0] * v[0] + mat[1][1] * v[1] + mat[1][2] * v[2],
              mat[2][0] * v[0] + mat[2][1] * v[1] + mat[2][2] * v[2] ]
@@ -50,41 +63,49 @@
     mat =  [[ 3.240479,-1.53715 ,-0.498535],
             [-0.969256, 1.875991, 0.041556],
             [ 0.055648,-0.204043, 1.057311]];
-    v = [ (mat[0][0] * v[0] + mat[0][1] * v[1] + mat[0][2] * v[2]),
-          (mat[1][0] * v[0] + mat[1][1] * v[1] + mat[1][2] * v[2]),
-          (mat[2][0] * v[0] + mat[2][1] * v[1] + mat[2][2] * v[2]) ]
-    return ( v[0]**(1/gamma), v[1]**(1/gamma), v[2]**(1/gamma) )
+    return [ (mat[0][0] * v[0] + mat[0][1] * v[1] + mat[0][2] * v[2]),
+             (mat[1][0] * v[0] + mat[1][1] * v[1] + mat[1][2] * v[2]),
+             (mat[2][0] * v[0] + mat[2][1] * v[1] + mat[2][2] * v[2]) ]
+
+# CIE L*a*b* conversions
+
+def f(X):
+    """The perceptual nonlinearity used in the CIE L*a*b* color space"""
+    if X <= (216./24389):
+        return (841./108) * X + (16./116)
+    else:
+        return X**(1./3)
+    
+def inv_f(X):
+    """Inverse of the the perceptual nonlinearity"""
+    if X <= (6./29):
+        return (X - 16./116) * (108./841)
+    else:
+        return X**3
+
 
 def RGBtoLAB(RGB):
     XYZ = RGBtoXYZ(RGB)
     XYZn = RGBtoXYZ([1,1,1])
 
-    X = XYZ[0] / XYZn[0]
-    Y = XYZ[1] / XYZn[1]
-    Z = XYZ[2] / XYZn[2]
-    
-    if Y <= (216./24389):
-        L = Y * (24389./27)
-    else:
-        L = 116 * pow(Y, 1./3) - 16
-
-    return [ L,
-             500 * (pow(X, 1./3.) - pow(Y, 1./3.)),
-             200 * (pow(Y, 1./3.) - pow(Z, 1./3.)) ]
+    X3 = f(XYZ[0] / XYZn[0])
+    Y3 = f(XYZ[1] / XYZn[1])
+    Z3 = f(XYZ[2] / XYZn[2])
+
+    return [ 116 * Y3 - 16,
+             500 * (X3 - Y3),
+             200 * (Y3 - Z3) ]
 
 def LABtoRGB(LAB):
-    L = LAB[0]
-    if L <= 8:
-        Y3 = pow(L * (27./24389), 1/3.0)
-    else:
-        Y3 = (L + 16.0) / 116
+    Y3 = (LAB[0] + 16.) / 116
+    X3 = LAB[1] / 500. + Y3
+    Z3 = Y3 - LAB[2] / 200.
 
     XYZn = RGBtoXYZ([1,1,1])
-    XYZ = [ XYZn[0] * pow(Y3 + LAB[1] / 500.0, 3),
-            XYZn[1] * pow(Y3, 3),
-            XYZn[2] * pow(Y3 - LAB[2] / 200.0, 3) ]
-
-
+    XYZ = [ XYZn[0] * inv_f(X3),
+            XYZn[1] * inv_f(Y3),
+            XYZn[2] * inv_f(Z3) ]
+    
     return XYZtoRGB(XYZ);
 
 def LABhue(RGB):
@@ -243,7 +264,6 @@
     Y: luminance between 0 and 1
     returns: lightness between 0 and 100
     """
-    Y = Y**gamma
     if Y <= (216./24389):
         return Y * (24389./27)
     else:
@@ -256,6 +276,6 @@
     returns: luminance between 0 and 1
     """
     if L <= 8:
-        return pow(L * (27./24389), 1.0 / gamma)
+        return pow(L * (27./24389), 1.0)
     else:
-        return pow((L + 16.0) / 116, 3.0 / gamma)
+        return pow((L + 16.0) / 116, 3.0)
Index: libvob/vob/paper/colors.py
diff -u libvob/vob/paper/colors.py:1.2 libvob/vob/paper/colors.py:1.3
--- libvob/vob/paper/colors.py:1.2      Tue May  6 23:43:57 2003
+++ libvob/vob/paper/colors.py  Sun Sep 14 06:46:53 2003
@@ -23,9 +23,12 @@
 
 # Choosing colors and 3-dotproduct factors for papers.
 
-from vob.color.spaces import 
getRandomColor,getRandomColor2,YSTtoRGB,clampSat,LtoY
+from vob.color.spaces import YSTtoRGB,clampSat,LtoY,linear_to_monitor
 from vob.color.spaces import RGBtoLAB,LABtoRGB,LABclamp
 
+def toLAB(rgb):
+    return RGBtoLAB(monitor_to_linear(rgb))
+
 from math import sin,cos,atan2,pi,log,sqrt
 from random import Random,shuffle
 
@@ -93,8 +96,8 @@
                   sats[i] * cos(hues[i]*pi/180),
                   sats[i] * sin(hues[i]*pi/180) )
                 for i in range(0,colors)]
-                   
-        col = [clampSat(YSTtoRGB(c)) for c in yst]
+
+        col = [linear_to_monitor(clampSat(YSTtoRGB(c))) for c in yst]
         shuffle(col, rnd.nextDouble)
 
         if blend > 0:
@@ -127,7 +130,7 @@
     def _AB_angle(self, cols):
         #print cols
         getangle = lambda lab: 180 / pi * atan2(lab[2], lab[1])
-        angles = [ getangle(RGBtoLAB(col)) for col in cols ] 
+        angles = [ getangle(toLAB(col)) for col in cols ] 
         #print angles
         angles.sort() 
         #print angles
@@ -143,7 +146,7 @@
 
     def _AB_avg_dot(self, cols):
         print cols
-        ab = [ (lab[1]/100.0,lab[2]/100.0) for lab in map(RGBtoLAB, cols) ]
+        ab = [ (lab[1]/100.0,lab[2]/100.0) for lab in map(toLAB, cols) ]
 
         dot = lambda x,y: x[0] * y[0] + x[1] * y[1]
         dots = [ dot(x,y) for x in ab for y in ab ]
@@ -151,7 +154,7 @@
         return reduce(lambda x,y: x+y, dots) / len(dots)
     
     def _AB_area(self, cols):
-        ab = [ (lab[1]/100.0,lab[2]/100.0) for lab in map(RGBtoLAB, cols) ]
+        ab = [ (lab[1]/100.0,lab[2]/100.0) for lab in map(toLAB, cols) ]
         #print [ (int(100*a),int(100*b)) for (a,b) in ab ]
         ab = convex_hull(ab)
         #print [ (int(100*a),int(100*b)) for (a,b) in ab ]




reply via email to

[Prev in Thread] Current Thread [Next in Thread]