/* * STV0680 Vision Camera Chipset Driver * Copyright 2000 Adam Harrison * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA */ #include #include #include #include "bayer.h" /* Enhanced by Kurt Garloff to do scaling and debayering at the same time. */ void bayer_unshuffle_preview(int w, int h, int scale, unsigned char *raw, unsigned char *output) { int x, y, nx, ny; int colour; int rgb[3]; int nw = w >> scale; int nh = h >> scale; int incr = 1<>1) + ((x&1)? 0: (w>>1))]; } } output[0] = rgb[0]>>(2*scale-2); output[1] = rgb[1]>>(2*scale-1); output[2] = rgb[2]>>(2*scale-2); } } } /****** gamma correction from trans[], plus hardcoded white balance */ /* Thanks to Alexander Schwartx for this code. Gamma correction (trans[] values generated by (pow((i-17)/239, GAMMA)*254) where GAMMA=0.5x, 11) multiple colours to max, * which would be a loss of information. * - The gamma mainly determines how fast values increase after ZERO1. * Influence on the highlights is small; therefore the description * with amplifiaction and gamma seems not very appropriate; a better * correction function would allow to influence the slope for small * and for large values indepentently without incurring loss of * accuracy/information. It should not be hard to construct such a * thing. (Splines or Bézier or Triginometric/Hyperbolic functions * could be used, e.g.) * - The below parameters have been found by lots of experiments with * pictures taken at different light levels. They're optimized for * my PenCam (and my screens), of course. No theory behind this; * I don't have insight into the physics of the imaging sensor. * CCDs are linear, basically; but higher order effects may play * a role as well as the electronics that controls the shutter * and the one doing the readout. */ static const rgbgamma gampar[6][3] = { { { 1.02, 0.56 }, { 1.00, 0.61 }, { 0.99, 0.65 } }, /* cold */ { { 1.01, 0.56 }, { 1.00, 0.58 }, { 1.00, 0.61 } }, /* coldish */ { { 1.00, 0.55 }, { 1.00, 0.57 }, { 1.00, 0.59 } }, /* mid */ { { 1.00, 0.55 }, { 1.00, 0.56 }, { 1.01, 0.55 } }, /* warmish */ { { 1.01, 0.56 }, { 0.99, 0.57 }, { 1.03, 0.50 } }, /* warm */ { { 1.03, 0.52 }, { 0.97, 0.57 }, { 1.04, 0.49 } } /* warm bright */ }; void light_enhance(int vw, int vh, int coarse, int fine, unsigned char avg_pix, unsigned char *output) { unsigned long int i; int lt=3; /* 3 is auto */ /* float wb[3][3]; */ unsigned char trans[3][256]; unsigned char col; /* int tmp1, tmp2, tmp3, whitex=20, whitey=20, j, k; */ double brightness = 1.00; /* FIXME: configurable? */ /* fprintf(stderr, "(FineExp=%i CoarseExp=%i => filter=", fine, coarse); */ #if 0 if (fine >= (coarse<<1)) { lt = 0; /* fprintf(stderr, "natural)\n"); */ } else if (((fine<<1) < coarse) && (coarse < 400)) { lt = 2; /* fprintf(stderr, "incandescent)\n"); */ } else { lt = 1; /* fprintf(stderr, "fluorescent)\n"); */ } wb[0][0] = 1.08 * x; wb[0][1] = 1.00 * x; wb[0][2] = 0.95 * x; /* natural */ wb[1][0] = 1.00 * x; wb[1][1] = 1.00 * x; wb[1][2] = 1.00 * x; /* fluorescent */ wb[2][0] = 0.90 * x; wb[2][1] = 1.00 * x; wb[2][2] = 1.11 * x; /* incandescent */ #else if (fine > coarse) { lt = 0; /* fprintf (stderr, "cold)\n"); */ } else if (coarse < 100) { lt = 1; /* fprintf (stderr, "coldish)\n"); */ } else if (coarse < 200) { lt = 2; /* fprintf (stderr, "mid)\n"); */ } else if (coarse < 400) { lt = 3; /* fprintf (stderr, "warmish)\n"); */ } else if (avg_pix < 94) { lt = 4; /* fprintf (stderr, "warm)\n"); */ } else { lt = 5; /* fprintf (stderr, "warm, bright)\n"); */ } #endif #if 0 /* find white pixel */ for (j=0;j=160)) { whitex = k; whitey = j; break; } } } #endif for (col = 0; col < 3; col++) { double y; const rgbgamma *gp = gampar[lt] + col; for(i=0; i<256; ++i) { if (i < ZERO0) y = 0; else if (i < ZERO1) y = 1; else y = brightness * gp->ampl * (2 + pow((i-ZERO1)/((double)254-ZERO1),gp->gamma) * 253.5); if (y > 255.0) y = 255.0; trans[col][i] = (unsigned char) y; } } for (i=0;i<(vw*vh*3);i+=3) { int r,g,b; r = *(output+i); g = *(output+i+1); b = *(output+i+2); /* this (adjusting white) isn't quite right yet, so I turned it off */ if ( 0 && (abs(r-g) < 8) && (abs(r-b) < 8) && (abs(b-g) < 8)) { int v = trans[1][(r+b+g+1)/3]; *(output+i) = (unsigned char) (v); *(output+i+1) = (unsigned char) (v); *(output+i+2) = (unsigned char) (v); fprintf(stderr,"Adjusting white\n"); } else { /* this is OK */ *(output+i) = trans[0][r]; *(output+i+1) = trans[1][g]; *(output+i+2) = trans[2][b]; } } /* for */ } /* light_enhance */