Coverage Report

Created: 2026-02-14 07:09

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.77k
{
23
1.77k
  ushort(*img)[4];
24
1.77k
  int row, col, c;
25
1.77k
  RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 0, 2);
26
1.77k
  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.77k
  if (filters > 1000 && colors == 3)
65
1.21k
  {
66
1.21k
    mix_green = four_color_rgb ^ half_size;
67
1.21k
    if (four_color_rgb | half_size)
68
0
      colors++;
69
1.21k
    else
70
1.21k
    {
71
689k
      for (row = FC(1, 0) >> 1; row < height; row += 2)
72
116M
        for (col = FC(row, 1) & 1; col < width; col += 2)
73
115M
          image[row * width + col][1] = image[row * width + col][3];
74
1.21k
      filters &= ~((filters & 0x55555555U) << 1);
75
1.21k
    }
76
1.21k
  }
77
1.77k
  if (half_size)
78
0
    filters = 0;
79
1.77k
  RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 1, 2);
80
1.77k
}
81
82
void LibRaw::border_interpolate(int border)
83
1.43k
{
84
1.43k
  unsigned row, col, y, x, f, c, sum[8];
85
86
1.53M
  for (row = 0; row < height; row++)
87
34.7M
    for (col = 0; col < width; col++)
88
33.1M
    {
89
33.1M
      if (col == (unsigned)border && row >= (unsigned)border && row < (unsigned)(height - border))
90
1.51M
        col = width - border;
91
33.1M
      memset(sum, 0, sizeof sum);
92
132M
      for (y = row - 1; y != row + 2; y++)
93
398M
        for (x = col - 1; x != col + 2; x++)
94
298M
          if (y < height && x < width)
95
275M
          {
96
275M
            f = fcol(y, x);
97
275M
            sum[f] += image[y * width + x][f];
98
275M
            sum[f + 4]++;
99
275M
          }
100
33.1M
      f = fcol(row, col);
101
100M
      FORC(unsigned(colors)) if (c != f && sum[c + 4]) image[row * width + col][c] =
102
66.1M
          sum[c] / sum[c + 4];
103
33.1M
    }
104
1.43k
}
105
106
void LibRaw::lin_interpolate_loop(int *code, int size)
107
213
{
108
213
  int row;
109
151k
  for (row = 1; row < height - 1; row++)
110
150k
  {
111
150k
    int col, *ip;
112
150k
    ushort *pix;
113
66.8M
    for (col = 1; col < width - 1; col++)
114
66.6M
    {
115
66.6M
      int i;
116
66.6M
      int sum[4];
117
66.6M
      pix = image[row * width + col];
118
66.6M
      ip = code + ((((row % size) * 16) + (col % size)) * 32);
119
66.6M
      memset(sum, 0, sizeof sum);
120
494M
      for (i = *ip++; i--; ip += 3)
121
427M
        sum[ip[2]] += pix[ip[0]] << ip[1];
122
265M
      for (i = colors; --i; ip += 2)
123
199M
        pix[ip[0]] = sum[ip[0]] * ip[1] >> 8;
124
66.6M
    }
125
150k
  }
126
213
}
127
128
void LibRaw::lin_interpolate()
129
213
{
130
213
  std::vector<int> code_buffer(16 * 16 * 32);
131
213
  int* code = &code_buffer[0], size = 16, *ip, sum[4];
132
213
  int f, c, x, y, row, col, shift, color;
133
134
213
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 0, 3);
135
136
213
  if (filters == 9)
137
1
    size = 6;
138
213
  border_interpolate(1);
139
3.61k
  for (row = 0; row < size; row++)
140
57.7k
    for (col = 0; col < size; col++)
141
54.3k
    {
142
54.3k
      ip = code + (((row * 16) + col) * 32) + 1;
143
54.3k
      f = fcol(row, col);
144
54.3k
      memset(sum, 0, sizeof sum);
145
217k
      for (y = -1; y <= 1; y++)
146
651k
        for (x = -1; x <= 1; x++)
147
488k
        {
148
488k
          shift = (y == 0) + (x == 0);
149
488k
          color = fcol(row + y + 48, col + x + 48);
150
488k
          if (color == f)
151
165k
            continue;
152
322k
          *ip++ = (width * y + x) * 4 + color;
153
322k
          *ip++ = shift;
154
322k
          *ip++ = color;
155
322k
          sum[color] += 1 << shift;
156
322k
        }
157
54.3k
      code[(row * 16 + col) * 32] = int((ip - (code + ((row * 16) + col) * 32)) / 3);
158
54.3k
      FORCC
159
213k
      if (c != f)
160
160k
      {
161
160k
        *ip++ = c;
162
160k
        *ip++ = sum[c] > 0 ? 256 / sum[c] : 0;
163
160k
      }
164
54.3k
    }
165
213
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 1, 3);
166
213
  lin_interpolate_loop(code, size);
167
213
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 2, 3);
168
213
}
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
213
{
183
213
  static const signed char *cp,
184
213
      terms[] =
185
213
          {-2, -2, +0,   -1, 0,  0x01, -2, -2, +0,   +0, 1,  0x01, -2, -1, -1,
186
213
           +0, 0,  0x01, -2, -1, +0,   -1, 0,  0x02, -2, -1, +0,   +0, 0,  0x03,
187
213
           -2, -1, +0,   +1, 1,  0x01, -2, +0, +0,   -1, 0,  0x06, -2, +0, +0,
188
213
           +0, 1,  0x02, -2, +0, +0,   +1, 0,  0x03, -2, +1, -1,   +0, 0,  0x04,
189
213
           -2, +1, +0,   -1, 1,  0x04, -2, +1, +0,   +0, 0,  0x06, -2, +1, +0,
190
213
           +1, 0,  0x02, -2, +2, +0,   +0, 1,  0x04, -2, +2, +0,   +1, 0,  0x04,
191
213
           -1, -2, -1,   +0, 0,  -128, -1, -2, +0,   -1, 0,  0x01, -1, -2, +1,
192
213
           -1, 0,  0x01, -1, -2, +1,   +0, 1,  0x01, -1, -1, -1,   +1, 0,  -120,
193
213
           -1, -1, +1,   -2, 0,  0x40, -1, -1, +1,   -1, 0,  0x22, -1, -1, +1,
194
213
           +0, 0,  0x33, -1, -1, +1,   +1, 1,  0x11, -1, +0, -1,   +2, 0,  0x08,
195
213
           -1, +0, +0,   -1, 0,  0x44, -1, +0, +0,   +1, 0,  0x11, -1, +0, +1,
196
213
           -2, 1,  0x40, -1, +0, +1,   -1, 0,  0x66, -1, +0, +1,   +0, 1,  0x22,
197
213
           -1, +0, +1,   +1, 0,  0x33, -1, +0, +1,   +2, 1,  0x10, -1, +1, +1,
198
213
           -1, 1,  0x44, -1, +1, +1,   +0, 0,  0x66, -1, +1, +1,   +1, 0,  0x22,
199
213
           -1, +1, +1,   +2, 0,  0x10, -1, +2, +0,   +1, 0,  0x04, -1, +2, +1,
200
213
           +0, 1,  0x04, -1, +2, +1,   +1, 0,  0x04, +0, -2, +0,   +0, 1,  -128,
201
213
           +0, -1, +0,   +1, 1,  -120, +0, -1, +1,   -2, 0,  0x40, +0, -1, +1,
202
213
           +0, 0,  0x11, +0, -1, +2,   -2, 0,  0x40, +0, -1, +2,   -1, 0,  0x20,
203
213
           +0, -1, +2,   +0, 0,  0x30, +0, -1, +2,   +1, 1,  0x10, +0, +0, +0,
204
213
           +2, 1,  0x08, +0, +0, +2,   -2, 1,  0x40, +0, +0, +2,   -1, 0,  0x60,
205
213
           +0, +0, +2,   +0, 1,  0x20, +0, +0, +2,   +1, 0,  0x30, +0, +0, +2,
206
213
           +2, 1,  0x10, +0, +1, +1,   +0, 0,  0x44, +0, +1, +1,   +2, 0,  0x10,
207
213
           +0, +1, +2,   -1, 1,  0x40, +0, +1, +2,   +0, 0,  0x60, +0, +1, +2,
208
213
           +1, 0,  0x20, +0, +1, +2,   +2, 0,  0x10, +1, -2, +1,   +0, 0,  -128,
209
213
           +1, -1, +1,   +1, 0,  -120, +1, +0, +1,   +2, 0,  0x08, +1, +0, +2,
210
213
           -1, 0,  0x40, +1, +0, +2,   +1, 0,  0x10},
211
213
      chood[] = {-1, -1, -1, 0, -1, +1, 0, +1, +1, +1, +1, 0, +1, -1, 0, -1};
212
213
  ushort(*brow[5])[4], *pix;
213
213
  int prow = 8, pcol = 2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4];
214
213
  int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
215
213
  int g, diff, thold, num, c;
216
217
213
  lin_interpolate();
218
219
213
  if (filters == 1)
220
7
    prow = pcol = 16;
221
213
  if (filters == 9)
222
1
    prow = pcol = 6;
223
213
  ip = (int *)calloc(prow * pcol, 1280);
224
1.97k
  for (row = 0; row < prow; row++) /* Precalculate for VNG */
225
6.86k
    for (col = 0; col < pcol; col++)
226
5.10k
    {
227
5.10k
      code[row][col] = ip;
228
332k
      for (cp = terms, t = 0; t < 64; t++)
229
326k
      {
230
326k
        y1 = *cp++;
231
326k
        x1 = *cp++;
232
326k
        y2 = *cp++;
233
326k
        x2 = *cp++;
234
326k
        weight = *cp++;
235
326k
        grads = *cp++;
236
326k
        color = fcol(row + y1 + 144, col + x1 + 144);
237
326k
        if (fcol(row + y2 + 144, col + x2 + 144) != color)
238
183k
          continue;
239
143k
        diag = (fcol(row, col + 1) == color && fcol(row + 1, col) == color) ? 2
240
143k
                                                                            : 1;
241
143k
        if (abs(y1 - y2) == diag && abs(x1 - x2) == diag)
242
14.7k
          continue;
243
128k
        *ip++ = (y1 * width + x1) * 4 + color;
244
128k
        *ip++ = (y2 * width + x2) * 4 + color;
245
128k
        *ip++ = weight;
246
1.15M
        for (g = 0; g < 8; g++)
247
1.03M
          if (grads & 1 << g)
248
184k
            *ip++ = g;
249
128k
        *ip++ = -1;
250
128k
      }
251
5.10k
      *ip++ = INT_MAX;
252
45.9k
      for (cp = chood, g = 0; g < 8; g++)
253
40.8k
      {
254
40.8k
        y = *cp++;
255
40.8k
        x = *cp++;
256
40.8k
        *ip++ = (y * width + x) * 4;
257
40.8k
        color = fcol(row, col);
258
40.8k
        if (fcol(row + y + 144, col + x + 144) != color &&
259
31.7k
            fcol(row + y * 2 + 144, col + x * 2 + 144) == color)
260
18.6k
          *ip++ = (y * width + x) * 8 + color;
261
22.2k
        else
262
22.2k
          *ip++ = 0;
263
40.8k
      }
264
5.10k
    }
265
213
  brow[4] = (ushort(*)[4])calloc(width * 3, sizeof **brow);
266
852
  for (row = 0; row < 3; row++)
267
639
    brow[row] = brow[4] + row * width;
268
150k
  for (row = 2; row < height - 2; row++)
269
150k
  { /* Do VNG interpolation */
270
150k
    if (!((row - 2) % 256))
271
711
      RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, (row - 2) / 256 + 1,
272
150k
                   ((height - 3) / 256) + 1);
273
65.6M
    for (col = 2; col < width - 2; col++)
274
65.5M
    {
275
65.5M
      pix = image[row * width + col];
276
65.5M
      ip = code[row % prow][col % pcol];
277
65.5M
      memset(gval, 0, sizeof gval);
278
2.16G
      while ((g = ip[0]) != INT_MAX)
279
2.09G
      { /* Calculate gradients */
280
2.09G
        diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
281
2.09G
        gval[ip[3]] += diff;
282
2.09G
        ip += 5;
283
2.09G
        if ((g = ip[-1]) == -1)
284
1.38G
          continue;
285
711M
        gval[g] += diff;
286
858M
        while ((g = *ip++) != -1)
287
146M
          gval[g] += diff;
288
711M
      }
289
65.5M
      ip++;
290
65.5M
      gmin = gmax = gval[0]; /* Choose a threshold */
291
524M
      for (g = 1; g < 8; g++)
292
458M
      {
293
458M
        if (gmin > gval[g])
294
33.9M
          gmin = gval[g];
295
458M
        if (gmax < gval[g])
296
31.6M
          gmax = gval[g];
297
458M
      }
298
65.5M
      if (gmax == 0)
299
37.4M
      {
300
37.4M
        memcpy(brow[2][col], pix, sizeof *image);
301
37.4M
        continue;
302
37.4M
      }
303
28.0M
      thold = gmin + (gmax >> 1);
304
28.0M
      memset(sum, 0, sizeof sum);
305
28.0M
      color = fcol(row, col);
306
252M
      for (num = g = 0; g < 8; g++, ip += 2)
307
224M
      { /* Average the neighbors */
308
224M
        if (gval[g] <= thold)
309
137M
        {
310
137M
          FORCC
311
550M
          if (c == color && ip[1])
312
92.7M
            sum[c] += (pix[c] + pix[ip[1]]) >> 1;
313
457M
          else
314
457M
            sum[c] += pix[ip[0] + c];
315
137M
          num++;
316
137M
        }
317
224M
      }
318
28.0M
      FORCC
319
112M
      { /* Save to buffer */
320
112M
        t = pix[color];
321
112M
        if (c != color)
322
84.0M
          t += (sum[c] - sum[color]) / num;
323
112M
        brow[2][col][c] = CLIP(t);
324
112M
      }
325
28.0M
    }
326
150k
    if (row > 3) /* Write buffer to image */
327
149k
      memcpy(image[(row - 2) * width + 2], brow[0] + 2,
328
149k
             (width - 4) * sizeof *image);
329
751k
    for (g = 0; g < 4; g++)
330
601k
      brow[(g - 1) & 3] = brow[g];
331
150k
  }
332
213
  memcpy(image[(row - 2) * width + 2], brow[0] + 2,
333
213
         (width - 4) * sizeof *image);
334
213
  memcpy(image[(row - 1) * width + 2], brow[1] + 2,
335
213
         (width - 4) * sizeof *image);
336
213
  free(brow[4]);
337
213
  free(code[0][0]);
338
213
}
339
340
/*
341
   Patterned Pixel Grouping Interpolation by Alain Desbiolles
342
*/
343
void LibRaw::ppg_interpolate()
344
0
{
345
0
  int dir[5] = {1, width, -1, -width, 1};
346
0
  int row, col, diff[2], guess[2], c, d, i;
347
0
  ushort(*pix)[4];
348
349
0
  border_interpolate(3);
350
351
  /*  Fill in the green layer with gradients and pattern recognition: */
352
0
  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
0
  for (row = 3; row < height - 3; row++)
358
0
    for (col = 3 + (FC(row, 3) & 1), c = FC(row, col); col < width - 3;
359
0
         col += 2)
360
0
    {
361
0
      pix = image + row * width + col;
362
0
      for (i = 0; i < 2; i++)
363
0
      {
364
0
        d = dir[i];
365
0
        guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 - pix[-2 * d][c] -
366
0
                   pix[2 * d][c];
367
0
        diff[i] =
368
0
            (ABS(pix[-2 * d][c] - pix[0][c]) + ABS(pix[2 * d][c] - pix[0][c]) +
369
0
             ABS(pix[-d][1] - pix[d][1])) *
370
0
                3 +
371
0
            (ABS(pix[3 * d][1] - pix[d][1]) +
372
0
             ABS(pix[-3 * d][1] - pix[-d][1])) *
373
0
                2;
374
0
      }
375
0
      d = dir[i = diff[0] > diff[1]];
376
0
      pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]);
377
0
    }
378
  /*  Calculate red and blue for each green pixel:    */
379
0
  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
0
  for (row = 1; row < height - 1; row++)
385
0
    for (col = 1 + (FC(row, 2) & 1), c = FC(row, col + 1); col < width - 1;
386
0
         col += 2)
387
0
    {
388
0
      pix = image + row * width + col;
389
0
      for (i = 0; i < 2; c = 2 - c, i++)
390
0
      {
391
0
        d = dir[i];
392
0
        pix[0][c] = CLIP(
393
0
            (pix[-d][c] + pix[d][c] + 2 * pix[0][1] - pix[-d][1] - pix[d][1]) >>
394
0
            1);
395
0
      }
396
0
    }
397
  /*  Calculate blue for red pixels and vice versa:   */
398
0
  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
0
  for (row = 1; row < height - 1; row++)
404
0
    for (col = 1 + (FC(row, 1) & 1), c = 2 - FC(row, col); col < width - 1;
405
0
         col += 2)
406
0
    {
407
0
      pix = image + row * width + col;
408
0
      for (i = 0; i < 2; i++)
409
0
      {
410
0
        d = dir[i] + dir[i+1];
411
0
        diff[i] = ABS(pix[-d][c] - pix[d][c]) + ABS(pix[-d][1] - pix[0][1]) +
412
0
                  ABS(pix[d][1] - pix[0][1]);
413
0
        guess[i] =
414
0
            pix[-d][c] + pix[d][c] + 2 * pix[0][1] - pix[-d][1] - pix[d][1];
415
0
      }
416
0
      if (diff[0] != diff[1])
417
0
        pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1);
418
0
      else
419
0
        pix[0][c] = CLIP((guess[0] + guess[1]) >> 2);
420
0
    }
421
0
}