File indexing completed on 2025-01-05 03:57:06

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 void LibRaw::hat_transform(float *temp, float *base, int st, int size, int sc)
0022 {
0023   int i;
0024   for (i = 0; i < sc; i++)
0025     temp[i] = 2 * base[st * i] + base[st * (sc - i)] + base[st * (i + sc)];
0026   for (; i + sc < size; i++)
0027     temp[i] = 2 * base[st * i] + base[st * (i - sc)] + base[st * (i + sc)];
0028   for (; i < size; i++)
0029     temp[i] = 2 * base[st * i] + base[st * (i - sc)] +
0030               base[st * (2 * size - 2 - (i + sc))];
0031 }
0032 
0033 #if !defined(LIBRAW_USE_OPENMP)
0034 void LibRaw::wavelet_denoise()
0035 {
0036   float *fimg = 0, *temp, thold, mul[2], avg, diff;
0037   int scale = 1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2];
0038   ushort *window[4];
0039   static const float noise[] = {0.8002f, 0.2735f, 0.1202f, 0.0585f,
0040                                 0.0291f, 0.0152f, 0.0080f, 0.0044f};
0041 
0042   if (iwidth < 65 || iheight < 65) return;
0043 
0044   while (maximum << scale < 0x10000)
0045     scale++;
0046   maximum <<= --scale;
0047   black <<= scale;
0048   FORC4 cblack[c] <<= scale;
0049   if ((size = iheight * iwidth) < 0x15550000)
0050     fimg = (float *)malloc((size * 3 + iheight + iwidth + 128) * sizeof *fimg);
0051   temp = fimg + size * 3;
0052   if ((nc = colors) == 3 && filters)
0053     nc++;
0054   FORC(nc)
0055   { /* denoise R,G1,B,G3 individually */
0056     for (i = 0; i < size; i++)
0057       fimg[i] = 256 * sqrt((double)(image[i][c] << scale));
0058     for (hpass = lev = 0; lev < 5; lev++)
0059     {
0060       lpass = size * ((lev & 1) + 1);
0061       for (row = 0; row < iheight; row++)
0062       {
0063         hat_transform(temp, fimg + hpass + row * iwidth, 1, iwidth, 1 << lev);
0064         for (col = 0; col < iwidth; col++)
0065           fimg[lpass + row * iwidth + col] = temp[col] * 0.25;
0066       }
0067       for (col = 0; col < iwidth; col++)
0068       {
0069         hat_transform(temp, fimg + lpass + col, iwidth, iheight, 1 << lev);
0070         for (row = 0; row < iheight; row++)
0071           fimg[lpass + row * iwidth + col] = temp[row] * 0.25;
0072       }
0073       thold = threshold * noise[lev];
0074       for (i = 0; i < size; i++)
0075       {
0076         fimg[hpass + i] -= fimg[lpass + i];
0077         if (fimg[hpass + i] < -thold)
0078           fimg[hpass + i] += thold;
0079         else if (fimg[hpass + i] > thold)
0080           fimg[hpass + i] -= thold;
0081         else
0082           fimg[hpass + i] = 0;
0083         if (hpass)
0084           fimg[i] += fimg[hpass + i];
0085       }
0086       hpass = lpass;
0087     }
0088     for (i = 0; i < size; i++)
0089       image[i][c] = CLIP(SQR(fimg[i] + fimg[lpass + i]) / 0x10000);
0090   }
0091   if (filters && colors == 3)
0092   { /* pull G1 and G3 closer together */
0093     for (row = 0; row < 2; row++)
0094     {
0095       mul[row] = 0.125 * pre_mul[FC(row + 1, 0) | 1] / pre_mul[FC(row, 0) | 1];
0096       blk[row] = cblack[FC(row, 0) | 1];
0097     }
0098     for (i = 0; i < 4; i++)
0099       window[i] = (ushort *)fimg + width * i;
0100     for (wlast = -1, row = 1; row < height - 1; row++)
0101     {
0102       while (wlast < row + 1)
0103       {
0104         for (wlast++, i = 0; i < 4; i++)
0105           window[(i + 3) & 3] = window[i];
0106         for (col = FC(wlast, 1) & 1; col < width; col += 2)
0107           window[2][col] = BAYER(wlast, col);
0108       }
0109       thold = threshold / 512;
0110       for (col = (FC(row, 0) & 1) + 1; col < width - 1; col += 2)
0111       {
0112         avg = (window[0][col - 1] + window[0][col + 1] + window[2][col - 1] +
0113                window[2][col + 1] - blk[~row & 1] * 4) *
0114                   mul[row & 1] +
0115               (window[1][col] + blk[row & 1]) * 0.5;
0116         avg = avg < 0 ? 0 : sqrt(avg);
0117         diff = sqrt((double)BAYER(row, col)) - avg;
0118         if (diff < -thold)
0119           diff += thold;
0120         else if (diff > thold)
0121           diff -= thold;
0122         else
0123           diff = 0;
0124         BAYER(row, col) = CLIP(SQR(avg + diff) + 0.5);
0125       }
0126     }
0127   }
0128   free(fimg);
0129 }
0130 #else /* LIBRAW_USE_OPENMP */
0131 void LibRaw::wavelet_denoise()
0132 {
0133   float *fimg = 0, *temp, thold, mul[2], avg, diff;
0134   int scale = 1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2];
0135   ushort *window[4];
0136   static const float noise[] = {0.8002, 0.2735, 0.1202, 0.0585,
0137                                 0.0291, 0.0152, 0.0080, 0.0044};
0138 
0139   if (iwidth < 65 || iheight < 65)
0140     return;
0141 
0142   while (maximum << scale < 0x10000)
0143     scale++;
0144   maximum <<= --scale;
0145   black <<= scale;
0146   FORC4 cblack[c] <<= scale;
0147   if ((size = iheight * iwidth) < 0x15550000)
0148     fimg = (float *)malloc((size * 3 + iheight + iwidth) * sizeof *fimg);
0149   temp = fimg + size * 3;
0150   if ((nc = colors) == 3 && filters)
0151     nc++;
0152 #pragma omp parallel default(shared) private(                                  \
0153     i, col, row, thold, lev, lpass, hpass, temp, c) firstprivate(scale, size)
0154   {
0155     temp = (float *)malloc((iheight + iwidth) * sizeof *fimg);
0156     FORC(nc)
0157     { /* denoise R,G1,B,G3 individually */
0158 #pragma omp for
0159       for (i = 0; i < size; i++)
0160         fimg[i] = 256 * sqrt((double)(image[i][c] << scale));
0161       for (hpass = lev = 0; lev < 5; lev++)
0162       {
0163         lpass = size * ((lev & 1) + 1);
0164 #pragma omp for
0165         for (row = 0; row < iheight; row++)
0166         {
0167           hat_transform(temp, fimg + hpass + row * iwidth, 1, iwidth, 1 << lev);
0168           for (col = 0; col < iwidth; col++)
0169             fimg[lpass + row * iwidth + col] = temp[col] * 0.25;
0170         }
0171 #pragma omp for
0172         for (col = 0; col < iwidth; col++)
0173         {
0174           hat_transform(temp, fimg + lpass + col, iwidth, iheight, 1 << lev);
0175           for (row = 0; row < iheight; row++)
0176             fimg[lpass + row * iwidth + col] = temp[row] * 0.25;
0177         }
0178         thold = threshold * noise[lev];
0179 #pragma omp for
0180         for (i = 0; i < size; i++)
0181         {
0182           fimg[hpass + i] -= fimg[lpass + i];
0183           if (fimg[hpass + i] < -thold)
0184             fimg[hpass + i] += thold;
0185           else if (fimg[hpass + i] > thold)
0186             fimg[hpass + i] -= thold;
0187           else
0188             fimg[hpass + i] = 0;
0189           if (hpass)
0190             fimg[i] += fimg[hpass + i];
0191         }
0192         hpass = lpass;
0193       }
0194 #pragma omp for
0195       for (i = 0; i < size; i++)
0196         image[i][c] = CLIP(SQR(fimg[i] + fimg[lpass + i]) / 0x10000);
0197     }
0198     free(temp);
0199   } /* end omp parallel */
0200   /* the following loops are hard to parallelize, no idea yes,
0201    * problem is wlast which is carrying dependency
0202    * second part should be easier, but did not yet get it right.
0203    */
0204   if (filters && colors == 3)
0205   { /* pull G1 and G3 closer together */
0206     for (row = 0; row < 2; row++)
0207     {
0208       mul[row] = 0.125 * pre_mul[FC(row + 1, 0) | 1] / pre_mul[FC(row, 0) | 1];
0209       blk[row] = cblack[FC(row, 0) | 1];
0210     }
0211     for (i = 0; i < 4; i++)
0212       window[i] = (ushort *)fimg + width * i;
0213     for (wlast = -1, row = 1; row < height - 1; row++)
0214     {
0215       while (wlast < row + 1)
0216       {
0217         for (wlast++, i = 0; i < 4; i++)
0218           window[(i + 3) & 3] = window[i];
0219         for (col = FC(wlast, 1) & 1; col < width; col += 2)
0220           window[2][col] = BAYER(wlast, col);
0221       }
0222       thold = threshold / 512;
0223       for (col = (FC(row, 0) & 1) + 1; col < width - 1; col += 2)
0224       {
0225         avg = (window[0][col - 1] + window[0][col + 1] + window[2][col - 1] +
0226                window[2][col + 1] - blk[~row & 1] * 4) *
0227                   mul[row & 1] +
0228               (window[1][col] + blk[row & 1]) * 0.5;
0229         avg = avg < 0 ? 0 : sqrt(avg);
0230         diff = sqrt((double)BAYER(row, col)) - avg;
0231         if (diff < -thold)
0232           diff += thold;
0233         else if (diff > thold)
0234           diff -= thold;
0235         else
0236           diff = 0;
0237         BAYER(row, col) = CLIP(SQR(avg + diff) + 0.5);
0238       }
0239     }
0240   }
0241   free(fimg);
0242 }
0243 
0244 #endif
0245 void LibRaw::median_filter()
0246 {
0247   ushort(*pix)[4];
0248   int pass, c, i, j, k, med[9];
0249   static const uchar opt[] = /* Optimal 9-element median search */
0250       {1, 2, 4, 5, 7, 8, 0, 1, 3, 4, 6, 7, 1, 2, 4, 5, 7, 8, 0,
0251        3, 5, 8, 4, 7, 3, 6, 1, 4, 2, 5, 4, 7, 4, 2, 6, 4, 4, 2};
0252 
0253   for (pass = 1; pass <= med_passes; pass++)
0254   {
0255     RUN_CALLBACK(LIBRAW_PROGRESS_MEDIAN_FILTER, pass - 1, med_passes);
0256     for (c = 0; c < 3; c += 2)
0257     {
0258       for (pix = image; pix < image + width * height; pix++)
0259         pix[0][3] = pix[0][c];
0260       for (pix = image + width; pix < image + width * (height - 1); pix++)
0261       {
0262         if ((pix - image + 1) % width < 2)
0263           continue;
0264         for (k = 0, i = -width; i <= width; i += width)
0265           for (j = i - 1; j <= i + 1; j++)
0266             med[k++] = pix[j][3] - pix[j][1];
0267         for (i = 0; i < int(sizeof opt); i += 2)
0268           if (med[opt[i]] > med[opt[i + 1]])
0269             SWAP(med[opt[i]], med[opt[i + 1]]);
0270         pix[0][c] = CLIP(med[4] + pix[0][1]);
0271       }
0272     }
0273   }
0274 }
0275 
0276 void LibRaw::blend_highlights()
0277 {
0278   int clip = INT_MAX, row, col, c, i, j;
0279   static const float trans[2][4][4] = {
0280       {{1, 1, 1}, {1.7320508f, -1.7320508f, 0}, {-1, -1, 2}},
0281       {{1, 1, 1, 1}, {1, -1, 1, -1}, {1, 1, -1, -1}, {1, -1, -1, 1}}};
0282   static const float itrans[2][4][4] = {
0283       {{1, 0.8660254f, -0.5}, {1, -0.8660254f, -0.5}, {1, 0, 1}},
0284       {{1, 1, 1, 1}, {1, -1, 1, -1}, {1, 1, -1, -1}, {1, -1, -1, 1}}};
0285   float cam[2][4], lab[2][4], sum[2], chratio;
0286 
0287   if ((unsigned)(colors - 3) > 1)
0288     return;
0289   RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, 0, 2);
0290   FORCC if (clip > (i = 65535 * pre_mul[c])) clip = i;
0291   for (row = 0; row < height; row++)
0292     for (col = 0; col < width; col++)
0293     {
0294       FORCC if (image[row * width + col][c] > clip) break;
0295       if (c == colors)
0296         continue;
0297       FORCC
0298       {
0299         cam[0][c] = image[row * width + col][c];
0300         cam[1][c] = MIN(cam[0][c], clip);
0301       }
0302       for (i = 0; i < 2; i++)
0303       {
0304         FORCC for (lab[i][c] = j = 0; j < colors; j++) lab[i][c] +=
0305             trans[colors - 3][c][j] * cam[i][j];
0306         for (sum[i] = 0, c = 1; c < colors; c++)
0307           sum[i] += SQR(lab[i][c]);
0308       }
0309       chratio = sqrt(sum[1] / sum[0]);
0310       for (c = 1; c < colors; c++)
0311         lab[0][c] *= chratio;
0312       FORCC for (cam[0][c] = j = 0; j < colors; j++) cam[0][c] +=
0313           itrans[colors - 3][c][j] * lab[0][j];
0314       FORCC image[row * width + col][c] = cam[0][c] / colors;
0315     }
0316   RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, 1, 2);
0317 }
0318 
0319 #define SCALE (4 >> shrink)
0320 void LibRaw::recover_highlights()
0321 {
0322   float *map, sum, wgt, grow;
0323   int hsat[4], count, spread, change, val, i;
0324   unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x;
0325   ushort *pixel;
0326   static const signed char dir[8][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, 1},
0327                                         {1, 1},   {1, 0},  {1, -1}, {0, -1}};
0328 
0329   grow = pow(2.0, 4 - highlight);
0330   FORC(unsigned(colors)) hsat[c] = 32000 * pre_mul[c];
0331   FORC(unsigned(colors))
0332       if(hsat[c]<1)
0333           return;
0334   for (kc = 0, c = 1; c < (unsigned)colors; c++)
0335     if (pre_mul[kc] < pre_mul[c])
0336       kc = c;
0337   high = height / SCALE;
0338   wide = width / SCALE;
0339   map = (float *)calloc(high, wide * sizeof *map);
0340   FORC(unsigned(colors)) if (c != kc)
0341   {
0342     RUN_CALLBACK(LIBRAW_PROGRESS_HIGHLIGHTS, c - 1, colors - 1);
0343     memset(map, 0, high * wide * sizeof *map);
0344     for (mrow = 0; mrow < high; mrow++)
0345       for (mcol = 0; mcol < wide; mcol++)
0346       {
0347         sum = wgt = count = 0;
0348         for (row = mrow * SCALE; row < (mrow + 1) * SCALE; row++)
0349           for (col = mcol * SCALE; col < (mcol + 1) * SCALE; col++)
0350           {
0351             pixel = image[row * width + col];
0352             if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000)
0353             {
0354               sum += pixel[c];
0355               wgt += pixel[kc];
0356               count++;
0357             }
0358           }
0359         if (count == SCALE * SCALE)
0360           map[mrow * wide + mcol] = sum / wgt;
0361       }
0362     for (spread = 32 / grow; spread--;)
0363     {
0364       for (mrow = 0; mrow < high; mrow++)
0365         for (mcol = 0; mcol < wide; mcol++)
0366         {
0367           if (map[mrow * wide + mcol])
0368             continue;
0369           sum = count = 0;
0370           for (d = 0; d < 8; d++)
0371           {
0372             y = mrow + dir[d][0];
0373             x = mcol + dir[d][1];
0374             if (y < high && x < wide && map[y * wide + x] > 0)
0375             {
0376               sum += (1 + (d & 1)) * map[y * wide + x];
0377               count += 1 + (d & 1);
0378             }
0379           }
0380           if (count > 3)
0381             map[mrow * wide + mcol] = -(sum + grow) / (count + grow);
0382         }
0383       for (change = i = 0; i < int(high * wide); i++)
0384         if (map[i] < 0)
0385         {
0386           map[i] = -map[i];
0387           change = 1;
0388         }
0389       if (!change)
0390         break;
0391     }
0392     for (i = 0; i < int(high * wide); i++)
0393       if (map[i] == 0)
0394         map[i] = 1;
0395     for (mrow = 0; mrow < high; mrow++)
0396       for (mcol = 0; mcol < wide; mcol++)
0397       {
0398         for (row = mrow * SCALE; row < (mrow + 1) * SCALE; row++)
0399           for (col = mcol * SCALE; col < (mcol + 1) * SCALE; col++)
0400           {
0401             pixel = image[row * width + col];
0402             if (pixel[c] / hsat[c] > 1)
0403             {
0404               val = pixel[kc] * map[mrow * wide + mcol];
0405               if (pixel[c] < val)
0406                 pixel[c] = CLIP(val);
0407             }
0408           }
0409       }
0410   }
0411   free(map);
0412 }
0413 #undef SCALE