e842747e6d4ba04a6209d8e6fab4f9239296a60d
[blender.git] / extern / libmv / libmv / image / sample.h
1 // Copyright (c) 2007, 2008 libmv authors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to
5 // deal in the Software without restriction, including without limitation the
6 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 // sell copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 // IN THE SOFTWARE.
20
21 #ifndef LIBMV_IMAGE_SAMPLE_H_
22 #define LIBMV_IMAGE_SAMPLE_H_
23
24 #include "libmv/image/image.h"
25
26 namespace libmv {
27
28 /// Nearest neighbor interpolation.
29 template<typename T>
30 inline T SampleNearest(const Array3D<T> &image,
31                        float y, float x, int v = 0) {
32   const int i = int(round(y));
33   const int j = int(round(x));
34   return image(i, j, v);
35 }
36
37 static inline void LinearInitAxis(float fx, int width,
38                                   int *x1, int *x2,
39                                   float *dx1, float *dx2) {
40   const int ix = int(fx);
41   if (ix < 0) {
42     *x1 = 0;
43     *x2 = 0;
44     *dx1 = 1;
45     *dx2 = 0;
46   } else if (ix > width-2) {
47     *x1 = width-1;
48     *x2 = width-1;
49     *dx1 = 1;
50     *dx2 = 0;
51   } else {
52     *x1 = ix;
53     *x2 = *x1 + 1;
54     *dx1 = *x2 - fx;
55     *dx2 = 1 - *dx1;
56   }
57 }
58
59 /// Linear interpolation.
60 template<typename T>
61 inline T SampleLinear(const Array3D<T> &image, float y, float x, int v = 0) {
62   int x1, y1, x2, y2;
63   float dx1, dy1, dx2, dy2;
64
65   LinearInitAxis(y, image.Height(), &y1, &y2, &dy1, &dy2);
66   LinearInitAxis(x, image.Width(),  &x1, &x2, &dx1, &dx2);
67
68   const T im11 = image(y1, x1, v);
69   const T im12 = image(y1, x2, v);
70   const T im21 = image(y2, x1, v);
71   const T im22 = image(y2, x2, v);
72
73   return T(dy1 * ( dx1 * im11 + dx2 * im12 ) +
74            dy2 * ( dx1 * im21 + dx2 * im22 ));
75 }
76
77 // Downsample all channels by 2. If the image has odd width or height, the last
78 // row or column is ignored.
79 // FIXME(MatthiasF): this implementation shouldn't be in an interface file
80 inline void DownsampleChannelsBy2(const Array3Df &in, Array3Df *out) {
81   int height = in.Height() / 2;
82   int width = in.Width() / 2;
83   int depth = in.Depth();
84
85   out->Resize(height, width, depth);
86
87   // 2x2 box filter downsampling.
88   for (int r = 0; r < height; ++r) {
89     for (int c = 0; c < width; ++c) {
90       for (int k = 0; k < depth; ++k) {
91         (*out)(r, c, k) = (in(2 * r,     2 * c,     k) +
92                            in(2 * r + 1, 2 * c,     k) +
93                            in(2 * r,     2 * c + 1, k) +
94                            in(2 * r + 1, 2 * c + 1, k)) / 4.0f;
95       }
96     }
97   }
98 }
99
100 // Sample a region centered at x,y in image with size extending by half_width
101 // from x,y. Channels specifies the number of channels to sample from.
102 inline void SamplePattern(const FloatImage &image,
103                    double x, double y,
104                    int half_width,
105                    int channels,
106                    FloatImage *sampled) {
107   sampled->Resize(2 * half_width + 1, 2 * half_width + 1, channels);
108   for (int r = -half_width; r <= half_width; ++r) {
109     for (int c = -half_width; c <= half_width; ++c) {
110       for (int i = 0; i < channels; ++i) {
111         (*sampled)(r + half_width, c + half_width, i) =
112             SampleLinear(image, y + r, x + c, i);
113       }
114     }
115   }
116 }
117
118 }  // namespace libmv
119
120 #endif  // LIBMV_IMAGE_SAMPLE_H_