1## Copyright (C) 1994-2017 John W. Eaton <jwe@octave.org>
2##
3## This program is free software: you can redistribute it and/or modify
4## it under the terms of the GNU General Public License as published by
5## the Free Software Foundation, either version 3 of the License, or
6## (at your option) any later version.
7##
8## This program is distributed in the hope that it will be useful,
9## but WITHOUT ANY WARRANTY; without even the implied warranty of
10## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11## GNU General Public License for more details.
12##
13## You should have received a copy of the GNU General Public License
14## along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16## -*- texinfo -*-
17## @deftypefn  {} {@var{yiq_map} =} rgb2ntsc (@var{rgb_map})
18## @deftypefnx {} {@var{yiq_img} =} rgb2ntsc (@var{rgb_img})
19## Transform a colormap or image from red-green-blue (RGB) color space to
20## luminance-chrominance (NTSC) space.  The input may be of class uint8,
21## uint16, single, or double.  The output is of class double.
22##
23## Implementation Note:
24## The reference matrix for the transformation is
25##
26## @example
27## @group
28## /Y\     0.299  0.587  0.114  /R\
29## |I|  =  0.596 -0.274 -0.322  |G|
30## \Q/     0.211 -0.523  0.312  \B/
31## @end group
32## @end example
33##
34## @noindent
35## as documented in @url{http://en.wikipedia.org/wiki/YIQ} and truncated to 3
36## significant figures.  Note: The FCC version of NTSC uses only 2 significant
37## digits and is slightly different.
38## @seealso{ntsc2rgb, rgb2hsv, rgb2ind}
39## @end deftypefn
40
41function yiq = rgb2ntsc (rgb)
42
43  if (nargin != 1)
44    print_usage ();
45  endif
46
47  [rgb, cls, sz, is_im, is_nd, is_int] ...
48    = colorspace_conversion_input_check ("rgb2ntsc", "RGB", rgb, false);
49
50  ## Reference matrix for transformation from http://en.wikipedia.org/wiki/YIQ
51  ## and truncated to 3 significant figures.  Matlab uses this matrix for their
52  ## conversion.
53  trans = [ 0.299,  0.596,  0.211;
54            0.587, -0.274, -0.523;
55            0.114, -0.322,  0.312 ];
56  yiq = rgb * trans;
57  ## Note that if the input is of class single, we also return an image
58  ## of class single.  This is Matlab incompatible by design, since
59  ## Matlab always returning class double, is a Matlab bug (see patch #8709)
60
61  yiq = colorspace_conversion_revert (yiq, cls, sz, is_im, is_nd, false);
62
63endfunction
64
65
66## Test pure RED, GREEN, BLUE colors
67%!assert (rgb2ntsc ([1 0 0]), [.299  .596  .211])
68%!assert (rgb2ntsc ([0 1 0]), [.587 -.274 -.523])
69%!assert (rgb2ntsc ([0 0 1]), [.114 -.322  .312])
70
71%!test
72%! rgb_map = rand (64, 3);
73%! assert (ntsc2rgb (rgb2ntsc (rgb_map)), rgb_map, 1e-3);
74
75%!test
76%! rgb_img = rand (64, 64, 3);
77%! assert (ntsc2rgb (rgb2ntsc (rgb_img)), rgb_img, 1e-3);
78
79## test tolerance input checking on floats
80%! assert (rgb2ntsc ([1.5 1 1]), [1.149   0.298   0.105], 1e-3);
81
82## Test input validation
83%!error rgb2ntsc ()
84%!error rgb2ntsc (1,2)
85%!error <invalid data type 'cell'> rgb2ntsc ({1})
86%!error <RGB must be a colormap or RGB image> rgb2ntsc (ones (2,2))
87
88## Test ND input
89%!test
90%! rgb = rand (16, 16, 3, 5);
91%! yiq = zeros (size (rgb));
92%! for i = 1:5
93%!   yiq(:,:,:,i) = rgb2ntsc (rgb(:,:,:,i));
94%! endfor
95%! assert (rgb2ntsc (rgb), yiq);
96
97## Test output class and size for input images.
98## Most of the tests only test for colormap input.
99
100%!test
101%! ntsc = rgb2ntsc (rand (10, 10, 3));
102%! assert (class (ntsc), "double");
103%! assert (size (ntsc), [10 10 3]);
104
105%!test
106%! ntsc = rgb2ntsc (rand (10, 10, 3, "single"));
107%! assert (class (ntsc), "single");
108%! assert (size (ntsc), [10 10 3]);
109
110%!test
111%! rgb = (rand (10, 10, 3) * 3 ) - 0.5; # values outside range [0 1]
112%! ntsc = rgb2ntsc (rgb);
113%! assert (class (ntsc), "double");
114%! assert (size (ntsc), [10 10 3]);
115
116%!test
117%! rgb = (rand (10, 10, 3, "single") * 3 ) - 0.5; # values outside range [0 1]
118%! ntsc = rgb2ntsc (rgb);
119%! assert (class (ntsc), "single");
120%! assert (size (ntsc), [10 10 3]);
121
122%!test
123%! ntsc = rgb2ntsc (randi ([0 255], 10, 10, 3, "uint8"));
124%! assert (class (ntsc), "double");
125%! assert (size (ntsc), [10 10 3]);
126
127%!test
128%! ntsc = rgb2ntsc (randi ([0 65535], 10, 10, 3, "uint16"));
129%! assert (class (ntsc), "double");
130%! assert (size (ntsc), [10 10 3]);
131
132%!test
133%! ntsc = rgb2ntsc (randi ([-128 127], 10, 10, 3, "int8"));
134%! assert (class (ntsc), "double");
135%! assert (size (ntsc), [10 10 3]);
136
137%!test
138%! rgb_double = reshape ([1 0 0 0 0 1 0 0 0 0 1 0], [2 2 3]);
139%! rgb_uint8  = reshape (uint8 ([255 0 0 0 0 255 0 0 0 0 255 0]),
140%!                       [2 2 3]);
141%! rgb_int16 = int16 (double (rgb_double * uint16 (65535)) -32768);
142%! expected = reshape ([.299 .587 .114 0 .596 -.274 -.322 0 .211 -.523 .312 0],
143%!                     [2 2 3]);
144%!
145%! assert (rgb2ntsc (rgb_double), expected);
146%! assert (rgb2ntsc (rgb_uint8), expected);
147%! assert (rgb2ntsc (single (rgb_double)), single (expected));
148