Coverage Report

Created: 2026-03-31 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libraw/src/demosaic/misc_demosaic.cpp
Line
Count
Source
1
/* -*- C++ -*-
2
 * Copyright 2019-2025 LibRaw LLC (info@libraw.org)
3
 *
4
 LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder,
5
 dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net.
6
 LibRaw do not use RESTRICTED code from dcraw.c
7
8
 LibRaw is free software; you can redistribute it and/or modify
9
 it under the terms of the one of two licenses as you choose:
10
11
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
12
   (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
13
14
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
15
   (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
16
17
 */
18
19
#include "../../internal/dcraw_defs.h"
20
21
void LibRaw::pre_interpolate()
22
1.93k
{
23
1.93k
  ushort(*img)[4];
24
1.93k
  int row, col, c;
25
1.93k
  RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 0, 2);
26
1.93k
  if (shrink)
27
0
  {
28
0
    if (half_size)
29
0
    {
30
0
      height = iheight;
31
0
      width = iwidth;
32
0
      if (filters == 9)
33
0
      {
34
0
        for (row = 0; row < 3; row++)
35
0
          for (col = 1; col < 4; col++)
36
0
            if (!(image[row * width + col][0] | image[row * width + col][2]))
37
0
              goto break2;
38
0
      break2:
39
0
        for (; row < height; row += 3)
40
0
          for (col = (col - 1) % 3 + 1; col < width - 1; col += 3)
41
0
          {
42
0
            img = image + row * width + col;
43
0
            for (c = 0; c < 3; c += 2)
44
0
              img[0][c] = (img[-1][c] + img[1][c]) >> 1;
45
0
          }
46
0
      }
47
0
    }
48
0
    else
49
0
    {
50
0
      int extra = filters ? (filters == 9 ? 6 : 2) : 0;
51
0
      img = (ushort(*)[4])calloc((height+extra), (width+extra) * sizeof *img);
52
0
      for (row = 0; row < height; row++)
53
0
        for (col = 0; col < width; col++)
54
0
        {
55
0
          c = fcol(row, col);
56
0
          img[row * width + col][c] =
57
0
              image[(row >> 1) * iwidth + (col >> 1)][c];
58
0
        }
59
0
      free(image);
60
0
      image = img;
61
0
      shrink = 0;
62
0
    }
63
0
  }
64
1.93k
  if (filters > 1000 && colors == 3)
65
1.43k
  {
66
1.43k
    mix_green = four_color_rgb ^ half_size;
67
1.43k
    if (four_color_rgb | half_size)
68
0
      colors++;
69
1.43k
    else
70
1.43k
    {
71
162k
      for (row = FC(1, 0) >> 1; row < height; row += 2)
72
34.6M
        for (col = FC(row, 1) & 1; col < width; col += 2)
73
34.4M
          image[row * width + col][1] = image[row * width + col][3];
74
1.43k
      filters &= ~((filters & 0x55555555U) << 1);
75
1.43k
    }
76
1.43k
  }
77
1.93k
  if (half_size)
78
0
    filters = 0;
79
1.93k
  RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 1, 2);
80
1.93k
}
81
82
void LibRaw::border_interpolate(int border)
83
1.74k
{
84
1.74k
  unsigned row, col, y, x, f, c, sum[8];
85
86
461k
  for (row = 0; row < height; row++)
87
9.51M
    for (col = 0; col < width; col++)
88
9.05M
    {
89
9.05M
      if (col == (unsigned)border && row >= (unsigned)border && row < (unsigned)(height - border))
90
443k
        col = width - border;
91
9.05M
      memset(sum, 0, sizeof sum);
92
36.2M
      for (y = row - 1; y != row + 2; y++)
93
108M
        for (x = col - 1; x != col + 2; x++)
94
81.4M
          if (y < height && x < width)
95
76.0M
          {
96
76.0M
            f = fcol(y, x);
97
76.0M
            sum[f] += image[y * width + x][f];
98
76.0M
            sum[f + 4]++;
99
76.0M
          }
100
9.05M
      f = fcol(row, col);
101
27.2M
      FORC(unsigned(colors)) if (c != f && sum[c + 4]) image[row * width + col][c] =
102
17.5M
          sum[c] / sum[c + 4];
103
9.05M
    }
104
1.74k
}
105
106
void LibRaw::lin_interpolate_loop(int *code, int size)
107
181
{
108
181
  int row;
109
52.7k
  for (row = 1; row < height - 1; row++)
110
52.5k
  {
111
52.5k
    int col, *ip;
112
52.5k
    ushort *pix;
113
9.65M
    for (col = 1; col < width - 1; col++)
114
9.60M
    {
115
9.60M
      int i;
116
9.60M
      int sum[4];
117
9.60M
      pix = image[row * width + col];
118
9.60M
      ip = code + ((((row % size) * 16) + (col % size)) * 32);
119
9.60M
      memset(sum, 0, sizeof sum);
120
57.9M
      for (i = *ip++; i--; ip += 3)
121
48.3M
        sum[ip[2]] += pix[ip[0]] << ip[1];
122
36.1M
      for (i = colors; --i; ip += 2)
123
26.5M
        pix[ip[0]] = sum[ip[0]] * ip[1] >> 8;
124
9.60M
    }
125
52.5k
  }
126
181
}
127
128
void LibRaw::lin_interpolate()
129
181
{
130
181
  std::vector<int> code_buffer(16 * 16 * 32);
131
181
  int* code = &code_buffer[0], size = 16, *ip, sum[4];
132
181
  int f, c, x, y, row, col, shift, color;
133
134
181
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 0, 3);
135
136
181
  if (filters == 9)
137
28
    size = 6;
138
181
  border_interpolate(1);
139
2.79k
  for (row = 0; row < size; row++)
140
42.7k
    for (col = 0; col < size; col++)
141
40.1k
    {
142
40.1k
      ip = code + (((row * 16) + col) * 32) + 1;
143
40.1k
      f = fcol(row, col);
144
40.1k
      memset(sum, 0, sizeof sum);
145
160k
      for (y = -1; y <= 1; y++)
146
482k
        for (x = -1; x <= 1; x++)
147
361k
        {
148
361k
          shift = (y == 0) + (x == 0);
149
361k
          color = fcol(row + y + 48, col + x + 48);
150
361k
          if (color == f)
151
175k
            continue;
152
186k
          *ip++ = (width * y + x) * 4 + color;
153
186k
          *ip++ = shift;
154
186k
          *ip++ = color;
155
186k
          sum[color] += 1 << shift;
156
186k
        }
157
40.1k
      code[(row * 16 + col) * 32] = int((ip - (code + ((row * 16) + col) * 32)) / 3);
158
40.1k
      FORCC
159
148k
      if (c != f)
160
109k
      {
161
109k
        *ip++ = c;
162
109k
        *ip++ = sum[c] > 0 ? 256 / sum[c] : 0;
163
109k
      }
164
40.1k
    }
165
181
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 1, 3);
166
181
  lin_interpolate_loop(code, size);
167
181
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 2, 3);
168
181
}
169
170
/*
171
   This algorithm is officially called:
172
173
   "Interpolation using a Threshold-based variable number of gradients"
174
175
   described in
176
   http://scien.stanford.edu/pages/labsite/1999/psych221/projects/99/tingchen/algodep/vargra.html
177
178
   I've extended the basic idea to work with non-Bayer filter arrays.
179
   Gradients are numbered clockwise from NW=0 to W=7.
180
 */
181
void LibRaw::vng_interpolate()
182
181
{
183
181
  static const signed char *cp,
184
181
      terms[] =
185
181
          {-2, -2, +0,   -1, 0,  0x01, -2, -2, +0,   +0, 1,  0x01, -2, -1, -1,
186
181
           +0, 0,  0x01, -2, -1, +0,   -1, 0,  0x02, -2, -1, +0,   +0, 0,  0x03,
187
181
           -2, -1, +0,   +1, 1,  0x01, -2, +0, +0,   -1, 0,  0x06, -2, +0, +0,
188
181
           +0, 1,  0x02, -2, +0, +0,   +1, 0,  0x03, -2, +1, -1,   +0, 0,  0x04,
189
181
           -2, +1, +0,   -1, 1,  0x04, -2, +1, +0,   +0, 0,  0x06, -2, +1, +0,
190
181
           +1, 0,  0x02, -2, +2, +0,   +0, 1,  0x04, -2, +2, +0,   +1, 0,  0x04,
191
181
           -1, -2, -1,   +0, 0,  -128, -1, -2, +0,   -1, 0,  0x01, -1, -2, +1,
192
181
           -1, 0,  0x01, -1, -2, +1,   +0, 1,  0x01, -1, -1, -1,   +1, 0,  -120,
193
181
           -1, -1, +1,   -2, 0,  0x40, -1, -1, +1,   -1, 0,  0x22, -1, -1, +1,
194
181
           +0, 0,  0x33, -1, -1, +1,   +1, 1,  0x11, -1, +0, -1,   +2, 0,  0x08,
195
181
           -1, +0, +0,   -1, 0,  0x44, -1, +0, +0,   +1, 0,  0x11, -1, +0, +1,
196
181
           -2, 1,  0x40, -1, +0, +1,   -1, 0,  0x66, -1, +0, +1,   +0, 1,  0x22,
197
181
           -1, +0, +1,   +1, 0,  0x33, -1, +0, +1,   +2, 1,  0x10, -1, +1, +1,
198
181
           -1, 1,  0x44, -1, +1, +1,   +0, 0,  0x66, -1, +1, +1,   +1, 0,  0x22,
199
181
           -1, +1, +1,   +2, 0,  0x10, -1, +2, +0,   +1, 0,  0x04, -1, +2, +1,
200
181
           +0, 1,  0x04, -1, +2, +1,   +1, 0,  0x04, +0, -2, +0,   +0, 1,  -128,
201
181
           +0, -1, +0,   +1, 1,  -120, +0, -1, +1,   -2, 0,  0x40, +0, -1, +1,
202
181
           +0, 0,  0x11, +0, -1, +2,   -2, 0,  0x40, +0, -1, +2,   -1, 0,  0x20,
203
181
           +0, -1, +2,   +0, 0,  0x30, +0, -1, +2,   +1, 1,  0x10, +0, +0, +0,
204
181
           +2, 1,  0x08, +0, +0, +2,   -2, 1,  0x40, +0, +0, +2,   -1, 0,  0x60,
205
181
           +0, +0, +2,   +0, 1,  0x20, +0, +0, +2,   +1, 0,  0x30, +0, +0, +2,
206
181
           +2, 1,  0x10, +0, +1, +1,   +0, 0,  0x44, +0, +1, +1,   +2, 0,  0x10,
207
181
           +0, +1, +2,   -1, 1,  0x40, +0, +1, +2,   +0, 0,  0x60, +0, +1, +2,
208
181
           +1, 0,  0x20, +0, +1, +2,   +2, 0,  0x10, +1, -2, +1,   +0, 0,  -128,
209
181
           +1, -1, +1,   +1, 0,  -120, +1, +0, +1,   +2, 0,  0x08, +1, +0, +2,
210
181
           -1, 0,  0x40, +1, +0, +2,   +1, 0,  0x10},
211
181
      chood[] = {-1, -1, -1, 0, -1, +1, 0, +1, +1, +1, +1, 0, +1, -1, 0, -1};
212
181
  ushort(*brow[5])[4], *pix;
213
181
  int prow = 8, pcol = 2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4];
214
181
  int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
215
181
  int g, diff, thold, num, c;
216
217
181
  lin_interpolate();
218
219
181
  if (filters == 1)
220
9
    prow = pcol = 16;
221
181
  if (filters == 9)
222
28
    prow = pcol = 6;
223
181
  ip = (int *)calloc(prow * pcol, 1280);
224
1.64k
  for (row = 0; row < prow; row++) /* Precalculate for VNG */
225
7.08k
    for (col = 0; col < pcol; col++)
226
5.61k
    {
227
5.61k
      code[row][col] = ip;
228
365k
      for (cp = terms, t = 0; t < 64; t++)
229
359k
      {
230
359k
        y1 = *cp++;
231
359k
        x1 = *cp++;
232
359k
        y2 = *cp++;
233
359k
        x2 = *cp++;
234
359k
        weight = *cp++;
235
359k
        grads = *cp++;
236
359k
        color = fcol(row + y1 + 144, col + x1 + 144);
237
359k
        if (fcol(row + y2 + 144, col + x2 + 144) != color)
238
198k
          continue;
239
160k
        diag = (fcol(row, col + 1) == color && fcol(row + 1, col) == color) ? 2
240
160k
                                                                            : 1;
241
160k
        if (abs(y1 - y2) == diag && abs(x1 - x2) == diag)
242
23.9k
          continue;
243
136k
        *ip++ = (y1 * width + x1) * 4 + color;
244
136k
        *ip++ = (y2 * width + x2) * 4 + color;
245
136k
        *ip++ = weight;
246
1.23M
        for (g = 0; g < 8; g++)
247
1.09M
          if (grads & 1 << g)
248
203k
            *ip++ = g;
249
136k
        *ip++ = -1;
250
136k
      }
251
5.61k
      *ip++ = INT_MAX;
252
50.5k
      for (cp = chood, g = 0; g < 8; g++)
253
44.9k
      {
254
44.9k
        y = *cp++;
255
44.9k
        x = *cp++;
256
44.9k
        *ip++ = (y * width + x) * 4;
257
44.9k
        color = fcol(row, col);
258
44.9k
        if (fcol(row + y + 144, col + x + 144) != color &&
259
29.5k
            fcol(row + y * 2 + 144, col + x * 2 + 144) == color)
260
13.9k
          *ip++ = (y * width + x) * 8 + color;
261
30.9k
        else
262
30.9k
          *ip++ = 0;
263
44.9k
      }
264
5.61k
    }
265
181
  brow[4] = (ushort(*)[4])calloc(width * 3, sizeof **brow);
266
724
  for (row = 0; row < 3; row++)
267
543
    brow[row] = brow[4] + row * width;
268
52.3k
  for (row = 2; row < height - 2; row++)
269
52.2k
  { /* Do VNG interpolation */
270
52.2k
    if (!((row - 2) % 256))
271
326
      RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, (row - 2) / 256 + 1,
272
52.2k
                   ((height - 3) / 256) + 1);
273
9.43M
    for (col = 2; col < width - 2; col++)
274
9.38M
    {
275
9.38M
      pix = image[row * width + col];
276
9.38M
      ip = code[row % prow][col % pcol];
277
9.38M
      memset(gval, 0, sizeof gval);
278
322M
      while ((g = ip[0]) != INT_MAX)
279
313M
      { /* Calculate gradients */
280
313M
        diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
281
313M
        gval[ip[3]] += diff;
282
313M
        ip += 5;
283
313M
        if ((g = ip[-1]) == -1)
284
205M
          continue;
285
107M
        gval[g] += diff;
286
127M
        while ((g = *ip++) != -1)
287
19.8M
          gval[g] += diff;
288
107M
      }
289
9.38M
      ip++;
290
9.38M
      gmin = gmax = gval[0]; /* Choose a threshold */
291
75.0M
      for (g = 1; g < 8; g++)
292
65.6M
      {
293
65.6M
        if (gmin > gval[g])
294
5.56M
          gmin = gval[g];
295
65.6M
        if (gmax < gval[g])
296
3.55M
          gmax = gval[g];
297
65.6M
      }
298
9.38M
      if (gmax == 0)
299
4.97M
      {
300
4.97M
        memcpy(brow[2][col], pix, sizeof *image);
301
4.97M
        continue;
302
4.97M
      }
303
4.40M
      thold = gmin + (gmax >> 1);
304
4.40M
      memset(sum, 0, sizeof sum);
305
4.40M
      color = fcol(row, col);
306
39.6M
      for (num = g = 0; g < 8; g++, ip += 2)
307
35.2M
      { /* Average the neighbors */
308
35.2M
        if (gval[g] <= thold)
309
17.6M
        {
310
17.6M
          FORCC
311
62.4M
          if (c == color && ip[1])
312
8.11M
            sum[c] += (pix[c] + pix[ip[1]]) >> 1;
313
54.3M
          else
314
54.3M
            sum[c] += pix[ip[0] + c];
315
17.6M
          num++;
316
17.6M
        }
317
35.2M
      }
318
4.40M
      FORCC
319
15.6M
      { /* Save to buffer */
320
15.6M
        t = pix[color];
321
15.6M
        if (c != color)
322
11.4M
          t += (sum[c] - sum[color]) / num;
323
15.6M
        brow[2][col][c] = CLIP(t);
324
15.6M
      }
325
4.40M
    }
326
52.2k
    if (row > 3) /* Write buffer to image */
327
51.8k
      memcpy(image[(row - 2) * width + 2], brow[0] + 2,
328
51.8k
             (width - 4) * sizeof *image);
329
261k
    for (g = 0; g < 4; g++)
330
208k
      brow[(g - 1) & 3] = brow[g];
331
52.2k
  }
332
181
  memcpy(image[(row - 2) * width + 2], brow[0] + 2,
333
181
         (width - 4) * sizeof *image);
334
181
  memcpy(image[(row - 1) * width + 2], brow[1] + 2,
335
181
         (width - 4) * sizeof *image);
336
181
  free(brow[4]);
337
181
  free(code[0][0]);
338
181
}
339
340
/*
341
   Patterned Pixel Grouping Interpolation by Alain Desbiolles
342
*/
343
void LibRaw::ppg_interpolate()
344
99
{
345
99
  int dir[5] = {1, width, -1, -width, 1};
346
99
  int row, col, diff[2], guess[2], c, d, i;
347
99
  ushort(*pix)[4];
348
349
99
  border_interpolate(3);
350
351
  /*  Fill in the green layer with gradients and pattern recognition: */
352
99
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 0, 3);
353
#ifdef LIBRAW_USE_OPENMP
354
#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c,  \
355
                                                 i, pix) schedule(static)
356
#endif
357
3.46k
  for (row = 3; row < height - 3; row++)
358
68.6k
    for (col = 3 + (FC(row, 3) & 1), c = FC(row, col); col < width - 3;
359
65.2k
         col += 2)
360
65.2k
    {
361
65.2k
      pix = image + row * width + col;
362
195k
      for (i = 0; i < 2; i++)
363
130k
      {
364
130k
        d = dir[i];
365
130k
        guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 - pix[-2 * d][c] -
366
130k
                   pix[2 * d][c];
367
130k
        diff[i] =
368
130k
            (ABS(pix[-2 * d][c] - pix[0][c]) + ABS(pix[2 * d][c] - pix[0][c]) +
369
130k
             ABS(pix[-d][1] - pix[d][1])) *
370
130k
                3 +
371
130k
            (ABS(pix[3 * d][1] - pix[d][1]) +
372
130k
             ABS(pix[-3 * d][1] - pix[-d][1])) *
373
130k
                2;
374
130k
      }
375
65.2k
      d = dir[i = diff[0] > diff[1]];
376
65.2k
      pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]);
377
65.2k
    }
378
  /*  Calculate red and blue for each green pixel:    */
379
99
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 1, 3);
380
#ifdef LIBRAW_USE_OPENMP
381
#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c,  \
382
                                                 i, pix) schedule(static)
383
#endif
384
3.86k
  for (row = 1; row < height - 1; row++)
385
83.4k
    for (col = 1 + (FC(row, 2) & 1), c = FC(row, col + 1); col < width - 1;
386
79.7k
         col += 2)
387
79.7k
    {
388
79.7k
      pix = image + row * width + col;
389
239k
      for (i = 0; i < 2; c = 2 - c, i++)
390
159k
      {
391
159k
        d = dir[i];
392
159k
        pix[0][c] = CLIP(
393
159k
            (pix[-d][c] + pix[d][c] + 2 * pix[0][1] - pix[-d][1] - pix[d][1]) >>
394
159k
            1);
395
159k
      }
396
79.7k
    }
397
  /*  Calculate blue for red pixels and vice versa:   */
398
99
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 2, 3);
399
#ifdef LIBRAW_USE_OPENMP
400
#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c,  \
401
                                                 i, pix) schedule(static)
402
#endif
403
3.86k
  for (row = 1; row < height - 1; row++)
404
83.4k
    for (col = 1 + (FC(row, 1) & 1), c = 2 - FC(row, col); col < width - 1;
405
79.7k
         col += 2)
406
79.7k
    {
407
79.7k
      pix = image + row * width + col;
408
239k
      for (i = 0; i < 2; i++)
409
159k
      {
410
159k
        d = dir[i] + dir[i+1];
411
159k
        diff[i] = ABS(pix[-d][c] - pix[d][c]) + ABS(pix[-d][1] - pix[0][1]) +
412
159k
                  ABS(pix[d][1] - pix[0][1]);
413
159k
        guess[i] =
414
159k
            pix[-d][c] + pix[d][c] + 2 * pix[0][1] - pix[-d][1] - pix[d][1];
415
159k
      }
416
79.7k
      if (diff[0] != diff[1])
417
33.3k
        pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1);
418
46.3k
      else
419
46.3k
        pix[0][c] = CLIP((guess[0] + guess[1]) >> 2);
420
79.7k
    }
421
99
}