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