Coverage Report

Created: 2026-09-03 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libraw/src/demosaic/aahd_demosaic.cpp
Line
Count
Source
1
/* -*- C++ -*-
2
 * File: aahd_demosaic.cpp
3
 * Copyright 2013 Anton Petrusevich
4
 * Created: Wed May  15, 2013
5
 *
6
 * This code is licensed under one of two licenses as you choose:
7
 *
8
 * 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
9
 *    (See file LICENSE.LGPL provided in LibRaw distribution archive for
10
 * details).
11
 *
12
 * 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
13
 *    (See file LICENSE.CDDL provided in LibRaw distribution archive for
14
 * details).
15
 *
16
 */
17
18
#include "../../internal/dmp_include.h"
19
20
typedef ushort ushort3[3];
21
typedef int int3[3];
22
23
#ifndef Pnw
24
329k
#define Pnw (-1 - nr_width)
25
53.1M
#define Pn (-nr_width)
26
164k
#define Pne (+1 - nr_width)
27
71.1M
#define Pe (+1)
28
#define Pse (+1 + nr_width)
29
45.8M
#define Ps (+nr_width)
30
164k
#define Psw (-1 + nr_width)
31
51.9M
#define Pw (-1)
32
#endif
33
34
struct AAHD
35
{
36
  int nr_height, nr_width;
37
  static const int nr_margin = 4;
38
  static const int Thot = 4;
39
  static const int Tdead = 4;
40
  static const int OverFraction = 8;
41
  ushort3 *rgb_ahd[2];
42
  int3 *yuv[2];
43
  char *ndir, *homo[2];
44
  ushort channel_maximum[3], channels_max;
45
  ushort channel_minimum[3];
46
  static const float yuv_coeff[3][3];
47
  static float gammaLUT[0x10000];
48
  float yuv_cam[3][3];
49
  LibRaw &libraw;
50
  enum
51
  {
52
    HVSH = 1,
53
    HOR = 2,
54
    VER = 4,
55
    HORSH = HOR | HVSH,
56
    VERSH = VER | HVSH,
57
    HOT = 8
58
  };
59
60
  static inline float calc_dist(int c1, int c2) throw()
61
0
  {
62
0
    return c1 > c2 ? (float)c1 / c2 : (float)c2 / c1;
63
0
  }
64
  int inline Y(ushort3 &rgb) throw()
65
31.5M
  {
66
31.5M
    return int(yuv_cam[0][0] * rgb[0] + yuv_cam[0][1] * rgb[1] +
67
31.5M
           yuv_cam[0][2] * rgb[2]);
68
31.5M
  }
69
  int inline U(ushort3 &rgb) throw()
70
31.5M
  {
71
31.5M
    return int(yuv_cam[1][0] * rgb[0] + yuv_cam[1][1] * rgb[1] +
72
31.5M
           yuv_cam[1][2] * rgb[2]);
73
31.5M
  }
74
  int inline V(ushort3 &rgb) throw()
75
31.5M
  {
76
31.5M
    return int(yuv_cam[2][0] * rgb[0] + yuv_cam[2][1] * rgb[1] +
77
31.5M
           yuv_cam[2][2] * rgb[2]);
78
31.5M
  }
79
  inline int nr_offset(int row, int col) throw()
80
239M
  {
81
239M
    return (row * nr_width + col);
82
239M
  }
83
  ~AAHD();
84
  AAHD(LibRaw &_libraw);
85
  void make_ahd_greens();
86
  void make_ahd_gline(int i);
87
  void make_ahd_rb();
88
  void make_ahd_rb_hv(int i);
89
  void make_ahd_rb_last(int i);
90
  void evaluate_ahd();
91
  void combine_image();
92
  void hide_hots();
93
  void refine_hv_dirs();
94
  void refine_hv_dirs(int i, int js);
95
  void refine_ihv_dirs(int i);
96
  void illustrate_dirs();
97
  void illustrate_dline(int i);
98
};
99
100
const float AAHD::yuv_coeff[3][3] = {
101
    // YPbPr
102
    //  {
103
    //    0.299f,
104
    //    0.587f,
105
    //    0.114f },
106
    //  {
107
    //    -0.168736,
108
    //    -0.331264f,
109
    //    0.5f },
110
    //  {
111
    //    0.5f,
112
    //    -0.418688f,
113
    //    -0.081312f }
114
    //
115
    //  Rec. 2020
116
    //  Y'= 0,2627R' + 0,6780G' + 0,0593B'
117
    //  U = (B-Y)/1.8814 =  (-0,2627R' - 0,6780G' + 0.9407B) / 1.8814 =
118
    //-0.13963R - 0.36037G + 0.5B
119
    //  V = (R-Y)/1.4647 = (0.7373R - 0,6780G - 0,0593B) / 1.4647 = 0.5R -
120
    //0.4629G - 0.04049B
121
    {+0.2627f, +0.6780f, +0.0593f},
122
    {-0.13963f, -0.36037f, +0.5f},
123
    {+0.5034f, -0.4629f, -0.0405f}
124
125
};
126
127
float AAHD::gammaLUT[0x10000] = {-1.f};
128
129
1.18k
AAHD::AAHD(LibRaw &_libraw) : libraw(_libraw)
130
1.18k
{
131
1.18k
  nr_height = libraw.imgdata.sizes.iheight + nr_margin * 2;
132
1.18k
  nr_width = libraw.imgdata.sizes.iwidth + nr_margin * 2;
133
1.18k
  rgb_ahd[0] = (ushort3 *)calloc(nr_height * nr_width,
134
1.18k
                                 (sizeof(ushort3) * 2 + sizeof(int3) * 2 + 3));
135
1.18k
  if (!rgb_ahd[0])
136
0
    throw LIBRAW_EXCEPTION_ALLOC;
137
138
1.18k
  rgb_ahd[1] = rgb_ahd[0] + nr_height * nr_width;
139
1.18k
  yuv[0] = (int3 *)(rgb_ahd[1] + nr_height * nr_width);
140
1.18k
  yuv[1] = yuv[0] + nr_height * nr_width;
141
1.18k
  ndir = (char *)(yuv[1] + nr_height * nr_width);
142
1.18k
  homo[0] = ndir + nr_height * nr_width;
143
1.18k
  homo[1] = homo[0] + nr_height * nr_width;
144
1.18k
  channel_maximum[0] = channel_maximum[1] = channel_maximum[2] = 0;
145
1.18k
  channel_minimum[0] = libraw.imgdata.image[0][0];
146
1.18k
  channel_minimum[1] = libraw.imgdata.image[0][1];
147
1.18k
  channel_minimum[2] = libraw.imgdata.image[0][2];
148
1.18k
  int iwidth = libraw.imgdata.sizes.iwidth;
149
4.74k
  for (int i = 0; i < 3; ++i)
150
14.2k
    for (int j = 0; j < 3; ++j)
151
10.6k
    {
152
10.6k
      yuv_cam[i][j] = 0;
153
42.7k
      for (int k = 0; k < 3; ++k)
154
32.0k
        yuv_cam[i][j] += yuv_coeff[i][k] * libraw.imgdata.color.rgb_cam[k][j];
155
10.6k
    }
156
1.18k
  if (gammaLUT[0] < -0.1f)
157
1
  {
158
1
    float r;
159
65.5k
    for (int i = 0; i < 0x10000; i++)
160
65.5k
    {
161
65.5k
      r = (float)i / 0x10000;
162
65.5k
      gammaLUT[i] =
163
65.5k
          0x10000 * (r < 0.0181 ? 4.5f * r : 1.0993f * pow(r, 0.45f) - .0993f);
164
65.5k
    }
165
1
  }
166
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
167
164k
  {
168
164k
    int col_cache[48];
169
8.07M
    for (int j = 0; j < 48; ++j)
170
7.90M
    {
171
7.90M
      int c = libraw.COLOR(i, j);
172
7.90M
      if (c == 3)
173
0
        c = 1;
174
7.90M
      col_cache[j] = c;
175
7.90M
    }
176
164k
    int moff = nr_offset(i + nr_margin, nr_margin);
177
12.9M
    for (int j = 0; j < iwidth; ++j, ++moff)
178
12.7M
    {
179
12.7M
      int c = col_cache[j % 48];
180
12.7M
      unsigned short d = libraw.imgdata.image[i * iwidth + j][c];
181
12.7M
      if (d != 0)
182
4.45M
      {
183
4.45M
        if (channel_maximum[c] < d)
184
23.2k
          channel_maximum[c] = d;
185
4.45M
        if (channel_minimum[c] > d)
186
9.31k
          channel_minimum[c] = d;
187
4.45M
        rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] = d;
188
4.45M
      }
189
12.7M
    }
190
164k
  }
191
1.18k
  channels_max =
192
1.18k
      MAX(MAX(channel_maximum[0], channel_maximum[1]), channel_maximum[2]);
193
1.18k
}
194
195
void AAHD::hide_hots()
196
1.18k
{
197
1.18k
  int iwidth = libraw.imgdata.sizes.iwidth;
198
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
199
164k
  {
200
164k
    int js = libraw.COLOR(i, 0) & 1;
201
164k
    int kc = libraw.COLOR(i, js);
202
    /*
203
     * js -- начальная х-координата, которая попадает мимо известного зелёного
204
     * kc -- известный цвет в точке интерполирования
205
     */
206
164k
    int moff = nr_offset(i + nr_margin, nr_margin + js);
207
6.55M
    for (int j = js; j < iwidth; j += 2, moff += 2)
208
6.39M
    {
209
6.39M
      ushort3 *rgb = &rgb_ahd[0][moff];
210
6.39M
      int c = rgb[0][kc];
211
6.39M
      if ((c > rgb[2 * Pe][kc] && c > rgb[2 * Pw][kc] && c > rgb[2 * Pn][kc] &&
212
69.3k
           c > rgb[2 * Ps][kc] && c > rgb[Pe][1] && c > rgb[Pw][1] &&
213
26.9k
           c > rgb[Pn][1] && c > rgb[Ps][1]) ||
214
6.37M
          (c < rgb[2 * Pe][kc] && c < rgb[2 * Pw][kc] && c < rgb[2 * Pn][kc] &&
215
54.5k
           c < rgb[2 * Ps][kc] && c < rgb[Pe][1] && c < rgb[Pw][1] &&
216
19.7k
           c < rgb[Pn][1] && c < rgb[Ps][1]))
217
34.5k
      {
218
34.5k
        int chot = c >> Thot;
219
34.5k
        int cdead = c << Tdead;
220
34.5k
        int avg = 0;
221
138k
        for (int k = -2; k < 3; k += 2)
222
414k
          for (int m = -2; m < 3; m += 2)
223
310k
            if (m == 0 && k == 0)
224
34.5k
              continue;
225
276k
            else
226
276k
              avg += rgb[nr_offset(k, m)][kc];
227
34.5k
        avg /= 8;
228
34.5k
        if (chot > avg || cdead < avg)
229
7.84k
        {
230
7.84k
          ndir[moff] |= HOT;
231
7.84k
          int dh =
232
7.84k
              ABS(rgb[2 * Pw][kc] - rgb[2 * Pe][kc]) +
233
7.84k
              ABS(rgb[Pw][1] - rgb[Pe][1]) +
234
7.84k
              ABS(rgb[Pw][1] - rgb[Pe][1] + rgb[2 * Pe][kc] - rgb[2 * Pw][kc]);
235
7.84k
          int dv =
236
7.84k
              ABS(rgb[2 * Pn][kc] - rgb[2 * Ps][kc]) +
237
7.84k
              ABS(rgb[Pn][1] - rgb[Ps][1]) +
238
7.84k
              ABS(rgb[Pn][1] - rgb[Ps][1] + rgb[2 * Ps][kc] - rgb[2 * Pn][kc]);
239
7.84k
          int d;
240
7.84k
          if (dv > dh)
241
2.81k
            d = Pw;
242
5.02k
          else
243
5.02k
            d = Pn;
244
7.84k
          rgb_ahd[1][moff][kc] = rgb[0][kc] =
245
7.84k
              (rgb[+2 * d][kc] + rgb[-2 * d][kc]) / 2;
246
7.84k
        }
247
34.5k
      }
248
6.39M
    }
249
164k
    js ^= 1;
250
164k
    moff = nr_offset(i + nr_margin, nr_margin + js);
251
6.55M
    for (int j = js; j < iwidth; j += 2, moff += 2)
252
6.39M
    {
253
6.39M
      ushort3 *rgb = &rgb_ahd[0][moff];
254
6.39M
      int c = rgb[0][1];
255
6.39M
      if ((c > rgb[2 * Pe][1] && c > rgb[2 * Pw][1] && c > rgb[2 * Pn][1] &&
256
68.7k
           c > rgb[2 * Ps][1] && c > rgb[Pe][kc] && c > rgb[Pw][kc] &&
257
25.7k
           c > rgb[Pn][kc ^ 2] && c > rgb[Ps][kc ^ 2]) ||
258
6.37M
          (c < rgb[2 * Pe][1] && c < rgb[2 * Pw][1] && c < rgb[2 * Pn][1] &&
259
53.0k
           c < rgb[2 * Ps][1] && c < rgb[Pe][kc] && c < rgb[Pw][kc] &&
260
15.4k
           c < rgb[Pn][kc ^ 2] && c < rgb[Ps][kc ^ 2]))
261
28.3k
      {
262
28.3k
        int chot = c >> Thot;
263
28.3k
        int cdead = c << Tdead;
264
28.3k
        int avg = 0;
265
113k
        for (int k = -2; k < 3; k += 2)
266
340k
          for (int m = -2; m < 3; m += 2)
267
255k
            if (k == 0 && m == 0)
268
28.3k
              continue;
269
226k
            else
270
226k
              avg += rgb[nr_offset(k, m)][1];
271
28.3k
        avg /= 8;
272
28.3k
        if (chot > avg || cdead < avg)
273
6.21k
        {
274
6.21k
          ndir[moff] |= HOT;
275
6.21k
          int dh =
276
6.21k
              ABS(rgb[2 * Pw][1] - rgb[2 * Pe][1]) +
277
6.21k
              ABS(rgb[Pw][kc] - rgb[Pe][kc]) +
278
6.21k
              ABS(rgb[Pw][kc] - rgb[Pe][kc] + rgb[2 * Pe][1] - rgb[2 * Pw][1]);
279
6.21k
          int dv = ABS(rgb[2 * Pn][1] - rgb[2 * Ps][1]) +
280
6.21k
                   ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2]) +
281
6.21k
                   ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2] + rgb[2 * Ps][1] -
282
6.21k
                       rgb[2 * Pn][1]);
283
6.21k
          int d;
284
6.21k
          if (dv > dh)
285
2.27k
            d = Pw;
286
3.94k
          else
287
3.94k
            d = Pn;
288
6.21k
          rgb_ahd[1][moff][1] = rgb[0][1] =
289
6.21k
              (rgb[+2 * d][1] + rgb[-2 * d][1]) / 2;
290
6.21k
        }
291
28.3k
      }
292
6.39M
    }
293
164k
  }
294
1.18k
}
295
296
void AAHD::evaluate_ahd()
297
1.18k
{
298
1.18k
  int hvdir[4] = {Pw, Pe, Pn, Ps};
299
  /*
300
   * YUV
301
   *
302
   */
303
3.56k
  for (int d = 0; d < 2; ++d)
304
2.37k
  {
305
31.5M
    for (int i = 0; i < nr_width * nr_height; ++i)
306
31.5M
    {
307
31.5M
      ushort3 rgb;
308
126M
      for (int c = 0; c < 3; ++c)
309
94.6M
      {
310
94.6M
        rgb[c] = ushort(gammaLUT[rgb_ahd[d][i][c]]);
311
94.6M
      }
312
31.5M
      yuv[d][i][0] = Y(rgb);
313
31.5M
      yuv[d][i][1] = U(rgb);
314
31.5M
      yuv[d][i][2] = V(rgb);
315
31.5M
    }
316
2.37k
  }
317
  /* */
318
  /*
319
   * Lab
320
   *
321
   float r, cbrt[0x10000], xyz[3], xyz_cam[3][4];
322
   for (int i = 0; i < 0x10000; i++) {
323
   r = i / 65535.0;
324
   cbrt[i] = r > 0.008856 ? pow((double) r, (double) (1 / 3.0)) : 7.787 * r + 16
325
   / 116.0;
326
   }
327
   for (int i = 0; i < 3; i++)
328
   for (int j = 0; j < 3; j++) {
329
   xyz_cam[i][j] = 0;
330
   for (int k = 0; k < 3; k++)
331
   xyz_cam[i][j] += xyz_rgb[i][k] * libraw.imgdata.color.rgb_cam[k][j] /
332
   d65_white[i];
333
   }
334
   for (int d = 0; d < 2; ++d)
335
   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) {
336
   int moff = nr_offset(i + nr_margin, nr_margin);
337
   for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff) {
338
   xyz[0] = xyz[1] = xyz[2] = 0.5;
339
   for (int c = 0; c < 3; c++) {
340
   xyz[0] += xyz_cam[0][c] * rgb_ahd[d][moff][c];
341
   xyz[1] += xyz_cam[1][c] * rgb_ahd[d][moff][c];
342
   xyz[2] += xyz_cam[2][c] * rgb_ahd[d][moff][c];
343
   }
344
   xyz[0] = cbrt[CLIP((int) xyz[0])];
345
   xyz[1] = cbrt[CLIP((int) xyz[1])];
346
   xyz[2] = cbrt[CLIP((int) xyz[2])];
347
   yuv[d][moff][0] = 64 * (116 * xyz[1] - 16);
348
   yuv[d][moff][1] = 64 * 500 * (xyz[0] - xyz[1]);
349
   yuv[d][moff][2] = 64 * 200 * (xyz[1] - xyz[2]);
350
   }
351
   }
352
   * Lab */
353
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
354
164k
  {
355
164k
    int moff = nr_offset(i + nr_margin, nr_margin);
356
12.9M
    for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff)
357
12.7M
    {
358
12.7M
      int3 *ynr;
359
12.7M
      float ydiff[2][4];
360
12.7M
      int uvdiff[2][4];
361
38.3M
      for (int d = 0; d < 2; ++d)
362
25.5M
      {
363
25.5M
        ynr = &yuv[d][moff];
364
127M
        for (int k = 0; k < 4; k++)
365
102M
        {
366
102M
          ydiff[d][k] = float(ABS(ynr[0][0] - ynr[hvdir[k]][0]));
367
102M
          uvdiff[d][k] = SQR(ynr[0][1] - ynr[hvdir[k]][1]) +
368
102M
                         SQR(ynr[0][2] - ynr[hvdir[k]][2]);
369
102M
        }
370
25.5M
      }
371
12.7M
      float yeps =
372
12.7M
          MIN(MAX(ydiff[0][0], ydiff[0][1]), MAX(ydiff[1][2], ydiff[1][3]));
373
12.7M
      int uveps =
374
12.7M
          MIN(MAX(uvdiff[0][0], uvdiff[0][1]), MAX(uvdiff[1][2], uvdiff[1][3]));
375
38.3M
      for (int d = 0; d < 2; d++)
376
25.5M
      {
377
25.5M
        ynr = &yuv[d][moff];
378
127M
        for (int k = 0; k < 4; k++)
379
102M
          if (ydiff[d][k] <= yeps && uvdiff[d][k] <= uveps)
380
68.6M
          {
381
68.6M
            homo[d][moff + hvdir[k]]++;
382
68.6M
            if (k / 2 == d)
383
38.8M
            {
384
              // если в сонаправленном направлении интеполяции следующие точки
385
              // так же гомогенны, учтём их тоже
386
44.4M
              for (int m = 2; m < 4; ++m)
387
43.6M
              {
388
43.6M
                int hvd = m * hvdir[k];
389
43.6M
                if (ABS(ynr[0][0] - ynr[hvd][0]) < yeps &&
390
6.49M
                    SQR(ynr[0][1] - ynr[hvd][1]) +
391
6.49M
                            SQR(ynr[0][2] - ynr[hvd][2]) <
392
6.49M
                        uveps)
393
5.60M
                {
394
5.60M
                  homo[d][moff + hvd]++;
395
5.60M
                }
396
38.0M
                else
397
38.0M
                  break;
398
43.6M
              }
399
38.8M
            }
400
68.6M
          }
401
25.5M
      }
402
12.7M
    }
403
164k
  }
404
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
405
164k
  {
406
164k
    int moff = nr_offset(i + nr_margin, nr_margin);
407
12.9M
    for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff)
408
12.7M
    {
409
12.7M
      char hm[2];
410
38.3M
      for (int d = 0; d < 2; d++)
411
25.5M
      {
412
25.5M
        hm[d] = 0;
413
25.5M
        char *hh = &homo[d][moff];
414
102M
        for (int hx = -1; hx < 2; hx++)
415
306M
          for (int hy = -1; hy < 2; hy++)
416
230M
            hm[d] += hh[nr_offset(hy, hx)];
417
25.5M
      }
418
12.7M
      char d = 0;
419
12.7M
      if (hm[0] != hm[1])
420
6.45M
      {
421
6.45M
        if (hm[1] > hm[0])
422
1.66M
        {
423
1.66M
          d = VERSH;
424
1.66M
        }
425
4.78M
        else
426
4.78M
        {
427
4.78M
          d = HORSH;
428
4.78M
        }
429
6.45M
      }
430
6.33M
      else
431
6.33M
      {
432
6.33M
        int3 *ynr = &yuv[1][moff];
433
6.33M
        int gv = SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]);
434
6.33M
        gv += SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
435
6.33M
              SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2]);
436
6.33M
        ynr = &yuv[1][moff + Pn];
437
6.33M
        gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) +
438
6.33M
               SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
439
6.33M
               SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) /
440
6.33M
              2;
441
6.33M
        ynr = &yuv[1][moff + Ps];
442
6.33M
        gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) +
443
6.33M
               SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
444
6.33M
               SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) /
445
6.33M
              2;
446
6.33M
        ynr = &yuv[0][moff];
447
6.33M
        int gh = SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]);
448
6.33M
        gh += SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
449
6.33M
              SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2]);
450
6.33M
        ynr = &yuv[0][moff + Pw];
451
6.33M
        gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) +
452
6.33M
               SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
453
6.33M
               SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) /
454
6.33M
              2;
455
6.33M
        ynr = &yuv[0][moff + Pe];
456
6.33M
        gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) +
457
6.33M
               SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
458
6.33M
               SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) /
459
6.33M
              2;
460
6.33M
        if (gv > gh)
461
426k
          d = HOR;
462
5.90M
        else
463
5.90M
          d = VER;
464
6.33M
      }
465
12.7M
      ndir[moff] |= d;
466
12.7M
    }
467
164k
  }
468
1.18k
}
469
470
void AAHD::combine_image()
471
1.18k
{
472
165k
  for (int i = 0, i_out = 0; i < libraw.imgdata.sizes.iheight; ++i)
473
164k
  {
474
164k
    int moff = nr_offset(i + nr_margin, nr_margin);
475
12.9M
    for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff, ++i_out)
476
12.7M
    {
477
12.7M
      if (ndir[moff] & HOT)
478
14.0k
      {
479
14.0k
        int c = libraw.COLOR(i, j);
480
14.0k
        rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] =
481
14.0k
            libraw.imgdata.image[i_out][c];
482
14.0k
      }
483
12.7M
      if (ndir[moff] & VER)
484
7.86M
      {
485
7.86M
        libraw.imgdata.image[i_out][0] = rgb_ahd[1][moff][0];
486
7.86M
        libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] =
487
7.86M
            rgb_ahd[1][moff][1];
488
7.86M
        libraw.imgdata.image[i_out][2] = rgb_ahd[1][moff][2];
489
7.86M
      }
490
4.92M
      else
491
4.92M
      {
492
4.92M
        libraw.imgdata.image[i_out][0] = rgb_ahd[0][moff][0];
493
4.92M
        libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] =
494
4.92M
            rgb_ahd[0][moff][1];
495
4.92M
        libraw.imgdata.image[i_out][2] = rgb_ahd[0][moff][2];
496
4.92M
      }
497
12.7M
    }
498
164k
  }
499
1.18k
}
500
501
void AAHD::refine_hv_dirs()
502
1.18k
{
503
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
504
164k
  {
505
164k
    refine_hv_dirs(i, i & 1);
506
164k
  }
507
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
508
164k
  {
509
164k
    refine_hv_dirs(i, (i & 1) ^ 1);
510
164k
  }
511
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
512
164k
  {
513
164k
    refine_ihv_dirs(i);
514
164k
  }
515
1.18k
}
516
517
void AAHD::refine_ihv_dirs(int i)
518
164k
{
519
164k
  int iwidth = libraw.imgdata.sizes.iwidth;
520
164k
  int moff = nr_offset(i + nr_margin, nr_margin);
521
12.9M
  for (int j = 0; j < iwidth; j++, ++moff)
522
12.7M
  {
523
12.7M
    if (ndir[moff] & HVSH)
524
6.45M
      continue;
525
6.33M
    int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) +
526
6.33M
             (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER);
527
6.33M
    int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) +
528
6.33M
             (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR);
529
6.33M
    nv /= VER;
530
6.33M
    nh /= HOR;
531
6.33M
    if ((ndir[moff] & VER) && nh > 3)
532
1.15k
    {
533
1.15k
      ndir[moff] &= ~VER;
534
1.15k
      ndir[moff] |= HOR;
535
1.15k
    }
536
6.33M
    if ((ndir[moff] & HOR) && nv > 3)
537
132
    {
538
132
      ndir[moff] &= ~HOR;
539
132
      ndir[moff] |= VER;
540
132
    }
541
6.33M
  }
542
164k
}
543
544
void AAHD::refine_hv_dirs(int i, int js)
545
329k
{
546
329k
  int iwidth = libraw.imgdata.sizes.iwidth;
547
329k
  int moff = nr_offset(i + nr_margin, nr_margin + js);
548
13.1M
  for (int j = js; j < iwidth; j += 2, moff += 2)
549
12.7M
  {
550
12.7M
    int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) +
551
12.7M
             (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER);
552
12.7M
    int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) +
553
12.7M
             (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR);
554
12.7M
    bool codir = (ndir[moff] & VER)
555
12.7M
                     ? ((ndir[moff + Pn] & VER) || (ndir[moff + Ps] & VER))
556
12.7M
                     : ((ndir[moff + Pw] & HOR) || (ndir[moff + Pe] & HOR));
557
12.7M
    nv /= VER;
558
12.7M
    nh /= HOR;
559
12.7M
    if ((ndir[moff] & VER) && (nh > 2 && !codir))
560
37.7k
    {
561
37.7k
      ndir[moff] &= ~VER;
562
37.7k
      ndir[moff] |= HOR;
563
37.7k
    }
564
12.7M
    if ((ndir[moff] & HOR) && (nv > 2 && !codir))
565
327k
    {
566
327k
      ndir[moff] &= ~HOR;
567
327k
      ndir[moff] |= VER;
568
327k
    }
569
12.7M
  }
570
329k
}
571
572
/*
573
 * вычисление недостающих зелёных точек.
574
 */
575
void AAHD::make_ahd_greens()
576
1.18k
{
577
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
578
164k
  {
579
164k
    make_ahd_gline(i);
580
164k
  }
581
1.18k
}
582
583
void AAHD::make_ahd_gline(int i)
584
164k
{
585
164k
  int iwidth = libraw.imgdata.sizes.iwidth;
586
164k
  int js = libraw.COLOR(i, 0) & 1;
587
164k
  int kc = libraw.COLOR(i, js);
588
  /*
589
   * js -- начальная х-координата, которая попадает мимо известного зелёного
590
   * kc -- известный цвет в точке интерполирования
591
   */
592
164k
  int hvdir[2] = {Pe, Ps};
593
494k
  for (int d = 0; d < 2; ++d)
594
329k
  {
595
329k
    int moff = nr_offset(i + nr_margin, nr_margin + js);
596
13.1M
    for (int j = js; j < iwidth; j += 2, moff += 2)
597
12.7M
    {
598
12.7M
      ushort3 *cnr;
599
12.7M
      cnr = &rgb_ahd[d][moff];
600
12.7M
      int h1 = 2 * cnr[-hvdir[d]][1] - int(cnr[-2 * hvdir[d]][kc] + cnr[0][kc]);
601
12.7M
      int h2 = 2 * cnr[+hvdir[d]][1] - int(cnr[+2 * hvdir[d]][kc] + cnr[0][kc]);
602
12.7M
      int h0 = (h1 + h2) / 4;
603
12.7M
      int eg = cnr[0][kc] + h0;
604
12.7M
      int min = MIN(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]);
605
12.7M
      int max = MAX(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]);
606
12.7M
      min -= min / OverFraction;
607
12.7M
      max += max / OverFraction;
608
12.7M
      if (eg < min)
609
479k
        eg = min - int(sqrtf(float(min - eg)));
610
12.3M
      else if (eg > max)
611
635k
        eg = max + int(sqrtf(float(eg - max)));
612
12.7M
      if (eg > channel_maximum[1])
613
303k
        eg = channel_maximum[1];
614
12.4M
      else if (eg < channel_minimum[1])
615
1.03M
        eg = channel_minimum[1];
616
12.7M
      cnr[0][1] = eg;
617
12.7M
    }
618
329k
  }
619
164k
}
620
621
/*
622
 * отладочная функция
623
 */
624
625
void AAHD::illustrate_dirs()
626
0
{
627
0
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
628
0
  {
629
0
    illustrate_dline(i);
630
0
  }
631
0
}
632
633
void AAHD::illustrate_dline(int i)
634
0
{
635
0
  int iwidth = libraw.imgdata.sizes.iwidth;
636
0
  for (int j = 0; j < iwidth; j++)
637
0
  {
638
0
    int x = j + nr_margin;
639
0
    int y = i + nr_margin;
640
0
    rgb_ahd[1][nr_offset(y, x)][0] = rgb_ahd[1][nr_offset(y, x)][1] =
641
0
        rgb_ahd[1][nr_offset(y, x)][2] = rgb_ahd[0][nr_offset(y, x)][0] =
642
0
            rgb_ahd[0][nr_offset(y, x)][1] = rgb_ahd[0][nr_offset(y, x)][2] = 0;
643
0
    int l = ndir[nr_offset(y, x)] & HVSH;
644
0
    l /= HVSH;
645
0
    if (ndir[nr_offset(y, x)] & VER)
646
0
      rgb_ahd[1][nr_offset(y, x)][0] =
647
0
          l * channel_maximum[0] / 4 + channel_maximum[0] / 4;
648
0
    else
649
0
      rgb_ahd[0][nr_offset(y, x)][2] =
650
0
          l * channel_maximum[2] / 4 + channel_maximum[2] / 4;
651
0
  }
652
0
}
653
654
void AAHD::make_ahd_rb_hv(int i)
655
164k
{
656
164k
  int iwidth = libraw.imgdata.sizes.iwidth;
657
164k
  int js = libraw.COLOR(i, 0) & 1;
658
164k
  int kc = libraw.COLOR(i, js);
659
164k
  js ^= 1; // начальная координата зелёного
660
164k
  int hvdir[2] = {Pe, Ps};
661
  // интерполяция вертикальных вертикально и горизонтальных горизонтально
662
6.55M
  for (int j = js; j < iwidth; j += 2)
663
6.39M
  {
664
6.39M
    int x = j + nr_margin;
665
6.39M
    int y = i + nr_margin;
666
6.39M
    int moff = nr_offset(y, x);
667
19.1M
    for (int d = 0; d < 2; ++d)
668
12.7M
    {
669
12.7M
      ushort3 *cnr;
670
12.7M
      cnr = &rgb_ahd[d][moff];
671
12.7M
      int c = kc ^ (d << 1); // цвет соответсвенного направления, для
672
                             // горизонтального c = kc, для вертикального c=kc^2
673
12.7M
      int h1 = cnr[-hvdir[d]][c] - cnr[-hvdir[d]][1];
674
12.7M
      int h2 = cnr[+hvdir[d]][c] - cnr[+hvdir[d]][1];
675
12.7M
      int h0 = (h1 + h2) / 2;
676
12.7M
      int eg = cnr[0][1] + h0;
677
      //      int min = MIN(cnr[-hvdir[d]][c], cnr[+hvdir[d]][c]);
678
      //      int max = MAX(cnr[-hvdir[d]][c], cnr[+hvdir[d]][c]);
679
      //      min -= min / OverFraction;
680
      //      max += max / OverFraction;
681
      //      if (eg < min)
682
      //        eg = min - sqrt(min - eg);
683
      //      else if (eg > max)
684
      //        eg = max + sqrt(eg - max);
685
12.7M
      if (eg > channel_maximum[c])
686
429k
        eg = channel_maximum[c];
687
12.3M
      else if (eg < channel_minimum[c])
688
2.06M
        eg = channel_minimum[c];
689
12.7M
      cnr[0][c] = eg;
690
12.7M
    }
691
6.39M
  }
692
164k
}
693
694
void AAHD::make_ahd_rb()
695
1.18k
{
696
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
697
164k
  {
698
164k
    make_ahd_rb_hv(i);
699
164k
  }
700
165k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
701
164k
  {
702
164k
    make_ahd_rb_last(i);
703
164k
  }
704
1.18k
}
705
706
void AAHD::make_ahd_rb_last(int i)
707
164k
{
708
164k
  int iwidth = libraw.imgdata.sizes.iwidth;
709
164k
  int js = libraw.COLOR(i, 0) & 1;
710
164k
  int kc = libraw.COLOR(i, js);
711
  /*
712
   * js -- начальная х-координата, которая попадает мимо известного зелёного
713
   * kc -- известный цвет в точке интерполирования
714
   */
715
164k
  int dirs[2][3] = {{Pnw, Pn, Pne}, {Pnw, Pw, Psw}};
716
164k
  int moff = nr_offset(i + nr_margin, nr_margin);
717
12.9M
  for (int j = 0; j < iwidth; j++)
718
12.7M
  {
719
38.3M
    for (int d = 0; d < 2; ++d)
720
25.5M
    {
721
25.5M
      ushort3 *cnr;
722
25.5M
      cnr = &rgb_ahd[d][moff + j];
723
25.5M
      int c = kc ^ 2;
724
25.5M
      if ((j & 1) != js)
725
12.7M
      {
726
        // точка зелёного, для вертикального направления нужен альтернативный
727
        // строчному цвет
728
12.7M
        c ^= d << 1;
729
12.7M
      }
730
25.5M
      int bh = 0, bk = 0;
731
25.5M
      int bgd = 0;
732
102M
      for (int k = 0; k < 3; ++k)
733
306M
        for (int h = 0; h < 3; ++h)
734
230M
        {
735
          // градиент зелёного плюс градиент {r,b}
736
230M
          int gd =
737
230M
              ABS(2 * cnr[0][1] - (cnr[+dirs[d][k]][1] + cnr[-dirs[d][h]][1])) +
738
230M
              ABS(cnr[+dirs[d][k]][c] - cnr[-dirs[d][h]][c]) / 4 +
739
230M
              ABS(cnr[+dirs[d][k]][c] - cnr[+dirs[d][k]][1] +
740
230M
                  cnr[-dirs[d][h]][1] - cnr[-dirs[d][h]][c]) /
741
230M
                  4;
742
230M
          if (bgd == 0 || gd < bgd)
743
161M
          {
744
161M
            bgd = gd;
745
161M
            bh = h;
746
161M
            bk = k;
747
161M
          }
748
230M
        }
749
25.5M
      int h1 = cnr[+dirs[d][bk]][c] - cnr[+dirs[d][bk]][1];
750
25.5M
      int h2 = cnr[-dirs[d][bh]][c] - cnr[-dirs[d][bh]][1];
751
25.5M
      int eg = cnr[0][1] + (h1 + h2) / 2;
752
      //      int min = MIN(cnr[+dirs[d][bk]][c], cnr[-dirs[d][bh]][c]);
753
      //      int max = MAX(cnr[+dirs[d][bk]][c], cnr[-dirs[d][bh]][c]);
754
      //      min -= min / OverFraction;
755
      //      max += max / OverFraction;
756
      //      if (eg < min)
757
      //        eg = min - sqrt(min - eg);
758
      //      else if (eg > max)
759
      //        eg = max + sqrt(eg - max);
760
25.5M
      if (eg > channel_maximum[c])
761
1.96M
        eg = channel_maximum[c];
762
23.6M
      else if (eg < channel_minimum[c])
763
3.34M
        eg = channel_minimum[c];
764
25.5M
      cnr[0][c] = eg;
765
25.5M
    }
766
12.7M
  }
767
164k
}
768
769
1.18k
AAHD::~AAHD() { free(rgb_ahd[0]); }
770
771
void LibRaw::aahd_interpolate()
772
1.18k
{
773
1.18k
  AAHD aahd(*this);
774
1.18k
  aahd.hide_hots();
775
1.18k
  aahd.make_ahd_greens();
776
1.18k
  aahd.make_ahd_rb();
777
1.18k
  aahd.evaluate_ahd();
778
1.18k
  aahd.refine_hv_dirs();
779
  //  aahd.illustrate_dirs();
780
1.18k
  aahd.combine_image();
781
1.18k
}