~ubuntu-branches/ubuntu/trusty/blender/trusty

« back to all changes in this revision

Viewing changes to source/blender/compositor/operations/COM_InpaintOperation.cpp

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-03-06 12:08:47 UTC
  • mfrom: (1.5.1) (14.1.8 experimental)
  • Revision ID: package-import@ubuntu.com-20130306120847-frjfaryb2zrotwcg
Tags: 2.66a-1ubuntu1
* Resynchronize with Debian (LP: #1076930, #1089256, #1052743, #999024,
  #1122888, #1147084)
* debian/control:
  - Lower build-depends on libavcodec-dev since we're not
    doing the libav9 transition in Ubuntu yet

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2011, Blender Foundation.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public License
 
6
 * as published by the Free Software Foundation; either version 2
 
7
 * of the License, or (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software Foundation,
 
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
17
 *
 
18
 * Contributor: Peter Schlaile
 
19
 *              Jeroen Bakker 
 
20
 *              Monique Dewanchand
 
21
 */
 
22
 
 
23
#include "MEM_guardedalloc.h"
 
24
 
 
25
#include "COM_InpaintOperation.h"
 
26
#include "COM_OpenCLDevice.h"
 
27
 
 
28
#include "BLI_math.h"
 
29
 
 
30
#define ASSERT_XY_RANGE(x, y)  \
 
31
        BLI_assert(x >= 0 && x < this->getWidth() && \
 
32
                   y >= 0 && y < this->getHeight())
 
33
 
 
34
 
 
35
// Inpaint (simple convolve using average of known pixels)
 
36
InpaintSimpleOperation::InpaintSimpleOperation() : NodeOperation()
 
37
{
 
38
        this->addInputSocket(COM_DT_COLOR);
 
39
        this->addOutputSocket(COM_DT_COLOR);
 
40
        this->setComplex(true);
 
41
        this->m_inputImageProgram = NULL;
 
42
        this->m_pixelorder = NULL;
 
43
        this->m_manhatten_distance = NULL;
 
44
        this->m_cached_buffer = NULL;
 
45
        this->m_cached_buffer_ready = false;
 
46
}
 
47
void InpaintSimpleOperation::initExecution()
 
48
{
 
49
        this->m_inputImageProgram = this->getInputSocketReader(0);
 
50
 
 
51
        this->m_cached_buffer = NULL;
 
52
        this->m_pixelorder = NULL;
 
53
        this->m_manhatten_distance = NULL;
 
54
        this->m_cached_buffer = NULL;
 
55
        this->m_cached_buffer_ready = false;
 
56
 
 
57
        this->initMutex();
 
58
}
 
59
 
 
60
void InpaintSimpleOperation::clamp_xy(int &x, int &y)
 
61
{
 
62
        int width = this->getWidth();
 
63
        int height = this->getHeight();
 
64
 
 
65
        if (x < 0) {
 
66
                x = 0;
 
67
        }
 
68
        else if (x >= width) {
 
69
                x = width - 1;
 
70
        }
 
71
 
 
72
        if (y < 0) {
 
73
                y = 0;
 
74
        }
 
75
        else if (y >= height) {
 
76
                y = height - 1;
 
77
        }
 
78
}
 
79
 
 
80
float *InpaintSimpleOperation::get_pixel(int x, int y)
 
81
{
 
82
        int width = this->getWidth();
 
83
 
 
84
        ASSERT_XY_RANGE(x, y);
 
85
 
 
86
        return &this->m_cached_buffer[
 
87
                y * width * COM_NUMBER_OF_CHANNELS +
 
88
                x * COM_NUMBER_OF_CHANNELS];
 
89
}
 
90
 
 
91
int InpaintSimpleOperation::mdist(int x, int y) 
 
92
{
 
93
        int width = this->getWidth();
 
94
 
 
95
        ASSERT_XY_RANGE(x, y);
 
96
 
 
97
        return this->m_manhatten_distance[y * width + x];
 
98
}
 
99
 
 
100
bool InpaintSimpleOperation::next_pixel(int &x, int &y, int & curr, int iters)
 
101
{
 
102
        int width = this->getWidth();
 
103
 
 
104
        if (curr >= this->m_area_size) {
 
105
                return false;
 
106
        }
 
107
        
 
108
        int r = this->m_pixelorder[curr++];
 
109
 
 
110
        x = r % width;
 
111
        y = r / width;
 
112
 
 
113
        if (this->mdist(x, y) > iters) {
 
114
                return false;
 
115
        }
 
116
        
 
117
        return true;
 
118
}
 
119
 
 
120
void InpaintSimpleOperation::calc_manhatten_distance() 
 
121
{
 
122
        int width = this->getWidth();
 
123
        int height = this->getHeight();
 
124
        short *m = this->m_manhatten_distance = (short *)MEM_mallocN(sizeof(short) * width * height, __func__);
 
125
        int *offsets;
 
126
 
 
127
        offsets = (int *)MEM_callocN(sizeof(int) * (width + height + 1), "InpaintSimpleOperation offsets");
 
128
 
 
129
        for (int j = 0; j < height; j++) {
 
130
                for (int i = 0; i < width; i++) {
 
131
                        int r = 0;
 
132
                        /* no need to clamp here */
 
133
                        if (this->get_pixel(i, j)[3] < 1.0f) {
 
134
                                r = width + height;
 
135
                                if (i > 0) 
 
136
                                        r = min_ii(r, m[j * width + i - 1] + 1);
 
137
                                if (j > 0) 
 
138
                                        r = min_ii(r, m[(j - 1) * width + i] + 1);
 
139
                        }
 
140
                        m[j * width + i] = r;
 
141
                }
 
142
        }
 
143
 
 
144
        for (int j = height - 1; j >= 0; j--) {
 
145
                for (int i = width - 1; i >= 0; i--) {
 
146
                        int r = m[j * width + i];
 
147
                        
 
148
                        if (i + 1 < width) 
 
149
                                r = min_ii(r, m[j * width + i + 1] + 1);
 
150
                        if (j + 1 < height) 
 
151
                                r = min_ii(r, m[(j + 1) * width + i] + 1);
 
152
                        
 
153
                        m[j * width + i] = r;
 
154
                        
 
155
                        offsets[r]++;
 
156
                }
 
157
        }
 
158
        
 
159
        offsets[0] = 0;
 
160
        
 
161
        for (int i = 1; i < width + height + 1; i++) {
 
162
                offsets[i] += offsets[i - 1];
 
163
        }
 
164
        
 
165
        this->m_area_size = offsets[width + height];
 
166
        this->m_pixelorder = (int *)MEM_mallocN(sizeof(int) * this->m_area_size, __func__);
 
167
        
 
168
        for (int i = 0; i < width * height; i++) {
 
169
                if (m[i] > 0) {
 
170
                        this->m_pixelorder[offsets[m[i] - 1]++] = i;
 
171
                }
 
172
        }
 
173
 
 
174
        MEM_freeN(offsets);
 
175
}
 
176
 
 
177
void InpaintSimpleOperation::pix_step(int x, int y)
 
178
{
 
179
        const int d = this->mdist(x, y);
 
180
        float pix[3] = {0.0f, 0.0f, 0.0f};
 
181
        float pix_divider = 0.0f;
 
182
 
 
183
        for (int dx = -1; dx <= 1; dx++) {
 
184
                for (int dy = -1; dy <= 1; dy++) {
 
185
                        /* changing to both != 0 gives dithering artifacts */
 
186
                        if (dx != 0 || dy != 0) {
 
187
                                int x_ofs = x + dx;
 
188
                                int y_ofs = y + dy;
 
189
 
 
190
                                this->clamp_xy(x_ofs, y_ofs);
 
191
 
 
192
                                if (this->mdist(x_ofs, y_ofs) < d) {
 
193
 
 
194
                                        float weight;
 
195
 
 
196
                                        if (dx == 0 || dy == 0) {
 
197
                                                weight = 1.0f;
 
198
                                        }
 
199
                                        else {
 
200
                                                weight = M_SQRT1_2;  /* 1.0f / sqrt(2) */
 
201
                                        }
 
202
 
 
203
                                        madd_v3_v3fl(pix, this->get_pixel(x_ofs, y_ofs), weight);
 
204
                                        pix_divider += weight;
 
205
                                }
 
206
                        }
 
207
                }
 
208
        }
 
209
 
 
210
        float *output = this->get_pixel(x, y);
 
211
        if (pix_divider != 0.0f) {
 
212
                mul_v3_fl(pix, 1.0f / pix_divider);
 
213
                /* use existing pixels alpha to blend into */
 
214
                interp_v3_v3v3(output, pix, output, output[3]);
 
215
                output[3] = 1.0f;
 
216
        }
 
217
}
 
218
 
 
219
void *InpaintSimpleOperation::initializeTileData(rcti *rect)
 
220
{
 
221
        if (this->m_cached_buffer_ready) {
 
222
                return this->m_cached_buffer;
 
223
        }
 
224
        lockMutex();
 
225
        if (!this->m_cached_buffer_ready) {
 
226
                MemoryBuffer *buf = (MemoryBuffer *)this->m_inputImageProgram->initializeTileData(rect);
 
227
                this->m_cached_buffer = (float *)MEM_dupallocN(buf->getBuffer());
 
228
 
 
229
                this->calc_manhatten_distance();
 
230
 
 
231
                int curr = 0;
 
232
                int x, y;
 
233
 
 
234
        
 
235
                while (this->next_pixel(x, y, curr, this->m_iterations)) {
 
236
                        this->pix_step(x, y);
 
237
                }
 
238
                this->m_cached_buffer_ready = true;
 
239
        }
 
240
 
 
241
        unlockMutex();
 
242
        return this->m_cached_buffer;
 
243
}
 
244
 
 
245
void InpaintSimpleOperation::executePixel(float output[4], int x, int y, void *data)
 
246
{
 
247
        this->clamp_xy(x, y);
 
248
        copy_v4_v4(output, this->get_pixel(x, y));
 
249
}
 
250
 
 
251
void InpaintSimpleOperation::deinitExecution()
 
252
{
 
253
        this->m_inputImageProgram = NULL;
 
254
        this->deinitMutex();
 
255
        if (this->m_cached_buffer) {
 
256
                MEM_freeN(this->m_cached_buffer);
 
257
                this->m_cached_buffer = NULL;
 
258
        }
 
259
 
 
260
        if (this->m_pixelorder) {
 
261
                MEM_freeN(this->m_pixelorder);
 
262
                this->m_pixelorder = NULL;
 
263
        }
 
264
 
 
265
        if (this->m_manhatten_distance) {
 
266
                MEM_freeN(this->m_manhatten_distance);
 
267
                this->m_manhatten_distance = NULL;
 
268
        }
 
269
        this->m_cached_buffer_ready = false;
 
270
}
 
271
 
 
272
bool InpaintSimpleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
 
273
{
 
274
        if (this->m_cached_buffer_ready) {
 
275
                return false;
 
276
        }
 
277
        else {
 
278
                rcti newInput;
 
279
        
 
280
                newInput.xmax = getWidth();
 
281
                newInput.xmin = 0;
 
282
                newInput.ymax = getHeight();
 
283
                newInput.ymin = 0;
 
284
        
 
285
                return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
 
286
        }
 
287
}
 
288