File indexing completed on 2025-01-05 03:56:55

0001 /* -*- C++ -*-
0002  * File: aahd_demosaic.cpp
0003  * Copyright 2013 Anton Petrusevich
0004  * Created: Wed May  15, 2013
0005  *
0006  * This code is licensed under one of two licenses as you choose:
0007  *
0008  * 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
0009  *    (See file LICENSE.LGPL provided in LibRaw distribution archive for
0010  * details).
0011  *
0012  * 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
0013  *    (See file LICENSE.CDDL provided in LibRaw distribution archive for
0014  * details).
0015  *
0016  */
0017 
0018 #include "../../internal/dmp_include.h"
0019 
0020 typedef ushort ushort3[3];
0021 typedef int int3[3];
0022 
0023 #ifndef Pnw
0024 #define Pnw (-1 - nr_width)
0025 #define Pn (-nr_width)
0026 #define Pne (+1 - nr_width)
0027 #define Pe (+1)
0028 #define Pse (+1 + nr_width)
0029 #define Ps (+nr_width)
0030 #define Psw (-1 + nr_width)
0031 #define Pw (-1)
0032 #endif
0033 
0034 struct AAHD
0035 {
0036   int nr_height, nr_width;
0037   static const int nr_margin = 4;
0038   static const int Thot = 4;
0039   static const int Tdead = 4;
0040   static const int OverFraction = 8;
0041   ushort3 *rgb_ahd[2];
0042   int3 *yuv[2];
0043   char *ndir, *homo[2];
0044   ushort channel_maximum[3], channels_max;
0045   ushort channel_minimum[3];
0046   static const float yuv_coeff[3][3];
0047   static float gammaLUT[0x10000];
0048   float yuv_cam[3][3];
0049   LibRaw &libraw;
0050   enum
0051   {
0052     HVSH = 1,
0053     HOR = 2,
0054     VER = 4,
0055     HORSH = HOR | HVSH,
0056     VERSH = VER | HVSH,
0057     HOT = 8
0058   };
0059 
0060   static inline float calc_dist(int c1, int c2) throw()
0061   {
0062     return c1 > c2 ? (float)c1 / c2 : (float)c2 / c1;
0063   }
0064   int inline Y(ushort3 &rgb) throw()
0065   {
0066     return yuv_cam[0][0] * rgb[0] + yuv_cam[0][1] * rgb[1] +
0067            yuv_cam[0][2] * rgb[2];
0068   }
0069   int inline U(ushort3 &rgb) throw()
0070   {
0071     return yuv_cam[1][0] * rgb[0] + yuv_cam[1][1] * rgb[1] +
0072            yuv_cam[1][2] * rgb[2];
0073   }
0074   int inline V(ushort3 &rgb) throw()
0075   {
0076     return yuv_cam[2][0] * rgb[0] + yuv_cam[2][1] * rgb[1] +
0077            yuv_cam[2][2] * rgb[2];
0078   }
0079   inline int nr_offset(int row, int col) throw()
0080   {
0081     return (row * nr_width + col);
0082   }
0083   ~AAHD();
0084   AAHD(LibRaw &_libraw);
0085   void make_ahd_greens();
0086   void make_ahd_gline(int i);
0087   void make_ahd_rb();
0088   void make_ahd_rb_hv(int i);
0089   void make_ahd_rb_last(int i);
0090   void evaluate_ahd();
0091   void combine_image();
0092   void hide_hots();
0093   void refine_hv_dirs();
0094   void refine_hv_dirs(int i, int js);
0095   void refine_ihv_dirs(int i);
0096   void illustrate_dirs();
0097   void illustrate_dline(int i);
0098 };
0099 
0100 const float AAHD::yuv_coeff[3][3] = {
0101     // YPbPr
0102     //  {
0103     //      0.299f,
0104     //      0.587f,
0105     //      0.114f },
0106     //  {
0107     //      -0.168736,
0108     //      -0.331264f,
0109     //      0.5f },
0110     //  {
0111     //      0.5f,
0112     //      -0.418688f,
0113     //      -0.081312f }
0114     //
0115     //  Rec. 2020
0116     //  Y'= 0,2627R' + 0,6780G' + 0,0593B'
0117     //  U = (B-Y)/1.8814 =  (-0,2627R' - 0,6780G' + 0.9407B) / 1.8814 =
0118     //-0.13963R - 0.36037G + 0.5B
0119     //  V = (R-Y)/1.4647 = (0.7373R - 0,6780G - 0,0593B) / 1.4647 = 0.5R -
0120     //0.4629G - 0.04049B
0121     {+0.2627f, +0.6780f, +0.0593f},
0122     {-0.13963f, -0.36037f, +0.5f},
0123     {+0.5034f, -0.4629f, -0.0405f}
0124 
0125 };
0126 
0127 float AAHD::gammaLUT[0x10000] = {-1.f};
0128 
0129 AAHD::AAHD(LibRaw &_libraw) : libraw(_libraw)
0130 {
0131   nr_height = libraw.imgdata.sizes.iheight + nr_margin * 2;
0132   nr_width = libraw.imgdata.sizes.iwidth + nr_margin * 2;
0133   rgb_ahd[0] = (ushort3 *)calloc(nr_height * nr_width,
0134                                  (sizeof(ushort3) * 2 + sizeof(int3) * 2 + 3));
0135   if (!rgb_ahd[0])
0136     throw LIBRAW_EXCEPTION_ALLOC;
0137 
0138   rgb_ahd[1] = rgb_ahd[0] + nr_height * nr_width;
0139   yuv[0] = (int3 *)(rgb_ahd[1] + nr_height * nr_width);
0140   yuv[1] = yuv[0] + nr_height * nr_width;
0141   ndir = (char *)(yuv[1] + nr_height * nr_width);
0142   homo[0] = ndir + nr_height * nr_width;
0143   homo[1] = homo[0] + nr_height * nr_width;
0144   channel_maximum[0] = channel_maximum[1] = channel_maximum[2] = 0;
0145   channel_minimum[0] = libraw.imgdata.image[0][0];
0146   channel_minimum[1] = libraw.imgdata.image[0][1];
0147   channel_minimum[2] = libraw.imgdata.image[0][2];
0148   int iwidth = libraw.imgdata.sizes.iwidth;
0149   for (int i = 0; i < 3; ++i)
0150     for (int j = 0; j < 3; ++j)
0151     {
0152       yuv_cam[i][j] = 0;
0153       for (int k = 0; k < 3; ++k)
0154         yuv_cam[i][j] += yuv_coeff[i][k] * libraw.imgdata.color.rgb_cam[k][j];
0155     }
0156   if (gammaLUT[0] < -0.1f)
0157   {
0158     float r;
0159     for (int i = 0; i < 0x10000; i++)
0160     {
0161       r = (float)i / 0x10000;
0162       gammaLUT[i] =
0163           0x10000 * (r < 0.0181 ? 4.5f * r : 1.0993f * pow(r, 0.45f) - .0993f);
0164     }
0165   }
0166   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0167   {
0168     int col_cache[48];
0169     for (int j = 0; j < 48; ++j)
0170     {
0171       int c = libraw.COLOR(i, j);
0172       if (c == 3)
0173         c = 1;
0174       col_cache[j] = c;
0175     }
0176     int moff = nr_offset(i + nr_margin, nr_margin);
0177     for (int j = 0; j < iwidth; ++j, ++moff)
0178     {
0179       int c = col_cache[j % 48];
0180       unsigned short d = libraw.imgdata.image[i * iwidth + j][c];
0181       if (d != 0)
0182       {
0183         if (channel_maximum[c] < d)
0184           channel_maximum[c] = d;
0185         if (channel_minimum[c] > d)
0186           channel_minimum[c] = d;
0187         rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] = d;
0188       }
0189     }
0190   }
0191   channels_max =
0192       MAX(MAX(channel_maximum[0], channel_maximum[1]), channel_maximum[2]);
0193 }
0194 
0195 void AAHD::hide_hots()
0196 {
0197   int iwidth = libraw.imgdata.sizes.iwidth;
0198   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0199   {
0200     int js = libraw.COLOR(i, 0) & 1;
0201     int kc = libraw.COLOR(i, js);
0202     /*
0203      * js -- начальная х-координата, которая попадает мимо известного зелёного
0204      * kc -- известный цвет в точке интерполирования
0205      */
0206     int moff = nr_offset(i + nr_margin, nr_margin + js);
0207     for (int j = js; j < iwidth; j += 2, moff += 2)
0208     {
0209       ushort3 *rgb = &rgb_ahd[0][moff];
0210       int c = rgb[0][kc];
0211       if ((c > rgb[2 * Pe][kc] && c > rgb[2 * Pw][kc] && c > rgb[2 * Pn][kc] &&
0212            c > rgb[2 * Ps][kc] && c > rgb[Pe][1] && c > rgb[Pw][1] &&
0213            c > rgb[Pn][1] && c > rgb[Ps][1]) ||
0214           (c < rgb[2 * Pe][kc] && c < rgb[2 * Pw][kc] && c < rgb[2 * Pn][kc] &&
0215            c < rgb[2 * Ps][kc] && c < rgb[Pe][1] && c < rgb[Pw][1] &&
0216            c < rgb[Pn][1] && c < rgb[Ps][1]))
0217       {
0218         int chot = c >> Thot;
0219         int cdead = c << Tdead;
0220         int avg = 0;
0221         for (int k = -2; k < 3; k += 2)
0222           for (int m = -2; m < 3; m += 2)
0223             if (m == 0 && k == 0)
0224               continue;
0225             else
0226               avg += rgb[nr_offset(k, m)][kc];
0227         avg /= 8;
0228         if (chot > avg || cdead < avg)
0229         {
0230           ndir[moff] |= HOT;
0231           int dh =
0232               ABS(rgb[2 * Pw][kc] - rgb[2 * Pe][kc]) +
0233               ABS(rgb[Pw][1] - rgb[Pe][1]) +
0234               ABS(rgb[Pw][1] - rgb[Pe][1] + rgb[2 * Pe][kc] - rgb[2 * Pw][kc]);
0235           int dv =
0236               ABS(rgb[2 * Pn][kc] - rgb[2 * Ps][kc]) +
0237               ABS(rgb[Pn][1] - rgb[Ps][1]) +
0238               ABS(rgb[Pn][1] - rgb[Ps][1] + rgb[2 * Ps][kc] - rgb[2 * Pn][kc]);
0239           int d;
0240           if (dv > dh)
0241             d = Pw;
0242           else
0243             d = Pn;
0244           rgb_ahd[1][moff][kc] = rgb[0][kc] =
0245               (rgb[+2 * d][kc] + rgb[-2 * d][kc]) / 2;
0246         }
0247       }
0248     }
0249     js ^= 1;
0250     moff = nr_offset(i + nr_margin, nr_margin + js);
0251     for (int j = js; j < iwidth; j += 2, moff += 2)
0252     {
0253       ushort3 *rgb = &rgb_ahd[0][moff];
0254       int c = rgb[0][1];
0255       if ((c > rgb[2 * Pe][1] && c > rgb[2 * Pw][1] && c > rgb[2 * Pn][1] &&
0256            c > rgb[2 * Ps][1] && c > rgb[Pe][kc] && c > rgb[Pw][kc] &&
0257            c > rgb[Pn][kc ^ 2] && c > rgb[Ps][kc ^ 2]) ||
0258           (c < rgb[2 * Pe][1] && c < rgb[2 * Pw][1] && c < rgb[2 * Pn][1] &&
0259            c < rgb[2 * Ps][1] && c < rgb[Pe][kc] && c < rgb[Pw][kc] &&
0260            c < rgb[Pn][kc ^ 2] && c < rgb[Ps][kc ^ 2]))
0261       {
0262         int chot = c >> Thot;
0263         int cdead = c << Tdead;
0264         int avg = 0;
0265         for (int k = -2; k < 3; k += 2)
0266           for (int m = -2; m < 3; m += 2)
0267             if (k == 0 && m == 0)
0268               continue;
0269             else
0270               avg += rgb[nr_offset(k, m)][1];
0271         avg /= 8;
0272         if (chot > avg || cdead < avg)
0273         {
0274           ndir[moff] |= HOT;
0275           int dh =
0276               ABS(rgb[2 * Pw][1] - rgb[2 * Pe][1]) +
0277               ABS(rgb[Pw][kc] - rgb[Pe][kc]) +
0278               ABS(rgb[Pw][kc] - rgb[Pe][kc] + rgb[2 * Pe][1] - rgb[2 * Pw][1]);
0279           int dv = ABS(rgb[2 * Pn][1] - rgb[2 * Ps][1]) +
0280                    ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2]) +
0281                    ABS(rgb[Pn][kc ^ 2] - rgb[Ps][kc ^ 2] + rgb[2 * Ps][1] -
0282                        rgb[2 * Pn][1]);
0283           int d;
0284           if (dv > dh)
0285             d = Pw;
0286           else
0287             d = Pn;
0288           rgb_ahd[1][moff][1] = rgb[0][1] =
0289               (rgb[+2 * d][1] + rgb[-2 * d][1]) / 2;
0290         }
0291       }
0292     }
0293   }
0294 }
0295 
0296 void AAHD::evaluate_ahd()
0297 {
0298   int hvdir[4] = {Pw, Pe, Pn, Ps};
0299   /*
0300    * YUV
0301    *
0302    */
0303   for (int d = 0; d < 2; ++d)
0304   {
0305     for (int i = 0; i < nr_width * nr_height; ++i)
0306     {
0307       ushort3 rgb;
0308       for (int c = 0; c < 3; ++c)
0309       {
0310         rgb[c] = gammaLUT[rgb_ahd[d][i][c]];
0311       }
0312       yuv[d][i][0] = Y(rgb);
0313       yuv[d][i][1] = U(rgb);
0314       yuv[d][i][2] = V(rgb);
0315     }
0316   }
0317   /* */
0318   /*
0319    * Lab
0320    *
0321    float r, cbrt[0x10000], xyz[3], xyz_cam[3][4];
0322    for (int i = 0; i < 0x10000; i++) {
0323    r = i / 65535.0;
0324    cbrt[i] = r > 0.008856 ? pow((double) r, (double) (1 / 3.0)) : 7.787 * r + 16
0325    / 116.0;
0326    }
0327    for (int i = 0; i < 3; i++)
0328    for (int j = 0; j < 3; j++) {
0329    xyz_cam[i][j] = 0;
0330    for (int k = 0; k < 3; k++)
0331    xyz_cam[i][j] += xyz_rgb[i][k] * libraw.imgdata.color.rgb_cam[k][j] /
0332    d65_white[i];
0333    }
0334    for (int d = 0; d < 2; ++d)
0335    for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i) {
0336    int moff = nr_offset(i + nr_margin, nr_margin);
0337    for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff) {
0338    xyz[0] = xyz[1] = xyz[2] = 0.5;
0339    for (int c = 0; c < 3; c++) {
0340    xyz[0] += xyz_cam[0][c] * rgb_ahd[d][moff][c];
0341    xyz[1] += xyz_cam[1][c] * rgb_ahd[d][moff][c];
0342    xyz[2] += xyz_cam[2][c] * rgb_ahd[d][moff][c];
0343    }
0344    xyz[0] = cbrt[CLIP((int) xyz[0])];
0345    xyz[1] = cbrt[CLIP((int) xyz[1])];
0346    xyz[2] = cbrt[CLIP((int) xyz[2])];
0347    yuv[d][moff][0] = 64 * (116 * xyz[1] - 16);
0348    yuv[d][moff][1] = 64 * 500 * (xyz[0] - xyz[1]);
0349    yuv[d][moff][2] = 64 * 200 * (xyz[1] - xyz[2]);
0350    }
0351    }
0352    * Lab */
0353   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0354   {
0355     int moff = nr_offset(i + nr_margin, nr_margin);
0356     for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff)
0357     {
0358       int3 *ynr;
0359       float ydiff[2][4];
0360       int uvdiff[2][4];
0361       for (int d = 0; d < 2; ++d)
0362       {
0363         ynr = &yuv[d][moff];
0364         for (int k = 0; k < 4; k++)
0365         {
0366           ydiff[d][k] = ABS(ynr[0][0] - ynr[hvdir[k]][0]);
0367           uvdiff[d][k] = SQR(ynr[0][1] - ynr[hvdir[k]][1]) +
0368                          SQR(ynr[0][2] - ynr[hvdir[k]][2]);
0369         }
0370       }
0371       float yeps =
0372           MIN(MAX(ydiff[0][0], ydiff[0][1]), MAX(ydiff[1][2], ydiff[1][3]));
0373       int uveps =
0374           MIN(MAX(uvdiff[0][0], uvdiff[0][1]), MAX(uvdiff[1][2], uvdiff[1][3]));
0375       for (int d = 0; d < 2; d++)
0376       {
0377         ynr = &yuv[d][moff];
0378         for (int k = 0; k < 4; k++)
0379           if (ydiff[d][k] <= yeps && uvdiff[d][k] <= uveps)
0380           {
0381             homo[d][moff + hvdir[k]]++;
0382             if (k / 2 == d)
0383             {
0384               // если в сонаправленном направлении интеполяции следующие точки
0385               // так же гомогенны, учтём их тоже
0386               for (int m = 2; m < 4; ++m)
0387               {
0388                 int hvd = m * hvdir[k];
0389                 if (ABS(ynr[0][0] - ynr[hvd][0]) < yeps &&
0390                     SQR(ynr[0][1] - ynr[hvd][1]) +
0391                             SQR(ynr[0][2] - ynr[hvd][2]) <
0392                         uveps)
0393                 {
0394                   homo[d][moff + hvd]++;
0395                 }
0396                 else
0397                   break;
0398               }
0399             }
0400           }
0401       }
0402     }
0403   }
0404   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0405   {
0406     int moff = nr_offset(i + nr_margin, nr_margin);
0407     for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff)
0408     {
0409       char hm[2];
0410       for (int d = 0; d < 2; d++)
0411       {
0412         hm[d] = 0;
0413         char *hh = &homo[d][moff];
0414         for (int hx = -1; hx < 2; hx++)
0415           for (int hy = -1; hy < 2; hy++)
0416             hm[d] += hh[nr_offset(hy, hx)];
0417       }
0418       char d = 0;
0419       if (hm[0] != hm[1])
0420       {
0421         if (hm[1] > hm[0])
0422         {
0423           d = VERSH;
0424         }
0425         else
0426         {
0427           d = HORSH;
0428         }
0429       }
0430       else
0431       {
0432         int3 *ynr = &yuv[1][moff];
0433         int gv = SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]);
0434         gv += SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
0435               SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2]);
0436         ynr = &yuv[1][moff + Pn];
0437         gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) +
0438                SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
0439                SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) /
0440               2;
0441         ynr = &yuv[1][moff + Ps];
0442         gv += (SQR(2 * ynr[0][0] - ynr[Pn][0] - ynr[Ps][0]) +
0443                SQR(2 * ynr[0][1] - ynr[Pn][1] - ynr[Ps][1]) +
0444                SQR(2 * ynr[0][2] - ynr[Pn][2] - ynr[Ps][2])) /
0445               2;
0446         ynr = &yuv[0][moff];
0447         int gh = SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]);
0448         gh += SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
0449               SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2]);
0450         ynr = &yuv[0][moff + Pw];
0451         gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) +
0452                SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
0453                SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) /
0454               2;
0455         ynr = &yuv[0][moff + Pe];
0456         gh += (SQR(2 * ynr[0][0] - ynr[Pw][0] - ynr[Pe][0]) +
0457                SQR(2 * ynr[0][1] - ynr[Pw][1] - ynr[Pe][1]) +
0458                SQR(2 * ynr[0][2] - ynr[Pw][2] - ynr[Pe][2])) /
0459               2;
0460         if (gv > gh)
0461           d = HOR;
0462         else
0463           d = VER;
0464       }
0465       ndir[moff] |= d;
0466     }
0467   }
0468 }
0469 
0470 void AAHD::combine_image()
0471 {
0472   for (int i = 0, i_out = 0; i < libraw.imgdata.sizes.iheight; ++i)
0473   {
0474     int moff = nr_offset(i + nr_margin, nr_margin);
0475     for (int j = 0; j < libraw.imgdata.sizes.iwidth; j++, ++moff, ++i_out)
0476     {
0477       if (ndir[moff] & HOT)
0478       {
0479         int c = libraw.COLOR(i, j);
0480         rgb_ahd[1][moff][c] = rgb_ahd[0][moff][c] =
0481             libraw.imgdata.image[i_out][c];
0482       }
0483       if (ndir[moff] & VER)
0484       {
0485         libraw.imgdata.image[i_out][0] = rgb_ahd[1][moff][0];
0486         libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] =
0487             rgb_ahd[1][moff][1];
0488         libraw.imgdata.image[i_out][2] = rgb_ahd[1][moff][2];
0489       }
0490       else
0491       {
0492         libraw.imgdata.image[i_out][0] = rgb_ahd[0][moff][0];
0493         libraw.imgdata.image[i_out][3] = libraw.imgdata.image[i_out][1] =
0494             rgb_ahd[0][moff][1];
0495         libraw.imgdata.image[i_out][2] = rgb_ahd[0][moff][2];
0496       }
0497     }
0498   }
0499 }
0500 
0501 void AAHD::refine_hv_dirs()
0502 {
0503   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0504   {
0505     refine_hv_dirs(i, i & 1);
0506   }
0507   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0508   {
0509     refine_hv_dirs(i, (i & 1) ^ 1);
0510   }
0511   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0512   {
0513     refine_ihv_dirs(i);
0514   }
0515 }
0516 
0517 void AAHD::refine_ihv_dirs(int i)
0518 {
0519   int iwidth = libraw.imgdata.sizes.iwidth;
0520   int moff = nr_offset(i + nr_margin, nr_margin);
0521   for (int j = 0; j < iwidth; j++, ++moff)
0522   {
0523     if (ndir[moff] & HVSH)
0524       continue;
0525     int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) +
0526              (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER);
0527     int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) +
0528              (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR);
0529     nv /= VER;
0530     nh /= HOR;
0531     if ((ndir[moff] & VER) && nh > 3)
0532     {
0533       ndir[moff] &= ~VER;
0534       ndir[moff] |= HOR;
0535     }
0536     if ((ndir[moff] & HOR) && nv > 3)
0537     {
0538       ndir[moff] &= ~HOR;
0539       ndir[moff] |= VER;
0540     }
0541   }
0542 }
0543 
0544 void AAHD::refine_hv_dirs(int i, int js)
0545 {
0546   int iwidth = libraw.imgdata.sizes.iwidth;
0547   int moff = nr_offset(i + nr_margin, nr_margin + js);
0548   for (int j = js; j < iwidth; j += 2, moff += 2)
0549   {
0550     int nv = (ndir[moff + Pn] & VER) + (ndir[moff + Ps] & VER) +
0551              (ndir[moff + Pw] & VER) + (ndir[moff + Pe] & VER);
0552     int nh = (ndir[moff + Pn] & HOR) + (ndir[moff + Ps] & HOR) +
0553              (ndir[moff + Pw] & HOR) + (ndir[moff + Pe] & HOR);
0554     bool codir = (ndir[moff] & VER)
0555                      ? ((ndir[moff + Pn] & VER) || (ndir[moff + Ps] & VER))
0556                      : ((ndir[moff + Pw] & HOR) || (ndir[moff + Pe] & HOR));
0557     nv /= VER;
0558     nh /= HOR;
0559     if ((ndir[moff] & VER) && (nh > 2 && !codir))
0560     {
0561       ndir[moff] &= ~VER;
0562       ndir[moff] |= HOR;
0563     }
0564     if ((ndir[moff] & HOR) && (nv > 2 && !codir))
0565     {
0566       ndir[moff] &= ~HOR;
0567       ndir[moff] |= VER;
0568     }
0569   }
0570 }
0571 
0572 /*
0573  * вычисление недостающих зелёных точек.
0574  */
0575 void AAHD::make_ahd_greens()
0576 {
0577   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0578   {
0579     make_ahd_gline(i);
0580   }
0581 }
0582 
0583 void AAHD::make_ahd_gline(int i)
0584 {
0585   int iwidth = libraw.imgdata.sizes.iwidth;
0586   int js = libraw.COLOR(i, 0) & 1;
0587   int kc = libraw.COLOR(i, js);
0588   /*
0589    * js -- начальная х-координата, которая попадает мимо известного зелёного
0590    * kc -- известный цвет в точке интерполирования
0591    */
0592   int hvdir[2] = {Pe, Ps};
0593   for (int d = 0; d < 2; ++d)
0594   {
0595     int moff = nr_offset(i + nr_margin, nr_margin + js);
0596     for (int j = js; j < iwidth; j += 2, moff += 2)
0597     {
0598       ushort3 *cnr;
0599       cnr = &rgb_ahd[d][moff];
0600       int h1 = 2 * cnr[-hvdir[d]][1] - int(cnr[-2 * hvdir[d]][kc] + cnr[0][kc]);
0601       int h2 = 2 * cnr[+hvdir[d]][1] - int(cnr[+2 * hvdir[d]][kc] + cnr[0][kc]);
0602       int h0 = (h1 + h2) / 4;
0603       int eg = cnr[0][kc] + h0;
0604       int min = MIN(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]);
0605       int max = MAX(cnr[-hvdir[d]][1], cnr[+hvdir[d]][1]);
0606       min -= min / OverFraction;
0607       max += max / OverFraction;
0608       if (eg < min)
0609         eg = min - sqrt(float(min - eg));
0610       else if (eg > max)
0611         eg = max + sqrt(float(eg - max));
0612       if (eg > channel_maximum[1])
0613         eg = channel_maximum[1];
0614       else if (eg < channel_minimum[1])
0615         eg = channel_minimum[1];
0616       cnr[0][1] = eg;
0617     }
0618   }
0619 }
0620 
0621 /*
0622  * отладочная функция
0623  */
0624 
0625 void AAHD::illustrate_dirs()
0626 {
0627   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0628   {
0629     illustrate_dline(i);
0630   }
0631 }
0632 
0633 void AAHD::illustrate_dline(int i)
0634 {
0635   int iwidth = libraw.imgdata.sizes.iwidth;
0636   for (int j = 0; j < iwidth; j++)
0637   {
0638     int x = j + nr_margin;
0639     int y = i + nr_margin;
0640     rgb_ahd[1][nr_offset(y, x)][0] = rgb_ahd[1][nr_offset(y, x)][1] =
0641         rgb_ahd[1][nr_offset(y, x)][2] = rgb_ahd[0][nr_offset(y, x)][0] =
0642             rgb_ahd[0][nr_offset(y, x)][1] = rgb_ahd[0][nr_offset(y, x)][2] = 0;
0643     int l = ndir[nr_offset(y, x)] & HVSH;
0644     l /= HVSH;
0645     if (ndir[nr_offset(y, x)] & VER)
0646       rgb_ahd[1][nr_offset(y, x)][0] =
0647           l * channel_maximum[0] / 4 + channel_maximum[0] / 4;
0648     else
0649       rgb_ahd[0][nr_offset(y, x)][2] =
0650           l * channel_maximum[2] / 4 + channel_maximum[2] / 4;
0651   }
0652 }
0653 
0654 void AAHD::make_ahd_rb_hv(int i)
0655 {
0656   int iwidth = libraw.imgdata.sizes.iwidth;
0657   int js = libraw.COLOR(i, 0) & 1;
0658   int kc = libraw.COLOR(i, js);
0659   js ^= 1; // начальная координата зелёного
0660   int hvdir[2] = {Pe, Ps};
0661   // интерполяция вертикальных вертикально и горизонтальных горизонтально
0662   for (int j = js; j < iwidth; j += 2)
0663   {
0664     int x = j + nr_margin;
0665     int y = i + nr_margin;
0666     int moff = nr_offset(y, x);
0667     for (int d = 0; d < 2; ++d)
0668     {
0669       ushort3 *cnr;
0670       cnr = &rgb_ahd[d][moff];
0671       int c = kc ^ (d << 1); // цвет соответсвенного направления, для
0672                              // горизонтального c = kc, для вертикального c=kc^2
0673       int h1 = cnr[-hvdir[d]][c] - cnr[-hvdir[d]][1];
0674       int h2 = cnr[+hvdir[d]][c] - cnr[+hvdir[d]][1];
0675       int h0 = (h1 + h2) / 2;
0676       int eg = cnr[0][1] + h0;
0677       //            int min = MIN(cnr[-hvdir[d]][c], cnr[+hvdir[d]][c]);
0678       //            int max = MAX(cnr[-hvdir[d]][c], cnr[+hvdir[d]][c]);
0679       //            min -= min / OverFraction;
0680       //            max += max / OverFraction;
0681       //            if (eg < min)
0682       //                eg = min - sqrt(min - eg);
0683       //            else if (eg > max)
0684       //                eg = max + sqrt(eg - max);
0685       if (eg > channel_maximum[c])
0686         eg = channel_maximum[c];
0687       else if (eg < channel_minimum[c])
0688         eg = channel_minimum[c];
0689       cnr[0][c] = eg;
0690     }
0691   }
0692 }
0693 
0694 void AAHD::make_ahd_rb()
0695 {
0696   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0697   {
0698     make_ahd_rb_hv(i);
0699   }
0700   for (int i = 0; i < libraw.imgdata.sizes.iheight; ++i)
0701   {
0702     make_ahd_rb_last(i);
0703   }
0704 }
0705 
0706 void AAHD::make_ahd_rb_last(int i)
0707 {
0708   int iwidth = libraw.imgdata.sizes.iwidth;
0709   int js = libraw.COLOR(i, 0) & 1;
0710   int kc = libraw.COLOR(i, js);
0711   /*
0712    * js -- начальная х-координата, которая попадает мимо известного зелёного
0713    * kc -- известный цвет в точке интерполирования
0714    */
0715   int dirs[2][3] = {{Pnw, Pn, Pne}, {Pnw, Pw, Psw}};
0716   int moff = nr_offset(i + nr_margin, nr_margin);
0717   for (int j = 0; j < iwidth; j++)
0718   {
0719     for (int d = 0; d < 2; ++d)
0720     {
0721       ushort3 *cnr;
0722       cnr = &rgb_ahd[d][moff + j];
0723       int c = kc ^ 2;
0724       if ((j & 1) != js)
0725       {
0726         // точка зелёного, для вертикального направления нужен альтернативный
0727         // строчному цвет
0728         c ^= d << 1;
0729       }
0730       int bh = 0, bk = 0;
0731       int bgd = 0;
0732       for (int k = 0; k < 3; ++k)
0733         for (int h = 0; h < 3; ++h)
0734         {
0735           // градиент зелёного плюс градиент {r,b}
0736           int gd =
0737               ABS(2 * cnr[0][1] - (cnr[+dirs[d][k]][1] + cnr[-dirs[d][h]][1])) +
0738               ABS(cnr[+dirs[d][k]][c] - cnr[-dirs[d][h]][c]) / 4 +
0739               ABS(cnr[+dirs[d][k]][c] - cnr[+dirs[d][k]][1] +
0740                   cnr[-dirs[d][h]][1] - cnr[-dirs[d][h]][c]) /
0741                   4;
0742           if (bgd == 0 || gd < bgd)
0743           {
0744             bgd = gd;
0745             bh = h;
0746             bk = k;
0747           }
0748         }
0749       int h1 = cnr[+dirs[d][bk]][c] - cnr[+dirs[d][bk]][1];
0750       int h2 = cnr[-dirs[d][bh]][c] - cnr[-dirs[d][bh]][1];
0751       int eg = cnr[0][1] + (h1 + h2) / 2;
0752       //            int min = MIN(cnr[+dirs[d][bk]][c], cnr[-dirs[d][bh]][c]);
0753       //            int max = MAX(cnr[+dirs[d][bk]][c], cnr[-dirs[d][bh]][c]);
0754       //            min -= min / OverFraction;
0755       //            max += max / OverFraction;
0756       //            if (eg < min)
0757       //                eg = min - sqrt(min - eg);
0758       //            else if (eg > max)
0759       //                eg = max + sqrt(eg - max);
0760       if (eg > channel_maximum[c])
0761         eg = channel_maximum[c];
0762       else if (eg < channel_minimum[c])
0763         eg = channel_minimum[c];
0764       cnr[0][c] = eg;
0765     }
0766   }
0767 }
0768 
0769 AAHD::~AAHD() { free(rgb_ahd[0]); }
0770 
0771 void LibRaw::aahd_interpolate()
0772 {
0773   AAHD aahd(*this);
0774   aahd.hide_hots();
0775   aahd.make_ahd_greens();
0776   aahd.make_ahd_rb();
0777   aahd.evaluate_ahd();
0778   aahd.refine_hv_dirs();
0779   //    aahd.illustrate_dirs();
0780   aahd.combine_image();
0781 }