Coverage Report

Created: 2026-06-30 07:12

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
936M
{
28
936M
  int c, i, j, k;
29
936M
  float r, xyz[3];
30
#ifdef LIBRAW_NOTHREADS
31
  static float cbrt[0x10000], xyz_cam[3][4];
32
#else
33
2.95G
#define cbrt tls->ahd_data.cbrt
34
8.40G
#define xyz_cam tls->ahd_data.xyz_cam
35
936M
#endif
36
37
936M
  if (!rgb)
38
2.22k
  {
39
2.22k
#ifndef LIBRAW_NOTHREADS
40
2.22k
    if (cbrt[0] < -1.0f)
41
2.22k
#endif
42
146M
      for (i = 0; i < 0x10000; i++)
43
146M
      {
44
146M
        r = i / 65535.0f;
45
146M
        cbrt[i] =
46
146M
            r > 0.008856f ? pow(r, 1.f / 3.0f) : 7.787f * r + 16.f / 116.0f;
47
146M
      }
48
8.91k
    for (i = 0; i < 3; i++)
49
26.4k
      for (j = 0; j < colors; j++)
50
78.9k
        for (xyz_cam[i][j] = float( k = 0); k < 3; k++)
51
59.1k
          xyz_cam[i][j] += float(LibRaw_constants::xyz_rgb[i][k] * rgb_cam[k][j] /
52
59.1k
                           LibRaw_constants::d65_white[i]);
53
2.22k
    return;
54
2.22k
  }
55
936M
  xyz[0] = xyz[1] = xyz[2] = 0.5;
56
936M
  FORCC
57
2.80G
  {
58
2.80G
    xyz[0] += xyz_cam[0][c] * rgb[c];
59
2.80G
    xyz[1] += xyz_cam[1][c] * rgb[c];
60
2.80G
    xyz[2] += xyz_cam[2][c] * rgb[c];
61
2.80G
  }
62
936M
  xyz[0] = cbrt[CLIP((int)xyz[0])];
63
936M
  xyz[1] = cbrt[CLIP((int)xyz[1])];
64
936M
  xyz[2] = cbrt[CLIP((int)xyz[2])];
65
936M
  lab[0] = short(64 * (116 * xyz[1] - 16));
66
936M
  lab[1] = short(64 * 500 * (xyz[0] - xyz[1]));
67
936M
  lab[2] = short(64 * 200 * (xyz[1] - xyz[2]));
68
936M
#ifndef LIBRAW_NOTHREADS
69
936M
#undef cbrt
70
936M
#undef xyz_cam
71
936M
#endif
72
936M
}
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.42k
{
77
3.42k
  int row, col;
78
3.42k
  int c, val;
79
3.42k
  ushort(*pix)[4];
80
3.42k
  const int rowlimit = MIN(top + LIBRAW_AHD_TILE, height - 2);
81
3.42k
  const int collimit = MIN(left + LIBRAW_AHD_TILE, width - 2);
82
83
810k
  for (row = top; row < rowlimit; row++)
84
806k
  {
85
806k
    col = left + (FC(row, left) & 1);
86
115M
    for (c = FC(row, col); col < collimit; col += 2)
87
114M
    {
88
114M
      pix = image + row * width + col;
89
114M
      val =
90
114M
          ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) >>
91
114M
          2;
92
114M
      out_rgb[0][row - top][col - left][1] = ULIM(val, pix[-1][1], pix[1][1]);
93
114M
      val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 -
94
114M
             pix[-2 * width][c] - pix[2 * width][c]) >>
95
114M
            2;
96
114M
      out_rgb[1][row - top][col - left][1] =
97
114M
          ULIM(val, pix[-width][1], pix[width][1]);
98
114M
    }
99
806k
  }
100
3.42k
}
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
6.85k
{
105
6.85k
  unsigned row, col;
106
6.85k
  int c, val;
107
6.85k
  ushort(*pix)[4];
108
6.85k
  ushort(*rix)[3];
109
6.85k
  short(*lix)[3];
110
6.85k
  const unsigned num_pix_per_row = 4 * width;
111
6.85k
  const unsigned rowlimit = MIN(top + LIBRAW_AHD_TILE - 1, height - 3);
112
6.85k
  const unsigned collimit = MIN(left + LIBRAW_AHD_TILE - 1, width - 3);
113
6.85k
  ushort *pix_above;
114
6.85k
  ushort *pix_below;
115
6.85k
  int t1, t2;
116
117
1.60M
  for (row = top + 1; row < rowlimit; row++)
118
1.59M
  {
119
1.59M
    pix = image + row * width + left;
120
1.59M
    rix = &inout_rgb[row - top][0];
121
1.59M
    lix = &out_lab[row - top][0];
122
123
454M
    for (col = left + 1; col < collimit; col++)
124
452M
    {
125
452M
      pix++;
126
452M
      pix_above = &pix[0][0] - num_pix_per_row;
127
452M
      pix_below = &pix[0][0] + num_pix_per_row;
128
452M
      rix++;
129
452M
      lix++;
130
131
452M
      c = 2 - FC(row, col);
132
133
452M
      if (c == 1)
134
226M
      {
135
226M
        c = FC(row + 1, col);
136
226M
        t1 = 2 - c;
137
226M
        val = pix[0][1] +
138
226M
              ((pix[-1][t1] + pix[1][t1] - rix[-1][1] - rix[1][1]) >> 1);
139
226M
        rix[0][t1] = CLIP(val);
140
226M
        val =
141
226M
            pix[0][1] + ((pix_above[c] + pix_below[c] -
142
226M
                          rix[-LIBRAW_AHD_TILE][1] - rix[LIBRAW_AHD_TILE][1]) >>
143
226M
                         1);
144
226M
      }
145
226M
      else
146
226M
      {
147
226M
        t1 = -4 + c; /* -4+c: pixel of color c to the left */
148
226M
        t2 = 4 + c;  /* 4+c: pixel of color c to the right */
149
226M
        val = rix[0][1] +
150
226M
              ((pix_above[t1] + pix_above[t2] + pix_below[t1] + pix_below[t2] -
151
226M
                rix[-LIBRAW_AHD_TILE - 1][1] - rix[-LIBRAW_AHD_TILE + 1][1] -
152
226M
                rix[+LIBRAW_AHD_TILE - 1][1] - rix[+LIBRAW_AHD_TILE + 1][1] +
153
226M
                1) >>
154
226M
               2);
155
226M
      }
156
452M
      rix[0][c] = CLIP(val);
157
452M
      c = FC(row, col);
158
452M
      rix[0][c] = pix[0][c];
159
452M
      cielab(rix[0], lix[0]);
160
452M
    }
161
1.59M
  }
162
6.85k
}
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.42k
{
167
3.42k
  int direction;
168
10.2k
  for (direction = 0; direction < 2; direction++)
169
6.85k
  {
170
6.85k
    ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(
171
6.85k
        top, left, inout_rgb[direction], out_lab[direction]);
172
6.85k
  }
173
3.42k
}
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.42k
{
179
3.42k
  int row, col;
180
3.42k
  int tr;
181
3.42k
  int direction;
182
3.42k
  int i;
183
3.42k
  short(*lix)[3];
184
3.42k
  short(*lixs[2])[3];
185
3.42k
  short *adjacent_lix;
186
3.42k
  unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
187
3.42k
  static const int dir[4] = {-1, 1, -LIBRAW_AHD_TILE, LIBRAW_AHD_TILE};
188
3.42k
  const int rowlimit = MIN(top + LIBRAW_AHD_TILE - 2, height - 4);
189
3.42k
  const int collimit = MIN(left + LIBRAW_AHD_TILE - 2, width - 4);
190
3.42k
  int homogeneity;
191
3.42k
  char(*homogeneity_map_p)[2];
192
193
3.42k
  memset(out_homogeneity_map, 0, 2 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE);
194
195
796k
  for (row = top + 2; row < rowlimit; row++)
196
792k
  {
197
792k
    tr = row - top;
198
792k
    homogeneity_map_p = &out_homogeneity_map[tr][1];
199
2.37M
    for (direction = 0; direction < 2; direction++)
200
1.58M
    {
201
1.58M
      lixs[direction] = &lab[direction][tr][1];
202
1.58M
    }
203
204
223M
    for (col = left + 2; col < collimit; col++)
205
223M
    {
206
223M
      homogeneity_map_p++;
207
208
669M
      for (direction = 0; direction < 2; direction++)
209
446M
      {
210
446M
        lix = ++lixs[direction];
211
2.23G
        for (i = 0; i < 4; i++)
212
1.78G
        {
213
1.78G
          adjacent_lix = lix[dir[i]];
214
1.78G
          ldiff[direction][i] = ABS(lix[0][0] - adjacent_lix[0]);
215
1.78G
          abdiff[direction][i] = SQR(lix[0][1] - adjacent_lix[1]) +
216
1.78G
                                 SQR(lix[0][2] - adjacent_lix[2]);
217
1.78G
        }
218
446M
      }
219
223M
      leps = MIN(MAX(ldiff[0][0], ldiff[0][1]), MAX(ldiff[1][2], ldiff[1][3]));
220
223M
      abeps =
221
223M
          MIN(MAX(abdiff[0][0], abdiff[0][1]), MAX(abdiff[1][2], abdiff[1][3]));
222
669M
      for (direction = 0; direction < 2; direction++)
223
446M
      {
224
446M
        homogeneity = 0;
225
2.23G
        for (i = 0; i < 4; i++)
226
1.78G
        {
227
1.78G
          if (ldiff[direction][i] <= leps && abdiff[direction][i] <= abeps)
228
1.53G
          {
229
1.53G
            homogeneity++;
230
1.53G
          }
231
1.78G
        }
232
446M
        homogeneity_map_p[0][direction] = homogeneity;
233
446M
      }
234
223M
    }
235
792k
  }
236
3.42k
}
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.42k
{
241
3.42k
  int row, col;
242
3.42k
  int tr, tc;
243
3.42k
  int i, j;
244
3.42k
  int direction;
245
3.42k
  int hm[2];
246
3.42k
  int c;
247
3.42k
  const int rowlimit = MIN(top + LIBRAW_AHD_TILE - 3, height - 5);
248
3.42k
  const int collimit = MIN(left + LIBRAW_AHD_TILE - 3, width - 5);
249
250
3.42k
  ushort(*pix)[4];
251
3.42k
  ushort(*rix[2])[3];
252
253
789k
  for (row = top + 3; row < rowlimit; row++)
254
786k
  {
255
786k
    tr = row - top;
256
786k
    pix = &image[row * width + left + 2];
257
2.35M
    for (direction = 0; direction < 2; direction++)
258
1.57M
    {
259
1.57M
      rix[direction] = &rgb[direction][tr][2];
260
1.57M
    }
261
262
220M
    for (col = left + 3; col < collimit; col++)
263
220M
    {
264
220M
      tc = col - left;
265
220M
      pix++;
266
660M
      for (direction = 0; direction < 2; direction++)
267
440M
      {
268
440M
        rix[direction]++;
269
440M
      }
270
271
660M
      for (direction = 0; direction < 2; direction++)
272
440M
      {
273
440M
        hm[direction] = 0;
274
1.76G
        for (i = tr - 1; i <= tr + 1; i++)
275
1.32G
        {
276
5.28G
          for (j = tc - 1; j <= tc + 1; j++)
277
3.96G
          {
278
3.96G
            hm[direction] += homogeneity_map[i][j][direction];
279
3.96G
          }
280
1.32G
        }
281
440M
      }
282
220M
      if (hm[0] != hm[1])
283
22.6M
      {
284
22.6M
        memcpy(pix[0], rix[hm[1] > hm[0]][0], 3 * sizeof(ushort));
285
22.6M
      }
286
197M
      else
287
197M
      {
288
592M
        FORC3 { pix[0][c] = (rix[0][0][c] + rix[1][0][c]) >> 1; }
289
197M
      }
290
220M
    }
291
786k
  }
292
3.42k
}
293
void LibRaw::ahd_interpolate()
294
2.08k
{
295
2.08k
    int terminate_flag = 0;
296
2.08k
    cielab(0, 0);
297
2.08k
    border_interpolate(5);
298
299
#ifdef LIBRAW_USE_OPENMP
300
    int buffer_count = omp_get_max_threads();
301
#else
302
2.08k
    int buffer_count = 1;
303
2.08k
#endif
304
305
2.08k
    size_t buffer_size = 26 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE; /* 1664 kB */
306
2.08k
    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
4.91k
    for (int top = 2; top < height - 5; top += LIBRAW_AHD_TILE - 6)
312
2.83k
    {
313
#ifdef LIBRAW_USE_OPENMP
314
        if (0 == omp_get_thread_num())
315
#endif
316
2.83k
            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
2.83k
        char* buffer = buffers[0];
329
2.83k
#endif
330
331
2.83k
        ushort(*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3];
332
2.83k
        short(*lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3];
333
2.83k
        char(*homo)[LIBRAW_AHD_TILE][2];
334
335
2.83k
        rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer;
336
2.83k
        lab = (short(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])(
337
2.83k
            buffer + 12 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE);
338
2.83k
        homo = (char(*)[LIBRAW_AHD_TILE][2])(buffer + 24 * LIBRAW_AHD_TILE *
339
2.83k
            LIBRAW_AHD_TILE);
340
341
6.26k
        for (int left = 2; !terminate_flag && (left < width - 5);
342
3.42k
            left += LIBRAW_AHD_TILE - 6)
343
3.42k
        {
344
3.42k
            ahd_interpolate_green_h_and_v(top, left, rgb);
345
3.42k
            ahd_interpolate_r_and_b_and_convert_to_cielab(top, left, rgb, lab);
346
3.42k
            ahd_interpolate_build_homogeneity_map(top, left, lab, homo);
347
3.42k
            ahd_interpolate_combine_homogeneous_pixels(top, left, rgb, homo);
348
3.42k
        }
349
2.83k
    }
350
351
2.08k
    free_omp_buffers(buffers, buffer_count);
352
353
2.08k
    if (terminate_flag)
354
0
        throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK;
355
2.08k
}