File Coverage

blib/lib/Color/Model/Munsell/Util.pm
Criterion Covered Total %
statement 190 230 82.6
branch 60 122 49.1
condition 16 33 48.4
subroutine 28 29 96.5
pod 7 7 100.0
total 301 421 71.5


line stmt bran cond sub pod time code
1             # =============================================================================
2             package Color::Model::Munsell::Util;
3             # -----------------------------------------------------------------------------
4             $Color::Model::Munsell::Util::VERSION = '0.03';
5             # -----------------------------------------------------------------------------
6 1     1   30074 use warnings;
  1         2  
  1         33  
7 1     1   5 use strict;
  1         2  
  1         38  
8              
9             =head1 NAME
10              
11             Color::Model::Munsell::Util - Utility functions for Color::Model::Munsell
12              
13             =head1 SYNOPSIS
14              
15             use Color::Model::Munsell;
16             use Color::Model::Munsell::Util;
17             use Color::Model::RGB;
18              
19             my $m = Color::Model::Munsell->new("5R 4.5/14");
20             printf("Munsell: %s = RGB: #%s\n", $m, Munsell2RGB($m));
21              
22             =head1 DESCRIPTION
23              
24             C gives some utility functions for color
25             conversion from Munsell to CIE xyY, XYZ or RGB, etc.
26              
27             =cut
28              
29             # =============================================================================
30 1     1   5 use Carp qw();
  1         6  
  1         17  
31 1     1   5 use List::Util qw(first);
  1         2  
  1         99  
32 1     1   4 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
  1         2  
  1         74  
33 1     1   4 use base qw(Exporter);
  1         2  
  1         114  
34             @EXPORT = qw(Munsell2RGB);
35             @EXPORT_OK = qw(
36             huedegree calc_Yc
37             Munsell2xyY Munsell2XYZ Munsell2XYZD65 Munsell2rgb
38             );
39              
40 1     1   911 use Math::VectorReal;
  1         3142  
  1         64  
41 1     1   7 use Color::Model::Munsell qw(@hue_order %hue_number);
  1         2  
  1         145  
42 1     1   1041 use Color::Model::RGB;
  1         12869  
  1         4000  
43              
44             my $_debug = 0;
45 0     0   0 sub _debug { warn join(" ",@_); }
46              
47             # =============================================================================
48             my @_tableAll = ();
49             my %_tableC = ();
50             my $_tableC_loaded = 0;
51              
52              
53             # -----------------------------------------------------------------------------
54             sub _table
55             {
56 10     10   24 my $v = shift;
57 10         84 $v = sprintf('%d',$v);
58 10         32 _load_table_C();
59 10 50 33     87 if ( $v && $_tableC{$v} ){
60             # return same value data sorted by chroma
61 10         16 return sort { $a->[2] <=> $b->[2] } @{$_tableC{$v}};
  35265         49930  
  10         341  
62             } else {
63 0 0       0 return wantarray? @_tableAll: \@_tableAll;
64             }
65             }
66              
67             sub _load_table_C
68             {
69 15 100   15   50 unless ( $_tableC_loaded ){
70 1         2 my $d;
71             # append neutral color for convenience
72 1         5 foreach my $v ( 0.2, 0.4, 0.6, 0.8, 1..10 ){
73 14         30 $d = [ 'N', $v, 0, _neutralxyY($v) ];
74 14         55 push @_tableAll, $d;
75 14         18 push @{$_tableC{$v}}, $d;
  14         78  
76             }
77              
78 1         8 while (){
79 5000         9077 tr/\r\n//d;
80 5000         19403 s/^ +//g;
81 5000 50       26267 next unless $_;
82 5000 100       10442 next if /^#/;
83 4995         25982 my @d = split(/\s+/);
84 4995         10932 $d[5] /= 100; # rescale Y to (0,1)
85 4995         15657 $d = [ @d ];
86 4995         10297 push @_tableAll, $d;
87 4995         4946 push @{$_tableC{$d[1]}}, $d; # key is value
  4995         30931  
88             }
89 1         7 $_tableC_loaded++;
90             }
91             }
92              
93              
94             # -----------------------------------------------------------------------------
95              
96             =head1 EXPORT SUBROUTINES
97              
98             Only subroutine Munsell2RGB is exported by defalut.
99              
100             =head2 huedegree()
101              
102             $n = huedegree( "5R" );
103              
104             Return degree number of Hue; considered 10.0RP is 0, 10R to be 10, 10YR 20,
105             ..., and ends 9.9RP as 99.9.
106             If bad formatted hue given, this returns undef.
107              
108             =cut
109              
110             sub huedegree
111             {
112 31 50 33 31 1 825 if ( defined($_[0]) && $_[0] =~ /^(\d{1,2}|\d{1,2}\.\d)(R|YR|Y|GY|G|BG|B|PB|P|RP)$/ ){
113 31         128 my ($n,$c) = ($1,$2);
114 31 50       175 if ( $n <= 10 ){
115 31         220 return $hue_number{$2} * 10 + $1;
116             }
117             }
118 0         0 return undef;
119             }
120              
121              
122             # =============================================================================
123             # get xyY with linear interpolation
124             # -----------------------------------------------------------------------------
125             my @_Wcxy = (0.310061, 0.316150);
126              
127             =head2 Munsell2xyY()
128              
129             Munsell2xyY() returns an array of CIE x, y and Y which are calculated with
130             linear interpolation from Munsell-xyY table.
131              
132             use Color::Model::Munsell::Util qw(Munsell2xyY);
133              
134             $m = Color::Model::Munsell->new("2.5G 5.5/10");
135             ($x, $y, $Y) = Munsell2xyY($m);
136              
137             This Munsell-xyY table is from MCSL, R.I.T. which condition is using illuminant
138             C and the CIE 1931 2 degree observer.
139              
140             =cut
141              
142             sub _getHueRange
143             {
144 10     10   18 my ($h1, $h2);
145 0         0 my ($hueStep, $hueCol);
146 10 50       74 if ( $_[0] =~ /^([0-9\.]+)([A-Z]+)$/ ){
147 10         44 ($hueStep, $hueCol) = ($1, $2);
148             }
149 10 50       74 if ( $hueStep < 2.5 ){
    50          
    50          
150 0 0       0 my $pre_hC = ($hueCol eq 'R')? 'RP': $hue_order[$hue_number{$hueCol}-1];
151 0         0 ($h1, $h2) = ( "10$pre_hC", "2.5$hueCol" );
152             } elsif ( $hueStep < 5.0 ){
153 0         0 ($h1, $h2) = ( "2.5$hueCol", "5$hueCol" );
154             } elsif ( $hueStep < 7.5 ){
155 10         58 ($h1, $h2) = ( "5$hueCol", "7.5$hueCol" );
156             } else {
157 0         0 ($h1, $h2) = ( "7.5$hueCol", "10$hueCol" );
158             }
159 10         39 return ($h1, $h2);
160             }
161              
162             sub _neutralxyY
163             {
164 14     14   21 my $value = shift;
165 14         26 return ( @_Wcxy, calc_Yc($value)/100 ); # White Point of illuminant C
166             }
167              
168             sub _getVectorOnValuePlane
169             {
170 10     10   131 my ($h0,$v0,$c0) = @_;
171              
172 10 50       33 _debug(" * Cheking: $h0 $v0 / $c0\n") if $_debug;
173              
174 10         36 my ($h1,$h2) = _getHueRange($h0);
175 10 50       26 _debug(" - - hue range = [ $h1, $h2 ]\n") if $_debug;
176              
177 10         47 my @luptable = _table($v0);
178 10 50   5100   486 my $eqcheck = first { $_->[0] eq $h0 && $_->[2] eq $c0 } @luptable;
  5100         11521  
179 10 50       85 return vector(@{$eqcheck}[3,4,5]) if ( $eqcheck ); # found just same data!
  0         0  
180 10 100       47 my @h1 = grep { $_->[0] eq 'N' or $_->[0] eq $h1 } @luptable;
  5100         21796  
181 10 100       81 my @h2 = grep { $_->[0] eq 'N' or $_->[0] eq $h2 } @luptable;
  5100         19960  
182              
183             # h1,h2 ... hue line ( h1 < h2)
184             # c1,c2 ... chroma line (c1 < c2 )
185             #
186             # [ on some value-plane ]
187             # c1 c2
188             # | P C/
189             # h2 ----+-----+----------/-- -
190             # B| | / ) 1-l
191             # | *Z / -
192             # | / | / ` l
193             # | / | / /
194             # h1 ----+-----+-----/--- -
195             # A Q D
196             # ` n ^ 1-n '
197             #
198             # ( = vector x )
199             # = (1-n) + n
200             # = n
201             # = m + (1-m)
202             # = (m-mn) + mn + (n-mn)
203             # = m + n + mn(--)
204             # = m + n + mn(-)
205              
206 10         22 my ($dA,$dB,$dC,$dD); # lookup data
207 0         0 my ($OA,$OB,$OC,$OD); # vectors
208 0         0 my ($c1,$c2); # chroma values of two points
209              
210             # - on line of h1
211 10     80   159 $dD = first { $_->[2] >= $c0 } @h1;
  80         142  
212 10 50       84 unless ( $dD ){
213             # not found, maybe target's chroma is larger than max chroma
214             # of lookup table
215 0         0 return undef;
216             }
217 10         27 $OD = vector( @{$dD}[3,4,5] );
  10         114  
218 10         365 ($c1,$c2) = ($dD->[2]-2, $dD->[2]);
219              
220 10     70   67 $dA = first { $_->[2] == $c1 } @h1;
  70         130  
221 10         35 $OA = vector( @{$dA}[3,4,5] );
  10         46  
222              
223 10 50       170 if ( $_debug ){
224 0         0 _debug(" - - - $h1> OA = ($dA->[0] $dA->[1]/ $dA->[2]) \n");
225 0         0 _debug(" - - - $h1> OD = ($dD->[0] $dD->[1]/ $dD->[2]) \n");
226             }
227              
228             # - on line of h2
229 10     80   89 $dC = first { $_->[2] >= $c0 } @h2;
  80         126  
230 10 50       56 unless ( $dC ){
231             # not found on lookup table
232 0         0 return undef;
233             }
234 10         22 $OC = vector( @{$dC}[3,4,5] );
  10         32  
235 10         182 ($c1,$c2) = ($dC->[2]-2, $dC->[2]);
236              
237 10     70   75 $dB = first { $_->[2] == $c1 } @h2;
  70         155  
238 10         38 $OB = vector( @{$dB}[3,4,5] );
  10         43  
239              
240 10 50       157 if ( $_debug ){
241 0         0 _debug(" - - - $h2> OB = ($dB->[0] $dB->[1]/ $dB->[2]) \n");
242 0         0 _debug(" - - - $h2> OC = ($dC->[0] $dC->[1]/ $dC->[2]) \n");
243             }
244              
245             # calculate ratio
246 10         45 my $n = ($c0 - $c1) / ($c2 - $c1); # ratio between chromas
247 10         20 my ($h0n, $h1n, $h2n) = map { huedegree($_) } ($h0, $h1, $h2);
  30         80  
248 10         34 my $l = ($h0n - $h1n) / ($h2n - $h1n); # ratio between hues
249 10 50       44 if ( $_debug ){
250 0         0 _debug(" - - - Ratio chroma; ($c0 - $1) / ($c2 - $c1) = $n\n");
251 0         0 _debug(" - - - Ratio hue; ($h0n - $h1n) / ($h2n - $h1n) = $l\n");
252             }
253              
254 10         158 my $AB = $OB - $OA;
255 10         717 my $AD = $OD - $OA;
256 10         434 my $BC = $OC - $OB;
257              
258             # return value is a vector with Math::RealVector;
259 10         499 my $AZ = $AB*$l + $AD*$n+ ($BC-$AD)*$l*$n;
260 10         2566 my $OZ = $OA + $AZ;
261              
262 10 50       482 _debug(map { sprintf("%s = (%.4f, %.4f, %.4f)\n", $_, eval"\$$_->array()") } qw(OA OB OC OD OZ)) if $_debug;
  0         0  
263 10         352 return $OZ;
264             }
265              
266             sub Munsell2xyY
267             {
268 5     5 1 11 my $m = shift;
269 5 50 33     41 unless ( defined($m) && ref($m) eq 'Color::Model::Munsell' ){
270 0         0 Carp::croak("Color::Model::Munsell object is not given");
271             }
272 5 50       16 _debug("<< Target: $m >>\n") if $_debug;
273 5         28 my $v = $m->value;
274              
275 5 50       57 if ( $m->isneutral ){
276 0         0 my @ret = _neutralxyY($v);
277 0 0       0 _debug(sprintf("xyY = (%.6f, %.6f, %.6f)\n",@ret)) if $_debug;
278 0         0 return @ret;
279             }
280              
281 5         53 _load_table_C();
282              
283 5         12 my ($LZ, $UZ, $Z);
284             # get lower value-plane
285 5 50       31 my $lv = ($v<1.0)? (int($v*10/2)*2/10): int($v);
286 5 50       21 _debug(" - nearest lower value of $m is $lv\n") if $_debug;
287 5 50       14 if ( $lv == 0 ){
288 0         0 $LZ = vector( _neutralxyY($v) );
289             } else {
290 5         40 $LZ = _getVectorOnValuePlane( $m->hue, $lv, $m->chroma );
291 5 50       23 unless ( defined($LZ) ){
292 0         0 Carp::croak("$m is out of calculatable color space.");
293             }
294             }
295             # get upper value-plane
296 5 50       30 my $uv = ($v<1.0)? (int($v*10/2)*2/10+0.2): int($v+1);
297 5 50       15 _debug(" - nearest upper value of $m is $uv\n") if $_debug;
298 5         39 $UZ = _getVectorOnValuePlane( $m->hue, $uv, $m->chroma );
299 5 50       24 unless ( defined($UZ) ){
300 0         0 Carp::croak("$m is out of calculatable color space.");
301             }
302              
303 5 50       21 _debug(" - value range = [ $lv, $uv ]\n") if $_debug;
304              
305 5         18 my $s = ($v - $lv) / ($uv - $lv ); # ratio between values;
306 5 50       14 _debug(" - value ratio = ($v - $lv) / ($uv - $lv) = $s\n") if $_debug;
307              
308 5         19 $Z = $UZ*$s + $LZ*(1-$s);
309 5 50       527 _debug(sprintf("xyY = (%.6f, %.6f, %.6f)\n",$Z->array())) if $_debug;
310              
311 5         18 return $Z->array(); # ( xc, yc , Yc );
312             }
313             # -----------------------------------------------------------------------------
314              
315              
316             # -----------------------------------------------------------------------------
317             # multiply matrix * vector
318             # -----------------------------------------------------------------------------
319             sub _mmult
320             {
321 5     5   10 my ($m,$v) = @_;
322             return (
323 5         55 $$m[0][0]*$$v[0] + $$m[0][1]*$$v[1] + $$m[0][2]*$$v[2],
324             $$m[1][0]*$$v[0] + $$m[1][1]*$$v[1] + $$m[1][2]*$$v[2],
325             $$m[2][0]*$$v[0] + $$m[2][1]*$$v[1] + $$m[2][2]*$$v[2]
326             );
327             }
328              
329              
330             # =============================================================================
331             # get XYZ from Munsell with xyY
332             # -----------------------------------------------------------------------------
333             my %_matCAdaptD65 = (
334             'XYZ' => [
335             [ 0.9691356, 0.0000000, 0.0000000],
336             [ 0.0000000, 1.0000000, 0.0000000],
337             [ 0.0000000, 0.0000000, 0.9209267]],
338             'Bradford' => [
339             [ 0.9904476,-0.0071683,-0.0116156],
340             [-0.0123712, 1.0155950,-0.0029282],
341             [-0.0035635, 0.0067697, 0.9181569]],
342             'vonKries' => [
343             [ 0.9972812,-0.0093756,-0.0154171],
344             [-0.0010298, 1.0007636, 0.0002084],
345             [ 0.0000000, 0.0000000, 0.9209267]]
346             );
347              
348             =head2 Munsell2XYZ()
349              
350             =head2 Munsell2XYZD65()
351              
352             Munsell2XYZ( $m )
353             Munsell2XYZD65( $m [, "ChromaticAdaptType" ] )
354              
355             Munsell2XYZ() and Munsell2XYZD65() returns an array of CIE X,Y and Z.
356              
357             $m = Color::Model::Munsell->new("7.5B 6/10");
358             printf("%s -> CIE XYZ (%.f, %.f, %.f)", $m, Munsell2XYZ($m));
359              
360             # perform cromatic adaptation from C to D65
361             printf("%s -> CIE XYZ (%.f, %.f, %.f) via Chromatic Adaptation", $m, Munsell2XYZD65($m));
362              
363             Munsell2XYZ() simply calculates XYZ from xyY. And Munsell2XYZD65() calculates
364             them with chromatic adaptatation to illuminant D65. Adaptation type must be
365             "XYZ", "vonKries", "Bradford" or "None". If Omitted, "Bradford" is used.
366             Specifying "None" is same as calling Munsell2XYZ().
367              
368             =cut
369              
370             sub Munsell2XYZ
371             {
372 4     4 1 449 my $m = shift; # Color::Model::Munsell object
373 4 50 33     30 unless ( defined($m) && ref($m) eq 'Color::Model::Munsell' ){
374 0         0 Carp::croak("Munsell2XYZ() needs Color::Model::Munsell object.");
375             }
376              
377 4         12 my ($x,$y,$Y) = Munsell2xyY($m);
378 4         57 my $X = ($x * $Y) / $y; # X = (Y/y) * x
379 4         12 my $Z = ( (1 - $x - $y) * $Y ) / $y; # Z = ( (1-x-y)/y ) * Y
380 4         45 return ($X, $Y, $Z);
381             }
382              
383             sub Munsell2XYZD65
384             {
385 3     3 1 7 my $m = shift; # Color::Model::Munsell object
386 3 50 33     30 unless ( defined($m) && ref($m) eq 'Color::Model::Munsell' ){
387 0         0 Carp::croak("Munsell2XYZD65() needs Color::Model::Munsell object.");
388             }
389              
390 3   100     14 my $atype = shift || 'Bradford'; # Chromatic Adaptation type
391 3 50       20 unless ( $atype =~ /^(None|XYZ|Bradford|vonKries)$/ ){
392 0         0 Carp::croak(qq(Chromatic Adaptation must be "XYZ", "Bradford" or "vonKries"));
393             }
394 3 50       9 _debug(" - Chromatic Adaptation = $atype\n") if $_debug;
395              
396 3         6 my @XYZ;
397 3 50       10 if ( $atype ne 'None' ){
398 3         14 @XYZ = _mmult($_matCAdaptD65{$atype}, [ Munsell2XYZ($m) ]);
399             } else {
400 0         0 @XYZ = Munsell2XYZ($m);
401             }
402 3 50       15 _debug(sprintf("XYZ = (%.6f, %.6f, %.6F)\n",@XYZ)) if $_debug;
403 3         20 return @XYZ;
404             }
405              
406              
407             # =============================================================================
408             # get RGB from XYZ
409             # -----------------------------------------------------------------------------
410             my %_matXYZ2rgb = (
411             'AdobeRGB' => [ # D65
412             [ 2.0413690, -0.5649464, -0.3446944],
413             [-0.9692660, 1.8760108, 0.0415560],
414             [ 0.0134474, -0.1183897, 1.0154096]],
415             'AppleRGB' => [ # D65
416             [ 2.9515373, -1.2894116, -0.4738445],
417             [-1.0851093, 1.9908566, 0.0372026],
418             [ 0.0854934, -0.2694964, 1.0912975]],
419             'PAL' => [ # D65
420             [ 3.0628971, -1.3931791, -0.4757517],
421             [-0.9692660, 1.8760108, 0.0415560],
422             [ 0.0678775, -0.2288548, 1.0693490]],
423             'sRGB' => [ # D65
424             [ 3.2404542, -1.5371385, -0.4985314],
425             [-0.9692660, 1.8760108, 0.0415560],
426             [ 0.0556434, -0.2040259, 1.0572252]],
427             'NTSC' => [ # C
428             [ 1.9099961, -0.5324542, -0.2882091],
429             [-0.9846663, 1.9991710, -0.0283082],
430             [ 0.0583056, -0.1183781, 0.8975535]],
431             );
432              
433              
434             =head2 Munsell2rgb()
435              
436             =head2 Munsell2RGB()
437              
438             Munsell2rgb( $m [, "RGBModel" [, "ChromaticAdaptType" ]] )
439             Munsell2RGB( $m [, "RGBModel" [, "ChromaticAdaptType" [, $gamma ]]] )
440              
441             Munsell2rgb() returns an array of R, G and B values which calculated from
442             XYZ with transformation matrix.
443             And Munsell2RGB() returns RGB values with C object which applied gamma value.
444              
445             $m = Color::Model::Munsell->new("7PB 2.5/3");
446             printf("%s -> RGB %s of sRGB", $m, Munsell2RGB($m));
447             printf("%s -> RGB %s of AdobeRGB(1998)", $m, Munsell2RGB($m,"AdobeRGB"), 2.2);
448              
449             RGBModel must be "sRGB", "AdobeRGB" that means Adobe RGB(1998), "AppleRGB"
450             or "NTSC". A gamma value will be used when RGB model is not sRGB.
451              
452             =cut
453              
454             sub Munsell2rgb
455             {
456 2     2 1 5 my $m = shift; # Color::Model::Munsell object
457 2 50 33     20 unless ( defined($m) && ref($m) eq 'Color::Model::Munsell' ){
458 0         0 Carp::croak("Munsell2rgb() needs Color::Model::Munsell object.");
459             }
460 2   100     11 my $rgbtype = shift || 'sRGB'; # RGB type
461 2   100     10 my $atype = shift || 'Bradford'; # Chromatic Adaptation type
462 2 50       15 unless ( $rgbtype =~ /^(AdobeRGB|AppleRGB|PAL|sRGB|NTSC)$/ ){
463 0         0 Carp::croak(qq(RGB type must be "AdobeRGB", "AppleRGB", "PAL", "NTSC" or "sRGB"));
464             }
465 2 50       8 _debug(" - RGB = $rgbtype\n") if $_debug;
466              
467 2         3 my @XYZ;
468 2 50       9 if ( $rgbtype eq 'NTSC' ){
469 0         0 @XYZ = Munsell2XYZ($m);
470             } else {
471 2         8 @XYZ = Munsell2XYZD65($m, $atype);
472             }
473              
474 2         13 my @rgb = _mmult($_matXYZ2rgb{$rgbtype}, \@XYZ);
475 2 50       8 _debug(sprintf("rgb = (%.6f, %.6f, %.6f)\n",@rgb)) if $_debug;
476 2         16 return @rgb;
477             }
478              
479             sub Munsell2RGB
480             {
481 1     1 1 4 my $m = shift; # Color::Model::Munsell object
482 1 50 33     12 unless ( defined($m) && ref($m) eq 'Color::Model::Munsell' ){
483 0         0 Carp::croak("Munsell2RGB() needs Color::Model::Munsell object.");
484             }
485 1   50     8 my $rgbtype = shift || 'sRGB'; # RGB type
486 1   50     8 my $atype = shift || 'Bradford'; # Chromatic Adaptation type
487 1   50     75 my $gamma = shift || 2.2; # Gamma value (uses when not sRGB)
488              
489 1         3 my @RGB;
490 1 50       7 if ( $rgbtype eq 'sRGB' ){
491 3 50       1049 @RGB = map {
492 1         4 $_ = $_>0.0031308?
493             (1.055 * ($_ ** (1/2.4)) - 0.055):
494             12.92 * $_;
495 3 50       30 $_ = $_<0 ? 0: ( $_>1? 1: $_);
    50          
496             } Munsell2rgb($m, 'sRGB', $atype);
497             } else {
498 0         0 @RGB = map {
499 0         0 $_ = $_ ** (1/$gamma);
500 0 0       0 $_ = $_<0 ? 0: ( $_>1? 1: $_);
    0          
501             } Munsell2rgb($m, $rgbtype, $atype);
502             }
503 1 50       21 _debug(sprintf("RGB = (%.6f, %.6f, %.6f)\n",@RGB)) if $_debug;
504 1         15 return Color::Model::RGB->new(@RGB);
505             }
506              
507              
508             # =============================================================================
509             # Calculation Y of illuminant C
510             # -----------------------------------------------------------------------------
511              
512             =head2 calc_Yc()
513              
514             calc_Yc( $m )
515              
516             calc_Yc() calculates Y value of illuminant C and 2 degree observer from Munsell
517             value with approximate calculation. Argument must be a I object or Munsell value.
518              
519             $m = Color::Model::Munsell->new("5R 4/14")
520             printf "%.4f", calc_Yc( $m );
521             printf "%.4f", calc_Yc( 7.5 );
522              
523             =cut
524              
525 1     1   11 use Scalar::Util qw(looks_like_number);
  1         2  
  1         229  
526              
527             sub calc_Yc
528             {
529             # Yc = 1.1913*V - 0.22532*V^2 + 0.23351*V^3 - 0.020483*V^4 + 0.00081936*V^5
530             # (ref. JIS Z 8721(1993) )
531              
532 16     16 1 49 my $m = shift;
533 16         21 my $v = undef;
534 16 50       39 if ( defined($m) ){
535 16 50       74 if ( ref($m) eq 'Color::Model::Munsell' ){
    50          
536 0         0 $v = $m->value;
537             } elsif ( looks_like_number($m) ){
538 16         31 $v = $m;
539             }
540             }
541 16 50       36 unless ( defined($v) ){
542 0         0 Carp::croak("Bad argument. calc_Yc() needs a number");
543             }
544 16         25 my $v2 = $v*$v;
545 16         28 my $v3 = $v*$v2;
546 16         18 my $v4 = $v2*$v2;
547 16         21 my $v5 = $v2*$v3;
548 16         123 return 1.1913*$v - 0.22532*$v2 + 0.23351*$v3 - 0.020483*$v4 + 0.00081936*$v5;
549             }
550              
551              
552             =head1 AUTHOR
553              
554             Takahiro Onodera, C<< >>
555              
556             =head1 BUGS
557              
558             Please report any bugs or feature requests to C, or through
559             the web interface at L. I will be notified, and then you'll
560             automatically be notified of progress on your bug as I make changes.
561              
562             =head1 SEE ALSO
563              
564             L, L
565              
566             =head1 REFERENCES
567              
568             Munsell Color Science Laboratory, R.I.T - L - Munsell-xyY data are from this site.
569              
570             BruceLindbloom.com - L - Chromatic adaptation matrixes, transformation matrixes and important knowledge are from this site.
571              
572             Japanese Industrial Standards(JIS) JIS Z 8721(1993)
573              
574             =head1 LICENSE AND COPYRIGHT
575              
576             Copyright 2010 Takahiro Onodera.
577              
578             This program is free software; you can redistribute it and/or modify it
579             under the terms of either: the GNU General Public License as published
580             by the Free Software Foundation; or the Artistic License.
581              
582             =cut
583              
584             1; # End of Color::Model::Munsell::Util
585             __DATA__