Coverage Report

Created: 2025-09-08 07:52

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