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 }