RGB to Lab to HSV¶
Animation control:
Visualization |
Frame Value |
---|---|
Surface geometry |
functional parameter per frame |
Surface position |
constant |
Surface color |
constant |
Shading and highlighting |
fixed to the coordinate axis |
Axis coordinate |
constant |
Based on the static plot from the Color Space example.
This animation is three simple transforms between RGB, Lab and HSV color coordinates. Considering the RGB to Lab transform, define XRGB as the initial RGB coordinate and XLab as the final Lab coordinate. The intermediate coordinate is linearly interpolated as :
X(β) = XRGB + β( XLab - XRGB )where β is in the domain from 0 to 1. The difference between initial and final coordinates is the same during the animation. Define this difference as :
Δ = XLab - XRGB
so that the intermediate coordinate is simply a linear function of β, ie:
X(β) = XRGB + βΔThe other two transforms, Lab to HSV, and HSV to RGB, are taken to be the same form. These equations are highlighted in the following code. Notice that the intermediateCoor function does not use the input xyz argument, only the passed f value is used. The coordinates change with each frame, not the face colors. To ‘slow-down’ the transitions near the RGB, Lab and HSV surfaces, a cosine function was used for β with respect to the frame, as defined in the get_beta_type function.
import copy
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.colors as colors
from matplotlib.animation import FuncAnimation
from colorspacious import cspace_converter
import s3dlib.surface as s3d
# 0. Define animation control parameters ............................
totalTime, f_domain, numFrames = 10, (0.0,1.0), 120 # time in seconds
frames=np.linspace(*f_domain, numFrames, endpoint=False)
interval = int(1000.0*totalTime/numFrames) # milliseconds
# 1. Define function to examine ...............
xyzCoor, labCoor, hsvCoor = None, None, None
delta_XYZ_Lab, delta_Lab_HSV, delta_HSV_XYZ = None, None, None
def intermediateCoor(xyz, f) :
def get_beta_type(f) :
t = int(3*f)
rng = 3*f - t
beta = 0.5*(1-np.cos(np.pi*rng))
return beta, t
beta, t = get_beta_type(f)
if t == 1 : return labCoor + beta*delta_Lab_HSV
if t == 2 : return hsvCoor + beta*delta_HSV_XYZ
return xyzCoor + beta*delta_XYZ_Lab
def rgb_to_labCoor(rgb):
L,a,b = cspace_converter("sRGB1", "CAM02-UCS" )(rgb.T).T
return a/80,b/80,L/100
def rgb_to_hsvCoor(rgb) :
h,s,v = colors.rgb_to_hsv(rgb.T).T
rtz = [ s/2, 2*np.pi*h, v ]
return s3d.CylindricalSurface.coor_convert(rtz,True)
# 2. Setup and map surface .........................................
base = s3d.CubicSurface().domain([0,1],[0,1],[0,1]).triangulate(5)
base.map_color_from_op(lambda xyz : xyz)
xyzCoor = base.vertices
labSurf = copy.copy(base).map_geom_from_op(rgb_to_labCoor)
labSurf.transform(translate=[0.5,0.5,0])
labCoor = labSurf.vertices
hsvSurf = copy.copy(base).map_geom_from_op(rgb_to_hsvCoor)
hsvSurf.transform(translate=[0.5,0.5,0])
hsvCoor = hsvSurf.vertices
delta_XYZ_Lab = np.subtract(labCoor,xyzCoor)
delta_Lab_HSV = np.subtract(hsvCoor,labCoor)
delta_HSV_XYZ = np.subtract(xyzCoor,hsvCoor)
frame = 0.0
surface = copy.copy(base)
surface.map_geom_from_op( lambda xyz : intermediateCoor(xyz, frame) ).shade(.6)
# 3. Construct figure, add surface plot ............................
fig = plt.figure(figsize=plt.figaspect(1))
ax = plt.axes(projection='3d',facecolor='k', aspect='equal', proj_type='ortho')
minmax, ticks, paneColor = (-0.2,1.2) , [0,0.5,1], '.05'
ax.set(xlim=minmax, ylim=minmax, zlim=minmax,
xticks=ticks, yticks=ticks, zticks=ticks )
ax.xaxis.set_pane_color(paneColor)
ax.yaxis.set_pane_color(paneColor)
ax.zaxis.set_pane_color(paneColor)
ax.view_init(30,-70)
ax.add_collection3d(surface)
fig.tight_layout(pad=0)
#plt.show()
# 4. Animation ======================================================
def update_fig(frame):
global surface
surface.remove()
surface = copy.copy(base)
surface.map_geom_from_op( lambda xyz : intermediateCoor(xyz, frame) ).shade(.6)
ax.add_collection3d(surface)
return
anim = FuncAnimation(fig, update_fig, frames, interval=interval, repeat=True)
anim.save('rgb_lab_hsv.html',writer='html')
msg = "saved {} frames, values: [{:.3f} to {:.3f}] @ {} milliseconds/frane"
print(msg.format(numFrames,np.min(frames),np.max(frames),interval))