1 // Copyright (C) 2013-2015 Carnë Draug <carandraug@octave.org>
2 //
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License as
5 // published by the Free Software Foundation; either version 3 of the
6 // License, or (at your option) any later version.
7 //
8 // This program is distributed in the hope that it will be useful, but
9 // WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // 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
15 // <http://www.gnu.org/licenses/>.
16 
17 // This function is implemented in C++ because it basically does
18 // indexing with base 0.  If implemented in a m file, it would
19 // require conversion of the image to a float just to add 1.
20 
21 #include <string>
22 
23 #include <octave/dim-vector.h>
24 #include <octave/oct-inttypes.h>
25 
26 #include <octave/defun-dld.h>
27 #include <octave/defun-int.h>
28 #include <octave/error.h>
29 #include <octave/ovl.h>
30 
31 template<class P>
32 static inline P
intlut_index(const typename P::val_type A,const P lut_vec[])33 intlut_index (const typename P::val_type A, const P lut_vec[])
34 {
35   return lut_vec[A];
36 }
37 
38 template<>
39 inline octave_int16
intlut_index(const typename octave_int16::val_type A,const octave_int16 lut_vec[])40 intlut_index (const typename octave_int16::val_type A,
41               const octave_int16 lut_vec[])
42 {
43   return lut_vec[32768 + A];
44 }
45 
46 template<class T>
47 static T
intlut(const T & A,const T & lut)48 intlut (const T& A, const T& lut)
49 {
50   const auto* A_vec = A.fortran_vec ();
51   const auto* lut_vec = lut.fortran_vec ();
52 
53   T B (A.dims ());
54   auto* B_vec = B.fortran_vec ();
55 
56   const octave_idx_type n = A.numel ();
57 
58   typedef typename T::element_type::val_type P_val_type;
59   for (octave_idx_type i = 0; i < n; i++, B_vec++, A_vec++)
60     *B_vec = intlut_index (static_cast<P_val_type> (*A_vec), lut_vec);
61 
62   return B;
63 }
64 
65 
66 DEFUN_DLD (intlut, args, , "\
67 -*- texinfo -*-\n\
68 @deftypefn {Function File} {} intlut (@var{A}, @var{LUT})\n\
69 Convert integer values with lookup table (LUT).\n\
70 \n\
71 Replace the values from the array @var{A} with the corresponding\n\
72 value from the lookup table @var{LUT}.  This is equivalent as indexing\n\
73 @var{LUT} with @var{A}, with a base equal to @var{A} minimum possible\n\
74 value, i.e., @code{intmin (@var{A})}.\n\
75 \n\
76 For the simplest case of uint8 and uint16 class, it corresponds to:\n\
77 \n\
78 @example\n\
79 @var{LUT}(double (@var{A}) +1)\n\
80 @end example\n\
81 \n\
82 but without the temporary conversion of @var{A} to floating point\n\
83 thus reducing memory usage.\n\
84 \n\
85 @var{A} and @var{LUT} must be of the same class, and uint8, uint16,\n\
86 or int16.  @var{LUT} must have exactly 256 elements for class uint8,\n\
87 and 65536 for classes uint16 and int16.  Output is of same class\n\
88 as @var{LUT}.\n\
89 \n\
90 @seealso{ind2gray, ind2rgb, rgb2ind}\n\
91 @end deftypefn")
92 {
93   octave_value_list rv (1);
94 
95   if (args.length () != 2)
96     print_usage ();
97 
98   const std::string cls = args(0).class_name ();
99   if (cls != args(1).class_name ())
100     error ("intlut: A and LUT must be of same class");
101 
102   const dim_vector lut_dims = args(1).dims ();
103   if (lut_dims.length () != 2 || (lut_dims(0) > 1 && lut_dims(1) > 1))
104     error ("intlut: LUT must be a vector");
105 
106 #define IF_TYPE(TYPE, TYPE_RANGE) \
107   if (args(0).is_ ## TYPE ## _type ()) \
108     { \
109       if (args(1).numel () != TYPE_RANGE) \
110         error ("intlut: LUT must have " #TYPE_RANGE " elements for class %s", \
111                cls.c_str ()); \
112       rv(0) = intlut (args(0).TYPE ## _array_value (), \
113                       args(1).TYPE ## _array_value ()); \
114     }
115 
116   IF_TYPE(uint8, 256)
117   else IF_TYPE(uint16, 65536)
118   else IF_TYPE(int16, 65536)
119   else
120     error ("intlut: A must be of class uint8, uint16, or int16");
121 
122 #undef IF_TYPE
123 
124   return rv;
125 }
126 
127 /*
128 %!assert (intlut (uint8  (1:4), uint8  (  255:-1:0)), uint8  (254:-1:251));
129 %!assert (intlut (uint16 (1:4), uint16 (65535:-1:0)), uint16 (65534:-1:65531));
130 %!assert (intlut (int16  (1:4), int16  (32767:-1:-32768)), int16 (-2:-1:-5));
131 
132 %!assert (intlut (uint8 (255), uint8 (0:255)), uint8 (255));
133 %!assert (intlut (uint16 (65535), uint16 (0:65535)), uint16 (65535));
134 %!assert (intlut (int16 (32767), int16 (-32768:32767)), int16 (32767));
135 
136 %!error intlut ()
137 %!error intlut ("text")
138 %!error <must be of same class> intlut (1:20, uint8 (0:255));
139 %!error <must be of same class> intlut (uint16 (1:20), uint8 (0:255));
140 %!error <must have 256 elements> intlut (uint8 (1:20), uint8 (0:200));
141 %!error <must have 65536 elements> intlut (uint16 (1:20), uint16 (0:500));
142 %!error <LUT must be a vector> intlut (uint8 (56), uint8 (magic (16) -1))
143 */
144