summaryrefslogtreecommitdiffstats
path: root/src/kernels/interpolator.cl
blob: 4d4eae808d72dd4219dc1f83dd8855498c77bf08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * Copyright (C) 2011-2013 Karlsruhe Institute of Technology
 *
 * This file is part of Ufo.
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

kernel void
interpolate (global float *a,
             global float *b,
             global float *output,
             float alpha)
{
    const int index = get_global_id(1) * get_global_size(0) + get_global_id(0);
    output[index] = (1.0f - alpha) * a[index] + alpha * b[index];
}

/*
 * Interpolate two arrays along the horizontal direction, *offset* is a linear
 * offset to the first and the output arrays. In stitching, *weight* is used to
 * match the mean of the second buffer's overlapping region to the first one's.
 */
kernel void
interpolate_horizontally (global float *a,
                          global float *b,
                          global float *output,
                          const int width,
                          const int left_width,
                          const int right_width,
                          const int offset,
                          const float weight)
{
    const int idx = get_global_id(0);
    const int idy = get_global_id(1);
    const float alpha = ((float) idx) / (get_global_size (0) - 1.0f);

    output[idy * width + idx + offset] = (1.0f - alpha) * a[idy * left_width + idx + offset] +
                                         alpha * weight * b[idy * right_width + idx];
}

kernel void
interpolate_mask_horizontally (global float *input,
                               global float *mask,
                               global float *output,
                               const int use_gradient)
{
   const int idx = get_global_id (0);
   const int idy = get_global_id (1);
   const int width = get_global_size (0);
   const int offset = idy * width;
   int left = idx, right = idx;
   float span, diff;

   if (mask[offset + idx]) {
        while (left > -1 && mask[offset + left] > 0) {
            left--;
        }
        while (right < width && mask[offset + right] > 0) {
            right++;
        }

        if (left < 0) {
            /* Mask spans to the left border, use only the right value */
            if (right < width - 1) {
                if (use_gradient) {
                    /* There are two valid pixels on the right, use gradient */
                    diff = input[offset + right] - input[offset + right + 1];
                    output[offset + idx] = input[offset + right] + diff * (right - idx);
                } else {
                    output[offset + idx] = input[offset + right];
                }
            } else if (right == width - 1) {
                /* There is only one valid pixel on the right, which is the only
                 * valid pixel in this row, so use it's value everywhere */
                output[offset + idx] = input[offset + right];
            } else {
                /* All pixels in this row are invalid, just copy the input */
                output[offset + idx] = input[offset + idx];
            }
        } else if (right >= width) {
            /* Mask spans to the right border, use only the left value */
            if (left > 0) {
                if (use_gradient) {
                    /* There are two valid pixels on the left, use gradient */
                    diff = input[offset + left] - input[offset + left - 1];
                    output[offset + idx] = input[offset + left] + diff * (idx - left);
                } else {
                    output[offset + idx] = input[offset + left];
                }
            } else if (left == 0) {
                /* There is only one valid pixel on the left, which is the only
                 * valid pixel in this row, so use it's value everywhere */
                output[offset + idx] = input[offset + left];
            }
        } else {
            /* There are valid pixels on both sides, use standard linear
             * interpolation */
            span = (float) (right - left);
            output[offset + idx] = (right - idx) / span * input[offset + left] +
                                   (idx - left) / span * input[offset + right];
        }
   } else {
       output[offset + idx] = input[offset + idx];
   }
}