Skip to content

Commit

Permalink
fixed LAB tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lichtkind committed May 3, 2024
1 parent f084522 commit e3958e6
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 106 deletions.
4 changes: 0 additions & 4 deletions Changes
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,3 @@
* = initial release - moved code out of Chart module
* \ created own distro
* ~ small POD fixes


* * added color set method: bowl
* * added getter method: near_names
52 changes: 25 additions & 27 deletions lib/Graphics/Toolkit/Color/Space/Instance/LAB.pm
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,39 @@ my $lab_def = Graphics::Toolkit::Color::Space->new( prefix => 'CIE',

$lab_def->add_converter('RGB', \&to_rgb, \&from_rgb );

my @xyz_range = (0.95047, 1, 1.08883);
my @D65 = (0.95047, 1, 1.08883); # illuminant
my $eta = 0.008856 ;
my $kappa = 903.3 / 100;

sub from_rgb {
my ($r, $g, $b) = @{$_[0]};
my ($x, $y, $z) = mult_matrix([[0.4124564, 0.2126729, 0.0193339],
[0.3575761, 0.7151522, 0.1191920],
[0.1804375, 0.0721750, 0.9503041]],
apply_d65( $r ), apply_d65( $g ), apply_d65( $b ));
say "x y z $x, $y, $z";
$x /= 0.95047;
$z /= 0.108883;

$x = ($x > 0.008856) ? ($x ** (1/3)) : (7.7870689 * $x + 0.137931034);
$y = ($y > 0.008856) ? ($y ** (1/3)) : (7.7870689 * $y + 0.137931034);
$z = ($z > 0.008856) ? ($z ** (1/3)) : (7.7870689 * $z + 0.137931034);

return ((116 * $y) - 16, $a = 500 * ($x - $y), 200 * ($y - $z));
my (@xyz) = mult_matrix([[0.4124564, 0.2126729, 0.0193339],
[0.3575761, 0.7151522, 0.1191920],
[0.1804375, 0.0721750, 0.9503041]], apply_d65($r), apply_d65($g), apply_d65($b));
@xyz = map { $xyz[$_] / $D65[$_] } 0 .. 2;
@xyz = map { $_ > $eta ? ($_ ** (1/3)) : ((($kappa * $_) + .16) / 1.16) } @xyz;

return ((1.16 * $xyz[1]) - .16, ($xyz[0] - $xyz[1] + 1) / 2, (($xyz[1] - $xyz[2] + 1) / 2)); # l a b
}


sub to_rgb {
my ($l, $a, $b) = @{$_[0]};
my $y = ($l + 16) / 116;
my $x = ($a / 500) + $y;
my $z = $y - ($b / 200);
$x = ($x**3 > 0.008856) ? ($x ** 3) : (($x - 0.137931034) / 7.7870689);
$y = ($y**3 > 0.008856) ? ($y ** 3) : (($y - 0.137931034) / 7.7870689);
$z = ($z**3 > 0.008856) ? ($z ** 3) : (($z - 0.137931034) / 7.7870689);
$x *= 0.95047;
$z *= 0.108883;
my ($r, $g, $bl) = mult_matrix([[ 3.2404542, -0.9692660, 0.0556434],
[-1.5371385, 1.8760108, -0.2040259],
[-0.4985314, 0.0415560, 1.0572252]], $x, $y, $z);

return ( remove_d65($r), remove_d65($g), remove_d65($bl));
my $y = ($l + .16) / 1.16;
my $x = $y + (($a * 2)-1);
my $z = $y - (($b * 2)-1);

$x = ($x**3 > $eta) ? ($x ** 3) : ($kappa * (($x * 1.16) - .16));
$y = ($y**3 > ($eta * $kappa)) ? ($y ** 3) : ($kappa * $l);
$z = ($z**3 > $eta) ? ($z ** 3) : ($kappa * (($z * 1.16) - .16));

$x *= $D65[0];
$z *= $D65[2];
my (@rgb) = mult_matrix([[ 3.2404542, -0.9692660, 0.0556434],
[-1.5371385, 1.8760108, -0.2040259],
[-0.4985314, 0.0415560, 1.0572252]], $x, $y, $z);

return ( map { remove_d65($_) } @rgb );
}

$lab_def;
47 changes: 34 additions & 13 deletions lib/Graphics/Toolkit/Color/Space/Instance/LUV.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,47 @@ use Graphics::Toolkit::Color::Space::Util qw/mult_matrix apply_d65 remove_d65/;


# cyan-orange balance, magenta-green balance
my $luv_def = Graphics::Toolkit::Color::Space->new( axis => [qw/L* u* v*/],
prefix => 'CIE',
range => [1, 1, 1] );
my $luv_def = Graphics::Toolkit::Color::Space->new( prefix => 'CIE',
axis => [qw/L* u* v*/],
range => [100, 1, 1] );

$luv_def->add_converter('RGB', \&to_rgb, \&from_rgb );

my @D65 = (0.95047, 1, 1.08883); # illuminant
my $eta = 0.008856 ;
my $kappa = 903.3 / 100;

sub from_rgb {
my ($r, $g, $b) = @_;
return mult_matrix([[0.4124564, 0.2126729, 0.0193339],
[0.3575761, 0.7151522, 0.1191920],
[0.1804375, 0.0721750, 0.9503041]], apply_d65( $r ), apply_d65( $g ), apply_d65( $b ));
my ($r, $g, $b) = @{$_[0]};
my (@xyz) = mult_matrix([[0.4124564, 0.2126729, 0.0193339],
[0.3575761, 0.7151522, 0.1191920],
[0.1804375, 0.0721750, 0.9503041]], apply_d65($r), apply_d65($g), apply_d65($b));
@xyz = map { $xyz[$_] / $D65[$_] } 0 .. 2;
@xyz = map { $_ > $eta ? ($_ ** (1/3)) : ((($kappa * $_) + .16) / 1.16) } @xyz;

return ((1.16 * $xyz[1]) - .16, ($xyz[0] - $xyz[1] + 1) / 2, (($xyz[1] - $xyz[2] + 1) / 2)); # l a b
}

sub to_rgb {
my ($x, $y, $z) = @_;
my ($r, $g, $b) = mult_matrix([[ 3.2404542, -0.9692660, 0.0556434],
[-1.5371385, 1.8760108, -0.2040259],
[-0.4985314, 0.0415560, 1.0572252]], $x, $y, $z);

return ( remove_d65($r), remove_d65($g), remove_d65($b));
sub to_rgb {
my ($l, $a, $b) = @{$_[0]};
my $y = ($l + .16) / 1.16;
my $x = $y + (($a * 2)-1);
my $z = $y - (($b * 2)-1);

$x = ($x**3 > $eta) ? ($x ** 3) : ($kappa * (($x * 1.16) - .16));
$y = ($y**3 > ($eta * $kappa)) ? ($y ** 3) : ($kappa * $l);
$z = ($z**3 > $eta) ? ($z ** 3) : ($kappa * (($z * 1.16) - .16));

$x *= $D65[0];
$z *= $D65[2];
my (@rgb) = mult_matrix([[ 3.2404542, -0.9692660, 0.0556434],
[-1.5371385, 1.8760108, -0.2040259],
[-0.4985314, 0.0415560, 1.0572252]], $x, $y, $z);

return ( map { remove_d65($_) } @rgb );
}

$luv_def;

#say "xyz r : @xyz";
8 changes: 4 additions & 4 deletions lib/Graphics/Toolkit/Color/Space/Instance/XYZ.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ package Graphics::Toolkit::Color::Space::Instance::XYZ;
use Graphics::Toolkit::Color::Space;
use Graphics::Toolkit::Color::Space::Util qw/mult_matrix apply_d65 remove_d65/;

my @range = (0.95047, 1, 1.08883);
my @D65 = (0.95047, 1, 1.08883);
my $xyz_def = Graphics::Toolkit::Color::Space->new( prefix => 'CIE',
axis => [qw/X Y Z/],
range => [map {$range[$_] * 100} 0 .. 2],
range => [map {$D65[$_] * 100} 0 .. 2],
precision => 3, );

$xyz_def->add_converter('RGB', \&to_rgb, \&from_rgb );
Expand All @@ -20,12 +20,12 @@ sub from_rgb {
my (@xyz) = mult_matrix([[0.4124564, 0.2126729, 0.0193339],
[0.3575761, 0.7151522, 0.1191920],
[0.1804375, 0.0721750, 0.9503041]], apply_d65( $r ), apply_d65( $g ), apply_d65( $b ));
map {$xyz[$_] / $range[$_]} 0 .. 2;
map {$xyz[$_] / $D65[$_]} 0 .. 2;
}

sub to_rgb {
my (@xyz) = @{$_[0]};
@xyz = map { $xyz[$_] * $range[$_] } 0 .. 2;
@xyz = map { $xyz[$_] * $D65[$_] } 0 .. 2;
my ($r, $g, $b) = mult_matrix([[ 3.2404542, -0.9692660, 0.0556434],
[-1.5371385, 1.8760108, -0.2040259],
[-0.4985314, 0.0415560, 1.0572252]], @xyz);
Expand Down
2 changes: 0 additions & 2 deletions lib/Graphics/Toolkit/Color/Space/Util.pm
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,3 @@ sub mult_matrix {


1;

# min(floor(val*256),255)
132 changes: 80 additions & 52 deletions t/22_lab_space.t
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

use v5.12;
use warnings;
use Test::More tests => 57;
use Test::More tests => 92;

BEGIN { unshift @INC, 'lib', '../lib'}
BEGIN { unshift @INC, 'lib', '../lib', 't/lib'}
my $module = 'Graphics::Toolkit::Color::Space::Instance::LAB';

my $space = eval "require $module";
use Graphics::Toolkit::Color::Space::Util ':all';
#use Test::Color ':all';

is( not($@), 1, 'could load the module');
is( ref $space, 'Graphics::Toolkit::Color::Space', 'got tight return value by loading module');
Expand Down Expand Up @@ -44,69 +45,96 @@ is( $val->[2], -0.1, 'third value good');
is( $space->format([0,1,0], 'css_string'), 'cielab(0, 1, 0)', 'can format css string');

$val = $space->deconvert( [ 0, 0, 0], 'RGB');
is( ref $val, 'ARRAY', 'deconverted tuple of zeros');
is( ref $val, 'ARRAY', 'deconverted tuple of zeros (black)');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , 0), 1, 'first value good');
is( close_enough( $val->[1] , 0.5), 1, 'second value good');
is( close_enough( $val->[2] , 0.5), 1, 'third value good');

$val = $space->denormalize( [0, .5, .5] );
is( ref $val, 'ARRAY', 'denormalized deconverted tuple of zeros');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , 0), 1, 'first value good');
is( close_enough( $val->[1] , 0), 1, 'second value good');
is( close_enough( $val->[2] , 0), 1, 'third value good');

$val = $space->convert( [ 0, 0, 0], 'RGB');
is( ref $val, 'ARRAY', 'converted tuple of zeros');
is( int @$val, 3, 'right amount of values');
$val = $space->normalize( [0, 0, 0] );
is( ref $val, 'ARRAY', 'normalized tuple of zeros');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , 0), 1, 'first value good');
is( close_enough( $val->[1] , 0.5), 1, 'second value good');
is( close_enough( $val->[2] , 0.5), 1, 'third value good');

$val = $space->convert( [ 0, 0.5, 0.5], 'RGB');
is( ref $val, 'ARRAY', 'converted white to RGB');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , 0), 1, 'first value good');
is( close_enough( $val->[1] , 0), 1, 'second value good');
is( close_enough( $val->[2] , 0), 1, 'third value good');

$val = $space->deconvert( [ 1, 1, 1,], 'RGB');
is( ref $val, 'ARRAY', 'deconverted tuple of zeros');
is( ref $val, 'ARRAY', 'deconverted tuple of ones (white)');
is( int @$val, 3, 'right amount of values');
is( close_enough($val->[0], 1), 1, 'first value good');
is( close_enough($val->[1], 0.5), 1, 'second value good');
is( close_enough($val->[2], 0.5), 1, 'third value good');

$val = $space->convert( [ 1, 0.5, 0.5], 'RGB');
is( ref $val, 'ARRAY', 'converted tuple of zeros');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , 1), 1, 'first value good');
is( close_enough( $val->[1] , 1), 1, 'second value good');
is( close_enough( $val->[2] , 1), 1, 'third value good');

$val = $space->deconvert( [ 0.5, 0.5, 0.5], 'RGB');
is( ref $val, 'ARRAY', 'converted gray to RGB');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , .53389), 1, 'first value good');
is( close_enough( $val->[1] , .5), 1, 'second value good');
is( close_enough( $val->[2] , .5), 1, 'third value good');

$val = $space->denormalize( [0.53389, .5, .5] );
is( ref $val, 'ARRAY', 'denormalized deconverted gray');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , 53.389), 1, 'first value good');
is( close_enough( $val->[1] , 0), 1, 'second value good');
is( $val->[2], 1, 'third value good');


exit 0;
is( close_enough( $val->[2] , 0), 1, 'third value good');

my @xyz = $space->deconvert( [ 0.5, 0.5, 0.5], 'RGB');
is( int @xyz, 3, 'converted color grey has three XYZ values');
is( close_enough($xyz[0], 0.20344), 1, 'converted color grey has computed right X value');
is( close_enough($xyz[1], 0.21404), 1, 'converted color grey has computed right Y value');
is( close_enough($xyz[2], 0.23305), 1, 'converted color grey has computed right Z value');

@xyz = $space->deconvert( [ 1, 1, 1], 'RGB');
is( int @xyz, 3, 'converted color white has three XYZ values');
is( close_enough($xyz[0], 0.95047), 1, 'converted color white has computed right X value');
is( close_enough($xyz[1], 1), 1, 'converted color white has computed right Y value');
is( close_enough($xyz[2], 1.08883), 1, 'converted color white has computed right Z value');

@xyz = $space->deconvert( [ 1, 0, 0.5], 'RGB');
is( int @xyz, 3, 'converted color pink has three XYZ values');
is( close_enough($xyz[0], 0.45108), 1, 'converted color pink has computed right X value');
is( close_enough($xyz[1], 0.22821), 1, 'converted color pink has computed right Y value');
is( close_enough($xyz[2], 0.22274), 1, 'converted color pink has computed right Z value');

my @rgb = $space->convert( [0, 0, 0], 'RGB');
is( int @rgb, 3, 'converted back black with 3 values');
is( close_enough($rgb[0], 0), 1, 'right red value');
is( close_enough($rgb[1], 0), 1, 'right green value');
is( close_enough($rgb[2], 0), 1, 'right blue value');

@rgb = $space->convert( [0.20344, 0.21404, 0.23305], 'RGB');
is( int @rgb, 3, 'converted back gray with 3 values');
is( close_enough($rgb[0], 0.5), 1, 'right red value');
is( close_enough($rgb[1], 0.5), 1, 'right green value');
is( close_enough($rgb[2], 0.5), 1, 'right blue value');

@rgb = $space->convert( [0.95047, 1, 1.08883], 'RGB');
is( int @rgb, 3, 'converted back gray with 3 values');
is( close_enough($rgb[0], 1), 1, 'right red value');
is( close_enough($rgb[1], 1), 1, 'right green value');
is( close_enough($rgb[2], 1), 1, 'right blue value');

@rgb = $space->convert( [0.45108, 0.22821, 0.22274], 'RGB');
is( int @rgb, 3, 'converted back gray with 3 values');
is( close_enough($rgb[0], 1 ), 1, 'right red value');
is( close_enough($rgb[1], 0 ), 1, 'right green value');
is( close_enough($rgb[2], 0.5), 1, 'right blue value');
$val = $space->convert( [ 0.53389, .5, .5], 'RGB');
is( ref $val, 'ARRAY', 'converted back gray to RGB');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , .5), 1, 'first value good');
is( close_enough( $val->[1] , .5), 1, 'second value good');
is( close_enough( $val->[2] , .5), 1, 'third value good');


$val = $space->deconvert( [ 1, 0, 0.5], 'RGB');
is( ref $val, 'ARRAY', 'converted purple from RGB');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , .54878), 1, 'first value good');
is( close_enough( $val->[1] , .584499), 1, 'second value good');
is( close_enough( $val->[2] , .5109), 1, 'third value good');

$val = $space->convert( [ 0.54878, .584499, .5109], 'RGB');
is( ref $val, 'ARRAY', 'converted back gray to RGB');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , 1), 1, 'first value good');
is( close_enough( $val->[1] , 0), 1, 'second value good');
is( close_enough( $val->[2] , .5), 1, 'third value good');


$val = $space->deconvert( [ .1, 0.2, 0.9], 'RGB');
is( ref $val, 'ARRAY', 'converted BLUE from RGB');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , .34526), 1, 'first value good');
is( close_enough( $val->[1] , .557165), 1, 'second value good');
is( close_enough( $val->[2] , .2757375),1, 'third value good');

$val = $space->convert( [ 0.34526, .557165, .2757375], 'RGB');
is( ref $val, 'ARRAY', 'converted back BLUE to RGB');
is( int @$val, 3, 'right amount of values');
is( close_enough( $val->[0] , .1), 1, 'first value good');
is( close_enough( $val->[1] , .2), 1, 'second value good');
is( close_enough( $val->[2] , .9), 1, 'third value good');

exit 0;
8 changes: 4 additions & 4 deletions t/23_luv_space.t
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ use warnings;
use Test::More tests => 40;

BEGIN { unshift @INC, 'lib', '../lib'}
my $module = 'Graphics::Toolkit::Color::Space::Instance::YIQ';
my $module = 'Graphics::Toolkit::Color::Space::Instance::LUV';

my $def = eval "require $module";
use Graphics::Toolkit::Color::Space::Util ':all';

is( not($@), 1, 'could load the module');
is( ref $def, 'Graphics::Toolkit::Color::Space', 'got tight return value by loading module');
is( $def->name, 'YIQ', 'color space has right name');
is( $def->dimensions, 3, 'color space has 3 dimensions');
is( $def->name, 'CIELUV', 'color space has right name');
is( $def->axis, 3, 'color space has 3 dimensions');
is( $def->is_array([0,0,0]), 1, 'vector has 3 elements');

Check failure on line 17 in t/23_luv_space.t

View workflow job for this annotation

GitHub Actions / OS ubuntu-latest Perl 5.32

Can't locate object method "is_array" via package "Graphics::Toolkit::Color::Space"
is( $def->is_partial_hash({i => 1, quadrature => 0}), 1, 'found hash with some keys');
is( $def->can_convert('rgb'), 1, 'do only convert from and to rgb');
is( $def->can_convert('yiq'), 0, 'can not convert to itself');
is( $def->format([0,0,0], 'css_string'), 'yiq(0,0,0)', 'can format css string');
my @val = $def->deformat(['YIQ', 1, 0, -0.1]);
my @val = $def->deformat(['LUV', 1, 0, -0.1]);
is( int @val, 3, 'deformated value triplet (vector)');
is( $val[0], 1, 'first value good');
is( $val[1], 0, 'second value good');
Expand Down
19 changes: 19 additions & 0 deletions t/lib/Test/Color.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use v5.12;
use warnings;

# utilities for any sub module of the distribution

package Test::Color;

use Exporter 'import';
our @EXPORT_OK = qw/close_enough/;
our %EXPORT_TAGS = (all => [@EXPORT_OK]);

my $half = 0.50000000000008;
my $tolerance = 0.00000000000008;


sub close_enough { abs($_[0] - $_[1]) < 0.008 if defined $_[1]}


1;

0 comments on commit e3958e6

Please sign in to comment.