1 // This is core/vil/vil_convert.h
2 #ifndef vil_convert_h_
3 #define vil_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 vil_image_view<T> to a vil_image_view<T>,
14 // the others take an unknown pixel type, using a
15 // vil_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 vil_convert with explicit pixel types
21 // These are useful when you have two vil_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 to save
25 // unnecessary work.
26 // - vil_convert_cast
27 // - vil_convert_round
28 // - vil_convert_rgb_to_grey
29 // - vil_convert_planes_to_grey
30 // - vil_convert_stretch_range
31 //
32 // \par vil_convert with unknown pixel types
33 // These functions are useful when taking an image from vil_load
34 // or vil_image_resource::get_view(), where you may not know the
35 // pixel type in advance, but want to force the image into a
36 // particular pixel type.
37 // - vil_convert_cast
38 // - vil_convert_round
39 // - vil_convert_rgb_to_grey
40 // - vil_convert_planes_to_grey
41 // - vil_convert_stretch_range
42 // - vil_convert_to_component_order
43 // - vil_convert_to_n_planes
44 //
45 // In general these functions expect to take scalar pixel images as
46 // inputs. Even though many of these functions could return a known
47 // pixel-typed image, they all return a vil_image_view_base_sptr,
48 // so that the functions can be strung along.
49 //
50 // Note that these vil_convert_..( vil_image_view_base_sptr ) functions
51 // are provided as a convenience for users of vil_load and
52 // vil_image_resource::get_view(). Their existence should not suggest
53 // that it is sensible to use a vil_image_view_base_sptr as storage,
54 // nor that it is a good idea to write functions that
55 // take or return a vil_image_view_base_sptr. If you need a
56 // pixel-type-agnostic image container then use a vil_image_resource_sptr
57 //
58 // It may be a good idea to provide vil_image_resource_sptr based
59 // vil_converts as well.
60 //
61 // The ITK project (in Code/IO/itkConvertPixelBuffer.hxx) has
62 // functionality similar to the RGB to grayscale conversion here.  A
63 // change was made in ITK so the computation is
64 // (2125.0*r+7154.0*g+0721.0*b)/1000.0 instead of
65 // 0.2125*r+0.7154*g+0.0721*b.  The reason is that the latter
66 // expression can produce different results between Intel and
67 // non-Intel platforms (even in cases where r==g && g==b), probably
68 // due to different floating point representations.  This may not be
69 // too important, but it is worth noting here.  In vil_convert.h we
70 // cannot make the same change without adding computation because
71 // vil_convert_rgb_to_grey() lets you pass in the weights.  We'd have
72 // to multiply by 10000 to maintain the current API.
73 //
74 // \verbatim
75 //  Modifications
76 //   23 Oct.2003 - Peter Vanroose - Added support for 64-bit int pixels
77 //   30 Mar.2007 - Peter Vanroose - Commented out deprecated versions of vil_convert_cast & vil_convert_to_grey_using_average
78 // \endverbatim
79 
80 #include <limits>
81 #include <cmath>
82 #include <cassert>
83 #include <vcl_compiler_detection.h>
84 #ifdef _MSC_VER
85 #  include <vcl_msvc_warnings.h>
86 #endif
87 #include "vil_transform.h"
88 #include "vil_math.h"
89 #include "vil_plane.h"
90 #include "vil_copy.h"
91 #include "vil_exception.h"
92 
93 
94 //: Performs conversion between different pixel types.
95 template <class In, class Out>
96 class vil_convert_cast_pixel
97 {
98  public:
99   void operator () (In v, Out &d) const;
100 };
101 
102 #ifndef DOXYGEN_SHOULD_SKIP_THIS
103 // deal with conversions from floating point types to/from some compounds
104 #define macro( in , out )\
105 template <> \
106 inline void vil_convert_cast_pixel<in, vil_rgb<out > >::operator () (in v, vil_rgb<out >& d) const \
107 { d.r = d.g = d.b = (out)v; } \
108 template <> \
109 inline void vil_convert_cast_pixel<vil_rgb<out >, in >::operator () (vil_rgb<out > v, in& d) const \
110 { d = (in)(0.2125*v.r+0.7154*v.g+0.0721*v.b); } \
111 template <> \
112 inline void vil_convert_cast_pixel<in, vil_rgba<out > >::operator () (in v, vil_rgba<out >& d) const \
113 { d.r = d.g = d.b = (out)v; d.a=1; } \
114 template <> \
115 inline void vil_convert_cast_pixel<vil_rgba<out >, in >::operator () (vil_rgba<out > v, in& d) const \
116 { d = (in)(0.2125*v.r+0.7154*v.g+0.0721*v.b); }
macro(vxl_byte,vxl_byte)117 macro( vxl_byte , vxl_byte )
118 macro( vxl_int_16 , vxl_byte )
119 macro( vxl_uint_16 , vxl_byte )
120 macro( vxl_int_32 , vxl_byte )
121 macro( vxl_uint_32 , vxl_byte )
122 macro( float , vxl_byte )
123 macro( double , vxl_byte )
124 macro( vxl_byte , vxl_sbyte )
125 macro( vxl_int_16 , vxl_sbyte )
126 macro( vxl_uint_16 , vxl_sbyte )
127 macro( vxl_int_32 , vxl_sbyte )
128 macro( vxl_uint_32 , vxl_sbyte )
129 macro( float , vxl_sbyte )
130 macro( double , vxl_sbyte )
131 macro( vxl_int_16 , vxl_int_16 )
132 macro( float , vxl_int_16 )
133 macro( double , vxl_int_16 )
134 macro( vxl_uint_16 , vxl_uint_16 )
135 macro( float , vxl_uint_16 )
136 macro( double , vxl_uint_16 )
137 macro( vxl_int_32 , vxl_int_32 )
138 macro( float , vxl_int_32 )
139 macro( double , vxl_int_32 )
140 macro( vxl_uint_32 , vxl_uint_32 )
141 macro( float , vxl_uint_32 )
142 macro( double , vxl_uint_32 )
143 macro( double , float )
144 #if VXL_HAS_INT_64
145 macro( vxl_int_64 , vxl_byte )
146 macro( vxl_uint_64 , vxl_byte )
147 macro( vxl_int_64 , vxl_sbyte )
148 macro( vxl_uint_64 , vxl_sbyte )
149 macro( vxl_int_64 , vxl_int_64 )
150 macro( float , vxl_int_64 )
151 macro( double , vxl_int_64 )
152 macro( vxl_uint_64 , vxl_uint_64 )
153 macro( float , vxl_uint_64 )
154 macro( double , vxl_uint_64 )
155 #endif
156 #undef macro
157 #define macro( inout )\
158 template <> \
159 inline void vil_convert_cast_pixel<inout, inout >::operator () ( \
160   inout v, inout& d) const { d=v; }
161 macro( vxl_byte )
162 macro( vxl_sbyte )
163 macro( vxl_uint_16 )
164 macro( vxl_int_16 )
165 macro( vxl_uint_32 )
166 macro( vxl_int_32 )
167 #if VXL_HAS_INT_64
168 macro( vxl_uint_64 )
169 macro( vxl_int_64 )
170 #endif
171 macro( float )
172 macro( double )
173 #undef macro
174 template <>
175 inline void vil_convert_cast_pixel<vil_rgb<vxl_byte>, vil_rgb<vxl_byte> >::operator () (
176   vil_rgb<vxl_byte> v, vil_rgb<vxl_byte>& d) const { d.r=v.r, d.g=v.g, d.b=v.b; }
177 template <>
operator()178 inline void vil_convert_cast_pixel<vil_rgba<vxl_byte>, vil_rgba<vxl_byte> >::operator () (
179   vil_rgba<vxl_byte> v, vil_rgba<vxl_byte>& d) const { d.r=v.r, d.g=v.g, d.b=v.b, d.a=v.a; }
180 #define macro( in )\
181 template <> \
182 inline void vil_convert_cast_pixel<in,std::complex<double> >::operator () (in v, std::complex<double>& d) const \
183 { d = std::complex<double>(double(v),0.0); } \
184 template <> \
185 inline void vil_convert_cast_pixel<in,std::complex<float> >::operator () (in v, std::complex<float>& d) const \
186 { d = std::complex<float>(float(v),0.0f); }
187 macro( vxl_byte )
macro(vxl_sbyte)188 macro( vxl_sbyte )
189 macro( vxl_int_16 )
190 macro( vxl_uint_16 )
191 macro( vxl_int_32 )
192 macro( vxl_uint_32 )
193 #if VXL_HAS_INT_64
194 macro( vxl_int_64 )
195 macro( vxl_uint_64 )
196 #endif
197 #undef macro
198 #define macro( out )\
199 template <> \
200 inline void vil_convert_cast_pixel<std::complex<double>,out >::operator () (std::complex<double> d, out& v) const \
201 { v = (out)(d.real()); } \
202 template <> \
203 inline void vil_convert_cast_pixel<std::complex<float>,out >::operator () (std::complex<float> d, out& v) const \
204 { v = (out)(d.real()); }
205 macro( vxl_byte )
206 macro( vxl_sbyte )
207 macro( vxl_int_16 )
208 macro( vxl_uint_16 )
209 macro( vxl_int_32 )
210 macro( vxl_uint_32 )
211 #if VXL_HAS_INT_64
212 macro( vxl_int_64 )
213 macro( vxl_uint_64 )
214 #endif
215 #undef macro
216 #endif // DOXYGEN_SHOULD_SKIP_THIS
217 // declare general case in case anyone needs something weird.
218 
219 #if defined(_MSC_VER)
220 // Visual C++ intentionally warns when a non-bool is assigned or
221 // cast to a bool. Since the following cast is valid, we suppress the
222 // warning.
223 # pragma warning( push )
224 # pragma warning( disable : 4800 )
225 #endif
226 
227 template <class In, class Out>
228 inline void vil_convert_cast_pixel<In, Out>::operator () (In v, Out &d) const
229 {
230   d = static_cast<Out>(v);
231 }
232 
233 #if defined(_MSC_VER)
234 # pragma warning( pop )
235 #endif
236 
237 
238 //: Cast one pixel type to another.
239 // There must be a cast operator from inP to outP
240 //
241 // If the two pixel types are the same, the destination may only be a shallow
242 // copy of the source.
243 // \relatesalso vil_image_view
244 template <class inP, class outP>
vil_convert_cast(const vil_image_view<inP> & src,vil_image_view<outP> & dest)245 inline void vil_convert_cast(const vil_image_view<inP >&src,
246                              vil_image_view<outP >&dest)
247 {
248   if (vil_pixel_format_of(inP()) == vil_pixel_format_of(outP()))
249     dest = src;
250   else
251     vil_transform2(src, dest, vil_convert_cast_pixel<inP, outP>());
252 }
253 
254 #if 0 // TODO ?
255 
256 //: Cast the unknown pixel type to the known one, if possible.
257 //
258 // Will call the other vil_convert_case to do the actual
259 // conversion. For template instantiation reasons, this will only
260 // convert to a scalar type, not an RGB or RGBA type.
261 // However, the destination image will have a plane step of 1 if the source
262 // image is RGB or RGBA, i.e., the pixel layout will still be RGBRGB...
263 //
264 // \relatesalso vil_image_view
265 //
266 template <class outP>
267 inline void vil_convert_cast(const vil_image_view_base_sptr&src, vil_image_view<outP >&dest)
268 {
269 #define docase(T) \
270    case T: \
271     vil_convert_cast( vil_image_view< typename vil_pixel_format_type_of<T >::component_type >(src), dest );\
272     break
273 
274   switch ( src->pixel_format() )
275   {
276     docase( VIL_PIXEL_FORMAT_UINT_32 );
277     docase( VIL_PIXEL_FORMAT_INT_32 );
278     docase( VIL_PIXEL_FORMAT_UINT_16 );
279     docase( VIL_PIXEL_FORMAT_INT_16 );
280     docase( VIL_PIXEL_FORMAT_BYTE );
281     docase( VIL_PIXEL_FORMAT_SBYTE );
282     docase( VIL_PIXEL_FORMAT_FLOAT );
283     docase( VIL_PIXEL_FORMAT_DOUBLE );
284     docase( VIL_PIXEL_FORMAT_BOOL );
285 
286     docase( VIL_PIXEL_FORMAT_RGB_UINT_32 );
287     docase( VIL_PIXEL_FORMAT_RGB_INT_32 );
288     docase( VIL_PIXEL_FORMAT_RGB_UINT_16 );
289     docase( VIL_PIXEL_FORMAT_RGB_INT_16 );
290     docase( VIL_PIXEL_FORMAT_RGB_BYTE );
291     docase( VIL_PIXEL_FORMAT_RGB_SBYTE );
292     docase( VIL_PIXEL_FORMAT_RGB_FLOAT );
293     docase( VIL_PIXEL_FORMAT_RGB_DOUBLE );
294 
295     docase( VIL_PIXEL_FORMAT_RGBA_UINT_32 );
296     docase( VIL_PIXEL_FORMAT_RGBA_INT_32 );
297     docase( VIL_PIXEL_FORMAT_RGBA_UINT_16 );
298     docase( VIL_PIXEL_FORMAT_RGBA_INT_16 );
299     docase( VIL_PIXEL_FORMAT_RGBA_BYTE );
300     docase( VIL_PIXEL_FORMAT_RGBA_SBYTE );
301     docase( VIL_PIXEL_FORMAT_RGBA_FLOAT );
302     docase( VIL_PIXEL_FORMAT_RGBA_DOUBLE );
303 
304     docase( VIL_PIXEL_FORMAT_COMPLEX_FLOAT );
305     docase( VIL_PIXEL_FORMAT_COMPLEX_DOUBLE );
306 
307    default:
308     ;
309   }
310 #undef docase
311 }
312 
313 #endif // 0
314 
315 //: Performs rounding between different pixel types.
316 template <class In, class Out>
317 class vil_convert_round_pixel
318 {
319  public:
320   void operator () (In v, Out &d) const;
321 };
322 
323 #ifndef DOXYGEN_SHOULD_SKIP_THIS
324 // deal with conversions from floating point types to some compounds
325 #define macro( in , out )\
326 template <> \
327 inline void vil_convert_round_pixel<in, out >::operator () ( \
328   in v, out& d) const { \
329   d.r = (out::value_type)(v.r+0.5); \
330   d.g = (out::value_type)(v.g+0.5); \
331   d.b = (out::value_type)(v.b+0.5); }
332 
macro(vil_rgb<float>,vil_rgb<vxl_byte>)333 macro( vil_rgb<float> , vil_rgb<vxl_byte> )
334 macro( vil_rgb<double> , vil_rgb<vxl_byte> )
335 macro( vil_rgb<float> , vil_rgb<vxl_sbyte> )
336 macro( vil_rgb<double> , vil_rgb<vxl_sbyte> )
337 macro( vil_rgb<float> , vil_rgb<vxl_int_16> )
338 macro( vil_rgb<double> , vil_rgb<vxl_int_16> )
339 macro( vil_rgb<float> , vil_rgb<vxl_uint_16> )
340 macro( vil_rgb<double> , vil_rgb<vxl_uint_16> )
341 macro( vil_rgb<float> , vil_rgb<vxl_int_32> )
342 macro( vil_rgb<double> , vil_rgb<vxl_int_32> )
343 macro( vil_rgb<float> , vil_rgb<vxl_uint_32> )
344 macro( vil_rgb<double> , vil_rgb<vxl_uint_32> )
345 #if VXL_HAS_INT_64
346 macro( vil_rgb<float> , vil_rgb<vxl_int_64> )
347 macro( vil_rgb<double> , vil_rgb<vxl_int_64> )
348 macro( vil_rgb<float> , vil_rgb<vxl_uint_64> )
349 macro( vil_rgb<double> , vil_rgb<vxl_uint_64> )
350 #endif
351 #undef macro
352 #define macro( in , out )\
353 template <> \
354 inline void vil_convert_round_pixel<in, out >::operator () (in v, out& d) \
355   const { \
356   d.r = (out::value_type)(v.r); \
357   d.g = (out::value_type)(v.g); \
358   d.b = (out::value_type)(v.b); }
359 macro( vil_rgb<float> , vil_rgb<float> )
360 macro( vil_rgb<double> , vil_rgb<double> )
361 #undef macro
362 #define macro( in , out )\
363 template <> \
364 inline void vil_convert_round_pixel<in, out >::operator () (in v, out& d) \
365   const { \
366   d.r = (out::value_type)(v.r+0.5); \
367   d.g = (out::value_type)(v.g+0.5); \
368   d.b = (out::value_type)(v.b+0.5); \
369   d.a = (out::value_type)(v.a+0.5); }
370 macro( vil_rgba<float> , vil_rgba<vxl_byte> )
371 macro( vil_rgba<double> , vil_rgba<vxl_byte> )
372 macro( vil_rgba<float> , vil_rgba<vxl_sbyte> )
373 macro( vil_rgba<double> , vil_rgba<vxl_sbyte> )
374 macro( vil_rgba<float> , vil_rgba<vxl_int_16> )
375 macro( vil_rgba<double> , vil_rgba<vxl_int_16> )
376 macro( vil_rgba<float> , vil_rgba<vxl_uint_16> )
377 macro( vil_rgba<double> , vil_rgba<vxl_uint_16> )
378 macro( vil_rgba<float> , vil_rgba<vxl_int_32> )
379 macro( vil_rgba<double> , vil_rgba<vxl_int_32> )
380 macro( vil_rgba<float> , vil_rgba<vxl_uint_32> )
381 macro( vil_rgba<double> , vil_rgba<vxl_uint_32> )
382 #if VXL_HAS_INT_64
383 macro( vil_rgba<float> , vil_rgba<vxl_int_64> )
384 macro( vil_rgba<double> , vil_rgba<vxl_int_64> )
385 macro( vil_rgba<float> , vil_rgba<vxl_uint_64> )
386 macro( vil_rgba<double> , vil_rgba<vxl_uint_64> )
387 #endif
388 #undef macro
389 #define macro( in , out )\
390 template <> \
391 inline void vil_convert_round_pixel<in, out >::operator () (in v, out& d) \
392   const { \
393   d.r = (out::value_type)(v.r); \
394   d.g = (out::value_type)(v.g); \
395   d.b = (out::value_type)(v.b); \
396   d.a = (out::value_type)(v.a); }
397 macro( vil_rgba<float> , vil_rgba<float> )
398 macro( vil_rgba<double> , vil_rgba<double> )
399 #undef macro
400 
401 #define macro( in , out )\
402 template <> \
403 inline void vil_convert_round_pixel<in, out >::operator () (in v, out& d) \
404 const { d = (out)(v > 0.0 ? v + 0.5 : v - 0.5); }
405 macro( float , vxl_byte )
406 macro( double , vxl_byte )
407 macro( float , vxl_sbyte )
408 macro( double , vxl_sbyte )
409 macro( float , vxl_int_16 )
410 macro( double , vxl_int_16 )
411 macro( float , vxl_uint_16 )
412 macro( double , vxl_uint_16 )
413 macro( float , vxl_int_32 )
414 macro( double , vxl_int_32 )
415 macro( float , vxl_uint_32 )
416 macro( double , vxl_uint_32 )
417 #if VXL_HAS_INT_64
418 macro( float , vxl_int_64 )
419 macro( double , vxl_int_64 )
420 macro( float , vxl_uint_64 )
421 macro( double , vxl_uint_64 )
422 #endif
423 #undef macro
424 #endif // DOXYGEN_SHOULD_SKIP_THIS
425 
426 // declare general case for scalars
427 template <class In, class Out>
428 inline void vil_convert_round_pixel<In, Out>::operator () (In v, Out &d) const
429 {
430   d = (Out)(v);
431 }
432 
433 
434 //: Convert one pixel type to another with rounding.
435 // This should only be used to convert scalar pixel types to other scalar
436 // pixel types, or RGBs to RGBs. This function only rounds in terms of the
437 // destination type.
438 //
439 // If the two pixel types are the same, the destination may only be a
440 // shallow copy of the source.
441 // \relatesalso vil_image_view
442 template <class inP, class outP>
vil_convert_round(const vil_image_view<inP> & src,vil_image_view<outP> & dest)443 inline void vil_convert_round(const vil_image_view<inP >&src,
444                               vil_image_view<outP >&dest)
445 {
446   if (vil_pixel_format_of(inP()) == vil_pixel_format_of(outP()))
447     dest = src;
448   else
449     vil_transform2(src, dest, vil_convert_round_pixel<inP, outP>());
450 }
451 
452 
453 //: Convert various rgb types to greyscale, using given weights
454 template <class inP, class outP>
455 class vil_convert_rgb_to_grey_pixel
456 {
457   double rw_, gw_, bw_;
458  public:
vil_convert_rgb_to_grey_pixel(double rw,double gw,double bw)459   vil_convert_rgb_to_grey_pixel(double rw, double gw, double bw):
460     rw_(rw), gw_(gw), bw_(bw) {}
461 
operator()462   void operator() (vil_rgb<inP> v, outP& d) const {
463     vil_convert_round_pixel<double,outP>()(rw_*v.r+gw_*v.g+bw_*v.b, d); }
operator()464   void operator() (vil_rgba<inP> v, outP& d) const {
465     vil_convert_round_pixel<double,outP>()(rw_*v.r+gw_*v.g+bw_*v.b, d); }
466 };
467 
468 //: Convert images with alpha plane (variable or binary) to images without alpha plane
469 template <class inP, class outP>
vil_convert_merge_alpha(const vil_image_view<inP> & src,vil_image_view<outP> & dest,const unsigned nplanes)470 inline void vil_convert_merge_alpha(const vil_image_view<inP>& src,
471                                         vil_image_view<outP>& dest,
472                                         const unsigned nplanes)
473 {
474   assert(vil_pixel_format_num_components(src.pixel_format()) == 1);
475   assert(vil_pixel_format_num_components(dest.pixel_format()) == 1);
476 
477   assert((nplanes == 2) || (nplanes == 4));
478 
479   dest.set_size(src.ni(), src.nj(), nplanes-1);
480 
481   for (unsigned j = 0; j < src.nj(); ++j)
482     for (unsigned i = 0; i < src.ni(); ++i)
483       for (unsigned k = 0; k < nplanes-1; ++k)
484       { vil_convert_round_pixel<double,outP>()(src(i,j,nplanes-1)/255.0*src(i,j,k), dest(i,j,k)); }
485 }
486 
487 //: Convert single plane rgb (or rgba) images to greyscale.
488 // Component types can be different. Rounding will take place if appropriate.
489 //
490 // Default weights convert from linear RGB to CIE luminance assuming a
491 // modern monitor.  See Charles Poynton's Colour FAQ
492 // http://www.poynton.com/ColorFAQ.html
493 template <class rgbP, class outP>
494 inline void vil_convert_rgb_to_grey(const vil_image_view<rgbP >&src,
495                                     vil_image_view<outP >&dest,
496                                     double rw=0.2125, double gw=0.7154, double bw=0.0721)
497 {
498   vil_convert_rgb_to_grey_pixel<typename rgbP::value_type, outP>
499     func(rw, gw, bw);
500   assert(src.nplanes() == 1);
501   vil_transform2(src, dest, func);
502 }
503 
504 
505 //: Convert first three planes of src image to grey, assuming rgb.
506 // Pixel types can be different. Rounding will take place if appropriate.
507 //
508 // Default weights convert from linear RGB to CIE luminance assuming a
509 // modern monitor.  See Charles Poynton's Colour FAQ
510 // http://www.poynton.com/ColorFAQ.html
511 template <class inP, class outP>
512 inline void vil_convert_planes_to_grey(const vil_image_view<inP>&src,
513                                        vil_image_view<outP>&dest,
514                                        double rw=0.2125, double gw=0.7154, double bw=0.0721)
515 {
516   assert(src.nplanes() >= 3);
517   assert(vil_pixel_format_num_components(src.pixel_format()) == 1);
518   assert(vil_pixel_format_num_components(dest.pixel_format()) == 1);
519   dest.set_size(src.ni(), src.nj(), 1);
520   for (unsigned j = 0; j < src.nj(); ++j)
521     for (unsigned i = 0; i < src.ni(); ++i)
522       vil_convert_round_pixel<double,outP>()(
523         src(i,j,0)*rw + src(i,j,1)*gw + src(i,j,2)*bw, dest(i,j));
524 }
525 
526 
527 //: Convert src to byte image dest by stretching to range [0,255]
528 // \relatesalso vil_image_view
529 template <class T>
vil_convert_stretch_range(const vil_image_view<T> & src,vil_image_view<vxl_byte> & dest)530 inline void vil_convert_stretch_range(const vil_image_view<T>& src,
531                                       vil_image_view<vxl_byte>& dest)
532 {
533   T min_b,max_b;
534   vil_math_value_range(src,min_b,max_b);
535   double a = -1.0*double(min_b);
536   double b = 0.0;
537   if (max_b-min_b >0) b = 255.0/(max_b-min_b);
538   dest.set_size(src.ni(), src.nj(), src.nplanes());
539   for (unsigned p = 0; p < src.nplanes(); ++p)
540     for (unsigned j = 0; j < src.nj(); ++j)
541       for (unsigned i = 0; i < src.ni(); ++i)
542         dest(i,j,p) = static_cast<vxl_byte>( b*( src(i,j,p)+ a ) );
543 }
544 
545 
546 // It doesn't seem sensible to write a general stretch
547 // conversion function from any type to any type.
548 // The individual pixel transfer function has to perform
549 // multiplications which have to be done in double
550 // to provide both the range and precision. You may as well
551 // leave the image in double, and convert it again later.
552 
553 //: Convert src to double image dest by stretching to range [dest_lo,dest_hi]
554 template <class inP>
vil_convert_stretch_range(const vil_image_view<inP> & src,vil_image_view<double> & dest,double dest_lo,double dest_hi)555 inline void vil_convert_stretch_range(const vil_image_view<inP>& src,
556                                       vil_image_view<double>& dest,
557                                       double dest_lo, double dest_hi)
558 {
559   inP min_b=0, max_b=0;
560   vil_math_value_range(src,min_b,max_b);
561   double b = 0.0;
562   if (max_b-min_b >0)
563     b = static_cast<double>(dest_hi-dest_lo)/static_cast<double>(max_b-min_b);
564   double a = -1.0*min_b*b + dest_lo;
565   dest.set_size(src.ni(), src.nj(), src.nplanes());
566   for (unsigned p = 0; p < src.nplanes(); ++p)
567     for (unsigned j = 0; j < src.nj(); ++j)
568       for (unsigned i = 0; i < src.ni(); ++i)
569         dest(i,j,p) =  b*src(i,j,p) + a;
570 }
571 
572 //: Convert src to float image dest by stretching to range [dest_lo,dest_hi]
573 template <class inP>
vil_convert_stretch_range(const vil_image_view<inP> & src,vil_image_view<float> & dest,float dest_lo,float dest_hi)574 inline void vil_convert_stretch_range(const vil_image_view<inP>& src,
575                                       vil_image_view<float>& dest,
576                                       float dest_lo, float dest_hi)
577 {
578   inP min_b=0, max_b=0;
579   vil_math_value_range(src,min_b,max_b);
580   float b = 0.0;
581   if (max_b-min_b >0)
582     b = (dest_hi-dest_lo)/static_cast<float>(max_b-min_b);
583   float a = -1.0f*min_b*b + dest_lo;
584   dest.set_size(src.ni(), src.nj(), src.nplanes());
585   for (unsigned p = 0; p < src.nplanes(); ++p)
586     for (unsigned j = 0; j < src.nj(); ++j)
587       for (unsigned i = 0; i < src.ni(); ++i)
588         dest(i,j,p) =  b*src(i,j,p) + a;
589 }
590 
591 
592 //: Convert src image<inP> to dest image<double> by stretching input range [src_lo, src_hi] to output range [dest_lo, dest_hi].
593 // Inputs < src_lo are mapped to dest_lo, and inputs > src_hi to dest_hi.
594 template <class inP>
vil_convert_stretch_range_limited(const vil_image_view<inP> & src,vil_image_view<double> & dest,const inP src_lo,const inP src_hi,const double dest_lo,const double dest_hi)595 inline void vil_convert_stretch_range_limited(const vil_image_view<inP>& src,
596                                               vil_image_view<double>& dest,
597                                               const inP src_lo,
598                                               const inP src_hi,
599                                               const double dest_lo,
600                                               const double dest_hi)
601 {
602   double ddest = dest_hi - dest_lo;
603   double dsrc = static_cast<double>(src_hi - src_lo);
604   double dds = ddest / dsrc;
605 
606   dest.set_size(src.ni(), src.nj(), src.nplanes());
607   for (unsigned p = 0; p < src.nplanes(); ++p)
608     for (unsigned j = 0; j < src.nj(); ++j)
609       for (unsigned i = 0; i < src.ni(); ++i)
610       {
611         inP s = src(i,j,p);
612         dest(i,j,p) = s<=src_lo ? dest_lo :
613                       s>=src_hi ? dest_hi :
614                                   dest_lo + dds*static_cast<double>(s-src_lo);
615       }
616 }
617 
618 //: Convert src image<inP> to dest image<float> by stretching input range [src_lo, src_hi] to output range [dest_lo, dest_hi].
619 // Inputs < src_lo are mapped to dest_lo, and inputs > src_hi to dest_hi.
620 template <class inP>
vil_convert_stretch_range_limited(const vil_image_view<inP> & src,vil_image_view<float> & dest,const inP src_lo,const inP src_hi,const float dest_lo,const float dest_hi)621 inline void vil_convert_stretch_range_limited(const vil_image_view<inP>& src,
622                                               vil_image_view<float>& dest,
623                                               const inP src_lo,
624                                               const inP src_hi,
625                                               const float dest_lo,
626                                               const float dest_hi)
627 {
628   float ddest = dest_hi - dest_lo;
629   float dsrc = static_cast<float>(src_hi - src_lo);
630   float dds = ddest / dsrc;
631 
632   dest.set_size(src.ni(), src.nj(), src.nplanes());
633   for (unsigned p = 0; p < src.nplanes(); ++p)
634     for (unsigned j = 0; j < src.nj(); ++j)
635       for (unsigned i = 0; i < src.ni(); ++i)
636       {
637         inP s = src(i,j,p);
638         dest(i,j,p) = s<=src_lo ? dest_lo :
639                       s>=src_hi ? dest_hi :
640                                   dest_lo + dds*static_cast<float>(s-src_lo);
641       }
642 }
643 
644 //: Convert src image<inP> to dest image<ushort> by stretching input range [src_lo, src_hi] to output range [dest_lo, dest_hi].
645 // Inputs < src_lo are mapped to dest_lo, and inputs > src_hi to dest_hi.
646 template <class inP>
vil_convert_stretch_range_limited(const vil_image_view<inP> & src,vil_image_view<unsigned short> & dest,const inP src_lo,const inP src_hi,const unsigned short dest_lo,const unsigned short dest_hi)647 inline void vil_convert_stretch_range_limited(const vil_image_view<inP>& src,
648                                               vil_image_view<unsigned short>& dest,
649                                               const inP src_lo,
650                                               const inP src_hi,
651                                               const unsigned short dest_lo,
652                                               const unsigned short dest_hi)
653 {
654   const double ddest = dest_hi - dest_lo;
655   const double dsrc = static_cast<double>(src_hi - src_lo);
656   const double dds = ddest / dsrc;
657 
658   dest.set_size(src.ni(), src.nj(), src.nplanes());
659   for (unsigned p = 0; p < src.nplanes(); ++p)
660     for (unsigned j = 0; j < src.nj(); ++j)
661       for (unsigned i = 0; i < src.ni(); ++i)
662       {
663         inP s = src(i,j,p);
664         dest(i,j,p) = s<=src_lo ? dest_lo :
665                       s>=src_hi ? dest_hi :
666                                   static_cast<unsigned short>(dest_lo + dds*(s-src_lo)+0.5);
667       }
668 }
669 
670 //: Convert src image<inP> to dest image<ubyte> by stretching input range [src_lo, src_hi] to output range [dest_lo, dest_hi].
671 // Inputs < src_lo are mapped to dest_lo, and inputs > src_hi to dest_hi.
672 template <class inP>
vil_convert_stretch_range_limited(const vil_image_view<inP> & src,vil_image_view<vxl_byte> & dest,const inP src_lo,const inP src_hi,const vxl_byte dest_lo,const vxl_byte dest_hi)673 inline void vil_convert_stretch_range_limited(const vil_image_view<inP>& src,
674                                               vil_image_view<vxl_byte>& dest,
675                                               const inP src_lo,
676                                               const inP src_hi,
677                                               const vxl_byte dest_lo,
678                                               const vxl_byte dest_hi)
679 {
680   const double ddest = dest_hi - dest_lo;
681   const double dsrc = static_cast<double>(src_hi - src_lo);
682   const double dds = ddest / dsrc;
683 
684   dest.set_size(src.ni(), src.nj(), src.nplanes());
685   for (unsigned p = 0; p < src.nplanes(); ++p)
686     for (unsigned j = 0; j < src.nj(); ++j)
687       for (unsigned i = 0; i < src.ni(); ++i)
688       {
689         inP s = src(i,j,p);
690         dest(i,j,p) = s<=src_lo ? dest_lo :
691                       s>=src_hi ? dest_hi :
692                                   static_cast<vxl_byte>(dest_lo + dds*(s-src_lo)+0.5);
693       }
694 }
695 
696 //: Convert src image<inP> to dest image<vxl_byte> by stretching input range [src_lo, src_hi] to output range [0, 255].
697 // Inputs < src_lo are mapped to 0, and inputs > src_hi to 255.
698 template <class inP>
vil_convert_stretch_range_limited(const vil_image_view<inP> & src,vil_image_view<vxl_byte> & dest,const inP src_lo,const inP src_hi)699 inline void vil_convert_stretch_range_limited(const vil_image_view<inP>& src,
700                                               vil_image_view<vxl_byte>& dest,
701                                               const inP src_lo,
702                                               const inP src_hi)
703 {
704   const double dsrc = static_cast<double>(src_hi - src_lo);
705   const double dds = 255.0 / dsrc;
706 
707   dest.set_size(src.ni(), src.nj(), src.nplanes());
708   for (unsigned p = 0; p < src.nplanes(); ++p)
709     for (unsigned j = 0; j < src.nj(); ++j)
710       for (unsigned i = 0; i < src.ni(); ++i)
711       {
712         inP s = src(i,j,p);
713         dest(i,j,p) = s<=src_lo ? 0 :
714                       static_cast<vxl_byte>( s>=src_hi ? 255 : (dds*(s-src_lo)+0.5) );
715       }
716 }
717 
718 //: Cast the unknown pixel type to the known one.
719 //
720 // This function is designed to be used with vil_load or
721 // vil_image_resource::get_view()
722 // where you do not know the pixel type in advance.
723 // If you need a
724 // multi-component view, then call this to get the corresponding
725 // multi-planar view, and do a second (cheap) conversion.
726 // The input image's storage arrangement may not be preserved.
727 template <class outP>
vil_convert_cast(outP,const vil_image_view_base_sptr & src)728 inline vil_image_view_base_sptr vil_convert_cast(outP /*dummy*/,
729                                                  const vil_image_view_base_sptr& src)
730 {
731   if (!src) return vil_image_view_base_sptr();
732 
733   vil_image_view_base_sptr dest = new vil_image_view<outP>;
734   vil_image_view<outP> & dest_ref = static_cast<vil_image_view<outP> &>(*dest);
735 
736   switch ( vil_pixel_format_component_format(src->pixel_format()) )
737   {
738 #ifndef DOXYGEN_SHOULD_SKIP_THIS
739 #define macro(F , T) \
740     case F: vil_convert_cast( vil_image_view<T >(*src), dest_ref ); break
741 
742 #if VXL_HAS_INT_64
743     macro( VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64 );
744     macro( VIL_PIXEL_FORMAT_INT_64, vxl_int_64 );
745 #endif
746     macro( VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32 );
747     macro( VIL_PIXEL_FORMAT_INT_32, vxl_int_32 );
748     macro( VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16 );
749     macro( VIL_PIXEL_FORMAT_INT_16, vxl_int_16 );
750     macro( VIL_PIXEL_FORMAT_BYTE, vxl_byte );
751     macro( VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte );
752     macro( VIL_PIXEL_FORMAT_FLOAT, float );
753     macro( VIL_PIXEL_FORMAT_DOUBLE, double );
754     macro( VIL_PIXEL_FORMAT_BOOL, bool );
755 #undef macro
756 #endif // DOXYGEN_SHOULD_SKIP_THIS
757     default:
758       vil_exception_warning(vil_exception_unsupported_pixel_format(
759         src->pixel_format(), "vil_convert_cast") );
760       dest = nullptr;
761   }
762   return dest;
763 }
764 
765 #if 0 // deprecated
766 //: Cast the unknown pixel type to the known one, if possible.
767 //
768 // Will call the other vil_convert_cast to do the actual
769 // conversion. For template instantiation reasons, this will only
770 // convert to a scalar type, not a RGB or RGBA type. If you need a
771 // multi-component view, then call this to get the corresponding
772 // multi-planar view, and do a second (cheap) conversion.
773 //
774 // \deprecated Use other vil_convert_cast()
775 // Can be removed after VXL 1.1.1
776 template <class outP>
777 inline void vil_convert_cast(const vil_image_view_base_sptr& src,
778                              vil_image_view<outP >&dest)
779 {
780   VXL_DEPRECATED_MACRO( "void vil_convert_cast(const vil_image_view_base_sptr&,"
781                   " vil_image_view<outP>&)" );
782 
783   switch ( src->pixel_format() )
784   {
785 #ifndef DOXYGEN_SHOULD_SKIP_THIS
786 #define macro(F , T) \
787     case F: vil_convert_cast( vil_image_view<T >(src), dest ); break;
788 
789 #if VXL_HAS_INT_64
790     macro( VIL_PIXEL_FORMAT_UINT_64, vxl_uint_64 )
791     macro( VIL_PIXEL_FORMAT_INT_64, vxl_int_64 )
792 #endif
793     macro( VIL_PIXEL_FORMAT_UINT_32, vxl_uint_32 )
794     macro( VIL_PIXEL_FORMAT_INT_32, vxl_int_32 )
795     macro( VIL_PIXEL_FORMAT_UINT_16, vxl_uint_16 )
796     macro( VIL_PIXEL_FORMAT_INT_16, vxl_int_16 )
797     macro( VIL_PIXEL_FORMAT_BYTE, vxl_byte )
798     macro( VIL_PIXEL_FORMAT_SBYTE, vxl_sbyte )
799     macro( VIL_PIXEL_FORMAT_FLOAT, float )
800     macro( VIL_PIXEL_FORMAT_DOUBLE, double )
801     macro( VIL_PIXEL_FORMAT_BOOL, bool )
802 #undef macro
803 #endif // DOXYGEN_SHOULD_SKIP_THIS
804 
805     // Skip the RGB type conversions because the vil_convert_cast are
806     // not complete. For example, a cast from vxl_uint_16 to
807     // vil_rgb<vxl_uint_32> is not defined.
808     default:
809       dest.clear();
810   }
811 }
812 #endif // 0
813 
814 //: Convert an image of any pixel type to another with rounding.
815 // This should only be used to convert to scalar
816 // pixel types. This function only rounds in terms of the
817 // destination type.
818 // This function is designed to be used with vil_load or
819 // vil_image_resource::get_view()
820 // where you do not know the pixel type in advance.
821 //
822 // If the input image already has outP as its pixel type, the destination
823 // may only be a shallow copy of the source.
824 // outP should be a scalar pixel type.
825 // The input image's storage arrangement may not be preserved.
826 template <class outP>
vil_convert_round(outP,const vil_image_view_base_sptr & src)827 inline vil_image_view_base_sptr vil_convert_round(
828   outP /*dummy*/, const vil_image_view_base_sptr &src)
829 {
830   assert(vil_pixel_format_num_components(vil_pixel_format_of(outP()))==1);
831 
832   if (!src) return vil_image_view_base_sptr();
833 
834   if (vil_pixel_format_component_format(src->pixel_format()) ==
835       vil_pixel_format_of(outP()))
836     return src;
837 
838   vil_image_view_base_sptr dest = new vil_image_view<outP >;
839   vil_image_view<outP > &dest_ref = static_cast<vil_image_view<outP >&>(*dest);
840 
841   switch (vil_pixel_format_component_format(src->pixel_format()))
842   {
843 #ifndef DOXYGEN_SHOULD_SKIP_THIS
844 #define macro( F , T ) \
845    case F: { \
846     vil_image_view<T > src1 = src; \
847     vil_transform2(src1, dest_ref, vil_convert_round_pixel<T , outP>()); \
848     break; }
849 macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
850 macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
851 #if VXL_HAS_INT_64
852 macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 )
853 macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 )
854 #endif
855 macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
856 macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
857 macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
858 macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
859 macro(VIL_PIXEL_FORMAT_FLOAT , float )
860 macro(VIL_PIXEL_FORMAT_DOUBLE , double )
861 #undef macro
862 #endif // DOXYGEN_SHOULD_SKIP_THIS
863   default:
864     vil_exception_warning(vil_exception_unsupported_pixel_format(
865       src->pixel_format(), "vil_convert_round") );
866     dest=nullptr;
867   }
868   return dest;
869 }
870 
871 
872 //: Force data to be suitable for viewing as multi component view.
873 // The output data will have values from different planes but the same
874 // pixel location stored in adjacent memory locations. After using this
875 // function on an input with 3 planes, an assignment to a
876 // vil_image_view<vil_rgb<T> > will always work.
877 // The input image's scalar pixel type will be preserved.
vil_convert_to_component_order(const vil_image_view_base_sptr & src)878 inline vil_image_view_base_sptr vil_convert_to_component_order(
879   const vil_image_view_base_sptr& src)
880 {
881   if (!src) return vil_image_view_base_sptr();
882 
883   vil_image_view_base_sptr dest;
884 
885   switch (vil_pixel_format_component_format(src->pixel_format()))
886   {
887 #ifndef DOXYGEN_SHOULD_SKIP_THIS
888 #define macro( F , T )\
889    case F: { \
890     vil_image_view<T > src_ref(src); \
891     if (!src_ref) return vil_image_view_base_sptr(); \
892     if (src_ref.planestep()==1) return src; \
893     const unsigned ni=src->ni(), nj=src->nj(), nplanes=src->nplanes(); \
894     vil_memory_chunk_sptr chunk = new vil_memory_chunk(ni*nj*nplanes*sizeof(T), \
895                                                        vil_pixel_format_component_format(F)); \
896     dest = new vil_image_view<T >(chunk, reinterpret_cast<T*>(chunk->data()), \
897                                   ni, nj, nplanes, nplanes, nplanes*ni, 1); \
898     vil_image_view<T > & dest_ref = static_cast<vil_image_view<T >&>(*dest); \
899     vil_copy_reformat(src_ref, dest_ref); \
900     break; }
901 macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
902 macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
903 #if VXL_HAS_INT_64
904 macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 )
905 macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 )
906 #endif
907 macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
908 macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
909 macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
910 macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
911 macro(VIL_PIXEL_FORMAT_FLOAT , float )
912 macro(VIL_PIXEL_FORMAT_DOUBLE , double )
913 #undef macro
914 #endif // DOXYGEN_SHOULD_SKIP_THIS
915 
916     default:
917       vil_exception_warning(vil_exception_unsupported_pixel_format(
918         src->pixel_format(), "vil_convert_to_compound_order") );
919       dest=nullptr;
920   }
921   return dest;
922 }
923 
924 #if 0 // deprecated
925 //: Create a greyscale image from any image src.
926 // This function is designed to be used with vil_load or
927 // vil_image_resource::get_view()
928 // where you do not know the pixel type in advance. e.g.
929 // \code
930 // vil_image_view<float> input =
931 //   vil_convert_to_grey_using_average(vil_load(filename), float());
932 // \endcode
933 // If you have an image_view of known pixel_type then you should use one of
934 // the other vil_convert functions.
935 // The output may be a reconfigured view of the input.
936 // \deprecated Use other vil_convert_to_grey_using_average()
937 template <class outP>
938 inline vil_image_view<outP> vil_convert_to_grey_using_average(
939   const vil_image_view_base_sptr &src, outP /*dummy*/)
940 {
941   VXL_DEPRECATED_MACRO( "vil_convert_to_grey_using_average<outP>("
942                   "const vil_image_view_base_sptr &, outP)" );
943 
944   // Check output is scalar component image.
945   assert (vil_pixel_format_num_components(vil_pixel_format_of(outP())) == 1);
946 
947   if (!src) return vil_image_view<outP>();
948 
949   // try to do it quickly
950   if (vil_pixel_format_of(outP()) == src->pixel_format() && src->nplanes() == 1)
951     return vil_image_view<outP>(src);
952 
953   // create output view
954   vil_image_view<outP> dest;
955 
956   // convert via vil_image_view<double>
957   switch (vil_pixel_format_component_format(src->pixel_format()))
958   {
959 #ifndef DOXYGEN_SHOULD_SKIP_THIS
960 #define macro( F , T ) \
961    case F: { \
962     vil_image_view<T > src1 = *src; \
963     vil_math_mean_over_planes(src1, dest, double()); \
964     break; }
965    macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
966    macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
967 #if VXL_HAS_INT_64
968    macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 )
969    macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 )
970 #endif
971    macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
972    macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
973    macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
974    macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
975    macro(VIL_PIXEL_FORMAT_FLOAT , float )
976    macro(VIL_PIXEL_FORMAT_DOUBLE , double )
977 #undef macro
978 #endif // DOXYGEN_SHOULD_SKIP_THIS
979    default:
980     dest.clear();
981   }
982   return dest;
983 }
984 #endif // 0
985 
986 //: Create a greyscale image of specified pixel type from any image src.
987 // This function is designed to be used with vil_load or
988 // vil_image_resource::get_view()
989 // where you do not know the pixel type in advance. e.g.
990 // \code
991 // vil_image_view<float> input = vil_convert_cast(
992 //   convert_to_grey_using_average(vil_load(filename)), float());
993 // \endcode
994 // The output may be a reconfigured view of the input.
995 // The input image's pixel type and storage arrangement may not be preserved.
vil_convert_to_grey_using_average(const vil_image_view_base_sptr & src)996 inline vil_image_view_base_sptr vil_convert_to_grey_using_average(
997   const vil_image_view_base_sptr &src)
998 {
999   if (!src) return vil_image_view_base_sptr();
1000 
1001   // convert via vil_image_view<double>
1002   switch (vil_pixel_format_component_format(src->pixel_format()))
1003   {
1004 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1005 #define macro( F , T ) \
1006   case F: { \
1007     /* try to do it quickly */ \
1008     if (src->nplanes() == 1 && \
1009         vil_pixel_format_component_format(src->pixel_format())==1) \
1010       return src; \
1011     /* create output view */ \
1012     vil_image_view<T > dest; \
1013     vil_image_view<T > src1 = *src; \
1014     vil_math_mean_over_planes(src1, dest, double()); \
1015     return vil_image_view_base_sptr(new vil_image_view<T >(dest)); }
1016   macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
1017   macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
1018 #if VXL_HAS_INT_64
1019   macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 )
1020   macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 )
1021 #endif
1022   macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
1023   macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
1024   macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
1025   macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
1026   macro(VIL_PIXEL_FORMAT_FLOAT , float )
1027   macro(VIL_PIXEL_FORMAT_DOUBLE , double )
1028 #undef macro
1029 #endif // DOXYGEN_SHOULD_SKIP_THIS
1030   default:
1031     vil_exception_warning(vil_exception_unsupported_pixel_format(
1032       src->pixel_format(), "vil_convert_to_grey_using_average") );
1033     return nullptr;
1034   }
1035 }
1036 
1037 
1038 //: Create a greyscale image from any image src.
1039 // This function is designed to be used with vil_load or
1040 // vil_image_resource::get_view()
1041 // where you do not know the pixel type in advance.
1042 // The output may be a reconfigured view of the input.
1043 // The input image's pixel type and storage arrangement may not be preserved.
vil_convert_to_grey_using_rgb_weighting(double rw,double gw,double bw,const vil_image_view_base_sptr & src)1044 inline vil_image_view_base_sptr vil_convert_to_grey_using_rgb_weighting(
1045   double rw, double gw, double bw, const vil_image_view_base_sptr &src)
1046 {
1047   if (!src)
1048     return vil_image_view_base_sptr();
1049 
1050   // convert via vil_image_view<double>
1051   switch (vil_pixel_format_component_format(src->pixel_format()))
1052   {
1053 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1054 #define macro( F , T ) \
1055   case F: { \
1056     /* try to do it quickly */ \
1057     if (src->nplanes() == 1 && \
1058         vil_pixel_format_num_components(src->pixel_format()) == 1) \
1059       return vil_image_view_base_sptr(src); \
1060     vil_image_view<T > src1 = src; \
1061     vil_image_view<double> dest1; \
1062     vil_convert_planes_to_grey(src1, dest1, rw, gw, bw); \
1063     vil_image_view<T > dest; \
1064     vil_convert_round(dest1,dest); \
1065     return vil_image_view_base_sptr(new vil_image_view<T >(dest)); }
1066   macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
1067   macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
1068 #if VXL_HAS_INT_64
1069   macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 )
1070   macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 )
1071 #endif
1072   macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
1073   macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
1074   macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
1075   macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
1076   macro(VIL_PIXEL_FORMAT_FLOAT , float )
1077   macro(VIL_PIXEL_FORMAT_DOUBLE , double )
1078 #undef macro
1079 #endif // DOXYGEN_SHOULD_SKIP_THIS
1080   default:
1081       vil_exception_warning(vil_exception_unsupported_pixel_format(
1082         src->pixel_format(), "vil_convert_to_grey_using_rgb_weighting") );
1083     return vil_image_view_base_sptr();
1084   }
1085 }
1086 
1087 //: Create a greyscale image from any image src using default weights.
1088 // This function is designed to be used with vil_load or
1089 // vil_image_resource::get_view()
1090 // where you do not know the pixel type in advance.
1091 // The output may be a reconfigured view of the input.
1092 // The input image's pixel type and storage arrangement may not be preserved.
1093 //
1094 // Default weights convert from linear RGB to CIE luminance assuming a
1095 // modern monitor.  See Charles Poynton's Colour FAQ
1096 // http://www.poynton.com/ColorFAQ.html
1097 
vil_convert_to_grey_using_rgb_weighting(const vil_image_view_base_sptr & src)1098 inline vil_image_view_base_sptr vil_convert_to_grey_using_rgb_weighting(
1099   const vil_image_view_base_sptr &src)
1100 {
1101   return vil_convert_to_grey_using_rgb_weighting(0.2125, 0.7154, 0.0721, src);
1102 }
1103 
1104 #if 0 // deprecated version of this function now commented out
1105 //: Create a greyscale image of specified pixel type from any image src.
1106 // This function is designed to be used with vil_load or
1107 // vil_image_resource::get_view()
1108 // where you do not know the pixel type in advance.
1109 // The output may be a reconfigured view of the input.
1110 //
1111 // Default weights convert from linear RGB to CIE luminance assuming a
1112 // modern monitor.  See Charles Poynton's Colour FAQ
1113 // http://www.poynton.com/ColorFAQ.html
1114 // \deprecated Use other version of vil_convert_to_grey_using_rgb_weighting
1115 template <class outP>
1116 inline vil_image_view<outP> vil_convert_to_grey_using_rgb_weighting(
1117                           const vil_image_view_base_sptr &src,
1118                           outP /*dummy*/,
1119                           double rw=0.2125,
1120                           double gw=0.7154,
1121                           double bw=0.0721)
1122 {
1123   VXL_DEPRECATED_MACRO( "vil_convert_to_grey_using_rgb_weighting<outP>("
1124                   "const vil_image_view_base_sptr &, outP)" );
1125 
1126   // Check output is scalar component image.
1127   assert (vil_pixel_format_num_components(vil_pixel_format_of(outP())) == 1);
1128 
1129   if (!src) return vil_image_view<outP>();
1130 
1131   // try to do it quickly
1132   if (vil_pixel_format_of(outP()) == src->pixel_format() && src->nplanes() == 1)
1133     return vil_image_view<outP>(src);
1134 
1135   // create output view
1136   vil_image_view<outP> dest;
1137 
1138   // convert via vil_image_view<double>
1139   switch (vil_pixel_format_component_format(src->pixel_format()))
1140   {
1141 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1142 #define macro( F , T ) \
1143    case F: { \
1144     vil_image_view<T > src1 = src; \
1145     vil_image_view<double> dest1; \
1146     vil_convert_planes_to_grey(src1, dest1, rw, gw, bw); \
1147     vil_convert_round(dest1,dest); \
1148     break; }
1149    macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
1150    macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
1151 #if VXL_HAS_INT_64
1152    macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 )
1153    macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 )
1154 #endif
1155    macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
1156    macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
1157    macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
1158    macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
1159    macro(VIL_PIXEL_FORMAT_FLOAT , float )
1160    macro(VIL_PIXEL_FORMAT_DOUBLE , double )
1161    // Don't even want to think about rgb<complex<float> >
1162 #undef macro
1163 #endif // DOXYGEN_SHOULD_SKIP_THIS
1164    default:
1165     dest.clear();
1166   }
1167   return dest;
1168 }
1169 #endif // 0
1170 
1171 //: Create an n plane image from any image src.
1172 // This function is designed to be used with vil_load or
1173 // vil_image_resource::get_view()
1174 // where you do not know the pixel type or number of planes in advance.
1175 // If the input images have too many planes, the higher planes will be
1176 // truncated. If the input image has too few planes, the new planes will be
1177 // copies of the first plane.
1178 //
1179 // The output may be a shallow copy of the input.
1180 // The input image's storage arrangement may not be preserved.
1181 //
1182 // This function works on scalar pixel types only, however it can be used to
1183 // produce an rgb image as in the following example
1184 // \code
1185 // vil_image_view<vil_rgb<float> > =
1186 //   vil_convert_cast(
1187 //     float(),
1188 //     vil_convert_to_component_order(
1189 //       vil_convert_to_n_planes(
1190 //         3,
1191 //         vil_load(filename)
1192 //       )
1193 //     )
1194 //   );
1195 // \endcode
vil_convert_to_n_planes(unsigned n_planes,const vil_image_view_base_sptr & src)1196 inline vil_image_view_base_sptr vil_convert_to_n_planes(
1197   unsigned n_planes, const vil_image_view_base_sptr &src)
1198 {
1199   if (!src || n_planes == 0)
1200     return vil_image_view_base_sptr();
1201 
1202   switch (vil_pixel_format_component_format(src->pixel_format()))
1203   {
1204 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1205  #define macro( F, T ) \
1206    case F: { \
1207     vil_image_view<T > src_ref = src; \
1208     if (!src_ref) return vil_image_view_base_sptr(); \
1209     /* try to do it quickly 1 */ \
1210     if (src_ref.nplanes() >= n_planes) /* reduce number of planes */ \
1211       return vil_image_view_base_sptr( new vil_image_view<T >( \
1212           vil_planes(vil_image_view<T > (src),0,1,n_planes) )); \
1213     else { /* expand number of planes with copying */ \
1214       vil_image_view_base_sptr dest = new vil_image_view<T >(src_ref.ni(), src_ref.nj(), n_planes); \
1215       vil_image_view<T > & dest_ref = static_cast<vil_image_view<T >&>(*dest); \
1216       vil_image_view<T > dest_slices = vil_planes(dest_ref, 0, 1, src_ref.nplanes()); \
1217       vil_copy_reformat(src_ref, dest_slices); \
1218       vil_image_view<T > src_slice(vil_plane(src_ref, 0)); \
1219       for (unsigned i=src_ref.nplanes(); i<n_planes; ++i) { \
1220         dest_slices = vil_plane(dest_ref, i); \
1221         vil_copy_reformat(src_slice,  dest_slices); } \
1222       return dest; } }
1223    macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
1224    macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
1225 #if VXL_HAS_INT_64
1226    macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 )
1227    macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 )
1228 #endif
1229    macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
1230    macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
1231    macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
1232    macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
1233    macro(VIL_PIXEL_FORMAT_FLOAT , float )
1234    macro(VIL_PIXEL_FORMAT_DOUBLE , double )
1235 #undef macro
1236 #endif // DOXYGEN_SHOULD_SKIP_THIS
1237    default:
1238      vil_exception_warning(vil_exception_unsupported_pixel_format(
1239         src->pixel_format(), "vil_convert_to_n_planes") );
1240 
1241     return vil_image_view_base_sptr();
1242   }
1243 }
1244 
1245 
1246 //: Create an image of the desired type by stretching the range to fit.
1247 // This function is designed to be used with vil_load or
1248 // vil_image_resource::get_view()
1249 // where you do not know the pixel type in advance.
1250 // In the case of floating point output pixels the range is set to [0,1]
1251 // The input image's storage arrangement may not be preserved.
1252 //
1253 // This function works on scalar pixel types only. You can convert the image
1254 // to rgb using a cheap assignment afterwards.
1255 template <class outP>
vil_convert_stretch_range(outP,const vil_image_view_base_sptr & src)1256 inline vil_image_view_base_sptr vil_convert_stretch_range(
1257   outP /*dummy*/, const vil_image_view_base_sptr &src)
1258 {
1259   // Check that input isn't trying to produce multi-component pixels
1260   assert (vil_pixel_format_num_components(vil_pixel_format_of(outP())) == 1);
1261 
1262   if (!src)
1263     return vil_image_view_base_sptr();
1264 
1265   double hi,lo;
1266 
1267   if (std::numeric_limits<outP>::is_integer)
1268   {
1269     hi = std::numeric_limits<outP>::max()+0.999;
1270     lo = std::numeric_limits<outP>::min();
1271   }
1272   else
1273   {
1274     hi=1.0;
1275     lo=0.0;
1276   }
1277 
1278   vil_image_view_base_sptr dest = new vil_image_view<outP>;
1279   vil_image_view<outP> & dest_ref = static_cast<vil_image_view<outP> &>(*dest);
1280   vil_image_view<double> inter;
1281   switch (vil_pixel_format_component_format(src->pixel_format()))
1282   {
1283 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1284 #define macro( F , T ) \
1285    case F: { \
1286     vil_image_view<T> src_ref = src; \
1287     if (!src_ref) return vil_image_view_base_sptr(); \
1288     vil_convert_stretch_range(src_ref, inter, lo, hi); \
1289     vil_convert_cast(inter, dest_ref); \
1290     break; }
1291    macro(VIL_PIXEL_FORMAT_BYTE, vxl_byte )
1292    macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
1293 #if VXL_HAS_INT_64
1294    macro(VIL_PIXEL_FORMAT_UINT_64 , vxl_uint_64 )
1295    macro(VIL_PIXEL_FORMAT_INT_64 , vxl_int_64 )
1296 #endif
1297    macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
1298    macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
1299    macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
1300    macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
1301    macro(VIL_PIXEL_FORMAT_FLOAT , float )
1302    macro(VIL_PIXEL_FORMAT_DOUBLE , double )
1303 #undef macro
1304 #endif // DOXYGEN_SHOULD_SKIP_THIS
1305   default:
1306     vil_exception_warning(vil_exception_unsupported_pixel_format(
1307       src->pixel_format(), "vil_convert_stretch_range") );
1308 
1309     dest_ref.clear();
1310   }
1311   return dest;
1312 }
1313 
1314 
1315 #endif // vil_convert_h_
1316