Pillow

Форк
0
/
BoxBlur.c 
330 строк · 9.7 Кб
1
#include "Imaging.h"
2

3
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
4
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
5

6
typedef UINT8 pixel[4];
7

8
void static inline ImagingLineBoxBlur32(
9
    pixel *lineOut,
10
    pixel *lineIn,
11
    int lastx,
12
    int radius,
13
    int edgeA,
14
    int edgeB,
15
    UINT32 ww,
16
    UINT32 fw
17
) {
18
    int x;
19
    UINT32 acc[4];
20
    UINT32 bulk[4];
21

22
#define MOVE_ACC(acc, subtract, add)                \
23
    acc[0] += lineIn[add][0] - lineIn[subtract][0]; \
24
    acc[1] += lineIn[add][1] - lineIn[subtract][1]; \
25
    acc[2] += lineIn[add][2] - lineIn[subtract][2]; \
26
    acc[3] += lineIn[add][3] - lineIn[subtract][3];
27

28
#define ADD_FAR(bulk, acc, left, right)                                  \
29
    bulk[0] = (acc[0] * ww) + (lineIn[left][0] + lineIn[right][0]) * fw; \
30
    bulk[1] = (acc[1] * ww) + (lineIn[left][1] + lineIn[right][1]) * fw; \
31
    bulk[2] = (acc[2] * ww) + (lineIn[left][2] + lineIn[right][2]) * fw; \
32
    bulk[3] = (acc[3] * ww) + (lineIn[left][3] + lineIn[right][3]) * fw;
33

34
#define SAVE(x, bulk)                                     \
35
    lineOut[x][0] = (UINT8)((bulk[0] + (1 << 23)) >> 24); \
36
    lineOut[x][1] = (UINT8)((bulk[1] + (1 << 23)) >> 24); \
37
    lineOut[x][2] = (UINT8)((bulk[2] + (1 << 23)) >> 24); \
38
    lineOut[x][3] = (UINT8)((bulk[3] + (1 << 23)) >> 24);
39

40
    /* Compute acc for -1 pixel (outside of image):
41
       From "-radius-1" to "-1" get first pixel,
42
       then from "0" to "radius-1". */
43
    acc[0] = lineIn[0][0] * (radius + 1);
44
    acc[1] = lineIn[0][1] * (radius + 1);
45
    acc[2] = lineIn[0][2] * (radius + 1);
46
    acc[3] = lineIn[0][3] * (radius + 1);
47
    /* As radius can be bigger than xsize, iterate to edgeA -1. */
48
    for (x = 0; x < edgeA - 1; x++) {
49
        acc[0] += lineIn[x][0];
50
        acc[1] += lineIn[x][1];
51
        acc[2] += lineIn[x][2];
52
        acc[3] += lineIn[x][3];
53
    }
54
    /* Then multiply remainder to last x. */
55
    acc[0] += lineIn[lastx][0] * (radius - edgeA + 1);
56
    acc[1] += lineIn[lastx][1] * (radius - edgeA + 1);
57
    acc[2] += lineIn[lastx][2] * (radius - edgeA + 1);
58
    acc[3] += lineIn[lastx][3] * (radius - edgeA + 1);
59

60
    if (edgeA <= edgeB) {
61
        /* Subtract pixel from left ("0").
62
           Add pixels from radius. */
63
        for (x = 0; x < edgeA; x++) {
64
            MOVE_ACC(acc, 0, x + radius);
65
            ADD_FAR(bulk, acc, 0, x + radius + 1);
66
            SAVE(x, bulk);
67
        }
68
        /* Subtract previous pixel from "-radius".
69
           Add pixels from radius. */
70
        for (x = edgeA; x < edgeB; x++) {
71
            MOVE_ACC(acc, x - radius - 1, x + radius);
72
            ADD_FAR(bulk, acc, x - radius - 1, x + radius + 1);
73
            SAVE(x, bulk);
74
        }
75
        /* Subtract previous pixel from "-radius".
76
           Add last pixel. */
77
        for (x = edgeB; x <= lastx; x++) {
78
            MOVE_ACC(acc, x - radius - 1, lastx);
79
            ADD_FAR(bulk, acc, x - radius - 1, lastx);
80
            SAVE(x, bulk);
81
        }
82
    } else {
83
        for (x = 0; x < edgeB; x++) {
84
            MOVE_ACC(acc, 0, x + radius);
85
            ADD_FAR(bulk, acc, 0, x + radius + 1);
86
            SAVE(x, bulk);
87
        }
88
        for (x = edgeB; x < edgeA; x++) {
89
            MOVE_ACC(acc, 0, lastx);
90
            ADD_FAR(bulk, acc, 0, lastx);
91
            SAVE(x, bulk);
92
        }
93
        for (x = edgeA; x <= lastx; x++) {
94
            MOVE_ACC(acc, x - radius - 1, lastx);
95
            ADD_FAR(bulk, acc, x - radius - 1, lastx);
96
            SAVE(x, bulk);
97
        }
98
    }
99

100
#undef MOVE_ACC
101
#undef ADD_FAR
102
#undef SAVE
103
}
104

105
void static inline ImagingLineBoxBlur8(
106
    UINT8 *lineOut,
107
    UINT8 *lineIn,
108
    int lastx,
109
    int radius,
110
    int edgeA,
111
    int edgeB,
112
    UINT32 ww,
113
    UINT32 fw
114
) {
115
    int x;
116
    UINT32 acc;
117
    UINT32 bulk;
118

119
#define MOVE_ACC(acc, subtract, add) acc += lineIn[add] - lineIn[subtract];
120

121
#define ADD_FAR(bulk, acc, left, right) \
122
    bulk = (acc * ww) + (lineIn[left] + lineIn[right]) * fw;
123

124
#define SAVE(x, bulk) lineOut[x] = (UINT8)((bulk + (1 << 23)) >> 24)
125

126
    acc = lineIn[0] * (radius + 1);
127
    for (x = 0; x < edgeA - 1; x++) {
128
        acc += lineIn[x];
129
    }
130
    acc += lineIn[lastx] * (radius - edgeA + 1);
131

132
    if (edgeA <= edgeB) {
133
        for (x = 0; x < edgeA; x++) {
134
            MOVE_ACC(acc, 0, x + radius);
135
            ADD_FAR(bulk, acc, 0, x + radius + 1);
136
            SAVE(x, bulk);
137
        }
138
        for (x = edgeA; x < edgeB; x++) {
139
            MOVE_ACC(acc, x - radius - 1, x + radius);
140
            ADD_FAR(bulk, acc, x - radius - 1, x + radius + 1);
141
            SAVE(x, bulk);
142
        }
143
        for (x = edgeB; x <= lastx; x++) {
144
            MOVE_ACC(acc, x - radius - 1, lastx);
145
            ADD_FAR(bulk, acc, x - radius - 1, lastx);
146
            SAVE(x, bulk);
147
        }
148
    } else {
149
        for (x = 0; x < edgeB; x++) {
150
            MOVE_ACC(acc, 0, x + radius);
151
            ADD_FAR(bulk, acc, 0, x + radius + 1);
152
            SAVE(x, bulk);
153
        }
154
        for (x = edgeB; x < edgeA; x++) {
155
            MOVE_ACC(acc, 0, lastx);
156
            ADD_FAR(bulk, acc, 0, lastx);
157
            SAVE(x, bulk);
158
        }
159
        for (x = edgeA; x <= lastx; x++) {
160
            MOVE_ACC(acc, x - radius - 1, lastx);
161
            ADD_FAR(bulk, acc, x - radius - 1, lastx);
162
            SAVE(x, bulk);
163
        }
164
    }
165

166
#undef MOVE_ACC
167
#undef ADD_FAR
168
#undef SAVE
169
}
170

171
Imaging
172
ImagingHorizontalBoxBlur(Imaging imOut, Imaging imIn, float floatRadius) {
173
    ImagingSectionCookie cookie;
174

175
    int y;
176

177
    int radius = (int)floatRadius;
178
    UINT32 ww = (UINT32)(1 << 24) / (floatRadius * 2 + 1);
179
    UINT32 fw = ((1 << 24) - (radius * 2 + 1) * ww) / 2;
180

181
    int edgeA = MIN(radius + 1, imIn->xsize);
182
    int edgeB = MAX(imIn->xsize - radius - 1, 0);
183

184
    UINT32 *lineOut = calloc(imIn->xsize, sizeof(UINT32));
185
    if (lineOut == NULL) {
186
        return ImagingError_MemoryError();
187
    }
188

189
    // printf(">>> %d %d %d\n", radius, ww, fw);
190

191
    ImagingSectionEnter(&cookie);
192

193
    if (imIn->image8) {
194
        for (y = 0; y < imIn->ysize; y++) {
195
            ImagingLineBoxBlur8(
196
                (imIn == imOut ? (UINT8 *)lineOut : imOut->image8[y]),
197
                imIn->image8[y],
198
                imIn->xsize - 1,
199
                radius,
200
                edgeA,
201
                edgeB,
202
                ww,
203
                fw
204
            );
205
            if (imIn == imOut) {
206
                // Commit.
207
                memcpy(imOut->image8[y], lineOut, imIn->xsize);
208
            }
209
        }
210
    } else {
211
        for (y = 0; y < imIn->ysize; y++) {
212
            ImagingLineBoxBlur32(
213
                imIn == imOut ? (pixel *)lineOut : (pixel *)imOut->image32[y],
214
                (pixel *)imIn->image32[y],
215
                imIn->xsize - 1,
216
                radius,
217
                edgeA,
218
                edgeB,
219
                ww,
220
                fw
221
            );
222
            if (imIn == imOut) {
223
                // Commit.
224
                memcpy(imOut->image32[y], lineOut, imIn->xsize * 4);
225
            }
226
        }
227
    }
228

229
    ImagingSectionLeave(&cookie);
230

231
    free(lineOut);
232

233
    return imOut;
234
}
235

236
Imaging
237
ImagingBoxBlur(Imaging imOut, Imaging imIn, float xradius, float yradius, int n) {
238
    int i;
239
    Imaging imTransposed;
240

241
    if (n < 1) {
242
        return ImagingError_ValueError("number of passes must be greater than zero");
243
    }
244
    if (xradius < 0 || yradius < 0) {
245
        return ImagingError_ValueError("radius must be >= 0");
246
    }
247

248
    if (strcmp(imIn->mode, imOut->mode) || imIn->type != imOut->type ||
249
        imIn->bands != imOut->bands || imIn->xsize != imOut->xsize ||
250
        imIn->ysize != imOut->ysize) {
251
        return ImagingError_Mismatch();
252
    }
253

254
    if (imIn->type != IMAGING_TYPE_UINT8) {
255
        return ImagingError_ModeError();
256
    }
257

258
    if (!(strcmp(imIn->mode, "RGB") == 0 || strcmp(imIn->mode, "RGBA") == 0 ||
259
          strcmp(imIn->mode, "RGBa") == 0 || strcmp(imIn->mode, "RGBX") == 0 ||
260
          strcmp(imIn->mode, "CMYK") == 0 || strcmp(imIn->mode, "L") == 0 ||
261
          strcmp(imIn->mode, "LA") == 0 || strcmp(imIn->mode, "La") == 0)) {
262
        return ImagingError_ModeError();
263
    }
264

265
    /* Apply blur in one dimension.
266
       Use imOut as a destination at first pass,
267
       then use imOut as a source too. */
268

269
    if (xradius != 0) {
270
        ImagingHorizontalBoxBlur(imOut, imIn, xradius);
271
        for (i = 1; i < n; i++) {
272
            ImagingHorizontalBoxBlur(imOut, imOut, xradius);
273
        }
274
    }
275
    if (yradius != 0) {
276
        imTransposed = ImagingNewDirty(imIn->mode, imIn->ysize, imIn->xsize);
277
        if (!imTransposed) {
278
            return NULL;
279
        }
280

281
        /* Transpose result for blur in another direction. */
282
        ImagingTranspose(imTransposed, xradius == 0 ? imIn : imOut);
283

284
        /* Reuse imTransposed as a source and destination there. */
285
        for (i = 0; i < n; i++) {
286
            ImagingHorizontalBoxBlur(imTransposed, imTransposed, yradius);
287
        }
288
        /* Restore original orientation. */
289
        ImagingTranspose(imOut, imTransposed);
290

291
        ImagingDelete(imTransposed);
292
    }
293
    if (xradius == 0 && yradius == 0) {
294
        if (!ImagingCopy2(imOut, imIn)) {
295
            return NULL;
296
        }
297
    }
298

299
    return imOut;
300
}
301

302
static float
303
_gaussian_blur_radius(float radius, int passes) {
304
    float sigma2, L, l, a;
305

306
    sigma2 = radius * radius / passes;
307
    // from https://www.mia.uni-saarland.de/Publications/gwosdek-ssvm11.pdf
308
    // [7] Box length.
309
    L = sqrt(12.0 * sigma2 + 1.0);
310
    // [11] Integer part of box radius.
311
    l = floor((L - 1.0) / 2.0);
312
    // [14], [Fig. 2] Fractional part of box radius.
313
    a = (2 * l + 1) * (l * (l + 1) - 3 * sigma2);
314
    a /= 6 * (sigma2 - (l + 1) * (l + 1));
315

316
    return l + a;
317
}
318

319
Imaging
320
ImagingGaussianBlur(
321
    Imaging imOut, Imaging imIn, float xradius, float yradius, int passes
322
) {
323
    return ImagingBoxBlur(
324
        imOut,
325
        imIn,
326
        _gaussian_blur_radius(xradius, passes),
327
        _gaussian_blur_radius(yradius, passes),
328
        passes
329
    );
330
}
331

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.