Coverage Report

Created: 2026-09-13 06:28

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
364k
#define Pnw (-1 - nr_width)
25
66.3M
#define Pn (-nr_width)
26
182k
#define Pne (+1 - nr_width)
27
87.9M
#define Pe (+1)
28
#define Pse (+1 + nr_width)
29
57.5M
#define Ps (+nr_width)
30
182k
#define Psw (-1 + nr_width)
31
64.0M
#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
36.3M
  {
66
36.3M
    return int(yuv_cam[0][0] * rgb[0] + yuv_cam[0][1] * rgb[1] +
67
36.3M
           yuv_cam[0][2] * rgb[2]);
68
36.3M
  }
69
  int inline U(ushort3 &rgb) throw()
70
36.3M
  {
71
36.3M
    return int(yuv_cam[1][0] * rgb[0] + yuv_cam[1][1] * rgb[1] +
72
36.3M
           yuv_cam[1][2] * rgb[2]);
73
36.3M
  }
74
  int inline V(ushort3 &rgb) throw()
75
36.3M
  {
76
36.3M
    return int(yuv_cam[2][0] * rgb[0] + yuv_cam[2][1] * rgb[1] +
77
36.3M
           yuv_cam[2][2] * rgb[2]);
78
36.3M
  }
79
  inline int nr_offset(int row, int col) throw()
80
286M
  {
81
286M
    return (row * nr_width + col);
82
286M
  }
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.30k
AAHD::AAHD(LibRaw &_libraw) : libraw(_libraw)
130
1.30k
{
131
1.30k
  nr_height = libraw.imgdata.sizes.iheight + nr_margin * 2;
132
1.30k
  nr_width = libraw.imgdata.sizes.iwidth + nr_margin * 2;
133
1.30k
  rgb_ahd[0] = (ushort3 *)calloc(nr_height * nr_width,
134
1.30k
                                 (sizeof(ushort3) * 2 + sizeof(int3) * 2 + 3));
135
1.30k
  if (!rgb_ahd[0])
136
0
    throw LIBRAW_EXCEPTION_ALLOC;
137
138
1.30k
  rgb_ahd[1] = rgb_ahd[0] + nr_height * nr_width;
139
1.30k
  yuv[0] = (int3 *)(rgb_ahd[1] + nr_height * nr_width);
140
1.30k
  yuv[1] = yuv[0] + nr_height * nr_width;
141
1.30k
  ndir = (char *)(yuv[1] + nr_height * nr_width);
142
1.30k
  homo[0] = ndir + nr_height * nr_width;
143
1.30k
  homo[1] = homo[0] + nr_height * nr_width;
144
1.30k
  channel_maximum[0] = channel_maximum[1] = channel_maximum[2] = 0;
145
1.30k
  channel_minimum[0] = libraw.imgdata.image[0][0];
146
1.30k
  channel_minimum[1] = libraw.imgdata.image[0][1];
147
1.30k
  channel_minimum[2] = libraw.imgdata.image[0][2];
148
1.30k
  int iwidth = libraw.imgdata.sizes.iwidth;
149
5.22k
  for (int i = 0; i < 3; ++i)
150
15.6k
    for (int j = 0; j < 3; ++j)
151
11.7k
    {
152
11.7k
      yuv_cam[i][j] = 0;
153
46.9k
      for (int k = 0; k < 3; ++k)
154
35.2k
        yuv_cam[i][j] += yuv_coeff[i][k] * libraw.imgdata.color.rgb_cam[k][j];
155
11.7k
    }
156
1.30k
  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
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
167
182k
  {
168
182k
    int col_cache[48];
169
8.91M
    for (int j = 0; j < 48; ++j)
170
8.73M
    {
171
8.73M
      int c = libraw.COLOR(i, j);
172
8.73M
      if (c == 3)
173
0
        c = 1;
174
8.73M
      col_cache[j] = c;
175
8.73M
    }
176
182k
    int moff = nr_offset(i + nr_margin, nr_margin);
177
15.5M
    for (int j = 0; j < iwidth; ++j, ++moff)
178
15.3M
    {
179
15.3M
      int c = col_cache[j % 48];
180
15.3M
      unsigned short d = libraw.imgdata.image[i * iwidth + j][c];
181
15.3M
      if (d != 0)
182
3.98M
      {
183
3.98M
        if (channel_maximum[c] < d)
184
11.9k
          channel_maximum[c] = d;
185
3.98M
        if (channel_minimum[c] > d)
186
15.4k
          channel_minimum[c] = d;
187
3.98M
        rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] = d;
188
3.98M
      }
189
15.3M
    }
190
182k
  }
191
1.30k
  channels_max =
192
1.30k
      MAX(MAX(channel_maximum[0], channel_maximum[1]), channel_maximum[2]);
193
1.30k
}
194
195
void AAHD::hide_hots()
196
1.30k
{
197
1.30k
  int iwidth = libraw.imgdata.sizes.iwidth;
198
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
199
182k
  {
200
182k
    int js = libraw.COLOR(i, 0) & 1;
201
182k
    int kc = libraw.COLOR(i, js);
202
    /*
203
     * js -- начальная х-координата, которая попадает мимо известного зелёного
204
     * kc -- известный цвет в точке интерполирования
205
     */
206
182k
    int moff = nr_offset(i + nr_margin, nr_margin + js);
207
7.84M
    for (int j = js; j < iwidth; j += 2, moff += 2)
208
7.66M
    {
209
7.66M
      ushort3 *rgb = &rgb_ahd[0][moff];
210
7.66M
      int c = rgb[0][kc];
211
7.66M
      if ((c > rgb[2 * Pe][kc] && c > rgb[2 * Pw][kc] && c > rgb[2 * Pn][kc] &&
212
75.3k
           c > rgb[2 * Ps][kc] && c > rgb[Pe][1] && c > rgb[Pw][1] &&
213
32.3k
           c > rgb[Pn][1] && c > rgb[Ps][1]) ||
214
7.63M
          (c < rgb[2 * Pe][kc] && c < rgb[2 * Pw][kc] && c < rgb[2 * Pn][kc] &&
215
42.1k
           c < rgb[2 * Ps][kc] && c < rgb[Pe][1] && c < rgb[Pw][1] &&
216
14.4k
           c < rgb[Pn][1] && c < rgb[Ps][1]))
217
36.7k
      {
218
36.7k
        int chot = c >> Thot;
219
36.7k
        int cdead = c << Tdead;
220
36.7k
        int avg = 0;
221
146k
        for (int k = -2; k < 3; k += 2)
222
440k
          for (int m = -2; m < 3; m += 2)
223
330k
            if (m == 0 && k == 0)
224
36.7k
              continue;
225
293k
            else
226
293k
              avg += rgb[nr_offset(k, m)][kc];
227
36.7k
        avg /= 8;
228
36.7k
        if (chot > avg || cdead < avg)
229
9.80k
        {
230
9.80k
          ndir[moff] |= HOT;
231
9.80k
          int dh =
232
9.80k
              ABS(rgb[2 * Pw][kc] - rgb[2 * Pe][kc]) +
233
9.80k
              ABS(rgb[Pw][1] - rgb[Pe][1]) +
234
9.80k
              ABS(rgb[Pw][1] - rgb[Pe][1] + rgb[2 * Pe][kc] - rgb[2 * Pw][kc]);
235
9.80k
          int dv =
236
9.80k
              ABS(rgb[2 * Pn][kc] - rgb[2 * Ps][kc]) +
237
9.80k
              ABS(rgb[Pn][1] - rgb[Ps][1]) +
238
9.80k
              ABS(rgb[Pn][1] - rgb[Ps][1] + rgb[2 * Ps][kc] - rgb[2 * Pn][kc]);
239
9.80k
          int d;
240
9.80k
          if (dv > dh)
241
3.41k
            d = Pw;
242
6.39k
          else
243
6.39k
            d = Pn;
244
9.80k
          rgb_ahd[1][moff][kc] = rgb[0][kc] =
245
9.80k
              (rgb[+2 * d][kc] + rgb[-2 * d][kc]) / 2;
246
9.80k
        }
247
36.7k
      }
248
7.66M
    }
249
182k
    js ^= 1;
250
182k
    moff = nr_offset(i + nr_margin, nr_margin + js);
251
7.84M
    for (int j = js; j < iwidth; j += 2, moff += 2)
252
7.66M
    {
253
7.66M
      ushort3 *rgb = &rgb_ahd[0][moff];
254
7.66M
      int c = rgb[0][1];
255
7.66M
      if ((c > rgb[2 * Pe][1] && c > rgb[2 * Pw][1] && c > rgb[2 * Pn][1] &&
256
72.2k
           c > rgb[2 * Ps][1] && c > rgb[Pe][kc] && c > rgb[Pw][kc] &&
257
30.9k
           c > rgb[Pn][kc ^ 2] && c > rgb[Ps][kc ^ 2]) ||
258
7.64M
          (c < rgb[2 * Pe][1] && c < rgb[2 * Pw][1] && c < rgb[2 * Pn][1] &&
259
50.0k
           c < rgb[2 * Ps][1] && c < rgb[Pe][kc] && c < rgb[Pw][kc] &&
260
13.3k
           c < rgb[Pn][kc ^ 2] && c < rgb[Ps][kc ^ 2]))
261
30.7k
      {
262
30.7k
        int chot = c >> Thot;
263
30.7k
        int cdead = c << Tdead;
264
30.7k
        int avg = 0;
265
123k
        for (int k = -2; k < 3; k += 2)
266
369k
          for (int m = -2; m < 3; m += 2)
267
276k
            if (k == 0 && m == 0)
268
30.7k
              continue;
269
246k
            else
270
246k
              avg += rgb[nr_offset(k, m)][1];
271
30.7k
        avg /= 8;
272
30.7k
        if (chot > avg || cdead < avg)
273
5.73k
        {
274
5.73k
          ndir[moff] |= HOT;
275
5.73k
          int dh =
276
5.73k
              ABS(rgb[2 * Pw][1] - rgb[2 * Pe][1]) +
277
5.73k
              ABS(rgb[Pw][kc] - rgb[Pe][kc]) +
278
5.73k
              ABS(rgb[Pw][kc] - rgb[Pe][kc] + rgb[2 * Pe][1] - rgb[2 * Pw][1]);
279
5.73k
          int dv = ABS(rgb[2 * Pn][1] - rgb[2 * Ps][1]) +
280
5.73k
                   ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2]) +
281
5.73k
                   ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2] + rgb[2 * Ps][1] -
282
5.73k
                       rgb[2 * Pn][1]);
283
5.73k
          int d;
284
5.73k
          if (dv > dh)
285
1.95k
            d = Pw;
286
3.78k
          else
287
3.78k
            d = Pn;
288
5.73k
          rgb_ahd[1][moff][1] = rgb[0][1] =
289
5.73k
              (rgb[+2 * d][1] + rgb[-2 * d][1]) / 2;
290
5.73k
        }
291
30.7k
      }
292
7.66M
    }
293
182k
  }
294
1.30k
}
295
296
void AAHD::evaluate_ahd()
297
1.30k
{
298
1.30k
  int hvdir[4] = {Pw, Pe, Pn, Ps};
299
  /*
300
   * YUV
301
   *
302
   */
303
3.91k
  for (int d = 0; d < 2; ++d)
304
2.61k
  {
305
36.3M
    for (int i = 0; i < nr_width * nr_height; ++i)
306
36.3M
    {
307
36.3M
      ushort3 rgb;
308
145M
      for (int c = 0; c < 3; ++c)
309
109M
      {
310
109M
        rgb[c] = ushort(gammaLUT[rgb_ahd[d][i][c]]);
311
109M
      }
312
36.3M
      yuv[d][i][0] = Y(rgb);
313
36.3M
      yuv[d][i][1] = U(rgb);
314
36.3M
      yuv[d][i][2] = V(rgb);
315
36.3M
    }
316
2.61k
  }
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
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
354
182k
  {
355
182k
    int moff = nr_offset(i + nr_margin, nr_margin);
356
15.5M
    for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff)
357
15.3M
    {
358
15.3M
      int3 *ynr;
359
15.3M
      float ydiff[2][4];
360
15.3M
      int uvdiff[2][4];
361
45.9M
      for (int d = 0; d < 2; ++d)
362
30.6M
      {
363
30.6M
        ynr = &yuv[d][moff];
364
153M
        for (int k = 0; k < 4; k++)
365
122M
        {
366
122M
          ydiff[d][k] = float(ABS(ynr[0][0] - ynr[hvdir[k]][0]));
367
122M
          uvdiff[d][k] = SQR(ynr[0][1] - ynr[hvdir[k]][1]) +
368
122M
                         SQR(ynr[0][2] - ynr[hvdir[k]][2]);
369
122M
        }
370
30.6M
      }
371
15.3M
      float yeps =
372
15.3M
          MIN(MAX(ydiff[0][0], ydiff[0][1]), MAX(ydiff[1][2], ydiff[1][3]));
373
15.3M
      int uveps =
374
15.3M
          MIN(MAX(uvdiff[0][0], uvdiff[0][1]), MAX(uvdiff[1][2], uvdiff[1][3]));
375
45.9M
      for (int d = 0; d < 2; d++)
376
30.6M
      {
377
30.6M
        ynr = &yuv[d][moff];
378
153M
        for (int k = 0; k < 4; k++)
379
122M
          if (ydiff[d][k] <= yeps && uvdiff[d][k] <= uveps)
380
82.9M
          {
381
82.9M
            homo[d][moff + hvdir[k]]++;
382
82.9M
            if (k / 2 == d)
383
47.2M
            {
384
              // если в сонаправленном направлении интеполяции следующие точки
385
              // так же гомогенны, учтём их тоже
386
55.8M
              for (int m = 2; m < 4; ++m)
387
54.8M
              {
388
54.8M
                int hvd = m * hvdir[k];
389
54.8M
                if (ABS(ynr[0][0] - ynr[hvd][0]) < yeps &&
390
9.52M
                    SQR(ynr[0][1] - ynr[hvd][1]) +
391
9.52M
                            SQR(ynr[0][2] - ynr[hvd][2]) <
392
9.52M
                        uveps)
393
8.66M
                {
394
8.66M
                  homo[d][moff + hvd]++;
395
8.66M
                }
396
46.2M
                else
397
46.2M
                  break;
398
54.8M
              }
399
47.2M
            }
400
82.9M
          }
401
30.6M
      }
402
15.3M
    }
403
182k
  }
404
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
405
182k
  {
406
182k
    int moff = nr_offset(i + nr_margin, nr_margin);
407
15.5M
    for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff)
408
15.3M
    {
409
15.3M
      char hm[2];
410
45.9M
      for (int d = 0; d < 2; d++)
411
30.6M
      {
412
30.6M
        hm[d] = 0;
413
30.6M
        char *hh = &homo[d][moff];
414
122M
        for (int hx = -1; hx < 2; hx++)
415
367M
          for (int hy = -1; hy < 2; hy++)
416
275M
            hm[d] += hh[nr_offset(hy, hx)];
417
30.6M
      }
418
15.3M
      char d = 0;
419
15.3M
      if (hm[0] != hm[1])
420
6.89M
      {
421
6.89M
        if (hm[1] > hm[0])
422
1.79M
        {
423
1.79M
          d = VERSH;
424
1.79M
        }
425
5.10M
        else
426
5.10M
        {
427
5.10M
          d = HORSH;
428
5.10M
        }
429
6.89M
      }
430
8.43M
      else
431
8.43M
      {
432
8.43M
        int3 *ynr = &yuv[1][moff];
433
8.43M
        int gv = SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]);
434
8.43M
        gv += SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
435
8.43M
              SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2]);
436
8.43M
        ynr = &yuv[1][moff + Pn];
437
8.43M
        gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) +
438
8.43M
               SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
439
8.43M
               SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) /
440
8.43M
              2;
441
8.43M
        ynr = &yuv[1][moff + Ps];
442
8.43M
        gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) +
443
8.43M
               SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
444
8.43M
               SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) /
445
8.43M
              2;
446
8.43M
        ynr = &yuv[0][moff];
447
8.43M
        int gh = SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]);
448
8.43M
        gh += SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
449
8.43M
              SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2]);
450
8.43M
        ynr = &yuv[0][moff + Pw];
451
8.43M
        gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) +
452
8.43M
               SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
453
8.43M
               SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) /
454
8.43M
              2;
455
8.43M
        ynr = &yuv[0][moff + Pe];
456
8.43M
        gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) +
457
8.43M
               SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
458
8.43M
               SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) /
459
8.43M
              2;
460
8.43M
        if (gv > gh)
461
690k
          d = HOR;
462
7.74M
        else
463
7.74M
          d = VER;
464
8.43M
      }
465
15.3M
      ndir[moff] |= d;
466
15.3M
    }
467
182k
  }
468
1.30k
}
469
470
void AAHD::combine_image()
471
1.30k
{
472
183k
  for (int i = 0, i_out = 0; i < libraw.imgdata.sizes.iheight; ++i)
473
182k
  {
474
182k
    int moff = nr_offset(i + nr_margin, nr_margin);
475
15.5M
    for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff, ++i_out)
476
15.3M
    {
477
15.3M
      if (ndir[moff] & HOT)
478
15.5k
      {
479
15.5k
        int c = libraw.COLOR(i, j);
480
15.5k
        rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] =
481
15.5k
            libraw.imgdata.image[i_out][c];
482
15.5k
      }
483
15.3M
      if (ndir[moff] & VER)
484
10.1M
      {
485
10.1M
        libraw.imgdata.image[i_out][0] = rgb_ahd[1][moff][0];
486
10.1M
        libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] =
487
10.1M
            rgb_ahd[1][moff][1];
488
10.1M
        libraw.imgdata.image[i_out][2] = rgb_ahd[1][moff][2];
489
10.1M
      }
490
5.22M
      else
491
5.22M
      {
492
5.22M
        libraw.imgdata.image[i_out][0] = rgb_ahd[0][moff][0];
493
5.22M
        libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] =
494
5.22M
            rgb_ahd[0][moff][1];
495
5.22M
        libraw.imgdata.image[i_out][2] = rgb_ahd[0][moff][2];
496
5.22M
      }
497
15.3M
    }
498
182k
  }
499
1.30k
}
500
501
void AAHD::refine_hv_dirs()
502
1.30k
{
503
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
504
182k
  {
505
182k
    refine_hv_dirs(i, i & 1);
506
182k
  }
507
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
508
182k
  {
509
182k
    refine_hv_dirs(i, (i & 1) ^ 1);
510
182k
  }
511
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
512
182k
  {
513
182k
    refine_ihv_dirs(i);
514
182k
  }
515
1.30k
}
516
517
void AAHD::refine_ihv_dirs(int i)
518
182k
{
519
182k
  int iwidth = libraw.imgdata.sizes.iwidth;
520
182k
  int moff = nr_offset(i + nr_margin, nr_margin);
521
15.5M
  for (int j = 0; j < iwidth; j++, ++moff)
522
15.3M
  {
523
15.3M
    if (ndir[moff] & HVSH)
524
6.89M
      continue;
525
8.43M
    int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) +
526
8.43M
             (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER);
527
8.43M
    int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) +
528
8.43M
             (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR);
529
8.43M
    nv /= VER;
530
8.43M
    nh /= HOR;
531
8.43M
    if ((ndir[moff] & VER) && nh > 3)
532
142
    {
533
142
      ndir[moff] &= ~VER;
534
142
      ndir[moff] |= HOR;
535
142
    }
536
8.43M
    if ((ndir[moff] & HOR) && nv > 3)
537
885
    {
538
885
      ndir[moff] &= ~HOR;
539
885
      ndir[moff] |= VER;
540
885
    }
541
8.43M
  }
542
182k
}
543
544
void AAHD::refine_hv_dirs(int i, int js)
545
364k
{
546
364k
  int iwidth = libraw.imgdata.sizes.iwidth;
547
364k
  int moff = nr_offset(i + nr_margin, nr_margin + js);
548
15.6M
  for (int j = js; j < iwidth; j += 2, moff += 2)
549
15.3M
  {
550
15.3M
    int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) +
551
15.3M
             (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER);
552
15.3M
    int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) +
553
15.3M
             (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR);
554
15.3M
    bool codir = (ndir[moff] & VER)
555
15.3M
                     ? ((ndir[moff + Pn] & VER) || (ndir[moff + Ps] & VER))
556
15.3M
                     : ((ndir[moff + Pw] & HOR) || (ndir[moff + Pe] & HOR));
557
15.3M
    nv /= VER;
558
15.3M
    nh /= HOR;
559
15.3M
    if ((ndir[moff] & VER) && (nh > 2 && !codir))
560
47.8k
    {
561
47.8k
      ndir[moff] &= ~VER;
562
47.8k
      ndir[moff] |= HOR;
563
47.8k
    }
564
15.3M
    if ((ndir[moff] & HOR) && (nv > 2 && !codir))
565
619k
    {
566
619k
      ndir[moff] &= ~HOR;
567
619k
      ndir[moff] |= VER;
568
619k
    }
569
15.3M
  }
570
364k
}
571
572
/*
573
 * вычисление недостающих зелёных точек.
574
 */
575
void AAHD::make_ahd_greens()
576
1.30k
{
577
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
578
182k
  {
579
182k
    make_ahd_gline(i);
580
182k
  }
581
1.30k
}
582
583
void AAHD::make_ahd_gline(int i)
584
182k
{
585
182k
  int iwidth = libraw.imgdata.sizes.iwidth;
586
182k
  int js = libraw.COLOR(i, 0) & 1;
587
182k
  int kc = libraw.COLOR(i, js);
588
  /*
589
   * js -- начальная х-координата, которая попадает мимо известного зелёного
590
   * kc -- известный цвет в точке интерполирования
591
   */
592
182k
  int hvdir[2] = {Pe, Ps};
593
546k
  for (int d = 0; d < 2; ++d)
594
364k
  {
595
364k
    int moff = nr_offset(i + nr_margin, nr_margin + js);
596
15.6M
    for (int j = js; j < iwidth; j += 2, moff += 2)
597
15.3M
    {
598
15.3M
      ushort3 *cnr;
599
15.3M
      cnr = &rgb_ahd[d][moff];
600
15.3M
      int h1 = 2 * cnr[-hvdir[d]][1] - int(cnr[-2 * hvdir[d]][kc] + cnr[0][kc]);
601
15.3M
      int h2 = 2 * cnr[+hvdir[d]][1] - int(cnr[+2 * hvdir[d]][kc] + cnr[0][kc]);
602
15.3M
      int h0 = (h1 + h2) / 4;
603
15.3M
      int eg = cnr[0][kc] + h0;
604
15.3M
      int min = MIN(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]);
605
15.3M
      int max = MAX(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]);
606
15.3M
      min -= min / OverFraction;
607
15.3M
      max += max / OverFraction;
608
15.3M
      if (eg < min)
609
490k
        eg = min - int(sqrtf(float(min - eg)));
610
14.8M
      else if (eg > max)
611
577k
        eg = max + int(sqrtf(float(eg - max)));
612
15.3M
      if (eg > channel_maximum[1])
613
183k
        eg = channel_maximum[1];
614
15.1M
      else if (eg < channel_minimum[1])
615
1.67M
        eg = channel_minimum[1];
616
15.3M
      cnr[0][1] = eg;
617
15.3M
    }
618
364k
  }
619
182k
}
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
182k
{
656
182k
  int iwidth = libraw.imgdata.sizes.iwidth;
657
182k
  int js = libraw.COLOR(i, 0) & 1;
658
182k
  int kc = libraw.COLOR(i, js);
659
182k
  js ^= 1; // начальная координата зелёного
660
182k
  int hvdir[2] = {Pe, Ps};
661
  // интерполяция вертикальных вертикально и горизонтальных горизонтально
662
7.84M
  for (int j = js; j < iwidth; j += 2)
663
7.66M
  {
664
7.66M
    int x = j + nr_margin;
665
7.66M
    int y = i + nr_margin;
666
7.66M
    int moff = nr_offset(y, x);
667
22.9M
    for (int d = 0; d < 2; ++d)
668
15.3M
    {
669
15.3M
      ushort3 *cnr;
670
15.3M
      cnr = &rgb_ahd[d][moff];
671
15.3M
      int c = kc ^ (d << 1); // цвет соответсвенного направления, для
672
                             // горизонтального c = kc, для вертикального c=kc^2
673
15.3M
      int h1 = cnr[-hvdir[d]][c] - cnr[-hvdir[d]][1];
674
15.3M
      int h2 = cnr[+hvdir[d]][c] - cnr[+hvdir[d]][1];
675
15.3M
      int h0 = (h1 + h2) / 2;
676
15.3M
      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
15.3M
      if (eg > channel_maximum[c])
686
638k
        eg = channel_maximum[c];
687
14.6M
      else if (eg < channel_minimum[c])
688
3.30M
        eg = channel_minimum[c];
689
15.3M
      cnr[0][c] = eg;
690
15.3M
    }
691
7.66M
  }
692
182k
}
693
694
void AAHD::make_ahd_rb()
695
1.30k
{
696
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
697
182k
  {
698
182k
    make_ahd_rb_hv(i);
699
182k
  }
700
183k
  for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
701
182k
  {
702
182k
    make_ahd_rb_last(i);
703
182k
  }
704
1.30k
}
705
706
void AAHD::make_ahd_rb_last(int i)
707
182k
{
708
182k
  int iwidth = libraw.imgdata.sizes.iwidth;
709
182k
  int js = libraw.COLOR(i, 0) & 1;
710
182k
  int kc = libraw.COLOR(i, js);
711
  /*
712
   * js -- начальная х-координата, которая попадает мимо известного зелёного
713
   * kc -- известный цвет в точке интерполирования
714
   */
715
182k
  int dirs[2][3] = {{Pnw, Pn, Pne}, {Pnw, Pw, Psw}};
716
182k
  int moff = nr_offset(i + nr_margin, nr_margin);
717
15.5M
  for (int j = 0; j < iwidth; j++)
718
15.3M
  {
719
45.9M
    for (int d = 0; d < 2; ++d)
720
30.6M
    {
721
30.6M
      ushort3 *cnr;
722
30.6M
      cnr = &rgb_ahd[d][moff + j];
723
30.6M
      int c = kc ^ 2;
724
30.6M
      if ((j & 1) != js)
725
15.3M
      {
726
        // точка зелёного, для вертикального направления нужен альтернативный
727
        // строчному цвет
728
15.3M
        c ^= d << 1;
729
15.3M
      }
730
30.6M
      int bh = 0, bk = 0;
731
30.6M
      int bgd = 0;
732
122M
      for (int k = 0; k < 3; ++k)
733
367M
        for (int h = 0; h < 3; ++h)
734
275M
        {
735
          // градиент зелёного плюс градиент {r,b}
736
275M
          int gd =
737
275M
              ABS(2 * cnr[0][1] - (cnr[+dirs[d][k]][1] + cnr[-dirs[d][h]][1])) +
738
275M
              ABS(cnr[+dirs[d][k]][c] - cnr[-dirs[d][h]][c]) / 4 +
739
275M
              ABS(cnr[+dirs[d][k]][c] - cnr[+dirs[d][k]][1] +
740
275M
                  cnr[-dirs[d][h]][1] - cnr[-dirs[d][h]][c]) /
741
275M
                  4;
742
275M
          if (bgd == 0 || gd < bgd)
743
197M
          {
744
197M
            bgd = gd;
745
197M
            bh = h;
746
197M
            bk = k;
747
197M
          }
748
275M
        }
749
30.6M
      int h1 = cnr[+dirs[d][bk]][c] - cnr[+dirs[d][bk]][1];
750
30.6M
      int h2 = cnr[-dirs[d][bh]][c] - cnr[-dirs[d][bh]][1];
751
30.6M
      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
30.6M
      if (eg > channel_maximum[c])
761
2.68M
        eg = channel_maximum[c];
762
27.9M
      else if (eg < channel_minimum[c])
763
4.83M
        eg = channel_minimum[c];
764
30.6M
      cnr[0][c] = eg;
765
30.6M
    }
766
15.3M
  }
767
182k
}
768
769
1.30k
AAHD::~AAHD() { free(rgb_ahd[0]); }
770
771
void LibRaw::aahd_interpolate()
772
1.30k
{
773
1.30k
  AAHD aahd(*this);
774
1.30k
  aahd.hide_hots();
775
1.30k
  aahd.make_ahd_greens();
776
1.30k
  aahd.make_ahd_rb();
777
1.30k
  aahd.evaluate_ahd();
778
1.30k
  aahd.refine_hv_dirs();
779
  //  aahd.illustrate_dirs();
780
1.30k
  aahd.combine_image();
781
1.30k
}