Coverage Report

Created: 2025-09-08 07:52

/src/LibRaw/src/demosaic/misc_demosaic.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- C++ -*-
2
 * Copyright 2019-2024 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.05k
{
23
2.05k
  ushort(*img)[4];
24
2.05k
  int row, col, c;
25
2.05k
  RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 0, 2);
26
2.05k
  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.05k
  if (filters > 1000 && colors == 3)
65
1.38k
  {
66
1.38k
    mix_green = four_color_rgb ^ half_size;
67
1.38k
    if (four_color_rgb | half_size)
68
0
      colors++;
69
1.38k
    else
70
1.38k
    {
71
851k
      for (row = FC(1, 0) >> 1; row < height; row += 2)
72
157M
        for (col = FC(row, 1) & 1; col < width; col += 2)
73
157M
          image[row * width + col][1] = image[row * width + col][3];
74
1.38k
      filters &= ~((filters & 0x55555555U) << 1);
75
1.38k
    }
76
1.38k
  }
77
2.05k
  if (half_size)
78
0
    filters = 0;
79
2.05k
  RUN_CALLBACK(LIBRAW_PROGRESS_PRE_INTERPOLATE, 1, 2);
80
2.05k
}
81
82
void LibRaw::border_interpolate(int border)
83
1.70k
{
84
1.70k
  unsigned row, col, y, x, f, c, sum[8];
85
86
2.16M
  for (row = 0; row < height; row++)
87
50.1M
    for (col = 0; col < width; col++)
88
47.9M
    {
89
47.9M
      if (col == (unsigned)border && row >= (unsigned)border && row < (unsigned)(height - border))
90
2.15M
        col = width - border;
91
47.9M
      memset(sum, 0, sizeof sum);
92
191M
      for (y = row - 1; y != row + 2; y++)
93
575M
        for (x = col - 1; x != col + 2; x++)
94
431M
          if (y < height && x < width)
95
400M
          {
96
400M
            f = fcol(y, x);
97
400M
            sum[f] += image[y * width + x][f];
98
400M
            sum[f + 4]++;
99
400M
          }
100
47.9M
      f = fcol(row, col);
101
144M
      FORC(unsigned(colors)) if (c != f && sum[c + 4]) image[row * width + col][c] =
102
95.6M
          sum[c] / sum[c + 4];
103
47.9M
    }
104
1.70k
}
105
106
void LibRaw::lin_interpolate_loop(int *code, int size)
107
306
{
108
306
  int row;
109
457k
  for (row = 1; row < height - 1; row++)
110
457k
  {
111
457k
    int col, *ip;
112
457k
    ushort *pix;
113
93.2M
    for (col = 1; col < width - 1; col++)
114
92.7M
    {
115
92.7M
      int i;
116
92.7M
      int sum[4];
117
92.7M
      pix = image[row * width + col];
118
92.7M
      ip = code + ((((row % size) * 16) + (col % size)) * 32);
119
92.7M
      memset(sum, 0, sizeof sum);
120
682M
      for (i = *ip++; i--; ip += 3)
121
589M
        sum[ip[2]] += pix[ip[0]] << ip[1];
122
369M
      for (i = colors; --i; ip += 2)
123
277M
        pix[ip[0]] = sum[ip[0]] * ip[1] >> 8;
124
92.7M
    }
125
457k
  }
126
306
}
127
128
void LibRaw::lin_interpolate()
129
306
{
130
306
  std::vector<int> code_buffer(16 * 16 * 32);
131
306
  int* code = &code_buffer[0], size = 16, *ip, sum[4];
132
306
  int f, c, x, y, row, col, shift, color;
133
134
306
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 0, 3);
135
136
306
  if (filters == 9)
137
18
    size = 6;
138
306
  border_interpolate(1);
139
5.02k
  for (row = 0; row < size; row++)
140
79.0k
    for (col = 0; col < size; col++)
141
74.3k
    {
142
74.3k
      ip = code + (((row * 16) + col) * 32) + 1;
143
74.3k
      f = fcol(row, col);
144
74.3k
      memset(sum, 0, sizeof sum);
145
297k
      for (y = -1; y <= 1; y++)
146
892k
        for (x = -1; x <= 1; x++)
147
669k
        {
148
669k
          shift = (y == 0) + (x == 0);
149
669k
          color = fcol(row + y + 48, col + x + 48);
150
669k
          if (color == f)
151
236k
            continue;
152
432k
          *ip++ = (width * y + x) * 4 + color;
153
432k
          *ip++ = shift;
154
432k
          *ip++ = color;
155
432k
          sum[color] += 1 << shift;
156
432k
        }
157
74.3k
      code[(row * 16 + col) * 32] = int((ip - (code + ((row * 16) + col) * 32)) / 3);
158
74.3k
      FORCC
159
290k
      if (c != f)
160
216k
      {
161
216k
        *ip++ = c;
162
216k
        *ip++ = sum[c] > 0 ? 256 / sum[c] : 0;
163
216k
      }
164
74.3k
    }
165
306
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 1, 3);
166
306
  lin_interpolate_loop(code, size);
167
306
  RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, 2, 3);
168
306
}
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
306
{
183
306
  static const signed char *cp,
184
306
      terms[] =
185
306
          {-2, -2, +0,   -1, 0,  0x01, -2, -2, +0,   +0, 1,  0x01, -2, -1, -1,
186
306
           +0, 0,  0x01, -2, -1, +0,   -1, 0,  0x02, -2, -1, +0,   +0, 0,  0x03,
187
306
           -2, -1, +0,   +1, 1,  0x01, -2, +0, +0,   -1, 0,  0x06, -2, +0, +0,
188
306
           +0, 1,  0x02, -2, +0, +0,   +1, 0,  0x03, -2, +1, -1,   +0, 0,  0x04,
189
306
           -2, +1, +0,   -1, 1,  0x04, -2, +1, +0,   +0, 0,  0x06, -2, +1, +0,
190
306
           +1, 0,  0x02, -2, +2, +0,   +0, 1,  0x04, -2, +2, +0,   +1, 0,  0x04,
191
306
           -1, -2, -1,   +0, 0,  -128, -1, -2, +0,   -1, 0,  0x01, -1, -2, +1,
192
306
           -1, 0,  0x01, -1, -2, +1,   +0, 1,  0x01, -1, -1, -1,   +1, 0,  -120,
193
306
           -1, -1, +1,   -2, 0,  0x40, -1, -1, +1,   -1, 0,  0x22, -1, -1, +1,
194
306
           +0, 0,  0x33, -1, -1, +1,   +1, 1,  0x11, -1, +0, -1,   +2, 0,  0x08,
195
306
           -1, +0, +0,   -1, 0,  0x44, -1, +0, +0,   +1, 0,  0x11, -1, +0, +1,
196
306
           -2, 1,  0x40, -1, +0, +1,   -1, 0,  0x66, -1, +0, +1,   +0, 1,  0x22,
197
306
           -1, +0, +1,   +1, 0,  0x33, -1, +0, +1,   +2, 1,  0x10, -1, +1, +1,
198
306
           -1, 1,  0x44, -1, +1, +1,   +0, 0,  0x66, -1, +1, +1,   +1, 0,  0x22,
199
306
           -1, +1, +1,   +2, 0,  0x10, -1, +2, +0,   +1, 0,  0x04, -1, +2, +1,
200
306
           +0, 1,  0x04, -1, +2, +1,   +1, 0,  0x04, +0, -2, +0,   +0, 1,  -128,
201
306
           +0, -1, +0,   +1, 1,  -120, +0, -1, +1,   -2, 0,  0x40, +0, -1, +1,
202
306
           +0, 0,  0x11, +0, -1, +2,   -2, 0,  0x40, +0, -1, +2,   -1, 0,  0x20,
203
306
           +0, -1, +2,   +0, 0,  0x30, +0, -1, +2,   +1, 1,  0x10, +0, +0, +0,
204
306
           +2, 1,  0x08, +0, +0, +2,   -2, 1,  0x40, +0, +0, +2,   -1, 0,  0x60,
205
306
           +0, +0, +2,   +0, 1,  0x20, +0, +0, +2,   +1, 0,  0x30, +0, +0, +2,
206
306
           +2, 1,  0x10, +0, +1, +1,   +0, 0,  0x44, +0, +1, +1,   +2, 0,  0x10,
207
306
           +0, +1, +2,   -1, 1,  0x40, +0, +1, +2,   +0, 0,  0x60, +0, +1, +2,
208
306
           +1, 0,  0x20, +0, +1, +2,   +2, 0,  0x10, +1, -2, +1,   +0, 0,  -128,
209
306
           +1, -1, +1,   +1, 0,  -120, +1, +0, +1,   +2, 0,  0x08, +1, +0, +2,
210
306
           -1, 0,  0x40, +1, +0, +2,   +1, 0,  0x10},
211
306
      chood[] = {-1, -1, -1, 0, -1, +1, 0, +1, +1, +1, +1, 0, +1, -1, 0, -1};
212
306
  ushort(*brow[5])[4], *pix;
213
306
  int prow = 8, pcol = 2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4];
214
306
  int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag;
215
306
  int g, diff, thold, num, c;
216
217
306
  lin_interpolate();
218
219
306
  if (filters == 1)
220
12
    prow = pcol = 16;
221
306
  if (filters == 9)
222
18
    prow = pcol = 6;
223
306
  ip = (int *)calloc(prow * pcol, 1280);
224
2.81k
  for (row = 0; row < prow; row++) /* Precalculate for VNG */
225
10.6k
    for (col = 0; col < pcol; col++)
226
8.13k
    {
227
8.13k
      code[row][col] = ip;
228
528k
      for (cp = terms, t = 0; t < 64; t++)
229
520k
      {
230
520k
        y1 = *cp++;
231
520k
        x1 = *cp++;
232
520k
        y2 = *cp++;
233
520k
        x2 = *cp++;
234
520k
        weight = *cp++;
235
520k
        grads = *cp++;
236
520k
        color = fcol(row + y1 + 144, col + x1 + 144);
237
520k
        if (fcol(row + y2 + 144, col + x2 + 144) != color)
238
307k
          continue;
239
213k
        diag = (fcol(row, col + 1) == color && fcol(row + 1, col) == color) ? 2
240
213k
                                                                            : 1;
241
213k
        if (abs(y1 - y2) == diag && abs(x1 - x2) == diag)
242
23.6k
          continue;
243
189k
        *ip++ = (y1 * width + x1) * 4 + color;
244
189k
        *ip++ = (y2 * width + x2) * 4 + color;
245
189k
        *ip++ = weight;
246
1.70M
        for (g = 0; g < 8; g++)
247
1.51M
          if (grads & 1 << g)
248
277k
            *ip++ = g;
249
189k
        *ip++ = -1;
250
189k
      }
251
8.13k
      *ip++ = INT_MAX;
252
73.2k
      for (cp = chood, g = 0; g < 8; g++)
253
65.0k
      {
254
65.0k
        y = *cp++;
255
65.0k
        x = *cp++;
256
65.0k
        *ip++ = (y * width + x) * 4;
257
65.0k
        color = fcol(row, col);
258
65.0k
        if (fcol(row + y + 144, col + x + 144) != color &&
259
65.0k
            fcol(row + y * 2 + 144, col + x * 2 + 144) == color)
260
25.0k
          *ip++ = (y * width + x) * 8 + color;
261
40.0k
        else
262
40.0k
          *ip++ = 0;
263
65.0k
      }
264
8.13k
    }
265
306
  brow[4] = (ushort(*)[4])calloc(width * 3, sizeof **brow);
266
1.22k
  for (row = 0; row < 3; row++)
267
918
    brow[row] = brow[4] + row * width;
268
456k
  for (row = 2; row < height - 2; row++)
269
456k
  { /* Do VNG interpolation */
270
456k
    if (!((row - 2) % 256))
271
1.96k
      RUN_CALLBACK(LIBRAW_PROGRESS_INTERPOLATE, (row - 2) / 256 + 1,
272
456k
                   ((height - 3) / 256) + 1);
273
91.9M
    for (col = 2; col < width - 2; col++)
274
91.5M
    {
275
91.5M
      pix = image[row * width + col];
276
91.5M
      ip = code[row % prow][col % pcol];
277
91.5M
      memset(gval, 0, sizeof gval);
278
2.80G
      while ((g = ip[0]) != INT_MAX)
279
2.71G
      { /* Calculate gradients */
280
2.71G
        diff = ABS(pix[g] - pix[ip[1]]) << ip[2];
281
2.71G
        gval[ip[3]] += diff;
282
2.71G
        ip += 5;
283
2.71G
        if ((g = ip[-1]) == -1)
284
1.74G
          continue;
285
970M
        gval[g] += diff;
286
1.20G
        while ((g = *ip++) != -1)
287
234M
          gval[g] += diff;
288
970M
      }
289
91.5M
      ip++;
290
91.5M
      gmin = gmax = gval[0]; /* Choose a threshold */
291
732M
      for (g = 1; g < 8; g++)
292
640M
      {
293
640M
        if (gmin > gval[g])
294
51.2M
          gmin = gval[g];
295
640M
        if (gmax < gval[g])
296
53.0M
          gmax = gval[g];
297
640M
      }
298
91.5M
      if (gmax == 0)
299
51.6M
      {
300
51.6M
        memcpy(brow[2][col], pix, sizeof *image);
301
51.6M
        continue;
302
51.6M
      }
303
39.9M
      thold = gmin + (gmax >> 1);
304
39.9M
      memset(sum, 0, sizeof sum);
305
39.9M
      color = fcol(row, col);
306
359M
      for (num = g = 0; g < 8; g++, ip += 2)
307
319M
      { /* Average the neighbors */
308
319M
        if (gval[g] <= thold)
309
193M
        {
310
193M
          FORCC
311
773M
          if (c == color && ip[1])
312
106M
            sum[c] += (pix[c] + pix[ip[1]]) >> 1;
313
667M
          else
314
667M
            sum[c] += pix[ip[0] + c];
315
193M
          num++;
316
193M
        }
317
319M
      }
318
39.9M
      FORCC
319
159M
      { /* Save to buffer */
320
159M
        t = pix[color];
321
159M
        if (c != color)
322
119M
          t += (sum[c] - sum[color]) / num;
323
159M
        brow[2][col][c] = CLIP(t);
324
159M
      }
325
39.9M
    }
326
456k
    if (row > 3) /* Write buffer to image */
327
455k
      memcpy(image[(row - 2) * width + 2], brow[0] + 2,
328
455k
             (width - 4) * sizeof *image);
329
2.28M
    for (g = 0; g < 4; g++)
330
1.82M
      brow[(g - 1) & 3] = brow[g];
331
456k
  }
332
306
  memcpy(image[(row - 2) * width + 2], brow[0] + 2,
333
306
         (width - 4) * sizeof *image);
334
306
  memcpy(image[(row - 1) * width + 2], brow[1] + 2,
335
306
         (width - 4) * sizeof *image);
336
306
  free(brow[4]);
337
306
  free(code[0][0]);
338
306
}
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
}