Coverage Report

Created: 2026-07-20 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libraw/src/demosaic/ahd_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
/*
22
   Adaptive Homogeneity-Directed interpolation is based on
23
   the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
24
 */
25
26
void LibRaw::cielab(ushort rgb[3], short lab[3])
27
1.12G
{
28
1.12G
  int c, i, j, k;
29
1.12G
  float r, xyz[3];
30
#ifdef LIBRAW_NOTHREADS
31
  static float cbrt[0x10000], xyz_cam[3][4];
32
#else
33
3.52G
#define cbrt tls->ahd_data.cbrt
34
10.0G
#define xyz_cam tls->ahd_data.xyz_cam
35
1.12G
#endif
36
37
1.12G
  if (!rgb)
38
2.48k
  {
39
2.48k
#ifndef LIBRAW_NOTHREADS
40
2.48k
    if (cbrt[0] < -1.0f)
41
2.48k
#endif
42
162M
      for (i = 0; i < 0x10000; i++)
43
162M
      {
44
162M
        r = i / 65535.0f;
45
162M
        cbrt[i] =
46
162M
            r > 0.008856f ? pow(r, 1.f / 3.0f) : 7.787f * r + 16.f / 116.0f;
47
162M
      }
48
9.93k
    for (i = 0; i < 3; i++)
49
29.5k
      for (j = 0; j < colors; j++)
50
88.5k
        for (xyz_cam[i][j] = float( k = 0); k < 3; k++)
51
66.4k
          xyz_cam[i][j] += float(LibRaw_constants::xyz_rgb[i][k] * rgb_cam[k][j] /
52
66.4k
                           LibRaw_constants::d65_white[i]);
53
2.48k
    return;
54
2.48k
  }
55
1.12G
  xyz[0] = xyz[1] = xyz[2] = 0.5;
56
1.12G
  FORCC
57
3.35G
  {
58
3.35G
    xyz[0] += xyz_cam[0][c] * rgb[c];
59
3.35G
    xyz[1] += xyz_cam[1][c] * rgb[c];
60
3.35G
    xyz[2] += xyz_cam[2][c] * rgb[c];
61
3.35G
  }
62
1.12G
  xyz[0] = cbrt[CLIP((int)xyz[0])];
63
1.12G
  xyz[1] = cbrt[CLIP((int)xyz[1])];
64
1.12G
  xyz[2] = cbrt[CLIP((int)xyz[2])];
65
1.12G
  lab[0] = short(64 * (116 * xyz[1] - 16));
66
1.12G
  lab[1] = short(64 * 500 * (xyz[0] - xyz[1]));
67
1.12G
  lab[2] = short(64 * 200 * (xyz[1] - xyz[2]));
68
1.12G
#ifndef LIBRAW_NOTHREADS
69
1.12G
#undef cbrt
70
1.12G
#undef xyz_cam
71
1.12G
#endif
72
1.12G
}
73
74
void LibRaw::ahd_interpolate_green_h_and_v(
75
    int top, int left, ushort (*out_rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])
76
3.90k
{
77
3.90k
  int row, col;
78
3.90k
  int c, val;
79
3.90k
  ushort(*pix)[4];
80
3.90k
  const int rowlimit = MIN(top + LIBRAW_AHD_TILE, height - 2);
81
3.90k
  const int collimit = MIN(left + LIBRAW_AHD_TILE, width - 2);
82
83
954k
  for (row = top; row < rowlimit; row++)
84
950k
  {
85
950k
    col = left + (FC(row, left) & 1);
86
136M
    for (c = FC(row, col); col < collimit; col += 2)
87
135M
    {
88
135M
      pix = image + row * width + col;
89
135M
      val =
90
135M
          ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) >>
91
135M
          2;
92
135M
      out_rgb[0][row - top][col - left][1] = ULIM(val, pix[-1][1], pix[1][1]);
93
135M
      val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 -
94
135M
             pix[-2 * width][c] - pix[2 * width][c]) >>
95
135M
            2;
96
135M
      out_rgb[1][row - top][col - left][1] =
97
135M
          ULIM(val, pix[-width][1], pix[width][1]);
98
135M
    }
99
950k
  }
100
3.90k
}
101
void LibRaw::ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(
102
    int top, int left, ushort (*inout_rgb)[LIBRAW_AHD_TILE][3],
103
    short (*out_lab)[LIBRAW_AHD_TILE][3])
104
7.81k
{
105
7.81k
  unsigned row, col;
106
7.81k
  int c, val;
107
7.81k
  ushort(*pix)[4];
108
7.81k
  ushort(*rix)[3];
109
7.81k
  short(*lix)[3];
110
7.81k
  const unsigned num_pix_per_row = 4 * width;
111
7.81k
  const unsigned rowlimit = MIN(top + LIBRAW_AHD_TILE - 1, height - 3);
112
7.81k
  const unsigned collimit = MIN(left + LIBRAW_AHD_TILE - 1, width - 3);
113
7.81k
  ushort *pix_above;
114
7.81k
  ushort *pix_below;
115
7.81k
  int t1, t2;
116
117
1.89M
  for (row = top + 1; row < rowlimit; row++)
118
1.88M
  {
119
1.88M
    pix = image + row * width + left;
120
1.88M
    rix = &inout_rgb[row - top][0];
121
1.88M
    lix = &out_lab[row - top][0];
122
123
536M
    for (col = left + 1; col < collimit; col++)
124
534M
    {
125
534M
      pix++;
126
534M
      pix_above = &pix[0][0] - num_pix_per_row;
127
534M
      pix_below = &pix[0][0] + num_pix_per_row;
128
534M
      rix++;
129
534M
      lix++;
130
131
534M
      c = 2 - FC(row, col);
132
133
534M
      if (c == 1)
134
267M
      {
135
267M
        c = FC(row + 1, col);
136
267M
        t1 = 2 - c;
137
267M
        val = pix[0][1] +
138
267M
              ((pix[-1][t1] + pix[1][t1] - rix[-1][1] - rix[1][1]) >> 1);
139
267M
        rix[0][t1] = CLIP(val);
140
267M
        val =
141
267M
            pix[0][1] + ((pix_above[c] + pix_below[c] -
142
267M
                          rix[-LIBRAW_AHD_TILE][1] - rix[LIBRAW_AHD_TILE][1]) >>
143
267M
                         1);
144
267M
      }
145
267M
      else
146
267M
      {
147
267M
        t1 = -4 + c; /* -4+c: pixel of color c to the left */
148
267M
        t2 = 4 + c;  /* 4+c: pixel of color c to the right */
149
267M
        val = rix[0][1] +
150
267M
              ((pix_above[t1] + pix_above[t2] + pix_below[t1] + pix_below[t2] -
151
267M
                rix[-LIBRAW_AHD_TILE - 1][1] - rix[-LIBRAW_AHD_TILE + 1][1] -
152
267M
                rix[+LIBRAW_AHD_TILE - 1][1] - rix[+LIBRAW_AHD_TILE + 1][1] +
153
267M
                1) >>
154
267M
               2);
155
267M
      }
156
534M
      rix[0][c] = CLIP(val);
157
534M
      c = FC(row, col);
158
534M
      rix[0][c] = pix[0][c];
159
534M
      cielab(rix[0], lix[0]);
160
534M
    }
161
1.88M
  }
162
7.81k
}
163
void LibRaw::ahd_interpolate_r_and_b_and_convert_to_cielab(
164
    int top, int left, ushort (*inout_rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3],
165
    short (*out_lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])
166
3.90k
{
167
3.90k
  int direction;
168
11.7k
  for (direction = 0; direction < 2; direction++)
169
7.81k
  {
170
7.81k
    ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(
171
7.81k
        top, left, inout_rgb[direction], out_lab[direction]);
172
7.81k
  }
173
3.90k
}
174
175
void LibRaw::ahd_interpolate_build_homogeneity_map(
176
    int top, int left, short (*lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3],
177
    char (*out_homogeneity_map)[LIBRAW_AHD_TILE][2])
178
3.90k
{
179
3.90k
  int row, col;
180
3.90k
  int tr;
181
3.90k
  int direction;
182
3.90k
  int i;
183
3.90k
  short(*lix)[3];
184
3.90k
  short(*lixs[2])[3];
185
3.90k
  short *adjacent_lix;
186
3.90k
  unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
187
3.90k
  static const int dir[4] = {-1, 1, -LIBRAW_AHD_TILE, LIBRAW_AHD_TILE};
188
3.90k
  const int rowlimit = MIN(top + LIBRAW_AHD_TILE - 2, height - 4);
189
3.90k
  const int collimit = MIN(left + LIBRAW_AHD_TILE - 2, width - 4);
190
3.90k
  int homogeneity;
191
3.90k
  char(*homogeneity_map_p)[2];
192
193
3.90k
  memset(out_homogeneity_map, 0, 2 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE);
194
195
938k
  for (row = top + 2; row < rowlimit; row++)
196
934k
  {
197
934k
    tr = row - top;
198
934k
    homogeneity_map_p = &out_homogeneity_map[tr][1];
199
2.80M
    for (direction = 0; direction < 2; direction++)
200
1.86M
    {
201
1.86M
      lixs[direction] = &lab[direction][tr][1];
202
1.86M
    }
203
204
264M
    for (col = left + 2; col < collimit; col++)
205
263M
    {
206
263M
      homogeneity_map_p++;
207
208
791M
      for (direction = 0; direction < 2; direction++)
209
527M
      {
210
527M
        lix = ++lixs[direction];
211
2.63G
        for (i = 0; i < 4; i++)
212
2.11G
        {
213
2.11G
          adjacent_lix = lix[dir[i]];
214
2.11G
          ldiff[direction][i] = ABS(lix[0][0] - adjacent_lix[0]);
215
2.11G
          abdiff[direction][i] = SQR(lix[0][1] - adjacent_lix[1]) +
216
2.11G
                                 SQR(lix[0][2] - adjacent_lix[2]);
217
2.11G
        }
218
527M
      }
219
263M
      leps = MIN(MAX(ldiff[0][0], ldiff[0][1]), MAX(ldiff[1][2], ldiff[1][3]));
220
263M
      abeps =
221
263M
          MIN(MAX(abdiff[0][0], abdiff[0][1]), MAX(abdiff[1][2], abdiff[1][3]));
222
791M
      for (direction = 0; direction < 2; direction++)
223
527M
      {
224
527M
        homogeneity = 0;
225
2.63G
        for (i = 0; i < 4; i++)
226
2.11G
        {
227
2.11G
          if (ldiff[direction][i] <= leps && abdiff[direction][i] <= abeps)
228
1.86G
          {
229
1.86G
            homogeneity++;
230
1.86G
          }
231
2.11G
        }
232
527M
        homogeneity_map_p[0][direction] = homogeneity;
233
527M
      }
234
263M
    }
235
934k
  }
236
3.90k
}
237
void LibRaw::ahd_interpolate_combine_homogeneous_pixels(
238
    int top, int left, ushort (*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3],
239
    char (*homogeneity_map)[LIBRAW_AHD_TILE][2])
240
3.90k
{
241
3.90k
  int row, col;
242
3.90k
  int tr, tc;
243
3.90k
  int i, j;
244
3.90k
  int direction;
245
3.90k
  int hm[2];
246
3.90k
  int c;
247
3.90k
  const int rowlimit = MIN(top + LIBRAW_AHD_TILE - 3, height - 5);
248
3.90k
  const int collimit = MIN(left + LIBRAW_AHD_TILE - 3, width - 5);
249
250
3.90k
  ushort(*pix)[4];
251
3.90k
  ushort(*rix[2])[3];
252
253
930k
  for (row = top + 3; row < rowlimit; row++)
254
926k
  {
255
926k
    tr = row - top;
256
926k
    pix = &image[row * width + left + 2];
257
2.78M
    for (direction = 0; direction < 2; direction++)
258
1.85M
    {
259
1.85M
      rix[direction] = &rgb[direction][tr][2];
260
1.85M
    }
261
262
261M
    for (col = left + 3; col < collimit; col++)
263
260M
    {
264
260M
      tc = col - left;
265
260M
      pix++;
266
780M
      for (direction = 0; direction < 2; direction++)
267
520M
      {
268
520M
        rix[direction]++;
269
520M
      }
270
271
780M
      for (direction = 0; direction < 2; direction++)
272
520M
      {
273
520M
        hm[direction] = 0;
274
2.08G
        for (i = tr - 1; i <= tr + 1; i++)
275
1.56G
        {
276
6.24G
          for (j = tc - 1; j <= tc + 1; j++)
277
4.68G
          {
278
4.68G
            hm[direction] += homogeneity_map[i][j][direction];
279
4.68G
          }
280
1.56G
        }
281
520M
      }
282
260M
      if (hm[0] != hm[1])
283
19.4M
      {
284
19.4M
        memcpy(pix[0], rix[hm[1] > hm[0]][0], 3 * sizeof(ushort));
285
19.4M
      }
286
240M
      else
287
240M
      {
288
722M
        FORC3 { pix[0][c] = (rix[0][0][c] + rix[1][0][c]) >> 1; }
289
240M
      }
290
260M
    }
291
926k
  }
292
3.90k
}
293
void LibRaw::ahd_interpolate()
294
2.30k
{
295
2.30k
    int terminate_flag = 0;
296
2.30k
    cielab(0, 0);
297
2.30k
    border_interpolate(5);
298
299
#ifdef LIBRAW_USE_OPENMP
300
    int buffer_count = omp_get_max_threads();
301
#else
302
2.30k
    int buffer_count = 1;
303
2.30k
#endif
304
305
2.30k
    size_t buffer_size = 26 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE; /* 1664 kB */
306
2.30k
    char** buffers = malloc_omp_buffers(buffer_count, buffer_size);
307
308
#ifdef LIBRAW_USE_OPENMP
309
#pragma omp parallel for schedule(dynamic) default(none) shared(terminate_flag) firstprivate(buffers)
310
#endif
311
5.45k
    for (int top = 2; top < height - 5; top += LIBRAW_AHD_TILE - 6)
312
3.14k
    {
313
#ifdef LIBRAW_USE_OPENMP
314
        if (0 == omp_get_thread_num())
315
#endif
316
3.14k
            if (callbacks.progress_cb)
317
0
            {
318
0
                int rr = (*callbacks.progress_cb)(callbacks.progresscb_data,
319
0
                    LIBRAW_PROGRESS_INTERPOLATE,
320
0
                    top - 2, height - 7);
321
0
                if (rr)
322
0
                    terminate_flag = 1;
323
0
            }
324
325
#if defined(LIBRAW_USE_OPENMP)
326
        char* buffer = buffers[omp_get_thread_num()];
327
#else
328
3.14k
        char* buffer = buffers[0];
329
3.14k
#endif
330
331
3.14k
        ushort(*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3];
332
3.14k
        short(*lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3];
333
3.14k
        char(*homo)[LIBRAW_AHD_TILE][2];
334
335
3.14k
        rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer;
336
3.14k
        lab = (short(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])(
337
3.14k
            buffer + 12 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE);
338
3.14k
        homo = (char(*)[LIBRAW_AHD_TILE][2])(buffer + 24 * LIBRAW_AHD_TILE *
339
3.14k
            LIBRAW_AHD_TILE);
340
341
7.05k
        for (int left = 2; !terminate_flag && (left < width - 5);
342
3.90k
            left += LIBRAW_AHD_TILE - 6)
343
3.90k
        {
344
3.90k
            ahd_interpolate_green_h_and_v(top, left, rgb);
345
3.90k
            ahd_interpolate_r_and_b_and_convert_to_cielab(top, left, rgb, lab);
346
3.90k
            ahd_interpolate_build_homogeneity_map(top, left, lab, homo);
347
3.90k
            ahd_interpolate_combine_homogeneous_pixels(top, left, rgb, homo);
348
3.90k
        }
349
3.14k
    }
350
351
2.30k
    free_omp_buffers(buffers, buffer_count);
352
353
2.30k
    if (terminate_flag)
354
0
        throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK;
355
2.30k
}