Coverage Report

Created: 2026-10-27 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/LibRaw/src/demosaic/xtrans_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
472M
#define fcol(row, col) xtrans[(row + 6) % 6][(col + 6) % 6]
22
/*
23
   Frank Markesteijn's algorithm for Fuji X-Trans sensors
24
 */
25
void LibRaw::xtrans_interpolate(int passes)
26
84
{
27
84
  int cstat[4] = {0, 0, 0, 0};
28
84
  int ndir;
29
84
  static const short orth[12] = {1, 0, 0, 1, -1, 0, 0, -1, 1, 0, 0, 1},
30
84
                     patt[2][16] = {{0, 1, 0, -1, 2, 0, -1, 0, 1, 1, 1, -1, 0,
31
84
                                     0, 0, 0},
32
84
                                    {0, 1, 0, -2, 1, 0, -2, 0, 1, 1, -2, -2, 1,
33
84
                                     -1, -1, 1}},
34
84
                     dir[4] = {1, LIBRAW_AHD_TILE, LIBRAW_AHD_TILE + 1,
35
84
                               LIBRAW_AHD_TILE - 1};
36
84
  short allhex[3][3][2][8];
37
84
  ushort sgrow = 0, sgcol = 0;
38
39
84
  if (width < LIBRAW_AHD_TILE || height < LIBRAW_AHD_TILE || filters != 9)
40
10
    throw LIBRAW_EXCEPTION_IO_CORRUPT; // too small image
41
                                       /* Check against right pattern */
42
518
  for (int row = 0; row < 6; row++)
43
3.10k
    for (int col = 0; col < 6; col++)
44
2.66k
      cstat[(unsigned)fcol(row, col)]++;
45
46
74
  if (cstat[0] < 6 || cstat[0] > 10 || cstat[1] < 16 || cstat[1] > 24 ||
47
69
      cstat[2] < 6 || cstat[2] > 10 || cstat[3])
48
8
    throw LIBRAW_EXCEPTION_IO_CORRUPT;
49
50
  // Init allhex table to unreasonable values
51
264
  for (int i = 0; i < 3; i++)
52
792
    for (int j = 0; j < 3; j++)
53
1.78k
      for (int k = 0; k < 2; k++)
54
10.6k
        for (int l = 0; l < 8; l++)
55
9.50k
          allhex[i][j][k][l] = 32700;
56
57
66
  cielab(0, 0);
58
66
  ndir = 4 << int(passes > 1);
59
60
66
  int minv = 0, maxv = 0, minh = 0, maxh = 0;
61
  /* Map a green hexagon around each non-green pixel and vice versa:  */
62
264
  for (int row = 0; row < 3; row++)
63
792
    for (int col = 0; col < 3; col++)
64
3.56k
      for (int ng = 0, d = 0; d < 10; d += 2)
65
2.97k
      {
66
2.97k
        int g = fcol(row, col) == 1;
67
2.97k
        if (fcol(row + orth[d], col + orth[d + 2]) == 1)
68
1.94k
          ng = 0;
69
1.02k
        else
70
1.02k
          ng++;
71
2.97k
        if (ng == 4)
72
35
        {
73
35
          sgrow = row;
74
35
          sgcol = col;
75
35
        }
76
2.97k
        if (ng == g + 1)
77
374
        {
78
374
            int c;
79
374
            FORC(8)
80
2.99k
            {
81
2.99k
                int v = orth[d] * patt[g][c * 2] + orth[d + 1] * patt[g][c * 2 + 1];
82
2.99k
                int h = orth[d + 2] * patt[g][c * 2] + orth[d + 3] * patt[g][c * 2 + 1];
83
2.99k
                minv = MIN(v, minv);
84
2.99k
                maxv = MAX(v, maxv);
85
2.99k
                minh = MIN(h, minh);
86
2.99k
                maxh = MAX(h, maxh);
87
2.99k
                allhex[row][col][0][c ^ (g * 2 & d)] = h + v * width;
88
2.99k
                allhex[row][col][1][c ^ (g * 2 & d)] = h + v * LIBRAW_AHD_TILE;
89
2.99k
            }
90
374
        }
91
2.97k
      }
92
93
  // Check allhex table initialization
94
233
  for (int i = 0; i < 3; i++)
95
684
    for (int j = 0; j < 3; j++)
96
1.52k
      for (int k = 0; k < 2; k++)
97
9.12k
        for (int l = 0; l < 8; l++)
98
8.11k
          if (allhex[i][j][k][l] > maxh + maxv * width + 1 ||
99
8.10k
              allhex[i][j][k][l] < minh + minv * width - 1)
100
11
            throw LIBRAW_EXCEPTION_IO_CORRUPT;
101
55
  int retrycount = 0;
102
103
  /* Set green1 and green3 to the minimum and maximum allowed values: */
104
31.3k
  for (int row = 2; row < height - 2; row++)
105
31.2k
  {
106
31.2k
      int col;
107
31.2k
      ushort min, max;
108
472M
      for (col = 2, max = 0u, min = 0xffffu; col < int(width) - 2; col++)
109
472M
      {
110
472M
          if (fcol(row, col) == 1 && (min = ~(max = 0)))
111
306M
              continue;
112
165M
          ushort(*pix)[4];
113
165M
          pix = image + row * width + col;
114
165M
          short* hex = allhex[row % 3][col % 3][0];
115
165M
          if (!max)
116
113M
          {
117
113M
              int c;
118
113M
              FORC(6)
119
679M
              {
120
679M
                  int val = pix[hex[c]][1];
121
679M
                  if (min > val)
122
172M
                      min = val;
123
679M
                  if (max < val)
124
114M
                      max = val;
125
679M
              }
126
113M
          }
127
165M
          pix[0][1] = min;
128
165M
          pix[0][3] = max;
129
165M
          switch ((row - sgrow) % 3)
130
165M
          {
131
52.5M
          case 1:
132
52.5M
              if (row < height - 3)
133
52.2M
              {
134
52.2M
                  row++;
135
52.2M
                  col--;
136
52.2M
              }
137
52.5M
              break;
138
52.2M
          case 2:
139
52.2M
              if ((min = ~(max = 0)) && (col += 2) < width - 3 && row > 2)
140
52.2M
              {
141
52.2M
                  row--;
142
52.2M
                  if (retrycount++ > width * height)
143
2
                      throw LIBRAW_EXCEPTION_IO_CORRUPT;
144
52.2M
              }
145
165M
          }
146
165M
      }
147
31.2k
  }
148
149
76
  for (int row = 3; row < 9 && row < height - 3; row++)
150
305
    for (int col = 3; col < 9 && col < width - 3; col++)
151
282
    {
152
282
      if ((fcol(row, col)) == 1)
153
120
        continue;
154
162
          short* hex = allhex[row % 3][col % 3][0];
155
162
          int c;
156
162
      FORC(2)
157
293
      {
158
293
        int idx3 = 3 * hex[4 + c] + row * width + col;
159
293
        int idx4 = -3 * hex[4 + c] + row * width + col;
160
293
        int maxidx = width * height;
161
293
        if (idx3 < 0 || idx3 >= maxidx)
162
20
          throw LIBRAW_EXCEPTION_IO_CORRUPT;
163
273
        if (idx4 < 0 || idx4 >= maxidx)
164
33
          throw LIBRAW_EXCEPTION_IO_CORRUPT;
165
273
      }
166
162
    }
167
168
#if defined(LIBRAW_USE_OPENMP)
169
  int buffer_count = omp_get_max_threads();
170
#else
171
0
  int buffer_count = 1;
172
0
#endif
173
174
0
  size_t buffer_size = LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 11 + 6);
175
0
  char** buffers = malloc_omp_buffers(buffer_count, buffer_size);
176
0
  INT64 allocate_sz = (INT64(iheight) + 6) * (INT64(iwidth) + 6) * sizeof(ushort)*4LL;
177
0
    ushort (*destimage)[4] = (ushort(*)[4])calloc(allocate_sz, 1);
178
  // For border interpolate: keep original pixels
179
0
  memmove(destimage,image,allocate_sz);
180
181
#if defined(LIBRAW_USE_OPENMP)
182
# pragma omp parallel for schedule(dynamic) default(none) firstprivate(buffers, allhex, passes, sgrow, sgcol, ndir) shared(dir, destimage) 
183
#endif
184
0
    for (int top = 3; top < height - 19; top += LIBRAW_AHD_TILE - 16)
185
0
    {
186
#if defined(LIBRAW_USE_OPENMP)
187
        char* buffer = buffers[omp_get_thread_num()];
188
#else
189
0
        char* buffer = buffers[0];
190
0
#endif
191
192
0
        ushort(*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3], (*rix)[3];
193
0
        short(*lab)[LIBRAW_AHD_TILE][3], (*lix)[3];
194
0
        float(*drv)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE];
195
0
        char(*homo)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE];
196
197
0
        rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer;
198
0
        lab = (short(*)[LIBRAW_AHD_TILE][3])(
199
0
            buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 6));
200
0
        drv = (float(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE])(
201
0
            buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 6 + 6));
202
0
        homo = (char(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE])(
203
0
            buffer + LIBRAW_AHD_TILE * LIBRAW_AHD_TILE * (ndir * 10 + 6));
204
205
0
        for (int left = 3; left < width - 19; left += LIBRAW_AHD_TILE - 16)
206
0
        {
207
0
            int mrow = MIN(top + LIBRAW_AHD_TILE, height - 3);
208
0
            int mcol = MIN(left + LIBRAW_AHD_TILE, width - 3);
209
0
            for (int row = top; row < mrow; row++)
210
0
                for (int col = left; col < mcol; col++)
211
0
                    memcpy(rgb[0][row - top][col - left], image[row * width + col], 6);
212
0
            int c;
213
0
            FORC3 memcpy(rgb[c + 1], rgb[0], sizeof * rgb);
214
215
            /* Interpolate green horizontally, vertically, and along both diagonals:
216
             */
217
0
            int color[3][8];
218
0
            for (int row = top; row < mrow; row++)
219
0
                for (int col = left; col < mcol; col++)
220
0
                {
221
0
                    int f;
222
0
                    if ((f = fcol(row, col)) == 1)
223
0
                        continue;
224
0
                    ushort (*pix)[4] = image + row * width + col;
225
0
                    short* hex = allhex[row % 3][col % 3][0];
226
0
                    color[1][0] = 174 * (pix[hex[1]][1] + pix[hex[0]][1]) -
227
0
                        46 * (pix[2 * hex[1]][1] + pix[2 * hex[0]][1]);
228
0
                    color[1][1] = 223 * pix[hex[3]][1] + pix[hex[2]][1] * 33 +
229
0
                        92 * (pix[0][f] - pix[-hex[2]][f]);
230
0
                    FORC(2)
231
0
                        color[1][2 + c] = 164 * pix[hex[4 + c]][1] +
232
0
                        92 * pix[-2 * hex[4 + c]][1] +
233
0
                        33 * (2 * pix[0][f] - pix[3 * hex[4 + c]][f] -
234
0
                            pix[-3 * hex[4 + c]][f]);
235
0
                    FORC4 rgb[c ^ !((row - sgrow) % 3)][row - top][col - left][1] =
236
0
                        LIM(color[1][c] >> 8, pix[0][1], pix[0][3]);
237
0
                }
238
239
0
            for (int pass = 0; pass < passes; pass++)
240
0
            {
241
0
                if (pass == 1)
242
0
                    memcpy(rgb += 4, buffer, 4 * sizeof * rgb);
243
244
                /* Recalculate green from interpolated values of closer pixels: */
245
0
                if (pass)
246
0
                {
247
0
                    for (int row = top + 2; row < mrow - 2; row++)
248
0
                        for (int col = left + 2; col < mcol - 2; col++)
249
0
                        {
250
0
                            int f;
251
0
                            if ((f = fcol(row, col)) == 1)
252
0
                                continue;
253
0
                            ushort(*pix)[4] = image + row * width + col;
254
0
                            short* hex = allhex[row % 3][col % 3][1];
255
0
                            for (int d = 3; d < 6; d++)
256
0
                            {
257
0
                                rix =
258
0
                                    &rgb[(d - 2) ^ !((row - sgrow) % 3)][row - top][col - left];
259
0
                                int val = rix[-2 * hex[d]][1] + 2 * rix[hex[d]][1] -
260
0
                                    rix[-2 * hex[d]][f] - 2 * rix[hex[d]][f] + 3 * rix[0][f];
261
0
                                rix[0][1] = LIM(val / 3, pix[0][1], pix[0][3]);
262
0
                            }
263
0
                        }
264
0
                }
265
266
                /* Interpolate red and blue values for solitary green pixels: */
267
0
                for (int row = (top - sgrow + 4) / 3 * 3 + sgrow; row < mrow - 2; row += 3)
268
0
                    for (int col = (left - sgcol + 4) / 3 * 3 + sgcol; col < mcol - 2; col += 3)
269
0
                {
270
0
                    rix = &rgb[0][row - top][col - left];
271
0
                    int h = fcol(row, col + 1);
272
273
0
          if (h == 1) // Incorrect pattern
274
0
                      break;
275
276
0
                    float diff[6];
277
0
                    memset(diff, 0, sizeof diff);
278
0
                    for (int i = 1, d = 0; d < 6; d++, i ^= LIBRAW_AHD_TILE ^ 1, h ^= 2)
279
0
                    {
280
0
                        for (c = 0; c < 2; c++, h ^= 2)
281
0
                        {
282
0
                            int g = 2 * rix[0][1] - rix[i << c][1] - rix[-i << c][1];
283
0
                            color[h][d] = g + rix[i << c][h] + rix[-i << c][h];
284
0
                            if (d > 1)
285
0
                                diff[d] += SQR((float)rix[i << c][1] - (float)rix[-i << c][1] -
286
0
                                    (float)rix[i << c][h] + (float)rix[-i << c][h]) + SQR((float)g);
287
0
                        }
288
0
                        if (d > 1 && (d & 1))
289
0
                            if (diff[d - 1] < diff[d])
290
0
                                FORC(2) color[c * 2][d] = color[c * 2][d - 1];
291
0
                        if (d < 2 || (d & 1))
292
0
                        {
293
0
                            FORC(2) rix[0][c * 2] = CLIP(color[c * 2][d] / 2);
294
0
                            rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE;
295
0
                        }
296
0
                    }
297
0
                }
298
299
                /* Interpolate red for blue pixels and vice versa:    */
300
0
                for (int row = top + 3; row < mrow - 3; row++)
301
0
                    for (int col = left + 3; col < mcol - 3; col++)
302
0
                    {
303
0
                        int f;
304
0
                        if ((f = 2 - fcol(row, col)) == 1)
305
0
                            continue;
306
0
                        rix = &rgb[0][row - top][col - left];
307
0
                        c = (row - sgrow) % 3 ? LIBRAW_AHD_TILE : 1;
308
0
                        int h = 3 * (c ^ LIBRAW_AHD_TILE ^ 1);
309
0
                        for (int d = 0; d < 4; d++, rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE)
310
0
                        {
311
0
                            int i = d > 1 || ((d ^ c) & 1) ||
312
0
                                ((ABS(rix[0][1] - rix[c][1]) +
313
0
                                    ABS(rix[0][1] - rix[-c][1])) <
314
0
                                    2 * (ABS(rix[0][1] - rix[h][1]) +
315
0
                                        ABS(rix[0][1] - rix[-h][1])))
316
0
                                ? c
317
0
                                : h;
318
0
                            rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + 2 * rix[0][1] -
319
0
                                rix[i][1] - rix[-i][1]) /
320
0
                                2);
321
0
                        }
322
0
                    }
323
324
                /* Fill in red and blue for 2x2 blocks of green:    */
325
0
                for (int row = top + 2; row < mrow - 2; row++)
326
0
                    if ((row - sgrow) % 3)
327
0
                        for (int col = left + 2; col < mcol - 2; col++)
328
0
                            if ((col - sgcol) % 3)
329
0
                            {
330
0
                                rix = &rgb[0][row - top][col - left];
331
0
                                short* hex = allhex[row % 3][col % 3][1];
332
0
                                for (int d = 0; d < 8;
333
0
                                    d += 2, rix += LIBRAW_AHD_TILE * LIBRAW_AHD_TILE)
334
0
                                    if (hex[d] + hex[d + 1])
335
0
                                    {
336
0
                                        int g = 3 * rix[0][1] - 2 * rix[hex[d]][1] - rix[hex[d + 1]][1];
337
0
                                        for (c = 0; c < 4; c += 2)
338
0
                                            rix[0][c] = CLIP(
339
0
                                                (g + 2 * rix[hex[d]][c] + rix[hex[d + 1]][c]) / 3);
340
0
                                    }
341
0
                                    else
342
0
                                    {
343
0
                                        int g = 2 * rix[0][1] - rix[hex[d]][1] - rix[hex[d + 1]][1];
344
0
                                        for (c = 0; c < 4; c += 2)
345
0
                                            rix[0][c] =
346
0
                                            CLIP((g + rix[hex[d]][c] + rix[hex[d + 1]][c]) / 2);
347
0
                                    }
348
0
                            }
349
0
            }
350
0
            rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer;
351
0
            mrow -= top;
352
0
            mcol -= left;
353
354
            /* Convert to CIELab and differentiate in all directions: */
355
            // no effect
356
0
            for (int d = 0; d < ndir; d++)
357
0
            {
358
0
                for (int row = 2; row < mrow - 2; row++)
359
0
                    for (int col = 2; col < mcol - 2; col++)
360
0
                        cielab(rgb[d][row][col], lab[row][col]);
361
0
                for (int f = dir[d & 3], row = 3; row < mrow - 3; row++)
362
0
                    for (int col = 3; col < mcol - 3; col++)
363
0
                    {
364
0
                        lix = &lab[row][col];
365
0
                        int g = 2 * lix[0][0] - lix[f][0] - lix[-f][0];
366
0
                        drv[d][row][col] =
367
0
              float(
368
0
                            SQR(g) +
369
0
                            SQR((2 * lix[0][1] - lix[f][1] - lix[-f][1] + g * 500 / 232)) +
370
0
                            SQR((2 * lix[0][2] - lix[f][2] - lix[-f][2] - g * 500 / 580))
371
0
                );
372
0
                    }
373
0
            }
374
375
            /* Build homogeneity maps from the derivatives:     */
376
0
            memset(homo, 0, ndir * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE);
377
0
            for (int row = 4; row < mrow - 4; row++)
378
0
                for (int col = 4; col < mcol - 4; col++)
379
0
                {
380
0
                    int d;
381
0
                    float tr;
382
0
                    for (tr = FLT_MAX, d = 0; d < ndir; d++)
383
0
                        if (tr > drv[d][row][col])
384
0
                            tr = drv[d][row][col];
385
0
                    tr *= 8;
386
0
                    for (int dd = 0; dd < ndir; dd++)
387
0
                        for (int v = -1; v <= 1; v++)
388
0
                            for (int h = -1; h <= 1; h++)
389
0
                                if (drv[dd][row + v][col + h] <= tr)
390
0
                                    homo[dd][row][col]++;
391
0
                }
392
393
            /* Average the most homogeneous pixels for the final result:  */
394
0
            if (height - top < LIBRAW_AHD_TILE + 4)
395
0
                mrow = height - top + 2;
396
0
            if (width - left < LIBRAW_AHD_TILE + 4)
397
0
                mcol = width - left + 2;
398
0
            for (int row = MIN(top, 8); row < mrow - 8; row++)
399
0
                for (int col = MIN(left, 8); col < mcol - 8; col++)
400
0
                {
401
0
                    int v;
402
0
                    int hm[8];
403
0
                    for (int d = 0; d < ndir; d++)
404
0
                        for (v = -2, hm[d] = 0; v <= 2; v++)
405
0
                            for (int h = -2; h <= 2; h++)
406
0
                                hm[d] += homo[d][row + v][col + h];
407
0
                    for (int d = 0; d < ndir - 4; d++)
408
0
                        if (hm[d] < hm[d + 4])
409
0
                            hm[d] = 0;
410
0
                        else if (hm[d] > hm[d + 4])
411
0
                            hm[d + 4] = 0;
412
0
                    ushort max;
413
0
                    int d;
414
0
                    for (d = 1, max = hm[0]; d < ndir; d++)
415
0
                        if (max < hm[d])
416
0
                            max = hm[d];
417
0
                    max -= max >> 3;
418
419
0
                    int avg[4];
420
0
                    memset(avg, 0, sizeof avg);
421
0
                    for (int dd = 0; dd < ndir; dd++)
422
0
                        if (hm[dd] >= max)
423
0
                        {
424
0
                            FORC3 avg[c] += rgb[dd][row][col][c];
425
0
                            avg[3]++;
426
0
                        }
427
0
                    FORC3 destimage[(row + top) * width + col + left][c] = avg[c] / avg[3];
428
0
                }
429
0
        }
430
0
    }
431
  
432
#ifdef LIBRAW_USE_OPENMP
433
#pragma omp barrier
434
#endif
435
436
0
    free_omp_buffers(buffers, buffer_count);
437
0
    free(image);
438
0
    image = destimage;
439
440
0
    border_interpolate(8);
441
0
}
442
#undef fcol