Coverage Report

Created: 2026-07-25 07:03

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
2.24k
{
23
2.24k
  ushort(*img)[4];
24
2.24k
  int row, col, c;
25
2.24k
  RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 0, 2);
26
2.24k
  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
2.24k
  if (filters > 1000 && colors == 3)
65
1.49k
  {
66
1.49k
    mix_green = four_color_rgb ^ half_size;
67
1.49k
    if (four_color_rgb | half_size)
68
0
      colors++;
69
1.49k
    else
70
1.49k
    {
71
975k
      for (row = FC(1, 0) >> 1; row < height; row += 2)
72
129M
        for (col = FC(row, 1) & 1; col < width; col += 2)
73
128M
          image[row * width + col][1] = image[row * width + col][3];
74
1.49k
      filters &= ~((filters & 0x55555555U) << 1);
75
1.49k
    }
76
1.49k
  }
77
2.24k
  if (half_size)
78
0
    filters = 0;
79
2.24k
  RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 1, 2);
80
2.24k
}
81
82
void LibRaw::border_interpolate(int border)
83
1.72k
{
84
1.72k
  unsigned row, col, y, x, f, c, sum[8];
85
86
2.14M
  for (row = 0; row < height; row++)
87
43.6M
    for (col = 0; col < width; col++)
88
41.5M
    {
89
41.5M
      if (col == (unsigned)border && row >= (unsigned)border && row < (unsigned)(height - border))
90
2.13M
        col = width - border;
91
41.5M
      memset(sum, 0, sizeof sum);
92
166M
      for (y = row - 1; y != row + 2; y++)
93
498M
        for (x = col - 1; x != col + 2; x++)
94
373M
          if (y < height && x < width)
95
345M
          {
96
345M
            f = fcol(y, x);
97
345M
            sum[f] += image[y * width + x][f];
98
345M
            sum[f + 4]++;
99
345M
          }
100
41.5M
      f = fcol(row, col);
101
125M
      FORC(unsigned(colors)) if (c != f && sum[c + 4]) image[row * width + col][c] =
102
82.9M
          sum[c] / sum[c + 4];
103
41.5M
    }
104
1.72k
}
105
106
void LibRaw::lin_interpolate_loop(int *code, int size)
107
259
{
108
259
  int row;
109
245k
  for (row = 1; row < height - 1; row++)
110
245k
  {
111
245k
    int col, *ip;
112
245k
    ushort *pix;
113
79.3M
    for (col = 1; col < width - 1; col++)
114
79.0M
    {
115
79.0M
      int i;
116
79.0M
      int sum[4];
117
79.0M
      pix = image[row * width + col];
118
79.0M
      ip = code + ((((row % size) * 16) + (col % size)) * 32);
119
79.0M
      memset(sum, 0, sizeof sum);
120
578M
      for (i = *ip++; i--; ip += 3)
121
499M
        sum[ip[2]] += pix[ip[0]] << ip[1];
122
299M
      for (i = colors; --i; ip += 2)
123
220M
        pix[ip[0]] = sum[ip[0]] * ip[1] >> 8;
124
79.0M
    }
125
245k
  }
126
259
}
127
128
void LibRaw::lin_interpolate()
129
259
{
130
259
  std::vector<int> code_buffer(16 * 16 * 32);
131
259
  int* code = &code_buffer[0], size = 16, *ip, sum[4];
132
259
  int f, c, x, y, row, col, shift, color;
133
134
259
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 0, 3);
135
136
259
  if (filters == 9)
137
8
    size = 6;
138
259
  border_interpolate(1);
139
4.32k
  for (row = 0; row < size; row++)
140
68.6k
    for (col = 0; col < size; col++)
141
64.5k
    {
142
64.5k
      ip = code + (((row * 16) + col) * 32) + 1;
143
64.5k
      f = fcol(row, col);
144
64.5k
      memset(sum, 0, sizeof sum);
145
258k
      for (y = -1; y <= 1; y++)
146
774k
        for (x = -1; x <= 1; x++)
147
580k
        {
148
580k
          shift = (y == 0) + (x == 0);
149
580k
          color = fcol(row + y + 48, col + x + 48);
150
580k
          if (color == f)
151
225k
            continue;
152
355k
          *ip++ = (width * y + x) * 4 + color;
153
355k
          *ip++ = shift;
154
355k
          *ip++ = color;
155
355k
          sum[color] += 1 << shift;
156
355k
        }
157
64.5k
      code[(row * 16 + col) * 32] = int((ip - (code + ((row * 16) + col) * 32)) / 3);
158
64.5k
      FORCC
159
234k
      if (c != f)
160
172k
      {
161
172k
        *ip++ = c;
162
172k
        *ip++ = sum[c] > 0 ? 256 / sum[c] : 0;
163
172k
      }
164
64.5k
    }
165
259
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 1, 3);
166
259
  lin_interpolate_loop(code, size);
167
259
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 2, 3);
168
259
}
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
259
{
183
259
  static const signed char *cp,
184
259
      terms[] =
185
259
          {-2, -2, +0,   -1, 0,  0x01, -2, -2, +0,   +0, 1,  0x01, -2, -1, -1,
186
259
           +0, 0,  0x01, -2, -1, +0,   -1, 0,  0x02, -2, -1, +0,   +0, 0,  0x03,
187
259
           -2, -1, +0,   +1, 1,  0x01, -2, +0, +0,   -1, 0,  0x06, -2, +0, +0,
188
259
           +0, 1,  0x02, -2, +0, +0,   +1, 0,  0x03, -2, +1, -1,   +0, 0,  0x04,
189
259
           -2, +1, +0,   -1, 1,  0x04, -2, +1, +0,   +0, 0,  0x06, -2, +1, +0,
190
259
           +1, 0,  0x02, -2, +2, +0,   +0, 1,  0x04, -2, +2, +0,   +1, 0,  0x04,
191
259
           -1, -2, -1,   +0, 0,  -128, -1, -2, +0,   -1, 0,  0x01, -1, -2, +1,
192
259
           -1, 0,  0x01, -1, -2, +1,   +0, 1,  0x01, -1, -1, -1,   +1, 0,  -120,
193
259
           -1, -1, +1,   -2, 0,  0x40, -1, -1, +1,   -1, 0,  0x22, -1, -1, +1,
194
259
           +0, 0,  0x33, -1, -1, +1,   +1, 1,  0x11, -1, +0, -1,   +2, 0,  0x08,
195
259
           -1, +0, +0,   -1, 0,  0x44, -1, +0, +0,   +1, 0,  0x11, -1, +0, +1,
196
259
           -2, 1,  0x40, -1, +0, +1,   -1, 0,  0x66, -1, +0, +1,   +0, 1,  0x22,
197
259
           -1, +0, +1,   +1, 0,  0x33, -1, +0, +1,   +2, 1,  0x10, -1, +1, +1,
198
259
           -1, 1,  0x44, -1, +1, +1,   +0, 0,  0x66, -1, +1, +1,   +1, 0,  0x22,
199
259
           -1, +1, +1,   +2, 0,  0x10, -1, +2, +0,   +1, 0,  0x04, -1, +2, +1,
200
259
           +0, 1,  0x04, -1, +2, +1,   +1, 0,  0x04, +0, -2, +0,   +0, 1,  -128,
201
259
           +0, -1, +0,   +1, 1,  -120, +0, -1, +1,   -2, 0,  0x40, +0, -1, +1,
202
259
           +0, 0,  0x11, +0, -1, +2,   -2, 0,  0x40, +0, -1, +2,   -1, 0,  0x20,
203
259
           +0, -1, +2,   +0, 0,  0x30, +0, -1, +2,   +1, 1,  0x10, +0, +0, +0,
204
259
           +2, 1,  0x08, +0, +0, +2,   -2, 1,  0x40, +0, +0, +2,   -1, 0,  0x60,
205
259
           +0, +0, +2,   +0, 1,  0x20, +0, +0, +2,   +1, 0,  0x30, +0, +0, +2,
206
259
           +2, 1,  0x10, +0, +1, +1,   +0, 0,  0x44, +0, +1, +1,   +2, 0,  0x10,
207
259
           +0, +1, +2,   -1, 1,  0x40, +0, +1, +2,   +0, 0,  0x60, +0, +1, +2,
208
259
           +1, 0,  0x20, +0, +1, +2,   +2, 0,  0x10, +1, -2, +1,   +0, 0,  -128,
209
259
           +1, -1, +1,   +1, 0,  -120, +1, +0, +1,   +2, 0,  0x08, +1, +0, +2,
210
259
           -1, 0,  0x40, +1, +0, +2,   +1, 0,  0x10},
211
259
      chood[] = {-1, -1, -1, 0, -1, +1, 0, +1, +1, +1, +1, 0, +1, -1, 0, -1};
212
259
  ushort(*brow[5])[4], *pix;
213
259
  int prow = 8, pcol = 2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4];
214
259
  int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
215
259
  int g, diff, thold, num, c;
216
217
259
  if (width < 8 || height < 8) return;  // skip interploation on too small images
218
219
259
  lin_interpolate();
220
221
259
  if (filters == 1)
222
12
    prow = pcol = 16;
223
259
  if (filters == 9)
224
8
    prow = pcol = 6;
225
259
  ip = (int *)calloc(prow * pcol, 1280);
226
2.41k
  for (row = 0; row < prow; row++) /* Precalculate for VNG */
227
9.33k
    for (col = 0; col < pcol; col++)
228
7.18k
    {
229
7.18k
      code[row][col] = ip;
230
466k
      for (cp = terms, t = 0; t < 64; t++)
231
459k
      {
232
459k
        y1 = *cp++;
233
459k
        x1 = *cp++;
234
459k
        y2 = *cp++;
235
459k
        x2 = *cp++;
236
459k
        weight = *cp++;
237
459k
        grads = *cp++;
238
459k
        color = fcol(row + y1 + 144, col + x1 + 144);
239
459k
        if (fcol(row + y2 + 144, col + x2 + 144) != color)
240
267k
          continue;
241
192k
        diag = (fcol(row, col + 1) == color && fcol(row + 1, col) == color) ? 2
242
192k
                                                                            : 1;
243
192k
        if (abs(y1 - y2) == diag && abs(x1 - x2) == diag)
244
22.1k
          continue;
245
169k
        *ip++ = (y1 * width + x1) * 4 + color;
246
169k
        *ip++ = (y2 * width + x2) * 4 + color;
247
169k
        *ip++ = weight;
248
1.52M
        for (g = 0; g < 8; g++)
249
1.35M
          if (grads & 1 << g)
250
250k
            *ip++ = g;
251
169k
        *ip++ = -1;
252
169k
      }
253
7.18k
      *ip++ = INT_MAX;
254
64.6k
      for (cp = chood, g = 0; g < 8; g++)
255
57.4k
      {
256
57.4k
        y = *cp++;
257
57.4k
        x = *cp++;
258
57.4k
        *ip++ = (y * width + x) * 4;
259
57.4k
        color = fcol(row, col);
260
57.4k
        if (fcol(row + y + 144, col + x + 144) != color &&
261
43.0k
            fcol(row + y * 2 + 144, col + x * 2 + 144) == color)
262
21.2k
          *ip++ = (y * width + x) * 8 + color;
263
36.2k
        else
264
36.2k
          *ip++ = 0;
265
57.4k
      }
266
7.18k
    }
267
259
  brow[4] = (ushort(*)[4])calloc(width * 3, sizeof **brow);
268
1.03k
  for (row = 0; row < 3; row++)
269
777
    brow[row] = brow[4] + row * width;
270
244k
  for (row = 2; row < height - 2; row++)
271
244k
  { /* Do VNG interpolation */
272
244k
    if (!((row - 2) % 256))
273
1.10k
      RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, (row - 2) / 256 + 1,
274
244k
                   ((height - 3) / 256) + 1);
275
78.1M
    for (col = 2; col < width - 2; col++)
276
77.9M
    {
277
77.9M
      pix = image[row * width + col];
278
77.9M
      ip = code[row % prow][col % pcol];
279
77.9M
      memset(gval, 0, sizeof gval);
280
2.51G
      while ((g = ip[0]) != INT_MAX)
281
2.43G
      { /* Calculate gradients */
282
2.43G
        diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
283
2.43G
        gval[ip[3]] += diff;
284
2.43G
        ip += 5;
285
2.43G
        if ((g = ip[-1]) == -1)
286
1.57G
          continue;
287
857M
        gval[g] += diff;
288
1.07G
        while ((g = *ip++) != -1)
289
218M
          gval[g] += diff;
290
857M
      }
291
77.9M
      ip++;
292
77.9M
      gmin = gmax = gval[0]; /* Choose a threshold */
293
623M
      for (g = 1; g < 8; g++)
294
545M
      {
295
545M
        if (gmin > gval[g])
296
42.7M
          gmin = gval[g];
297
545M
        if (gmax < gval[g])
298
46.5M
          gmax = gval[g];
299
545M
      }
300
77.9M
      if (gmax == 0)
301
42.2M
      {
302
42.2M
        memcpy(brow[2][col], pix, sizeof *image);
303
42.2M
        continue;
304
42.2M
      }
305
35.6M
      thold = gmin + (gmax >> 1);
306
35.6M
      memset(sum, 0, sizeof sum);
307
35.6M
      color = fcol(row, col);
308
320M
      for (num = g = 0; g < 8; g++, ip += 2)
309
285M
      { /* Average the neighbors */
310
285M
        if (gval[g] <= thold)
311
180M
        {
312
180M
          FORCC
313
712M
          if (c == color && ip[1])
314
119M
            sum[c] += (pix[c] + pix[ip[1]]) >> 1;
315
593M
          else
316
593M
            sum[c] += pix[ip[0] + c];
317
180M
          num++;
318
180M
        }
319
285M
      }
320
35.6M
      FORCC
321
139M
      { /* Save to buffer */
322
139M
        t = pix[color];
323
139M
        if (c != color)
324
104M
          t += (sum[c] - sum[color]) / num;
325
139M
        brow[2][col][c] = CLIP(t);
326
139M
      }
327
35.6M
    }
328
244k
    if (row > 3) /* Write buffer to image */
329
244k
      memcpy(image[(row - 2) * width + 2], brow[0] + 2,
330
244k
             (width - 4) * sizeof *image);
331
1.22M
    for (g = 0; g < 4; g++)
332
978k
      brow[(g - 1) & 3] = brow[g];
333
244k
  }
334
259
  memcpy(image[(row - 2) * width + 2], brow[0] + 2,
335
259
         (width - 4) * sizeof *image);
336
259
  memcpy(image[(row - 1) * width + 2], brow[1] + 2,
337
259
         (width - 4) * sizeof *image);
338
259
  free(brow[4]);
339
259
  free(code[0][0]);
340
259
}
341
342
/*
343
   Patterned Pixel Grouping Interpolation by Alain Desbiolles
344
*/
345
void LibRaw::ppg_interpolate()
346
0
{
347
0
  int dir[5] = {1, width, -1, -width, 1};
348
0
  int row, col, diff[2], guess[2], c, d, i;
349
0
  ushort(*pix)[4];
350
351
0
  border_interpolate(3);
352
353
  /*  Fill in the green layer with gradients and pattern recognition: */
354
0
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 0, 3);
355
#ifdef LIBRAW_USE_OPENMP
356
#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c,  \
357
                                                 i, pix) schedule(static)
358
#endif
359
0
  for (row = 3; row < height - 3; row++)
360
0
    for (col = 3 + (FC(row, 3) & 1), c = FC(row, col); col < width - 3;
361
0
         col += 2)
362
0
    {
363
0
      pix = image + row * width + col;
364
0
      for (i = 0; i < 2; i++)
365
0
      {
366
0
        d = dir[i];
367
0
        guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 - pix[-2 * d][c] -
368
0
                   pix[2 * d][c];
369
0
        diff[i] =
370
0
            (ABS(pix[-2 * d][c] - pix[0][c]) + ABS(pix[2 * d][c] - pix[0][c]) +
371
0
             ABS(pix[-d][1] - pix[d][1])) *
372
0
                3 +
373
0
            (ABS(pix[3 * d][1] - pix[d][1]) +
374
0
             ABS(pix[-3 * d][1] - pix[-d][1])) *
375
0
                2;
376
0
      }
377
0
      d = dir[i = diff[0] > diff[1]];
378
0
      pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]);
379
0
    }
380
  /*  Calculate red and blue for each green pixel:    */
381
0
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 1, 3);
382
#ifdef LIBRAW_USE_OPENMP
383
#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c,  \
384
                                                 i, pix) schedule(static)
385
#endif
386
0
  for (row = 1; row < height - 1; row++)
387
0
    for (col = 1 + (FC(row, 2) & 1), c = FC(row, col + 1); col < width - 1;
388
0
         col += 2)
389
0
    {
390
0
      pix = image + row * width + col;
391
0
      for (i = 0; i < 2; c = 2 - c, i++)
392
0
      {
393
0
        d = dir[i];
394
0
        pix[0][c] = CLIP(
395
0
            (pix[-d][c] + pix[d][c] + 2 * pix[0][1] - pix[-d][1] - pix[d][1]) >>
396
0
            1);
397
0
      }
398
0
    }
399
  /*  Calculate blue for red pixels and vice versa:   */
400
0
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 2, 3);
401
#ifdef LIBRAW_USE_OPENMP
402
#pragma omp parallel for default(shared) private(guess, diff, row, col, d, c,  \
403
                                                 i, pix) schedule(static)
404
#endif
405
0
  for (row = 1; row < height - 1; row++)
406
0
    for (col = 1 + (FC(row, 1) & 1), c = 2 - FC(row, col); col < width - 1;
407
0
         col += 2)
408
0
    {
409
0
      pix = image + row * width + col;
410
0
      for (i = 0; i < 2; i++)
411
0
      {
412
0
        d = dir[i] + dir[i+1];
413
0
        diff[i] = ABS(pix[-d][c] - pix[d][c]) + ABS(pix[-d][1] - pix[0][1]) +
414
0
                  ABS(pix[d][1] - pix[0][1]);
415
0
        guess[i] =
416
0
            pix[-d][c] + pix[d][c] + 2 * pix[0][1] - pix[-d][1] - pix[d][1];
417
0
      }
418
0
      if (diff[0] != diff[1])
419
0
        pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1);
420
0
      else
421
0
        pix[0][c] = CLIP((guess[0] + guess[1]) >> 2);
422
0
    }
423
0
}