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.minRawValue()+blackLevel;
00021 unsigned short maxRaw = f.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.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 src.rawToRGBColorMatrix(colorMatrix);
00130
00131 for (int by = 0; by < rawHeight-8-BLOCK_HEIGHT+1; by += BLOCK_HEIGHT) {
00132 for (int bx = 0; bx < rawWidth-8-BLOCK_WIDTH+1; bx += BLOCK_WIDTH) {
00133
00134
00135
00136 short inBlock[4][BLOCK_HEIGHT/2+4][BLOCK_WIDTH/2+4];
00137
00138 for (int y = 0; y < BLOCK_HEIGHT/2+4; y++) {
00139 for (int x = 0; x < BLOCK_WIDTH/2+4; x++) {
00140 inBlock[GR][y][x] = ((short *)input(bx + 2*x, by + 2*y))[0];
00141 inBlock[R][y][x] = ((short *)input(bx + 2*x+1, by + 2*y))[0];
00142 inBlock[B][y][x] = ((short *)input(bx + 2*x, by + 2*y+1))[0];
00143 inBlock[GB][y][x] = ((short *)input(bx + 2*x+1, by + 2*y+1))[0];
00144 }
00145 }
00146
00147
00148 short linear[3][4][BLOCK_HEIGHT/2+4][BLOCK_WIDTH/2+4];
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161 if (denoise) {
00162 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00163 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00164 linear[G][GR][y][x] = min(inBlock[GR][y][x],
00165 max(inBlock[GR][y-1][x],
00166 inBlock[GR][y+1][x],
00167 inBlock[GR][y][x+1],
00168 inBlock[GR][y][x-1]));
00169 linear[R][R][y][x] = min(inBlock[R][y][x],
00170 max(inBlock[R][y-1][x],
00171 inBlock[R][y+1][x],
00172 inBlock[R][y][x+1],
00173 inBlock[R][y][x-1]));
00174 linear[B][B][y][x] = min(inBlock[B][y][x],
00175 max(inBlock[B][y-1][x],
00176 inBlock[B][y+1][x],
00177 inBlock[B][y][x+1],
00178 inBlock[B][y][x-1]));
00179 linear[G][GB][y][x] = min(inBlock[GB][y][x],
00180 max(inBlock[GB][y-1][x],
00181 inBlock[GB][y+1][x],
00182 inBlock[GB][y][x+1],
00183 inBlock[GB][y][x-1]));
00184 }
00185 }
00186 } else {
00187 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00188 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00189 linear[G][GR][y][x] = inBlock[GR][y][x];
00190 linear[R][R][y][x] = inBlock[R][y][x];
00191 linear[B][B][y][x] = inBlock[B][y][x];
00192 linear[G][GB][y][x] = inBlock[GB][y][x];
00193 }
00194 }
00195 }
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00222 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00223 short gv_r = (linear[G][GB][y-1][x] + linear[G][GB][y][x])/2;
00224 short gvd_r = abs(linear[G][GB][y-1][x] - linear[G][GB][y][x]);
00225 short gh_r = (linear[G][GR][y][x] + linear[G][GR][y][x+1])/2;
00226 short ghd_r = abs(linear[G][GR][y][x] - linear[G][GR][y][x+1]);
00227 linear[G][R][y][x] = ghd_r < gvd_r ? gh_r : gv_r;
00228
00229 short gv_b = (linear[G][GR][y+1][x] + linear[G][GR][y][x])/2;
00230 short gvd_b = abs(linear[G][GR][y+1][x] - linear[G][GR][y][x]);
00231 short gh_b = (linear[G][GB][y][x] + linear[G][GB][y][x-1])/2;
00232 short ghd_b = abs(linear[G][GB][y][x] - linear[G][GB][y][x-1]);
00233 linear[G][B][y][x] = ghd_b < gvd_b ? gh_b : gv_b;
00234 }
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00255 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00256 linear[R][GR][y][x] = ((linear[R][R][y][x-1] + linear[R][R][y][x])/2 +
00257 linear[G][GR][y][x] -
00258 (linear[G][R][y][x-1] + linear[G][R][y][x])/2);
00259
00260 linear[B][GR][y][x] = ((linear[B][B][y-1][x] + linear[B][B][y][x])/2 +
00261 linear[G][GR][y][x] -
00262 (linear[G][B][y-1][x] + linear[G][B][y][x])/2);
00263
00264 linear[R][GB][y][x] = ((linear[R][R][y][x] + linear[R][R][y+1][x])/2 +
00265 linear[G][GB][y][x] -
00266 (linear[G][R][y][x] + linear[G][R][y+1][x])/2);
00267
00268 linear[B][GB][y][x] = ((linear[B][B][y][x] + linear[B][B][y][x+1])/2 +
00269 linear[G][GB][y][x] -
00270 (linear[G][B][y][x] + linear[G][B][y][x+1])/2);
00271
00272 }
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297 for (int y = 1; y < BLOCK_HEIGHT/2+3; y++) {
00298 for (int x = 1; x < BLOCK_WIDTH/2+3; x++) {
00299 short rp_b = ((linear[R][R][y+1][x-1] + linear[R][R][y][x])/2 +
00300 linear[G][B][y][x] -
00301 (linear[G][R][y+1][x-1] + linear[G][R][y][x])/2);
00302 short rpd_b = abs(linear[R][R][y+1][x-1] - linear[R][R][y][x]);
00303
00304 short rn_b = ((linear[R][R][y][x-1] + linear[R][R][y+1][x])/2 +
00305 linear[G][B][y][x] -
00306 (linear[G][R][y][x-1] + linear[G][R][y+1][x])/2);
00307 short rnd_b = abs(linear[R][R][y][x-1] - linear[R][R][y+1][x]);
00308
00309 linear[R][B][y][x] = rpd_b < rnd_b ? rp_b : rn_b;
00310
00311 short bp_r = ((linear[B][B][y-1][x+1] + linear[B][B][y][x])/2 +
00312 linear[G][R][y][x] -
00313 (linear[G][B][y-1][x+1] + linear[G][B][y][x])/2);
00314 short bpd_r = abs(linear[B][B][y-1][x+1] - linear[B][B][y][x]);
00315
00316 short bn_r = ((linear[B][B][y][x+1] + linear[B][B][y-1][x])/2 +
00317 linear[G][R][y][x] -
00318 (linear[G][B][y][x+1] + linear[G][B][y-1][x])/2);
00319 short bnd_r = abs(linear[B][B][y][x+1] - linear[B][B][y-1][x]);
00320
00321 linear[B][R][y][x] = bpd_r < bnd_r ? bp_r : bn_r;
00322 }
00323 }
00324
00325
00326
00327
00328
00329
00330
00331
00332 float r, g, b;
00333 unsigned short ri, gi, bi;
00334 for (int y = 2; y < BLOCK_HEIGHT/2+2; y++) {
00335 for (int x = 2; x < BLOCK_WIDTH/2+2; x++) {
00336
00337
00338 r = colorMatrix[0]*linear[R][GR][y][x] +
00339 colorMatrix[1]*linear[G][GR][y][x] +
00340 colorMatrix[2]*linear[B][GR][y][x] +
00341 colorMatrix[3];
00342
00343 g = colorMatrix[4]*linear[R][GR][y][x] +
00344 colorMatrix[5]*linear[G][GR][y][x] +
00345 colorMatrix[6]*linear[B][GR][y][x] +
00346 colorMatrix[7];
00347
00348 b = colorMatrix[8]*linear[R][GR][y][x] +
00349 colorMatrix[9]*linear[G][GR][y][x] +
00350 colorMatrix[10]*linear[B][GR][y][x] +
00351 colorMatrix[11];
00352
00353
00354 ri = r < 0 ? 0 : (r > 1023 ? 1023 : (unsigned short)(r+0.5f));
00355 gi = g < 0 ? 0 : (g > 1023 ? 1023 : (unsigned short)(g+0.5f));
00356 bi = b < 0 ? 0 : (b > 1023 ? 1023 : (unsigned short)(b+0.5f));
00357
00358
00359 out(bx+(x-2)*2, by+(y-2)*2)[0] = lut[ri];
00360 out(bx+(x-2)*2, by+(y-2)*2)[1] = lut[gi];
00361 out(bx+(x-2)*2, by+(y-2)*2)[2] = lut[bi];
00362
00363
00364 r = colorMatrix[0]*linear[R][R][y][x] +
00365 colorMatrix[1]*linear[G][R][y][x] +
00366 colorMatrix[2]*linear[B][R][y][x] +
00367 colorMatrix[3];
00368
00369 g = colorMatrix[4]*linear[R][R][y][x] +
00370 colorMatrix[5]*linear[G][R][y][x] +
00371 colorMatrix[6]*linear[B][R][y][x] +
00372 colorMatrix[7];
00373
00374 b = colorMatrix[8]*linear[R][R][y][x] +
00375 colorMatrix[9]*linear[G][R][y][x] +
00376 colorMatrix[10]*linear[B][R][y][x] +
00377 colorMatrix[11];
00378
00379
00380 ri = r < 0 ? 0 : (r > 1023 ? 1023 : (unsigned short)(r+0.5f));
00381 gi = g < 0 ? 0 : (g > 1023 ? 1023 : (unsigned short)(g+0.5f));
00382 bi = b < 0 ? 0 : (b > 1023 ? 1023 : (unsigned short)(b+0.5f));
00383
00384
00385 out(bx+(x-2)*2+1, by+(y-2)*2)[0] = lut[ri];
00386 out(bx+(x-2)*2+1, by+(y-2)*2)[1] = lut[gi];
00387 out(bx+(x-2)*2+1, by+(y-2)*2)[2] = lut[bi];
00388
00389
00390 r = colorMatrix[0]*linear[R][B][y][x] +
00391 colorMatrix[1]*linear[G][B][y][x] +
00392 colorMatrix[2]*linear[B][B][y][x] +
00393 colorMatrix[3];
00394
00395 g = colorMatrix[4]*linear[R][B][y][x] +
00396 colorMatrix[5]*linear[G][B][y][x] +
00397 colorMatrix[6]*linear[B][B][y][x] +
00398 colorMatrix[7];
00399
00400 b = colorMatrix[8]*linear[R][B][y][x] +
00401 colorMatrix[9]*linear[G][B][y][x] +
00402 colorMatrix[10]*linear[B][B][y][x] +
00403 colorMatrix[11];
00404
00405
00406 ri = r < 0 ? 0 : (r > 1023 ? 1023 : (unsigned short)(r+0.5f));
00407 gi = g < 0 ? 0 : (g > 1023 ? 1023 : (unsigned short)(g+0.5f));
00408 bi = b < 0 ? 0 : (b > 1023 ? 1023 : (unsigned short)(b+0.5f));
00409
00410
00411 out(bx+(x-2)*2, by+(y-2)*2+1)[0] = lut[ri];
00412 out(bx+(x-2)*2, by+(y-2)*2+1)[1] = lut[gi];
00413 out(bx+(x-2)*2, by+(y-2)*2+1)[2] = lut[bi];
00414
00415
00416 r = colorMatrix[0]*linear[R][GB][y][x] +
00417 colorMatrix[1]*linear[G][GB][y][x] +
00418 colorMatrix[2]*linear[B][GB][y][x] +
00419 colorMatrix[3];
00420
00421 g = colorMatrix[4]*linear[R][GB][y][x] +
00422 colorMatrix[5]*linear[G][GB][y][x] +
00423 colorMatrix[6]*linear[B][GB][y][x] +
00424 colorMatrix[7];
00425
00426 b = colorMatrix[8]*linear[R][GB][y][x] +
00427 colorMatrix[9]*linear[G][GB][y][x] +
00428 colorMatrix[10]*linear[B][GB][y][x] +
00429 colorMatrix[11];
00430
00431
00432 ri = r < 0 ? 0 : (r > 1023 ? 1023 : (unsigned short)(r+0.5f));
00433 gi = g < 0 ? 0 : (g > 1023 ? 1023 : (unsigned short)(g+0.5f));
00434 bi = b < 0 ? 0 : (b > 1023 ? 1023 : (unsigned short)(b+0.5f));
00435
00436
00437 out(bx+(x-2)*2+1, by+(y-2)*2+1)[0] = lut[ri];
00438 out(bx+(x-2)*2+1, by+(y-2)*2+1)[1] = lut[gi];
00439 out(bx+(x-2)*2+1, by+(y-2)*2+1)[2] = lut[bi];
00440
00441 }
00442 }
00443 }
00444 }
00445
00446 return out;
00447 }
00448
00449
00450 Image makeThumbnailRAW(Frame src, const Size &thumbSize, float contrast, int blackLevel, float gamma) {
00451
00452
00453 #ifdef FCAM_ARCH_ARM
00454 if (src.image().width() == 2592 &&
00455 src.image().height() == 1968 &&
00456 thumbSize.width == 640 &&
00457 thumbSize.height == 480 &&
00458 src.bayerPattern() == GRBG) {
00459 return makeThumbnailRAW_ARM(src, contrast, blackLevel, gamma);
00460 }
00461 #endif
00462
00463
00464 unsigned char lut[4096];
00465 makeLUT(src, contrast, blackLevel, gamma, lut);
00466
00467 Image thumb;
00469 bool redRowEven, blueRowGreenPixelEven;
00470 switch (src.bayerPattern()) {
00471 case RGGB:
00472 redRowEven = true;
00473 blueRowGreenPixelEven = true;
00474 break;
00475 case BGGR:
00476 redRowEven = false;
00477 blueRowGreenPixelEven = false;
00478 break;
00479 case GRBG:
00480 redRowEven = true;
00481 blueRowGreenPixelEven = false;
00482 break;
00483 case GBRG:
00484 redRowEven = false;
00485 blueRowGreenPixelEven = true;
00486 break;
00487 default:
00488 return thumb;
00489 break;
00490 }
00491
00492 Time startTime = Time::now();
00493
00494 thumb = Image(thumbSize, RGB24);
00495
00496 unsigned int w = src.image().width();
00497 unsigned int h = src.image().height();
00498 unsigned int tw = thumbSize.width;
00499 unsigned int th = thumbSize.height;
00500 short maxPixel = 1023;
00501 short minPixel = 0;
00502 unsigned int scaleX = (int)std::floor((float)w / tw);
00503 unsigned int scaleY = (int)std::floor((float)h / th);
00504 unsigned int scale = std::min(scaleX, scaleY);
00505
00506 int cropX = (w-scale*tw)/2;
00507 if (cropX % 2 == 1) cropX--;
00508 int cropY = (h-scale*th)/2;
00509 if (cropY % 2 == 1) cropY--;
00510
00511 float colorMatrix[12];
00512 src.rawToRGBColorMatrix(colorMatrix);
00513
00514
00515
00516
00517
00518
00519 for (unsigned int ty=0; ty < th; ty++) {
00520 unsigned char *tpix = thumb(0,ty);
00521 for (unsigned int tx=0; tx < tw; tx++) {
00522 unsigned int r=0,g=0,b=0;
00523 unsigned int rc=0,gc=0,bc=0;
00524
00525 unsigned char *rowStart = src.image()(cropX + tx*scale, cropY + ty*scale);
00526
00527 bool isRedRow = ((ty*scale % 2 == 0) == redRowEven);
00528
00529 for(unsigned int i=0; i<scale; i++, rowStart+=src.image().bytesPerRow(), isRedRow = !isRedRow) {
00530 unsigned short *px = (unsigned short *)rowStart;
00531 if (isRedRow) {
00532 bool isRed=((tx*scale)%2==0) == blueRowGreenPixelEven;
00533 for (unsigned int j=0; j < scale; j++, isRed=!isRed) {
00534 if (isRed) {
00535 r += *(px++);
00536 rc++;
00537 } else {
00538 g += *(px++);
00539 gc++;
00540 }
00541 }
00542 } else {
00543 bool isGreen=((tx*scale)%2==0) == blueRowGreenPixelEven;
00544 for (unsigned int j=0; j < scale; j++, isGreen=!isGreen) {
00545 if (isGreen) {
00546 g += *(px++);
00547 gc++;
00548 } else {
00549 b += *(px++);
00550 bc++;
00551 }
00552
00553 }
00554 }
00555 }
00556 float r_sensor = ((float)r / rc);
00557 float g_sensor = ((float)g / gc);
00558 float b_sensor = ((float)b / bc);
00559 float r_srgb = (r_sensor * colorMatrix[0] +
00560 g_sensor * colorMatrix[1] +
00561 b_sensor * colorMatrix[2] +
00562 colorMatrix[3]);
00563 float g_srgb = (r_sensor * colorMatrix[4] +
00564 g_sensor * colorMatrix[5] +
00565 b_sensor * colorMatrix[6] +
00566 colorMatrix[7]);
00567 float b_srgb = (r_sensor * colorMatrix[8] +
00568 g_sensor * colorMatrix[9] +
00569 b_sensor * colorMatrix[10] +
00570 colorMatrix[11]);
00571 unsigned short r_linear = std::min(maxPixel,std::max(minPixel,(short int)std::floor(r_srgb+0.5)));
00572 unsigned short g_linear = std::min(maxPixel,std::max(minPixel,(short int)std::floor(g_srgb+0.5)));
00573 unsigned short b_linear = std::min(maxPixel,std::max(minPixel,(short int)std::floor(b_srgb+0.5)));
00574 *(tpix++) = lut[r_linear];
00575 *(tpix++) = lut[g_linear];
00576 *(tpix++) = lut[b_linear];
00577 }
00578 }
00579
00580
00581
00582 return thumb;
00583
00584 }
00585
00586 Image makeThumbnail(Frame src, const Size &thumbSize, float contrast, int blackLevel, float gamma) {
00587 Image thumb;
00588
00589
00590 if (not src.image().valid()) return thumb;
00591 if (thumbSize.width == 0 or thumbSize.height == 0) return thumb;
00592
00593 switch (src.image().type()) {
00594 case RAW:
00595 thumb = makeThumbnailRAW(src, thumbSize, contrast, blackLevel, gamma);
00596 break;
00597 case RGB24:
00598 case RGB16:
00599 case UYVY:
00600 case YUV24:
00601 case UNKNOWN:
00602 default:
00604
00605 break;
00606 }
00607 return thumb;
00608 }
00609
00610 }