00001 #include <cmath>
00002 #include <iostream>
00003 #include <algorithm>
00004 #include <map>
00005 #include <vector>
00006 #include <string.h>
00007 #ifdef FCAM_ARCH_ARM
00008 #include "Demosaic_ARM.h"
00009 #endif
00010
00011 #include <FCam/processing/Demosaic.h>
00012 #include <FCam/Sensor.h>
00013 #include <FCam/Time.h>
00014
00015
00016 namespace FCam {
00017
00018
00019 void makeLUT(const Frame &f, float contrast, int blackLevel, float gamma, unsigned char *lut) {
00020 unsigned short minRaw = f.platform().minRawValue()+blackLevel;
00021 unsigned short maxRaw = f.platform().maxRawValue();
00022
00023 for (int i = 0; i <= minRaw; i++) {
00024 lut[i] = 0;
00025 }
00026
00027 float invRange = 1.0f/(maxRaw - minRaw);
00028 float b = 2 - powf(2.0f, contrast/100.0f);
00029 float a = 2 - 2*b;
00030 for (int i = minRaw+1; i <= maxRaw; i++) {
00031
00032 float y = (i-minRaw)*invRange;
00033
00034 y = powf(y, 1.0f/gamma);
00035
00036 if (y > 0.5) {
00037 y = 1-y;
00038 y = a*y*y + b*y;
00039 y = 1-y;
00040 } else {
00041 y = a*y*y + b*y;
00042 }
00043
00044 y = std::floor(y * 255 + 0.5f);
00045 if (y < 0) { y = 0; }
00046 if (y > 255) { y = 255; }
00047 lut[i] = (unsigned char)y;
00048 }
00049
00050
00051 for (int i = maxRaw+1; i < 4096; i++) {
00052 lut[i] = 255;
00053 }
00054 }
00055
00056
00057 inline short max(short a, short b) {return a>b ? a : b;}
00058 inline short max(short a, short b, short c, short d) {return max(max(a, b), max(c, d));}
00059 inline short min(short a, short b) {return a<b ? a : b;}
00060
00061 Image demosaic(Frame src, float contrast, bool denoise, int blackLevel, float gamma) {
00062 if (!src.image().valid()) {
00063 error(Event::DemosaicError, "Cannot demosaic an invalid image");
00064 return Image();
00065 }
00066 if (src.image().bytesPerRow() % 2 == 1) {
00067 error(Event::DemosaicError, "Cannot demosaic an image with bytesPerRow not divisible by 2");
00068 return Image();
00069 }
00070
00071
00072 #ifdef FCAM_ARCH_ARM
00073 return demosaic_ARM(src, contrast, denoise, blackLevel, gamma);
00074 #endif
00075
00076 Image input = src.image();
00077
00078
00079 switch ((int)src.platform().bayerPattern()) {
00080 case GRBG:
00081 break;
00082 case RGGB:
00083 input = input.subImage(1, 0, Size(input.width()-2, input.height()));
00084 break;
00085 case BGGR:
00086 input = input.subImage(0, 1, Size(input.width(), input.height()-2));
00087 break;
00088 case GBRG:
00089 input = input.subImage(1, 1, Size(input.width()-2, input.height()-2));
00090 default:
00091 error(Event::DemosaicError, "Can't demosaic from a non-bayer sensor\n");
00092 return Image();
00093 }
00094
00095 const int BLOCK_WIDTH = 40;
00096 const int BLOCK_HEIGHT = 24;
00097 const int G = 0, GR = 0, R = 1, B = 2, GB = 3;
00098
00099 int rawWidth = input.width();
00100 int rawHeight = input.height();
00101 int outWidth = rawWidth-8;
00102 int outHeight = rawHeight-8;
00103 outWidth /= BLOCK_WIDTH;
00104 outWidth *= BLOCK_WIDTH;
00105 outHeight /= BLOCK_HEIGHT;
00106 outHeight *= BLOCK_HEIGHT;
00107
00108 Image out(outWidth, outHeight, RGB24);
00109
00110
00111 if (((input.width() - 8) != (unsigned)outWidth) ||
00112 ((input.height() - 8) != (unsigned)outHeight)) {
00113 int offX = (input.width() - 8 - outWidth)/2;
00114 int offY = (input.height() - 8 - outHeight)/2;
00115 offX -= offX&1;
00116 offY -= offY&1;
00117
00118 if (offX || offY) {
00119 input = input.subImage(offX, offY, Size(outWidth+8, outHeight+8));
00120 }
00121 }
00122
00123
00124 unsigned char lut[4096];
00125 makeLUT(src, contrast, blackLevel, gamma, lut);
00126
00127
00128 float colorMatrix[12];
00129
00130 if (src.shot().colorMatrix().size() == 12) {
00131 for (int i = 0; i < 12; i++) {
00132 colorMatrix[i] = src.shot().colorMatrix()[i];
00133 }
00134 } else {
00135
00136 src.platform().rawToRGBColorMatrix(src.shot().whiteBalance, colorMatrix);
00137 }
00138
00139 for (int by = 0; by < rawHeight-8-BLOCK_HEIGHT+1; by += BLOCK_HEIGHT) {
00140 for (int bx = 0; bx < rawWidth-8-BLOCK_WIDTH+1; bx += BLOCK_WIDTH) {
00141
00142
00143
00144 short inBlock[4][BLOCK_HEIGHT/2+4][BLOCK_WIDTH/2+4];
00145
00146 for (int y = 0; y < BLOCK_HEIGHT/2+4; y++) {
00147 for (int x = 0; x < BLOCK_WIDTH/2+4; x++) {
00148 inBlock[GR][y][x] = ((short *)input(bx + 2*x, by + 2*y))[0];
00149 inBlock[R][y][x] = ((short *)input(bx + 2*x+1, by + 2*y))[0];
00150 inBlock[B][y][x] = ((short *)input(bx + 2*x, by + 2*y+1))[0];
00151 inBlock[GB][y][x] = ((short *)input(bx + 2*x+1, by + 2*y+1))[0];
00152 }
00153 }
00154
00155
00156 short linear[3][4][BLOCK_HEIGHT/2+4][BLOCK_WIDTH/2+4];
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 if (denoise) {
00170 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00171 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00172 linear[G][GR][y][x] = min(inBlock[GR][y][x],
00173 max(inBlock[GR][y-1][x],
00174 inBlock[GR][y+1][x],
00175 inBlock[GR][y][x+1],
00176 inBlock[GR][y][x-1]));
00177 linear[R][R][y][x] = min(inBlock[R][y][x],
00178 max(inBlock[R][y-1][x],
00179 inBlock[R][y+1][x],
00180 inBlock[R][y][x+1],
00181 inBlock[R][y][x-1]));
00182 linear[B][B][y][x] = min(inBlock[B][y][x],
00183 max(inBlock[B][y-1][x],
00184 inBlock[B][y+1][x],
00185 inBlock[B][y][x+1],
00186 inBlock[B][y][x-1]));
00187 linear[G][GB][y][x] = min(inBlock[GB][y][x],
00188 max(inBlock[GB][y-1][x],
00189 inBlock[GB][y+1][x],
00190 inBlock[GB][y][x+1],
00191 inBlock[GB][y][x-1]));
00192 }
00193 }
00194 } else {
00195 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00196 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00197 linear[G][GR][y][x] = inBlock[GR][y][x];
00198 linear[R][R][y][x] = inBlock[R][y][x];
00199 linear[B][B][y][x] = inBlock[B][y][x];
00200 linear[G][GB][y][x] = inBlock[GB][y][x];
00201 }
00202 }
00203 }
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00230 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00231 short gv_r = (linear[G][GB][y-1][x] + linear[G][GB][y][x])/2;
00232 short gvd_r = abs(linear[G][GB][y-1][x] - linear[G][GB][y][x]);
00233 short gh_r = (linear[G][GR][y][x] + linear[G][GR][y][x+1])/2;
00234 short ghd_r = abs(linear[G][GR][y][x] - linear[G][GR][y][x+1]);
00235 linear[G][R][y][x] = ghd_r < gvd_r ? gh_r : gv_r;
00236
00237 short gv_b = (linear[G][GR][y+1][x] + linear[G][GR][y][x])/2;
00238 short gvd_b = abs(linear[G][GR][y+1][x] - linear[G][GR][y][x]);
00239 short gh_b = (linear[G][GB][y][x] + linear[G][GB][y][x-1])/2;
00240 short ghd_b = abs(linear[G][GB][y][x] - linear[G][GB][y][x-1]);
00241 linear[G][B][y][x] = ghd_b < gvd_b ? gh_b : gv_b;
00242 }
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00263 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00264 linear[R][GR][y][x] = ((linear[R][R][y][x-1] + linear[R][R][y][x])/2 +
00265 linear[G][GR][y][x] -
00266 (linear[G][R][y][x-1] + linear[G][R][y][x])/2);
00267
00268 linear[B][GR][y][x] = ((linear[B][B][y-1][x] + linear[B][B][y][x])/2 +
00269 linear[G][GR][y][x] -
00270 (linear[G][B][y-1][x] + linear[G][B][y][x])/2);
00271
00272 linear[R][GB][y][x] = ((linear[R][R][y][x] + linear[R][R][y+1][x])/2 +
00273 linear[G][GB][y][x] -
00274 (linear[G][R][y][x] + linear[G][R][y+1][x])/2);
00275
00276 linear[B][GB][y][x] = ((linear[B][B][y][x] + linear[B][B][y][x+1])/2 +
00277 linear[G][GB][y][x] -
00278 (linear[G][B][y][x] + linear[G][B][y][x+1])/2);
00279
00280 }
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00306 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00307 short rp_b = ((linear[R][R][y+1][x-1] + linear[R][R][y][x])/2 +
00308 linear[G][B][y][x] -
00309 (linear[G][R][y+1][x-1] + linear[G][R][y][x])/2);
00310 short rpd_b = abs(linear[R][R][y+1][x-1] - linear[R][R][y][x]);
00311
00312 short rn_b = ((linear[R][R][y][x-1] + linear[R][R][y+1][x])/2 +
00313 linear[G][B][y][x] -
00314 (linear[G][R][y][x-1] + linear[G][R][y+1][x])/2);
00315 short rnd_b = abs(linear[R][R][y][x-1] - linear[R][R][y+1][x]);
00316
00317 linear[R][B][y][x] = rpd_b < rnd_b ? rp_b : rn_b;
00318
00319 short bp_r = ((linear[B][B][y-1][x+1] + linear[B][B][y][x])/2 +
00320 linear[G][R][y][x] -
00321 (linear[G][B][y-1][x+1] + linear[G][B][y][x])/2);
00322 short bpd_r = abs(linear[B][B][y-1][x+1] - linear[B][B][y][x]);
00323
00324 short bn_r = ((linear[B][B][y][x+1] + linear[B][B][y-1][x])/2 +
00325 linear[G][R][y][x] -
00326 (linear[G][B][y][x+1] + linear[G][B][y-1][x])/2);
00327 short bnd_r = abs(linear[B][B][y][x+1] - linear[B][B][y-1][x]);
00328
00329 linear[B][R][y][x] = bpd_r < bnd_r ? bp_r : bn_r;
00330 }
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340 float r, g, b;
00341 unsigned short ri, gi, bi;
00342 for (int y = 2; y < BLOCK_HEIGHT/2+2; y++) {
00343 for (int x = 2; x < BLOCK_WIDTH/2+2; x++) {
00344
00345
00346 r = colorMatrix[0]*linear[R][GR][y][x] +
00347 colorMatrix[1]*linear[G][GR][y][x] +
00348 colorMatrix[2]*linear[B][GR][y][x] +
00349 colorMatrix[3];
00350
00351 g = colorMatrix[4]*linear[R][GR][y][x] +
00352 colorMatrix[5]*linear[G][GR][y][x] +
00353 colorMatrix[6]*linear[B][GR][y][x] +
00354 colorMatrix[7];
00355
00356 b = colorMatrix[8]*linear[R][GR][y][x] +
00357 colorMatrix[9]*linear[G][GR][y][x] +
00358 colorMatrix[10]*linear[B][GR][y][x] +
00359 colorMatrix[11];
00360
00361
00362 ri = r < 0 ? 0 : (r > 1023 ? 1023 : (unsigned short)(r+0.5f));
00363 gi = g < 0 ? 0 : (g > 1023 ? 1023 : (unsigned short)(g+0.5f));
00364 bi = b < 0 ? 0 : (b > 1023 ? 1023 : (unsigned short)(b+0.5f));
00365
00366
00367 out(bx+(x-2)*2, by+(y-2)*2)[0] = lut[ri];
00368 out(bx+(x-2)*2, by+(y-2)*2)[1] = lut[gi];
00369 out(bx+(x-2)*2, by+(y-2)*2)[2] = lut[bi];
00370
00371
00372 r = colorMatrix[0]*linear[R][R][y][x] +
00373 colorMatrix[1]*linear[G][R][y][x] +
00374 colorMatrix[2]*linear[B][R][y][x] +
00375 colorMatrix[3];
00376
00377 g = colorMatrix[4]*linear[R][R][y][x] +
00378 colorMatrix[5]*linear[G][R][y][x] +
00379 colorMatrix[6]*linear[B][R][y][x] +
00380 colorMatrix[7];
00381
00382 b = colorMatrix[8]*linear[R][R][y][x] +
00383 colorMatrix[9]*linear[G][R][y][x] +
00384 colorMatrix[10]*linear[B][R][y][x] +
00385 colorMatrix[11];
00386
00387
00388 ri = r < 0 ? 0 : (r > 1023 ? 1023 : (unsigned short)(r+0.5f));
00389 gi = g < 0 ? 0 : (g > 1023 ? 1023 : (unsigned short)(g+0.5f));
00390 bi = b < 0 ? 0 : (b > 1023 ? 1023 : (unsigned short)(b+0.5f));
00391
00392
00393 out(bx+(x-2)*2+1, by+(y-2)*2)[0] = lut[ri];
00394 out(bx+(x-2)*2+1, by+(y-2)*2)[1] = lut[gi];
00395 out(bx+(x-2)*2+1, by+(y-2)*2)[2] = lut[bi];
00396
00397
00398 r = colorMatrix[0]*linear[R][B][y][x] +
00399 colorMatrix[1]*linear[G][B][y][x] +
00400 colorMatrix[2]*linear[B][B][y][x] +
00401 colorMatrix[3];
00402
00403 g = colorMatrix[4]*linear[R][B][y][x] +
00404 colorMatrix[5]*linear[G][B][y][x] +
00405 colorMatrix[6]*linear[B][B][y][x] +
00406 colorMatrix[7];
00407
00408 b = colorMatrix[8]*linear[R][B][y][x] +
00409 colorMatrix[9]*linear[G][B][y][x] +
00410 colorMatrix[10]*linear[B][B][y][x] +
00411 colorMatrix[11];
00412
00413
00414 ri = r < 0 ? 0 : (r > 1023 ? 1023 : (unsigned short)(r+0.5f));
00415 gi = g < 0 ? 0 : (g > 1023 ? 1023 : (unsigned short)(g+0.5f));
00416 bi = b < 0 ? 0 : (b > 1023 ? 1023 : (unsigned short)(b+0.5f));
00417
00418
00419 out(bx+(x-2)*2, by+(y-2)*2+1)[0] = lut[ri];
00420 out(bx+(x-2)*2, by+(y-2)*2+1)[1] = lut[gi];
00421 out(bx+(x-2)*2, by+(y-2)*2+1)[2] = lut[bi];
00422
00423
00424 r = colorMatrix[0]*linear[R][GB][y][x] +
00425 colorMatrix[1]*linear[G][GB][y][x] +
00426 colorMatrix[2]*linear[B][GB][y][x] +
00427 colorMatrix[3];
00428
00429 g = colorMatrix[4]*linear[R][GB][y][x] +
00430 colorMatrix[5]*linear[G][GB][y][x] +
00431 colorMatrix[6]*linear[B][GB][y][x] +
00432 colorMatrix[7];
00433
00434 b = colorMatrix[8]*linear[R][GB][y][x] +
00435 colorMatrix[9]*linear[G][GB][y][x] +
00436 colorMatrix[10]*linear[B][GB][y][x] +
00437 colorMatrix[11];
00438
00439
00440 ri = r < 0 ? 0 : (r > 1023 ? 1023 : (unsigned short)(r+0.5f));
00441 gi = g < 0 ? 0 : (g > 1023 ? 1023 : (unsigned short)(g+0.5f));
00442 bi = b < 0 ? 0 : (b > 1023 ? 1023 : (unsigned short)(b+0.5f));
00443
00444
00445 out(bx+(x-2)*2+1, by+(y-2)*2+1)[0] = lut[ri];
00446 out(bx+(x-2)*2+1, by+(y-2)*2+1)[1] = lut[gi];
00447 out(bx+(x-2)*2+1, by+(y-2)*2+1)[2] = lut[bi];
00448
00449 }
00450 }
00451 }
00452 }
00453
00454 return out;
00455 }
00456
00457
00458 Image makeThumbnailRAW(Frame src, const Size &thumbSize, float contrast, int blackLevel, float gamma) {
00459
00460
00461 #ifdef FCAM_ARCH_ARM
00462 if (src.image().width() == 2592 &&
00463 src.image().height() == 1968 &&
00464 thumbSize.width == 640 &&
00465 thumbSize.height == 480 &&
00466 src.platform().bayerPattern() == GRBG) {
00467 return makeThumbnailRAW_ARM(src, contrast, blackLevel, gamma);
00468 }
00469 #endif
00470
00471
00472 unsigned char lut[4096];
00473 makeLUT(src, contrast, blackLevel, gamma, lut);
00474
00475 Image thumb;
00477 bool redRowEven, blueRowGreenPixelEven;
00478 switch (src.platform().bayerPattern()) {
00479 case RGGB:
00480 redRowEven = true;
00481 blueRowGreenPixelEven = true;
00482 break;
00483 case BGGR:
00484 redRowEven = false;
00485 blueRowGreenPixelEven = false;
00486 break;
00487 case GRBG:
00488 redRowEven = true;
00489 blueRowGreenPixelEven = false;
00490 break;
00491 case GBRG:
00492 redRowEven = false;
00493 blueRowGreenPixelEven = true;
00494 break;
00495 default:
00496 return thumb;
00497 break;
00498 }
00499
00500 Time startTime = Time::now();
00501
00502 thumb = Image(thumbSize, RGB24);
00503
00504 unsigned int w = src.image().width();
00505 unsigned int h = src.image().height();
00506 unsigned int tw = thumbSize.width;
00507 unsigned int th = thumbSize.height;
00508 short maxPixel = 1023;
00509 short minPixel = 0;
00510 unsigned int scaleX = (int)std::floor((float)w / tw);
00511 unsigned int scaleY = (int)std::floor((float)h / th);
00512 unsigned int scale = std::min(scaleX, scaleY);
00513
00514 int cropX = (w-scale*tw)/2;
00515 if (cropX % 2 == 1) { cropX--; }
00516 int cropY = (h-scale*th)/2;
00517 if (cropY % 2 == 1) { cropY--; }
00518
00519 float colorMatrix[12];
00520
00521 if (src.shot().colorMatrix().size() == 12) {
00522 for (int i = 0; i < 12; i++) {
00523 colorMatrix[i] = src.shot().colorMatrix()[i];
00524 }
00525 } else {
00526
00527 src.platform().rawToRGBColorMatrix(src.shot().whiteBalance, colorMatrix);
00528 }
00529
00530
00531
00532
00533
00534
00535 for (unsigned int ty=0; ty < th; ty++) {
00536 unsigned char *tpix = thumb(0,ty);
00537 for (unsigned int tx=0; tx < tw; tx++) {
00538 unsigned int r=0,g=0,b=0;
00539 unsigned int rc=0,gc=0,bc=0;
00540
00541 unsigned char *rowStart = src.image()(cropX + tx*scale, cropY + ty*scale);
00542
00543 bool isRedRow = ((ty *scale % 2 == 0) == redRowEven);
00544
00545 for (unsigned int i=0; i<scale; i++, rowStart+=src.image().bytesPerRow(), isRedRow = !isRedRow) {
00546 unsigned short *px = (unsigned short *)rowStart;
00547 if (isRedRow) {
00548 bool isRed=((tx*scale)%2==0) == blueRowGreenPixelEven;
00549 for (unsigned int j=0; j < scale; j++, isRed=!isRed) {
00550 if (isRed) {
00551 r += *(px++);
00552 rc++;
00553 } else {
00554 g += *(px++);
00555 gc++;
00556 }
00557 }
00558 } else {
00559 bool isGreen=((tx*scale)%2==0) == blueRowGreenPixelEven;
00560 for (unsigned int j=0; j < scale; j++, isGreen=!isGreen) {
00561 if (isGreen) {
00562 g += *(px++);
00563 gc++;
00564 } else {
00565 b += *(px++);
00566 bc++;
00567 }
00568
00569 }
00570 }
00571 }
00572 float r_sensor = ((float)r / rc);
00573 float g_sensor = ((float)g / gc);
00574 float b_sensor = ((float)b / bc);
00575 float r_srgb = (r_sensor * colorMatrix[0] +
00576 g_sensor * colorMatrix[1] +
00577 b_sensor * colorMatrix[2] +
00578 colorMatrix[3]);
00579 float g_srgb = (r_sensor * colorMatrix[4] +
00580 g_sensor * colorMatrix[5] +
00581 b_sensor * colorMatrix[6] +
00582 colorMatrix[7]);
00583 float b_srgb = (r_sensor * colorMatrix[8] +
00584 g_sensor * colorMatrix[9] +
00585 b_sensor * colorMatrix[10] +
00586 colorMatrix[11]);
00587 unsigned short r_linear = std::min(maxPixel,std::max(minPixel,(short int)std::floor(r_srgb+0.5)));
00588 unsigned short g_linear = std::min(maxPixel,std::max(minPixel,(short int)std::floor(g_srgb+0.5)));
00589 unsigned short b_linear = std::min(maxPixel,std::max(minPixel,(short int)std::floor(b_srgb+0.5)));
00590 *(tpix++) = lut[r_linear];
00591 *(tpix++) = lut[g_linear];
00592 *(tpix++) = lut[b_linear];
00593 }
00594 }
00595
00596
00597
00598 return thumb;
00599
00600 }
00601
00602 Image makeThumbnail(Frame src, const Size &thumbSize, float contrast, int blackLevel, float gamma) {
00603 Image thumb;
00604
00605
00606 if (not src.image().valid()) { return thumb; }
00607 if (thumbSize.width == 0 or thumbSize.height == 0) { return thumb; }
00608
00609 switch (src.image().type()) {
00610 case RAW:
00611 thumb = makeThumbnailRAW(src, thumbSize, contrast, blackLevel, gamma);
00612 break;
00613 case RGB24:
00614 case RGB16:
00615 case UYVY:
00616 case YUV24:
00617 case UNKNOWN:
00618 default:
00620
00621 break;
00622 }
00623 return thumb;
00624 }
00625
00626 }