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

0001 /* -*- C++ -*-
0002  * Copyright 2019-2021 LibRaw LLC (info@libraw.org)
0003  *
0004  LibRaw uses code from dcraw.c -- Dave Coffin's raw photo decoder,
0005  dcraw.c is copyright 1997-2018 by Dave Coffin, dcoffin a cybercom o net.
0006  LibRaw do not use RESTRICTED code from dcraw.c
0007 
0008  LibRaw is free software; you can redistribute it and/or modify
0009  it under the terms of the one of two licenses as you choose:
0010 
0011 1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
0012    (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
0013 
0014 2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
0015    (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
0016 
0017  */
0018 
0019 #include "../../internal/dcraw_defs.h"
0020 
0021 /*
0022    Adaptive Homogeneity-Directed interpolation is based on
0023    the work of Keigo Hirakawa, Thomas Parks, and Paul Lee.
0024  */
0025 
0026 void LibRaw::cielab(ushort rgb[3], short lab[3])
0027 {
0028   int c, i, j, k;
0029   float r, xyz[3];
0030 #ifdef LIBRAW_NOTHREADS
0031   static float cbrt[0x10000], xyz_cam[3][4];
0032 #else
0033 #define cbrt tls->ahd_data.cbrt
0034 #define xyz_cam tls->ahd_data.xyz_cam
0035 #endif
0036 
0037   if (!rgb)
0038   {
0039 #ifndef LIBRAW_NOTHREADS
0040     if (cbrt[0] < -1.0f)
0041 #endif
0042       for (i = 0; i < 0x10000; i++)
0043       {
0044         r = i / 65535.0;
0045         cbrt[i] =
0046             r > 0.008856 ? pow(r, 1.f / 3.0f) : 7.787f * r + 16.f / 116.0f;
0047       }
0048     for (i = 0; i < 3; i++)
0049       for (j = 0; j < colors; j++)
0050         for (xyz_cam[i][j] = k = 0; k < 3; k++)
0051           xyz_cam[i][j] += LibRaw_constants::xyz_rgb[i][k] * rgb_cam[k][j] /
0052                            LibRaw_constants::d65_white[i];
0053     return;
0054   }
0055   xyz[0] = xyz[1] = xyz[2] = 0.5;
0056   FORCC
0057   {
0058     xyz[0] += xyz_cam[0][c] * rgb[c];
0059     xyz[1] += xyz_cam[1][c] * rgb[c];
0060     xyz[2] += xyz_cam[2][c] * rgb[c];
0061   }
0062   xyz[0] = cbrt[CLIP((int)xyz[0])];
0063   xyz[1] = cbrt[CLIP((int)xyz[1])];
0064   xyz[2] = cbrt[CLIP((int)xyz[2])];
0065   lab[0] = 64 * (116 * xyz[1] - 16);
0066   lab[1] = 64 * 500 * (xyz[0] - xyz[1]);
0067   lab[2] = 64 * 200 * (xyz[1] - xyz[2]);
0068 #ifndef LIBRAW_NOTHREADS
0069 #undef cbrt
0070 #undef xyz_cam
0071 #endif
0072 }
0073 
0074 void LibRaw::ahd_interpolate_green_h_and_v(
0075     int top, int left, ushort (*out_rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])
0076 {
0077   int row, col;
0078   int c, val;
0079   ushort(*pix)[4];
0080   const int rowlimit = MIN(top + LIBRAW_AHD_TILE, height - 2);
0081   const int collimit = MIN(left + LIBRAW_AHD_TILE, width - 2);
0082 
0083   for (row = top; row < rowlimit; row++)
0084   {
0085     col = left + (FC(row, left) & 1);
0086     for (c = FC(row, col); col < collimit; col += 2)
0087     {
0088       pix = image + row * width + col;
0089       val =
0090           ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) >>
0091           2;
0092       out_rgb[0][row - top][col - left][1] = ULIM(val, pix[-1][1], pix[1][1]);
0093       val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 -
0094              pix[-2 * width][c] - pix[2 * width][c]) >>
0095             2;
0096       out_rgb[1][row - top][col - left][1] =
0097           ULIM(val, pix[-width][1], pix[width][1]);
0098     }
0099   }
0100 }
0101 void LibRaw::ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(
0102     int top, int left, ushort (*inout_rgb)[LIBRAW_AHD_TILE][3],
0103     short (*out_lab)[LIBRAW_AHD_TILE][3])
0104 {
0105   unsigned row, col;
0106   int c, val;
0107   ushort(*pix)[4];
0108   ushort(*rix)[3];
0109   short(*lix)[3];
0110   const unsigned num_pix_per_row = 4 * width;
0111   const unsigned rowlimit = MIN(top + LIBRAW_AHD_TILE - 1, height - 3);
0112   const unsigned collimit = MIN(left + LIBRAW_AHD_TILE - 1, width - 3);
0113   ushort *pix_above;
0114   ushort *pix_below;
0115   int t1, t2;
0116 
0117   for (row = top + 1; row < rowlimit; row++)
0118   {
0119     pix = image + row * width + left;
0120     rix = &inout_rgb[row - top][0];
0121     lix = &out_lab[row - top][0];
0122 
0123     for (col = left + 1; col < collimit; col++)
0124     {
0125       pix++;
0126       pix_above = &pix[0][0] - num_pix_per_row;
0127       pix_below = &pix[0][0] + num_pix_per_row;
0128       rix++;
0129       lix++;
0130 
0131       c = 2 - FC(row, col);
0132 
0133       if (c == 1)
0134       {
0135         c = FC(row + 1, col);
0136         t1 = 2 - c;
0137         val = pix[0][1] +
0138               ((pix[-1][t1] + pix[1][t1] - rix[-1][1] - rix[1][1]) >> 1);
0139         rix[0][t1] = CLIP(val);
0140         val =
0141             pix[0][1] + ((pix_above[c] + pix_below[c] -
0142                           rix[-LIBRAW_AHD_TILE][1] - rix[LIBRAW_AHD_TILE][1]) >>
0143                          1);
0144       }
0145       else
0146       {
0147         t1 = -4 + c; /* -4+c: pixel of color c to the left */
0148         t2 = 4 + c;  /* 4+c: pixel of color c to the right */
0149         val = rix[0][1] +
0150               ((pix_above[t1] + pix_above[t2] + pix_below[t1] + pix_below[t2] -
0151                 rix[-LIBRAW_AHD_TILE - 1][1] - rix[-LIBRAW_AHD_TILE + 1][1] -
0152                 rix[+LIBRAW_AHD_TILE - 1][1] - rix[+LIBRAW_AHD_TILE + 1][1] +
0153                 1) >>
0154                2);
0155       }
0156       rix[0][c] = CLIP(val);
0157       c = FC(row, col);
0158       rix[0][c] = pix[0][c];
0159       cielab(rix[0], lix[0]);
0160     }
0161   }
0162 }
0163 void LibRaw::ahd_interpolate_r_and_b_and_convert_to_cielab(
0164     int top, int left, ushort (*inout_rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3],
0165     short (*out_lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])
0166 {
0167   int direction;
0168   for (direction = 0; direction < 2; direction++)
0169   {
0170     ahd_interpolate_r_and_b_in_rgb_and_convert_to_cielab(
0171         top, left, inout_rgb[direction], out_lab[direction]);
0172   }
0173 }
0174 
0175 void LibRaw::ahd_interpolate_build_homogeneity_map(
0176     int top, int left, short (*lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3],
0177     char (*out_homogeneity_map)[LIBRAW_AHD_TILE][2])
0178 {
0179   int row, col;
0180   int tr;
0181   int direction;
0182   int i;
0183   short(*lix)[3];
0184   short(*lixs[2])[3];
0185   short *adjacent_lix;
0186   unsigned ldiff[2][4], abdiff[2][4], leps, abeps;
0187   static const int dir[4] = {-1, 1, -LIBRAW_AHD_TILE, LIBRAW_AHD_TILE};
0188   const int rowlimit = MIN(top + LIBRAW_AHD_TILE - 2, height - 4);
0189   const int collimit = MIN(left + LIBRAW_AHD_TILE - 2, width - 4);
0190   int homogeneity;
0191   char(*homogeneity_map_p)[2];
0192 
0193   memset(out_homogeneity_map, 0, 2 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE);
0194 
0195   for (row = top + 2; row < rowlimit; row++)
0196   {
0197     tr = row - top;
0198     homogeneity_map_p = &out_homogeneity_map[tr][1];
0199     for (direction = 0; direction < 2; direction++)
0200     {
0201       lixs[direction] = &lab[direction][tr][1];
0202     }
0203 
0204     for (col = left + 2; col < collimit; col++)
0205     {
0206       homogeneity_map_p++;
0207 
0208       for (direction = 0; direction < 2; direction++)
0209       {
0210         lix = ++lixs[direction];
0211         for (i = 0; i < 4; i++)
0212         {
0213           adjacent_lix = lix[dir[i]];
0214           ldiff[direction][i] = ABS(lix[0][0] - adjacent_lix[0]);
0215           abdiff[direction][i] = SQR(lix[0][1] - adjacent_lix[1]) +
0216                                  SQR(lix[0][2] - adjacent_lix[2]);
0217         }
0218       }
0219       leps = MIN(MAX(ldiff[0][0], ldiff[0][1]), MAX(ldiff[1][2], ldiff[1][3]));
0220       abeps =
0221           MIN(MAX(abdiff[0][0], abdiff[0][1]), MAX(abdiff[1][2], abdiff[1][3]));
0222       for (direction = 0; direction < 2; direction++)
0223       {
0224         homogeneity = 0;
0225         for (i = 0; i < 4; i++)
0226         {
0227           if (ldiff[direction][i] <= leps && abdiff[direction][i] <= abeps)
0228           {
0229             homogeneity++;
0230           }
0231         }
0232         homogeneity_map_p[0][direction] = homogeneity;
0233       }
0234     }
0235   }
0236 }
0237 void LibRaw::ahd_interpolate_combine_homogeneous_pixels(
0238     int top, int left, ushort (*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3],
0239     char (*homogeneity_map)[LIBRAW_AHD_TILE][2])
0240 {
0241   int row, col;
0242   int tr, tc;
0243   int i, j;
0244   int direction;
0245   int hm[2];
0246   int c;
0247   const int rowlimit = MIN(top + LIBRAW_AHD_TILE - 3, height - 5);
0248   const int collimit = MIN(left + LIBRAW_AHD_TILE - 3, width - 5);
0249 
0250   ushort(*pix)[4];
0251   ushort(*rix[2])[3];
0252 
0253   for (row = top + 3; row < rowlimit; row++)
0254   {
0255     tr = row - top;
0256     pix = &image[row * width + left + 2];
0257     for (direction = 0; direction < 2; direction++)
0258     {
0259       rix[direction] = &rgb[direction][tr][2];
0260     }
0261 
0262     for (col = left + 3; col < collimit; col++)
0263     {
0264       tc = col - left;
0265       pix++;
0266       for (direction = 0; direction < 2; direction++)
0267       {
0268         rix[direction]++;
0269       }
0270 
0271       for (direction = 0; direction < 2; direction++)
0272       {
0273         hm[direction] = 0;
0274         for (i = tr - 1; i <= tr + 1; i++)
0275         {
0276           for (j = tc - 1; j <= tc + 1; j++)
0277           {
0278             hm[direction] += homogeneity_map[i][j][direction];
0279           }
0280         }
0281       }
0282       if (hm[0] != hm[1])
0283       {
0284         memcpy(pix[0], rix[hm[1] > hm[0]][0], 3 * sizeof(ushort));
0285       }
0286       else
0287       {
0288         FORC3 { pix[0][c] = (rix[0][0][c] + rix[1][0][c]) >> 1; }
0289       }
0290     }
0291   }
0292 }
0293 void LibRaw::ahd_interpolate()
0294 {
0295     int terminate_flag = 0;
0296     cielab(0, 0);
0297     border_interpolate(5);
0298 
0299 #ifdef LIBRAW_USE_OPENMP
0300     int buffer_count = omp_get_max_threads();
0301 #else
0302     int buffer_count = 1;
0303 #endif
0304 
0305     size_t buffer_size = 26 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE; /* 1664 kB */
0306     char** buffers = malloc_omp_buffers(buffer_count, buffer_size);
0307 
0308 #ifdef LIBRAW_USE_OPENMP
0309 #pragma omp parallel for schedule(dynamic) default(none) shared(terminate_flag) firstprivate(buffers)
0310 #endif
0311     for (int top = 2; top < height - 5; top += LIBRAW_AHD_TILE - 6)
0312     {
0313 #ifdef LIBRAW_USE_OPENMP
0314         if (0 == omp_get_thread_num())
0315 #endif
0316             if (callbacks.progress_cb)
0317             {
0318                 int rr = (*callbacks.progress_cb)(callbacks.progresscb_data,
0319                     LIBRAW_PROGRESS_INTERPOLATE,
0320                     top - 2, height - 7);
0321                 if (rr)
0322                     terminate_flag = 1;
0323             }
0324 
0325 #if defined(LIBRAW_USE_OPENMP)
0326         char* buffer = buffers[omp_get_thread_num()];
0327 #else
0328         char* buffer = buffers[0];
0329 #endif
0330 
0331         ushort(*rgb)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3];
0332         short(*lab)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3];
0333         char(*homo)[LIBRAW_AHD_TILE][2];
0334 
0335         rgb = (ushort(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])buffer;
0336         lab = (short(*)[LIBRAW_AHD_TILE][LIBRAW_AHD_TILE][3])(
0337             buffer + 12 * LIBRAW_AHD_TILE * LIBRAW_AHD_TILE);
0338         homo = (char(*)[LIBRAW_AHD_TILE][2])(buffer + 24 * LIBRAW_AHD_TILE *
0339             LIBRAW_AHD_TILE);
0340 
0341         for (int left = 2; !terminate_flag && (left < width - 5);
0342             left += LIBRAW_AHD_TILE - 6)
0343         {
0344             ahd_interpolate_green_h_and_v(top, left, rgb);
0345             ahd_interpolate_r_and_b_and_convert_to_cielab(top, left, rgb, lab);
0346             ahd_interpolate_build_homogeneity_map(top, left, lab, homo);
0347             ahd_interpolate_combine_homogeneous_pixels(top, left, rgb, homo);
0348         }
0349     }
0350 
0351     free_omp_buffers(buffers, buffer_count);
0352 
0353     if (terminate_flag)
0354         throw LIBRAW_EXCEPTION_CANCELLED_BY_CALLBACK;
0355 }