This is basically a continuation of the work from #1002 but her for the camlibs directory. The purpose was to replace spaces as a means for indentation with tab characters. Note: there are some files which are still offending the general rule but are (mostly) consistent within themselves. I let them be for the moment. Fixing them would basically replace the whole file. Also: there are still a ton of whitespace related inconsistencies like "x=10" vs "x = 10" or "func(10)" vs "func (10)". This is a whitespace only change (if you include newlines as whitespace).
200 lines
6.6 KiB
C
200 lines
6.6 KiB
C
/*
|
|
* STV0680 Vision Camera Chipset Driver
|
|
* Copyright 2000 Adam Harrison <adam@antispin.org>
|
|
*
|
|
* 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 <stdio.h>
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "stv0680-bayer.h"
|
|
|
|
/* Enhanced by Kurt Garloff to do scaling and debayering at the same time. */
|
|
void bayer_unshuffle_preview(unsigned int w, unsigned int h, unsigned 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<<scale;
|
|
|
|
for (ny = 0; ny < nh; ++ny, raw += w<<scale) {
|
|
for (nx = 0; nx < nw; ++nx, output += 3) {
|
|
rgb[0] = 0; rgb[1] = 0; rgb[2] = 0;
|
|
for (y = 0; y < incr; ++y) {
|
|
for (x = 0; x < incr; ++x) {
|
|
colour = 1 - (x&1) + (y&1);
|
|
rgb[colour] += raw[y*w + (nx<<(scale-1))+(x>>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 <alexander.schwartx@gmx.net> for this code.
|
|
Gamma correction (trans[] values generated by (pow((i-17)/239, GAMMA)*254)
|
|
where GAMMA=0.5x, 1<i<255. */
|
|
/* KG: Looking at very dark parts of images, the sensor seems to produce
|
|
* only very few points below 0x11 and almost none below 14. Therefore we map everything
|
|
* below 14 to 0 and ev'thing below 17 to 1; then the power function reigns.
|
|
*/
|
|
|
|
#define ZERO0 14 /* 0--13 mapped to 0 */
|
|
#define ZERO1 17 /* 14--16 mapped to 1 */
|
|
|
|
typedef struct _rgbgamma {
|
|
float ampl, gamma;
|
|
} rgbgamma;
|
|
|
|
|
|
/* KG: Some notes on these:
|
|
* - Try to avoid strong deviations from 1.00 for the amplification,
|
|
* because this potentially results in not using the full range
|
|
* of colours (<1) or in clipping (>1) 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 independently 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(unsigned int vw, unsigned int vh, unsigned int coarse, unsigned 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<vh;j++)
|
|
{
|
|
for (k=0; k<vw; k++)
|
|
{
|
|
i = (j*vw + k)*3;
|
|
tmp1 = abs(*(output+i) - *(output+i+1));
|
|
tmp2 = abs(*(output+i) - *(output+i+2));
|
|
tmp3 = abs(*(output+i+1) - *(output+i+2));
|
|
if ((tmp1<16) && (tmp2<16) && (tmp3<16) && (*(output+i)>=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 */
|