calibration and gamma correction enhancements by M.Reinelt <reinelt@eunet.at>

RELEASE_1_0_11_BRANCH
Nathaniel Rutman 2003-01-13 03:01:04 +00:00
rodzic 79871a2b79
commit b1d4dce599
2 zmienionych plików z 77 dodań i 17 usunięć

Wyświetl plik

@ -57,6 +57,7 @@
#include <string.h>
#include <unistd.h> /* usleep */
#include <time.h>
#include <math.h> /* exp() */
#ifdef HAVE_OS2_H
#include <sys/types.h> /* mode_t */
#endif
@ -454,6 +455,7 @@ typedef struct CANON_Handle
FILE *fp; /* output file pointer (for reading) */
char *buf, *ptr; /* data buffer */
unsigned char gain; /* static analog gain, 0 - 31 */
double gamma; /* gamma correction */
int flags;
#define FLG_GRAY 0x01 /* grayscale */
#define FLG_FORCE_CAL 0x02 /* force calibration */
@ -975,14 +977,14 @@ plugin_cal (CANON_Handle * s)
static SANE_Status
compute_ogn (char *calfilename)
{
byte *linebuf, *oldline, *newline;
mode_t oldmask;
FILE *fp;
int width, height, nlines = 0, region = -1, i, transition = 1, badcnt;
int pct;
int reglines[NREGIONS];
byte *linebuf, *oldline, *newline;
float *avg;
float pct;
float max_range[3], tmp1, tmp2;
mode_t oldmask;
fp = fopen (calfilename, "r");
if (!fp)
@ -1014,11 +1016,13 @@ compute_ogn (char *calfilename)
badcnt = 0;
for (i = 0; i < width; i++)
{
/* percentage change */
pct = newline[i] - oldline[i];
pct = ((pct < 0) ? -pct : pct) / newline[i];
/* count pixels that have changed by 10% */
if (pct > 0.10)
/* Fix by M.Reinelt <reinelt@eunet.at>
* do NOT use 10% (think of a dark area with
* oldline=4 and newline=5, which is a change of 20% !!
* Use an absolute difference of 10 as criteria
*/
if (pct < -10 || pct > 10)
{
badcnt++;
DBG (16, "pix%d[%d/%d] ", i, newline[i], oldline[i]);
@ -1122,11 +1126,18 @@ compute_ogn (char *calfilename)
/* Gain multiplier:
255 : 1.5 times brighter
511 : 2 times brighter
1023: 3 times brighter
So - why did I choose 512 here? I forgot. */
gain = 512 * ((max_range[i / (width / 3)] /
(avg[i + width] - avg[i])) - 1);
offset = avg[i];
1023: 3 times brighter */
/* Enhanced offset and gain calculation by M.Reinelt <reinelt@eunet.at>
* These expressions were found by an iterative calibration process,
* by changing gain and offset values for every pixel until the desired
* values for black and white were reached, and finding an approximation
* formula.
* Note that offset is linear, but gain isn't!
*/
offset=(double)3.53*avg[i]-125;
gain=(double)3861.0*exp(-0.0168*(avg[i+width]-avg[i]));
DBG (14, "%d wht=%f blk=%f diff=%f gain=%d\n", i,
avg[i + width], avg[i], avg[i + width] - avg[i], gain);
/* 10-bit gain, 6-bit offset (subtractor) in two bytes */
@ -1251,10 +1262,12 @@ scan (CANON_Handle * opt)
write_byte (fd, COMMAND, 0x01);
read_byte (fd, STATUS, &result); /* wants 0c */
/* use linear gamma for now */
/* create gamma table */
buf = malloc (0x400);
for (temp = 0; temp < 0x0400; temp++)
buf[temp] = temp / 4;
/* gamma calculation by M.Reinelt <reinelt@eunet.at> */
buf[temp] = (double) 255.0 * exp(log((temp+0.5)/1023.0)/opt->gamma) + 0.5;
/* Gamma R, write and verify */
write_byte (fd, DATAPORT_TARGET, DP_R | DP_GAMMA);
write_word (fd, DATAPORT_ADDR, DP_WRITE);
@ -1406,12 +1419,13 @@ CANON_set_scan_parameters (CANON_Handle * scan,
const int left,
const int top,
const int right,
const int bottom, const int res, const int gain)
const int bottom, const int res, const int gain, const double gamma)
{
DBG (2, "CANON_set_scan_parameters:\n");
DBG (2, "gray = %d (ignored)\n", gray);
DBG (2, "res = %d\n", res);
DBG (2, "gain = %d\n", gain);
DBG (2, "gamma = %f\n", gamma);
DBG (2, "in 600dpi pixels:\n");
DBG (2, "left = %d, top = %d\n", left, top);
DBG (2, "right = %d, bottom = %d\n", right, bottom);
@ -1433,12 +1447,16 @@ CANON_set_scan_parameters (CANON_Handle * scan,
if ((gain < 0) || (gain > 64))
return SANE_STATUS_INVAL;
if (gamma <= 0.0)
return SANE_STATUS_INVAL;
scan->resolution = res;
scan->x1 = left;
scan->x2 = right - /* subtract 1 pixel */ 600 / scan->resolution;
scan->y1 = top;
scan->y2 = bottom;
scan->gain = gain;
scan->gamma = gamma;
scan->flags = 0;
return SANE_STATUS_GOOD;

Wyświetl plik

@ -252,7 +252,7 @@ static SANE_Int optionAGainValue = 1;
static SANE_Option_Descriptor optionAGainDescriptor = {
SANE_I18N ("gain"),
SANE_I18N ("Analog gain"),
SANE_I18N ("Analog Gain"),
SANE_I18N ("Increase or decrease the analog gain of the CCD array"),
SANE_TYPE_INT,
SANE_UNIT_NONE,
@ -287,6 +287,46 @@ optionAGainCallback (SANE_Option * option, SANE_Handle handle,
}
static SANE_Fixed optionGammaValue = SANE_FIX (1.6);
static SANE_Option_Descriptor optionGammaDescriptor = {
SANE_I18N ("gamma"),
SANE_I18N ("Gamma Correction"),
SANE_I18N ("Selects the gamma corrected transfer curve"),
SANE_TYPE_FIXED,
SANE_UNIT_NONE,
sizeof (SANE_Int),
SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED,
SANE_CONSTRAINT_NONE,
{NULL}
};
static SANE_Status
optionGammaCallback (SANE_Option * option, SANE_Handle handle,
SANE_Action action, void *value, SANE_Int * info)
{
option = option;
handle = handle;
info = info; /* Eliminate warning about unused parameters */
switch (action)
{
case SANE_ACTION_SET_AUTO:
return SANE_STATUS_INVAL;
break;
case SANE_ACTION_SET_VALUE:
optionGammaValue = *(SANE_Fixed *) value;
*info |= SANE_INFO_RELOAD_PARAMS;
break;
case SANE_ACTION_GET_VALUE:
*(SANE_Fixed *) value = optionGammaValue;
break;
}
return SANE_STATUS_GOOD;
}
/*
Scan range
*/
@ -490,6 +530,7 @@ static SANE_Option so[] = {
{&optionGrayscaleDescriptor, optionGrayscaleCallback},
#endif
{&optionAGainDescriptor, optionAGainCallback},
{&optionGammaDescriptor, optionGammaCallback},
{&optionTopLeftXDescriptor, optionTopLeftXCallback},
{&optionTopLeftYDescriptor, optionTopLeftYCallback},
{&optionBotRightXDescriptor, optionBotRightXCallback},
@ -899,7 +940,8 @@ sane_start (SANE_Handle handle)
MM_IN_INCH * 600,
SANE_UNFIX (optionBotRightYValue) /
MM_IN_INCH * 600,
optionResolutionValue, optionAGainValue);
optionResolutionValue, optionAGainValue,
SANE_UNFIX (optionGammaValue));
if (res != SANE_STATUS_GOOD)
return res;