kopia lustrzana https://gitlab.com/sane-project/backends
gl847 shading calibration refactor
rodzic
55d5ef6fd9
commit
adc2060579
|
@ -2958,6 +2958,165 @@ compute_coefficient (unsigned int coeff, unsigned int target, unsigned int value
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief compute shading coefficients for LiDE scanners
|
||||||
|
*
|
||||||
|
The dark/white shading is actually performed _after_ reducing
|
||||||
|
resolution via averaging. only dark/white shading data for what would be
|
||||||
|
first pixel at full resolution is used.
|
||||||
|
|
||||||
|
scanner raw input to output value calculation:
|
||||||
|
o=(i-off)*(gain/coeff)
|
||||||
|
|
||||||
|
from datasheet:
|
||||||
|
off=dark_average
|
||||||
|
gain=coeff*bright_target/(bright_average-dark_average)
|
||||||
|
works for dark_target==0
|
||||||
|
|
||||||
|
what we want is these:
|
||||||
|
bright_target=(bright_average-off)*(gain/coeff)
|
||||||
|
dark_target=(dark_average-off)*(gain/coeff)
|
||||||
|
leading to
|
||||||
|
off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target)
|
||||||
|
gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff
|
||||||
|
*
|
||||||
|
* @param dev scanner's device
|
||||||
|
* @param shading_data memory area where to store the computed shading coefficients
|
||||||
|
* @param pixels_per_line number of pixels per line
|
||||||
|
* @param words_per_color memory words per color channel
|
||||||
|
* @param channels number of color channels (actually 1 or 3)
|
||||||
|
* @param o shading coefficients left offset
|
||||||
|
* @param coeff 4000h or 2000h depending on fast scan mode or not (GAIN4 bit)
|
||||||
|
* @param target_bright value of the white target code
|
||||||
|
* @param target_dark value of the black target code
|
||||||
|
*/
|
||||||
|
#ifndef UNIT_TESTING
|
||||||
|
static
|
||||||
|
#endif
|
||||||
|
void
|
||||||
|
compute_averaged_planar (Genesys_Device * dev,
|
||||||
|
uint8_t * shading_data,
|
||||||
|
unsigned int pixels_per_line,
|
||||||
|
unsigned int words_per_color,
|
||||||
|
unsigned int channels,
|
||||||
|
unsigned int o,
|
||||||
|
unsigned int coeff,
|
||||||
|
unsigned int target_bright,
|
||||||
|
unsigned int target_dark)
|
||||||
|
{
|
||||||
|
unsigned int x, i, j, br, dk, res, avgpixels, val;
|
||||||
|
|
||||||
|
/* initialize result */
|
||||||
|
/* memset (shading_data, 0xff, words_per_color * 3 * 2); */
|
||||||
|
|
||||||
|
/* duplicate half-ccd logic */
|
||||||
|
res = dev->settings.xres;
|
||||||
|
if ((dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)
|
||||||
|
&& dev->settings.xres <= dev->sensor.optical_res / 2)
|
||||||
|
{
|
||||||
|
/* scanner is using half-ccd mode */
|
||||||
|
res *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*this should be evenly dividable */
|
||||||
|
avgpixels = dev->sensor.optical_res / res;
|
||||||
|
|
||||||
|
/* gl841 and gl847 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */
|
||||||
|
if (avgpixels < 1)
|
||||||
|
avgpixels = 1;
|
||||||
|
else if (avgpixels < 6)
|
||||||
|
avgpixels = avgpixels;
|
||||||
|
else if (avgpixels < 8)
|
||||||
|
avgpixels = 6;
|
||||||
|
else if (avgpixels < 10)
|
||||||
|
avgpixels = 8;
|
||||||
|
else if (avgpixels < 12)
|
||||||
|
avgpixels = 10;
|
||||||
|
else if (avgpixels < 15)
|
||||||
|
avgpixels = 12;
|
||||||
|
else
|
||||||
|
avgpixels = 15;
|
||||||
|
|
||||||
|
DBG (DBG_info, "compute_planar_averaged: averaging over %d pixels\n",
|
||||||
|
avgpixels);
|
||||||
|
|
||||||
|
for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ((x + o) * 2 * 2 + 3 > words_per_color * 2)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (j = 0; j < channels; j++)
|
||||||
|
{
|
||||||
|
|
||||||
|
dk = 0;
|
||||||
|
br = 0;
|
||||||
|
for (i = 0; i < avgpixels; i++)
|
||||||
|
{
|
||||||
|
/* dark data */
|
||||||
|
dk += (dev->dark_average_data[(x + i + pixels_per_line * j) * 2]
|
||||||
|
| (dev-> dark_average_data[(x + i + pixels_per_line * j) * 2 + 1] << 8));
|
||||||
|
|
||||||
|
/* white data */
|
||||||
|
br += (dev->white_average_data[(x + i + pixels_per_line * j) * 2]
|
||||||
|
| (dev-> white_average_data[(x + i + pixels_per_line * j) * 2 + 1] << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
br /= avgpixels;
|
||||||
|
dk /= avgpixels;
|
||||||
|
|
||||||
|
if (br * target_dark > dk * target_bright)
|
||||||
|
val = 0;
|
||||||
|
else if (dk * target_bright - br * target_dark > 65535
|
||||||
|
* (target_bright - target_dark))
|
||||||
|
val = 65535;
|
||||||
|
else
|
||||||
|
val = (dk * target_bright - br * target_dark) / (target_bright
|
||||||
|
- target_dark);
|
||||||
|
|
||||||
|
/*fill all pixels, even if only the last one is relevant */
|
||||||
|
for (i = 0; i < avgpixels; i++)
|
||||||
|
{
|
||||||
|
shading_data[(x + o + i) * 2 * 2 + words_per_color * 2 * j] = val & 0xff;
|
||||||
|
shading_data[(x + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = val >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = br - dk;
|
||||||
|
|
||||||
|
if (65535 * val > (target_bright - target_dark) * coeff)
|
||||||
|
val = (coeff * (target_bright - target_dark)) / val;
|
||||||
|
else
|
||||||
|
val = 65535;
|
||||||
|
|
||||||
|
/*fill all pixels, even if only the last one is relevant */
|
||||||
|
for (i = 0; i < avgpixels; i++)
|
||||||
|
{
|
||||||
|
shading_data[(x + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = val & 0xff;
|
||||||
|
shading_data[(x + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = val >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*fill remaining channels */
|
||||||
|
for (j = channels; j < 3; j++)
|
||||||
|
{
|
||||||
|
for (i = 0; i < avgpixels; i++)
|
||||||
|
{
|
||||||
|
shading_data[(x + o + i) * 2 * 2 + words_per_color * 2 * j]
|
||||||
|
= shading_data[(x + o + i) * 2 * 2 + words_per_color * 0];
|
||||||
|
shading_data[(x + o + i) * 2 * 2 + words_per_color * 2 * j + 1]
|
||||||
|
= shading_data[(x + o + i) * 2 * 2 + words_per_color
|
||||||
|
* 2 * 0 + 1];
|
||||||
|
shading_data[(x + o + i) * 2 * 2 + words_per_color * 2 * j + 2]
|
||||||
|
= shading_data[(x + o + i) * 2 * 2 + words_per_color
|
||||||
|
* 2 * 0 + 2];
|
||||||
|
shading_data[(x + o + i) * 2 * 2 + words_per_color * 2 * j + 3]
|
||||||
|
= shading_data[(x + o + i) * 2 * 2 + words_per_color
|
||||||
|
* 2 * 0 + 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes shading coefficient using formula in data sheet. 16bit data values
|
* Computes shading coefficient using formula in data sheet. 16bit data values
|
||||||
* manipulated here are little endian. For now we assume deletion scanning type
|
* manipulated here are little endian. For now we assume deletion scanning type
|
||||||
|
@ -3305,9 +3464,19 @@ genesys_send_shading_coefficient (Genesys_Device * dev)
|
||||||
coeff,
|
coeff,
|
||||||
target_code);
|
target_code);
|
||||||
break;
|
break;
|
||||||
case CCD_CANONLIDE35:
|
|
||||||
case CIS_CANONLIDE100:
|
case CIS_CANONLIDE100:
|
||||||
case CIS_CANONLIDE200:
|
case CIS_CANONLIDE200:
|
||||||
|
compute_averaged_planar(dev,
|
||||||
|
shading_data,
|
||||||
|
pixels_per_line,
|
||||||
|
words_per_color,
|
||||||
|
channels,
|
||||||
|
4,
|
||||||
|
coeff,
|
||||||
|
0xfa00,
|
||||||
|
0x0a00);
|
||||||
|
break;
|
||||||
|
case CCD_CANONLIDE35:
|
||||||
target_bright = 0xfa00;
|
target_bright = 0xfa00;
|
||||||
target_dark = 0xa00;
|
target_dark = 0xa00;
|
||||||
o = 4; /*first four pixels are ignored */
|
o = 4; /*first four pixels are ignored */
|
||||||
|
@ -5531,7 +5700,7 @@ init_gamma_vector_option (Genesys_Scanner * scanner, int option)
|
||||||
* @param size maximum size of the range
|
* @param size maximum size of the range
|
||||||
* @return a poiter to a valid range or NULL
|
* @return a poiter to a valid range or NULL
|
||||||
*/
|
*/
|
||||||
static create_range(SANE_Fixed size)
|
static SANE_Range *create_range(SANE_Fixed size)
|
||||||
{
|
{
|
||||||
SANE_Range *range=NULL;
|
SANE_Range *range=NULL;
|
||||||
|
|
||||||
|
|
|
@ -971,7 +971,7 @@ static Genesys_Model canon_lide_100_model = {
|
||||||
| GENESYS_FLAG_DARK_CALIBRATION
|
| GENESYS_FLAG_DARK_CALIBRATION
|
||||||
| GENESYS_FLAG_CUSTOM_GAMMA,
|
| GENESYS_FLAG_CUSTOM_GAMMA,
|
||||||
GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW,
|
GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW,
|
||||||
50,
|
150,
|
||||||
400
|
400
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue