moduleTermmoduleANSIColormoduleRGBColorMetricsHelpersmoduleWeightedEuclideanDistancedefweighted_euclidean_distance_to(other,weights=[1.0]*values.size)sum=0.0values.zip(other.values,weights)do|s,o,w|sum+=w*(s-o)**2endMath.sqrt(sum)endendmoduleNormalizeRGBTripleprivatedefnormalize(v)v/=255.0ifv<=0.04045v/12else((v+0.055)/1.055)**2.4endenddefnormalize_rgb_triple(rgb_triple)[normalize(rgb_triple.red),normalize(rgb_triple.green),normalize(rgb_triple.blue),]endendendmoduleRGBColorMetricsdefself.metric(name)metric?(name)orraiseArgumentError,"unknown metric #{name.inspect}"enddefself.metric?(name)ifconst_defined?(name)const_getnameendenddefself.metricsconstants.map(&:to_sym)end# Implements color distance how the old greeks and most donkeys would…moduleEuclideandefself.distance(rgb1,rgb2)rgb1.weighted_euclidean_distance_torgb2endend# Implements color distance the best way everybody knows…moduleNTSCdefself.distance(rgb1,rgb2)rgb1.weighted_euclidean_distance_torgb2,[0.299,0.587,0.114]endend# Implements color distance as given in:# http://www.compuphase.com/cmetric.htmmoduleCompuPhasedefself.distance(rgb1,rgb2)rmean=(rgb1.red+rgb2.red)/2rgb1.weighted_euclidean_distance_torgb2,[2+(rmean>>8),4,2+((255-rmean)>>8)]endendmoduleYUVclassYUVTriple<Struct.new(:y,:u,:v)includeRGBColorMetricsHelpers::WeightedEuclideanDistancedefself.from_rgb_triple(rgb_triple)r,g,b=rgb_triple.red,rgb_triple.green,rgb_triple.bluey=(0.299*r+0.587*g+0.114*b).roundu=((b-y)*0.492).roundv=((r-y)*0.877).roundnew(y,u,v)endenddefself.distance(rgb1,rgb2)yuv1=YUVTriple.from_rgb_triple(rgb1)yuv2=YUVTriple.from_rgb_triple(rgb2)yuv1.weighted_euclidean_distance_toyuv2endendmoduleCIEXYZclassCIEXYZTriple<Struct.new(:x,:y,:z)includeRGBColorMetricsHelpers::WeightedEuclideanDistanceextendRGBColorMetricsHelpers::NormalizeRGBTripledefself.from_rgb_triple(rgb_triple)r,g,b=normalize_rgb_triplergb_triplex=0.436052025*r+0.385081593*g+0.143087414*by=0.222491598*r+0.71688606*g+0.060621486*bz=0.013929122*r+0.097097002*g+0.71418547*bx*=255y*=255z*=255new(x.round,y.round,z.round)endenddefself.distance(rgb1,rgb2)xyz1=CIEXYZTriple.from_rgb_triple(rgb1)xyz2=CIEXYZTriple.from_rgb_triple(rgb2)xyz1.weighted_euclidean_distance_toxyz2endendmoduleCIELabclassCIELabTriple<Struct.new(:l,:a,:b)includeRGBColorMetricsHelpers::WeightedEuclideanDistanceextendRGBColorMetricsHelpers::NormalizeRGBTripledefself.from_rgb_triple(rgb_triple)r,g,b=normalize_rgb_triplergb_triplex=0.436052025*r+0.385081593*g+0.143087414*by=0.222491598*r+0.71688606*g+0.060621486*bz=0.013929122*r+0.097097002*g+0.71418547*bxr=x/0.964221yr=yzr=z/0.825211eps=216.0/24389k=24389.0/27fx=xr>eps?xr**(1.0/3):(k*xr+16)/116fy=yr>eps?yr**(1.0/3):(k*yr+16)/116fz=zr>eps?zr**(1.0/3):(k*zr+16)/116l=2.55*((116*fy)-16)a=500*(fx-fy)b=200*(fy-fz)new(l.round,a.round,b.round)endenddefself.distance(rgb1,rgb2)lab1=CIELabTriple.from_rgb_triple(rgb1)lab2=CIELabTriple.from_rgb_triple(rgb2)lab1.weighted_euclidean_distance_tolab2endendendendend