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 }