1 // This is mul/vil3d/vil3d_convert.h
2 #ifndef vil3d_convert_h_
3 #define vil3d_convert_h_
4 //:
5 // \file
6 // \brief Some standard conversion functions.
7 // \author Ian Scott.
8 //
9 // This file contains a large number of image to image conversion
10 // functions.
11 // They are in two basic function types (plus a few helper functions.)
12 // Some involve only explicit types and convert
13 // a vil3d_image_view<T> to a vil3d_image_view<T>,
14 // the others take an unknown pixel type, using a
15 // vil3d_image_view_base_sptr. The basic conversion
16 // operations (e.g. casting, rounding) are available in both types.
17 // All of the conversions attempt to find shortcuts, so the output
18 // may be a reconfigured, or shallow copy of the input.
19 //
20 // \par vil3d_convert with explicit pixel types
21 // These are useful when you have two vil3d_image_view objects you want
22 // to convert between. You can use them in templates where the pixel
23 // type is one of the template parameters. These functions
24 // may create a shallow copy of the input if the types match too save
25 // unnecessary work.
26 // - vil3d_convert_cast
27 // - vil3d_convert_round
28 // - vil3d_convert_stretch_range
29 //
30 // \par vil3d_convert with unknown pixel types
31 // These functions are useful when taking an image from vil3d_load
32 // of vil3d_image_resource::get_view(), where you may not know the
33 // pixel type in advance, but want to force the image into a
34 // particular pixel type.
35 // - vil3d_convert_cast
36 // - vil3d_convert_round
37 // - vil3d_convert_stretch_range
38 // - vil3d_convert_to_n_planes
39 // In general these functions expect to take scalar pixel images as
40 // inputs. Even though many of these functions could return a known
41 // pixel-typed image, they all return a vil3d_image_view_base_sptr,
42 // so that the functions can be strung along
43 //
44 // Note that these vil3d_convert_..( vil3d_image_view_base_sptr ) functions
45 // are provided as a convenience for users of vil3d_load and
46 // vil3d_image_resource::get_view(). Their existence should not suggest
47 // that it is sensible to use a vil3d_image_view_base_sptr as storage,
48 // nor that it is a good idea to write a functions that
49 // take or return a vil3d_image_view_base_sptr. If you need a
50 // pixel-type-agnostic image container then use a vil3d_image_resource_sptr
51 //
52 // It may be a good idea to provide vil3d_image_resource_sptr based
53 // vil3d_converts as well.
54 
55 #include <iostream>
56 #include <limits>
57 #include <cassert>
58 #ifdef _MSC_VER
59 #  include <vcl_msvc_warnings.h>
60 #endif
61 #include <vil/vil_convert.h>
62 #include <vil3d/vil3d_transform.h>
63 #include <vil3d/vil3d_math.h>
64 #include <vil3d/vil3d_plane.h>
65 #include <vil3d/vil3d_copy.h>
66 
67 
68 //: Cast one pixel type to another.
69 // There must be a cast operator from inP to outP
70 //
71 // If the two pixel types are the same, the destination may only be a shallow
72 // copy of the source.
73 // \relatesalso vil3d_image_view
74 template <class inP, class outP>
vil3d_convert_cast(const vil3d_image_view<inP> & src,vil3d_image_view<outP> & dest)75 inline void vil3d_convert_cast(const vil3d_image_view<inP >&src,
76                                vil3d_image_view<outP >&dest)
77 {
78   if (vil_pixel_format_of(inP()) == vil_pixel_format_of(outP()))
79     dest = src;
80   else
81     vil3d_transform2(src, dest, vil_convert_cast_pixel<inP, outP>());
82 }
83 
84 
85 //: Convert one pixel type to another with rounding.
86 // This should only be used to convert scalar pixel types to other scalar
87 // pixel types, or RGBs to RGBs. This function only rounds in terms of the
88 // destination type.
89 //
90 // If the two pixel types are the same, the destination may only be a
91 // shallow copy of the source.
92 // \relatesalso vil3d_image_view
93 template <class inP, class outP>
vil3d_convert_round(const vil3d_image_view<inP> & src,vil3d_image_view<outP> & dest)94 inline void vil3d_convert_round(const vil3d_image_view<inP >&src,
95                                 vil3d_image_view<outP >&dest)
96 {
97   if (vil_pixel_format_of(inP()) == vil_pixel_format_of(outP()))
98     dest = src;
99   else
100     vil3d_transform2(src, dest, vil_convert_round_pixel<inP, outP>());
101 }
102 
103 
104 //: Convert src to byte image dest by stretching to range [0,255]
105 // \relatesalso vil3d_image_view
106 template <class T>
vil3d_convert_stretch_range(const vil3d_image_view<T> & src,vil3d_image_view<vxl_byte> & dest)107 inline void vil3d_convert_stretch_range(const vil3d_image_view<T>& src,
108                                         vil3d_image_view<vxl_byte>& dest)
109 {
110   T min_b,max_b;
111   vil3d_math_value_range(src,min_b,max_b);
112   double a = -1.0*double(min_b);
113   double b = 0.0;
114   if (max_b-min_b >0) b = 255.0/(max_b-min_b);
115   dest.set_size(src.ni(), src.nj(), src.nk(), src.nplanes());
116   for (unsigned p = 0; p < src.nplanes(); ++p)
117     for (unsigned k = 0; k < src.nk(); ++k)
118       for (unsigned j = 0; j < src.nj(); ++j)
119         for (unsigned i = 0; i < src.ni(); ++i)
120            dest(i,j,k,p) = static_cast<vxl_byte>( b*( src(i,j,k,p)+ a ) );
121 }
122 
123 
124 // It doesn't seem sensible to write a general stretch
125 // conversion function from any type to any type.
126 // The individual pixel transfer function has to perform
127 // multiplications which have to be done in double
128 // to provide both the range and precision. You may as well
129 // leave the image in double, and convert it again later.
130 
131 //: Convert src to double image dest by stretching to range [lo,hi]
132 template <class inP>
vil3d_convert_stretch_range(const vil3d_image_view<inP> & src,vil3d_image_view<double> & dest,double lo,double hi)133 inline void vil3d_convert_stretch_range(const vil3d_image_view<inP>& src,
134                                         vil3d_image_view<double>& dest,
135                                         double lo, double hi)
136 {
137   inP min_b=0, max_b=0;
138   vil3d_math_value_range(src,min_b,max_b);
139   double b = 0.0;
140   if (max_b-min_b >0)
141     b = (hi-lo)/static_cast<double>(max_b-min_b);
142   double a = -1.0*min_b*b + lo;
143   dest.set_size(src.ni(), src.nj(), src.nk(), src.nplanes());
144   for (unsigned p = 0; p < src.nplanes(); ++p)
145     for (unsigned k = 0; k < src.nk(); ++k)
146       for (unsigned j = 0; j < src.nj(); ++j)
147         for (unsigned i = 0; i < src.ni(); ++i)
148           dest(i,j,k,p) =  b*src(i,j,k,p) + a;
149 }
150 
151 
152 //: Convert src image<inP> to dest image<double> by stretching input range [src_lo, src_hi] to output range [dest_lo, dest_hi].
153 // Inputs < src_lo are mapped to dest_lo, and inputs > src_hi to dest_hi.
154 template <class inP>
vil3d_convert_stretch_range_limited(const vil3d_image_view<inP> & src,vil3d_image_view<double> & dest,const inP src_lo,const inP src_hi,const double dest_lo,const double dest_hi)155 inline void vil3d_convert_stretch_range_limited(const vil3d_image_view<inP>& src,
156                                                 vil3d_image_view<double>& dest,
157                                                 const inP src_lo,
158                                                 const inP src_hi,
159                                                 const double dest_lo,
160                                                 const double dest_hi)
161 {
162   double ddest = dest_hi - dest_lo;
163   double dsrc = static_cast<double>(src_hi - src_lo);
164   double dds = ddest / dsrc;
165 
166   dest.set_size(src.ni(), src.nj(), src.nk(), src.nplanes());
167   for (unsigned p = 0; p < src.nplanes(); ++p)
168     for (unsigned k = 0; k < src.nk(); ++k)
169       for (unsigned j = 0; j < src.nj(); ++j)
170         for (unsigned i = 0; i < src.ni(); ++i)
171         {
172           inP s = src(i,j,k,p);
173           dest(i,j,k,p) = s<=src_lo ? dest_lo :
174                           s>=src_hi ? dest_hi :
175                                       dest_lo + dds*static_cast<double>(s-src_lo);
176         }
177 }
178 
179 
180 //: Cast the unknown pixel type to the known one.
181 //
182 // This function is designed to be used with vil3d_load or
183 // vil3d_image_resource::get_view()
184 // where you do not know the pixel type in advance.
185 // If you need a multi-component view, then call this to get the corresponding
186 // multi-planar view, and do a second (cheap) conversion.
187 // The input image's storage arrangement may not be preserved.
188 template <class outP>
vil3d_convert_cast(outP,const vil3d_image_view_base_sptr & src)189 inline vil3d_image_view_base_sptr vil3d_convert_cast(outP /*dummy*/,
190                                                      const vil3d_image_view_base_sptr& src)
191 {
192   if (!src) return vil3d_image_view_base_sptr();
193 
194   vil3d_image_view_base_sptr dest = new vil3d_image_view<outP>;
195   vil3d_image_view<outP> & dest_ref = static_cast<vil3d_image_view<outP> &>(*dest);
196 
197   switch ( vil_pixel_format_component_format(src->pixel_format()) )
198   {
199 #define macro(F , T) \
200    case F: \
201     vil3d_convert_cast( vil3d_image_view<T >( src ), dest_ref );\
202     break;
203 
204     macro( VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32 )
205     macro( VIL_PIXEL_FORMAT_INT_32, vxl_int_32 )
206     macro( VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16 )
207     macro( VIL_PIXEL_FORMAT_INT_16, vxl_int_16 )
208     macro( VIL_PIXEL_FORMAT_BYTE, vxl_byte )
209     macro( VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte )
210     macro( VIL_PIXEL_FORMAT_FLOAT, float )
211     macro( VIL_PIXEL_FORMAT_DOUBLE, double )
212     macro( VIL_PIXEL_FORMAT_BOOL, bool )
213 #undef macro
214     default: dest=nullptr;
215   }
216   return dest;
217 }
218 
219 
220 //: Convert an image of any pixel type to another with rounding.
221 // This should only be used to convert to scalar
222 // pixel types. This function only rounds in terms of the
223 // destination type.
224 // This function is designed to be used with vil3d_load or
225 // vil3d_image_resource::get_view()
226 // where you do not know the pixel type in advance.
227 //
228 // If the input image already has outP as its pixel type, the destination
229 // may only be a shallow copy of the source.
230 // outP should be a scalar pixel type.
231 // The input image's storage arrangement may not be preserved.
232 template <class outP>
vil3d_convert_round(outP,const vil3d_image_view_base_sptr & src)233 inline vil3d_image_view_base_sptr vil3d_convert_round(
234   outP /*dummy*/, const vil3d_image_view_base_sptr &src)
235 {
236   assert(vil_pixel_format_num_components(vil_pixel_format_of(outP()))==1);
237 
238   if (!src) return vil3d_image_view_base_sptr();
239 
240   if (vil_pixel_format_component_format(src->pixel_format()) ==
241       vil_pixel_format_of(outP()))
242     return src;
243 
244   vil3d_image_view_base_sptr dest = new vil3d_image_view<outP >;
245   vil3d_image_view<outP > &dest_ref = static_cast<vil3d_image_view<outP >&>(*dest);
246 
247   switch (vil_pixel_format_component_format(src->pixel_format()))
248   {
249 #define macro( F , T ) \
250    case F: { \
251     vil3d_image_view<T > src1 = src; \
252     vil3d_transform2(src1, dest_ref, vil_convert_round_pixel<T , outP>()); \
253     break; }
254 
255     macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
256     macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
257     macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
258     macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
259     macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
260     macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
261     macro(VIL_PIXEL_FORMAT_FLOAT , float )
262     macro(VIL_PIXEL_FORMAT_DOUBLE , double )
263 #undef macro
264    default: dest=nullptr;
265   }
266   return dest;
267 }
268 
269 
270 //: Create a greyscale image of specified pixel type from any image src.
271 // This function is designed to be used with vil3d_load or
272 // vil3d_image_resource::get_view()
273 // where you do not know the pixel type in advance. e.g.
274 // \verbatim
275 // vil3d_image_view<float> input = vil3d_convert_cast(
276 //   convert_to_grey_using_average(vil3d_load(filename)), float());
277 // \endverbatim
278 // The output may be a reconfigured view of the input.
279 // The input image's pixel type and storage arrangement may not be preserved.
vil3d_convert_to_grey_using_average(const vil3d_image_view_base_sptr & src)280 inline vil3d_image_view_base_sptr vil3d_convert_to_grey_using_average(
281   const vil3d_image_view_base_sptr &src)
282 {
283   if (!src) return vil3d_image_view_base_sptr();
284 
285   // convert via vil3d_image_view<double>
286   switch (vil_pixel_format_component_format(src->pixel_format()))
287   {
288 #define macro( F , T ) \
289    case F: { \
290     /* try to do it quickly */ \
291     if (src->nplanes() == 1 && \
292         vil_pixel_format_component_format(src->pixel_format())==1) \
293       return src; \
294     /* create output view */ \
295     vil3d_image_view<T > dest; \
296     vil3d_image_view<T > src1 = *src; \
297     vil3d_math_mean_over_planes(src1, dest, double()); \
298     return vil3d_image_view_base_sptr(new vil3d_image_view<T >(dest)); }
299 
300     macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
301     macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
302     macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
303     macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
304     macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
305     macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
306     macro(VIL_PIXEL_FORMAT_FLOAT , float )
307     macro(VIL_PIXEL_FORMAT_DOUBLE , double )
308 #undef macro
309    default:
310     return vil3d_image_view_base_sptr();
311   }
312 }
313 
314 
315 //: Create an n plane image from any image src.
316 // This function is designed to be used with vil3d_load or
317 // vil3d_image_resource::get_view()
318 // where you do not know the pixel type or number of planes in advance.
319 // If the input images have too many planes, the higher planes will be
320 // truncated. If the input image has too few planes, the new planes will be
321 // copies of the first plane.
322 //
323 // The output may be a shallow copy of the input.
324 // The input image's storage arrangement may not be preserved.
325 // \endverbatim
vil3d_convert_to_n_planes(unsigned n_planes,const vil3d_image_view_base_sptr & src)326 inline vil3d_image_view_base_sptr vil3d_convert_to_n_planes(
327   unsigned n_planes, const vil3d_image_view_base_sptr &src)
328 {
329   if (!src || n_planes == 0)
330     return vil3d_image_view_base_sptr();
331 
332 
333   switch (vil_pixel_format_component_format(src->pixel_format()))
334   {
335  #define macro( F, T ) \
336    case F: { \
337     vil3d_image_view<T > src_ref = src; \
338     if (!src_ref) return vil3d_image_view_base_sptr(); \
339     /* try to do it quickly 1 */ \
340     if (src_ref.nplanes() >= n_planes)  /* reduce number of planes */ \
341       return vil3d_image_view_base_sptr( new vil3d_image_view<T >( \
342         vil3d_planes(vil3d_image_view<T > (src),0,1,n_planes) )); \
343     else { /* expand number of planes with copying */ \
344       vil3d_image_view_base_sptr dest = new vil3d_image_view<T >( \
345         src_ref.ni(), src_ref.nj(), src_ref.nk(), n_planes); \
346       vil3d_image_view<T > & dest_ref = \
347         static_cast<vil3d_image_view<T > &>(*dest); \
348       vil3d_image_view<T > dest_slices = \
349         vil3d_planes(dest_ref, 0, 1, src_ref.nplanes()); \
350       vil3d_copy_reformat(src_ref, dest_slices); \
351       vil3d_image_view<T > src_slice(vil3d_plane(src_ref, 0)); \
352       for (unsigned i=src_ref.nplanes(); i<n_planes; ++i) { \
353         dest_slices = vil3d_plane(dest_ref, i); \
354         vil3d_copy_reformat(src_slice,  dest_slices); } \
355       return dest;  } } \
356 
357     macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
358     macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
359     macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
360     macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
361     macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
362     macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
363     macro(VIL_PIXEL_FORMAT_FLOAT , float )
364     macro(VIL_PIXEL_FORMAT_DOUBLE , double )
365 #undef macro
366 
367    default:
368     return vil3d_image_view_base_sptr();
369   }
370 }
371 
372 
373 //: Create an image of the desired type by stretching the range to fit.
374 // This function is designed to be used with vil3d_load or
375 // vil3d_image_resource::get_view()
376 // where you do not know the pixel type in advance.
377 // In the case of floating point output pixels the range is set to [0,1]
378 // The input image's storage arrangement may not be preserved.
379 //
380 // This function works on scalar pixel types only. You can convert the image
381 // to rgb using a cheap assignment afterwards.
382 template <class outP>
vil3d_convert_stretch_range(outP,const vil3d_image_view_base_sptr & src)383 inline vil3d_image_view_base_sptr vil3d_convert_stretch_range(
384   outP /*dummy*/, const vil3d_image_view_base_sptr &src)
385 {
386   // Check that input isn't trying to produce multi-component pixels
387   assert (vil_pixel_format_num_components(vil_pixel_format_of(outP())) == 1);
388 
389   if (!src)
390     return vil3d_image_view_base_sptr();
391 
392   double hi,lo;
393 
394   if (std::numeric_limits<outP>::is_integer)
395   {
396     hi = std::numeric_limits<outP>::max()+0.999;
397     lo = std::numeric_limits<outP>::min();
398   }
399   else
400   {
401     hi=1.0;
402     lo=0.0;
403   }
404 
405   vil3d_image_view_base_sptr dest = new vil3d_image_view<outP>;
406   vil3d_image_view<outP> & dest_ref = static_cast<vil3d_image_view<outP> &>(*dest);
407   vil3d_image_view<double> inter;
408   switch (vil_pixel_format_component_format(src->pixel_format()))
409   {
410 #define macro( F , T ) \
411    case F: { \
412     vil3d_image_view<T> src_ref = src; \
413     if (!src_ref) return vil3d_image_view_base_sptr(); \
414     vil3d_convert_stretch_range(src_ref, inter, lo, hi); \
415     vil3d_convert_cast(inter, dest_ref); \
416     break; }
417 
418     macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
419     macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
420     macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
421     macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
422     macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
423     macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
424     macro(VIL_PIXEL_FORMAT_FLOAT , float )
425     macro(VIL_PIXEL_FORMAT_DOUBLE , double )
426 #undef macro
427    default:
428     dest_ref.clear();
429   }
430   return dest;
431 }
432 
433 
434 #endif // vil3d_convert_h_
435