• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/processing/Demosaic.cpp

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     // Make a linear luminance -> pixel value lookup table
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             // Get a linear luminance in the range 0-1
00032             float y = (i-minRaw)*invRange;
00033             // Gamma correct it
00034             y = powf(y, 1.0f/gamma);
00035             // Apply a piecewise quadratic contrast curve
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             // Convert to 8 bit and save
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         // add a guard band
00051         for (int i = maxRaw+1; i < 4096; i++) {
00052             lut[i] = 255;
00053         }
00054     }
00055 
00056     // Some functions used by demosaic
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         // We've vectorized this code for arm
00072         #ifdef FCAM_ARCH_ARM
00073         return demosaic_ARM(src, contrast, denoise, blackLevel, gamma);
00074         #endif
00075 
00076         Image input = src.image();
00077 
00078         // First check we're the right bayer pattern. If not crop and continue.
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         // Check we're the right size, if not, crop center
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         // Prepare the lookup table
00124         unsigned char lut[4096];
00125         makeLUT(src, contrast, blackLevel, gamma, lut);
00126 
00127         // Grab the color matrix
00128         float colorMatrix[12];
00129         // Check if there's a custom color matrix
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             // Otherwise use the platform version
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                   Stage 1: Load a block of input, treat it as 4-channel gr, r, b, gb
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                 // linear luminance outputs
00156                 short linear[3][4][BLOCK_HEIGHT/2+4][BLOCK_WIDTH/2+4];
00157 
00158                 /*                  
00159 
00160                 Stage 1.5: Suppress hot pixels
00161 
00162                 gr[HERE] = min(gr[HERE], max(gr[UP], gr[LEFT], gr[RIGHT], gr[DOWN]));
00163                 r[HERE]  = min(r[HERE], max(r[UP], r[LEFT], r[RIGHT], r[DOWN]));
00164                 b[HERE]  = min(b[HERE], max(b[UP], b[LEFT], b[RIGHT], b[DOWN]));
00165                 gb[HERE] = min(gb[HERE], max(gb[UP], gb[LEFT], gb[RIGHT], gb[DOWN]));
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                   2: Interpolate g at r 
00208                   
00209                   gv_r = (gb[UP] + gb[HERE])/2;
00210                   gvd_r = |gb[UP] - gb[HERE]|;
00211                   
00212                   gh_r = (gr[HERE] + gr[RIGHT])/2;
00213                   ghd_r = |gr[HERE] - gr[RIGHT]|;
00214                   
00215                   g_r = ghd_r < gvd_r ? gh_r : gv_r;
00216                   
00217                   3: Interpolate g at b
00218                   
00219                   gv_b = (gr[DOWN] + gr[HERE])/2;
00220                   gvd_b = |gr[DOWN] - gr[HERE]|;
00221                   
00222                   gh_b = (gb[LEFT] + gb[HERE])/2;
00223                   ghd_b = |gb[LEFT] - gb[HERE]|;
00224                   
00225                   g_b = ghd_b < gvd_b ? gh_b : gv_b;
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                   4: Interpolate r at gr
00247                   
00248                   r_gr = (r[LEFT] + r[HERE])/2 + gr[HERE] - (g_r[LEFT] + g_r[HERE])/2;
00249                   
00250                   5: Interpolate b at gr
00251                   
00252                   b_gr = (b[UP] + b[HERE])/2 + gr[HERE] - (g_b[UP] + g_b[HERE])/2;
00253                   
00254                   6: Interpolate r at gb
00255                   
00256                   r_gb = (r[HERE] + r[DOWN])/2 + gb[HERE] - (g_r[HERE] + g_r[DOWN])/2;
00257                   
00258                   7: Interpolate b at gb
00259                   
00260                   b_gb = (b[HERE] + b[RIGHT])/2 + gb[HERE] - (g_b[HERE] + g_b[RIGHT])/2;
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                 8: Interpolate r at b
00287                 
00288                 rp_b = (r[DOWNLEFT] + r[HERE])/2 + g_b[HERE] - (g_r[DOWNLEFT] + g_r[HERE])/2;
00289                 rn_b = (r[LEFT] + r[DOWN])/2 + g_b[HERE] - (g_r[LEFT] + g_r[DOWN])/2;
00290                 rpd_b = (r[DOWNLEFT] - r[HERE]);
00291                 rnd_b = (r[LEFT] - r[DOWN]);    
00292                 
00293                 r_b = rpd_b < rnd_b ? rp_b : rn_b;
00294                 
00295                 9: Interpolate b at r
00296                 
00297                 bp_r = (b[UPRIGHT] + b[HERE])/2 + g_r[HERE] - (g_b[UPRIGHT] + g_b[HERE])/2;
00298                 bn_r = (b[RIGHT] + b[UP])/2 + g_r[HERE] - (g_b[RIGHT] + g_b[UP])/2;     
00299                 bpd_r = |b[UPRIGHT] - b[HERE]|;
00300                 bnd_r = |b[RIGHT] - b[UP]|;     
00301                 
00302                 b_r = bpd_r < bnd_r ? bp_r : bn_r;             
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                   10: Color matrix
00335                     
00336                   11: Gamma correct
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                         // Convert from sensor rgb to srgb
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                         // Clamp
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                         // Gamma correct and store
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                         // Convert from sensor rgb to srgb
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                         // Clamp
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                         // Gamma correct and store
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                         // Convert from sensor rgb to srgb
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                         // Clamp
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                         // Gamma correct and store
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                         // Convert from sensor rgb to srgb
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                         // Clamp
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                         // Gamma correct and store
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     // Generic RAW to thumbnail converter
00458     Image makeThumbnailRAW(Frame src, const Size &thumbSize, float contrast, int blackLevel, float gamma) {
00459         
00460         // Special-case the N900's common case for speed (5 MP GRGB -> 640x480 RGB24 on ARM)
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         // Make the response curve
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); // Maintain aspect ratio
00513         
00514         int cropX = (w-scale*tw)/2;
00515         if (cropX % 2 == 1) cropX--; // Ensure we're at start of 2x2 block
00516         int cropY = (h-scale*th)/2;
00517         if (cropY % 2 == 1) cropY--; // Ensure we're at start of 2x2 block
00518 
00519         float colorMatrix[12];
00520         // Check if there's a custom color matrix
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             // Otherwise use the platform version
00527             src.platform().rawToRGBColorMatrix(src.shot().whiteBalance, colorMatrix);
00528         }
00529 
00530         /* A fast downsampling/demosaicing - average down color
00531            channels over the whole source pixel block under a single
00532            thumbnail pixel, and just use those colors directly as the
00533            pixel colors. */        
00534 
00535         for (unsigned int ty=0; ty < th; ty++) {
00536             unsigned char *tpix = thumb(0,ty); // Get a pointer to the beginning of the row
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         //std::cout << "Done creating thumbnail. time = " << ((Time::now()-startTime)/1000) << std::endl;
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         // Sanity checks
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             // These formats can't be thumbnailed yet
00621             break;
00622         }
00623         return thumb;
00624     }
00625 
00626 }

Generated on Fri Sep 24 2010 15:53:00 for FCam by  doxygen 1.7.1