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