genesys: Deduplicate gain calibration

pixma-axis-driver
Povilas Kanapickas 2020-03-14 23:19:28 +02:00
rodzic 233cb4bd5a
commit cd43109966
7 zmienionych plików z 263 dodań i 614 usunięć

Wyświetl plik

@ -1590,6 +1590,259 @@ void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& senso
dev.frontend.get_offset(2));
}
/* With offset and coarse calibration we only want to get our input range into
a reasonable shape. the fine calibration of the upper and lower bounds will
be done with shading.
*/
void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, unsigned dpi)
{
DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
if (dev.model->asic_type == AsicType::GL843 &&
dev.frontend.layout.type != FrontendType::WOLFSON)
{
return;
}
if (dev.model->asic_type == AsicType::GL845 ||
dev.model->asic_type == AsicType::GL846)
{
// no gain nor offset for AKM AFE
std::uint8_t reg04 = dev.interface->read_register(gl846::REG_0x04);
if ((reg04 & gl846::REG_0x04_FESET) == 0x02) {
return;
}
}
if (dev.model->asic_type == AsicType::GL847) {
// no gain nor offset for AKM AFE
std::uint8_t reg04 = dev.interface->read_register(gl847::REG_0x04);
if ((reg04 & gl847::REG_0x04_FESET) == 0x02) {
return;
}
}
if (dev.model->asic_type == AsicType::GL124) {
// no gain nor offset for TI AFE
std::uint8_t reg0a = dev.interface->read_register(gl124::REG_0x0A);
if (((reg0a & gl124::REG_0x0A_SIFSEL) >> gl124::REG_0x0AS_SIFSEL) == 3) {
return;
}
}
if (dev.model->asic_type == AsicType::GL841) {
// feed to white strip if needed
if (dev.model->y_offset_calib_white > 0) {
unsigned move = static_cast<unsigned>(
(dev.model->y_offset_calib_white * (dev.motor.base_ydpi)) / MM_PER_INCH);
scanner_move(dev, dev.model->default_method, move, Direction::FORWARD);
}
}
unsigned resolution = sensor.optical_res;
if (dev.model->asic_type == AsicType::GL841) {
resolution = sensor.get_register_hwdpi(dev.settings.xres);
}
if (dev.model->asic_type == AsicType::GL843) {
resolution = sensor.get_register_hwdpi(dpi);
}
// coarse gain calibration is always done in color mode
unsigned channels = 3;
float coeff = 1;
// Follow CKSEL
if (dev.model->sensor_id == SensorId::CCD_KVSS080 ||
dev.model->asic_type == AsicType::GL845 ||
dev.model->asic_type == AsicType::GL846 ||
dev.model->asic_type == AsicType::GL847 ||
dev.model->asic_type == AsicType::GL124)
{
if (dev.settings.xres < sensor.optical_res) {
coeff = 0.9f;
}
}
unsigned lines = 10;
if (dev.model->asic_type == AsicType::GL841) {
lines = 1;
}
const Genesys_Sensor* calib_sensor = &sensor;
if (dev.model->asic_type == AsicType::GL841 ||
dev.model->asic_type == AsicType::GL843)
{
calib_sensor = &sanei_genesys_find_sensor(&dev, resolution, channels,
dev.settings.scan_method);
}
ScanFlag flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
if (dev.settings.scan_method == ScanMethod::TRANSPARENCY ||
dev.settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
flags |= ScanFlag::USE_XPA;
}
ScanSession session;
session.params.xres = resolution;
session.params.yres = dev.model->asic_type == AsicType::GL841 ? dev.settings.yres : resolution;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = dev.model->x_size_calib_mm * resolution / MM_PER_INCH;
session.params.lines = lines;
session.params.depth = dev.model->asic_type == AsicType::GL841 ? 16 : 8;
session.params.channels = channels;
session.params.scan_method = dev.settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev.settings.color_filter;
session.params.flags = flags;
compute_session(&dev, session, *calib_sensor);
std::size_t pixels = session.output_pixels;
try {
dev.cmd_set->init_regs_for_scan_session(&dev, *calib_sensor, &regs, session);
} catch (...) {
if (dev.model->asic_type != AsicType::GL841) {
catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
}
throw;
}
if (dev.model->asic_type != AsicType::GL841) {
sanei_genesys_set_motor_power(regs, false);
}
dev.interface->write_registers(regs);
if (dev.model->asic_type != AsicType::GL841) {
dev.cmd_set->set_fe(&dev, *calib_sensor, AFE_SET);
}
dev.cmd_set->begin_scan(&dev, *calib_sensor, &regs, true);
if (is_testing_mode()) {
dev.interface->test_checkpoint("coarse_gain_calibration");
if (dev.model->asic_type == AsicType::GL841) {
gl841::gl841_stop_action(&dev);
} else {
scanner_stop_action(dev);
}
dev.cmd_set->move_back_home(&dev, true);
return;
}
Image image;
if (dev.model->asic_type == AsicType::GL843) {
image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes_raw);
} else if (dev.model->asic_type == AsicType::GL124) {
// BUG: we probably want to read whole image, not just first line
image = read_unshuffled_image_from_scanner(&dev, session, session.output_line_bytes);
} else {
image = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
}
if (dev.model->asic_type == AsicType::GL843) {
scanner_stop_action_no_move(dev, regs);
}
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl_coarse_gain.pnm", image);
}
for (unsigned ch = 0; ch < channels; ch++) {
float curr_output = 0;
float target_value = 0;
if (dev.model->asic_type == AsicType::GL843) {
std::vector<uint16_t> values;
// FIXME: start from the second line because the first line often has artifacts. Probably
// caused by unclean cleanup of previous scan
for (std::size_t x = pixels / 4; x < (pixels * 3 / 4); x++) {
values.push_back(image.get_raw_channel(x, 1, ch));
}
// pick target value at 95th percentile of all values. There may be a lot of black values
// in transparency scans for example
std::sort(values.begin(), values.end());
curr_output = static_cast<float>(values[unsigned((values.size() - 1) * 0.95)]);
target_value = calib_sensor->gain_white_ref * coeff;
} else if (dev.model->asic_type == AsicType::GL841) {
// FIXME: use the GL843 approach
unsigned max = 0;
for (std::size_t x = 0; x < image.get_width(); x++) {
auto value = image.get_raw_channel(x, 0, ch);
if (value > max) {
max = value;
}
}
curr_output = max;
target_value = 65535.0f;
} else {
// FIXME: use the GL843 approach
auto width = image.get_width();
std::uint64_t total = 0;
for (std::size_t x = width / 4; x < (width * 3 / 4); x++) {
total += image.get_raw_channel(x, 0, ch);
}
curr_output = total / (width / 2);
target_value = calib_sensor->gain_white_ref * coeff;
}
std::uint8_t out_gain = compute_frontend_gain(curr_output, target_value,
dev.frontend.layout.type);
dev.frontend.set_gain(ch, out_gain);
DBG(DBG_proc, "%s: channel %d, curr=%f, target=%f, out_gain:%d\n", __func__, ch,
curr_output, target_value, out_gain);
if (dev.model->asic_type == AsicType::GL841 &&
target_value / curr_output > 30)
{
DBG(DBG_error0, "****************************************\n");
DBG(DBG_error0, "* *\n");
DBG(DBG_error0, "* Extremely low Brightness detected. *\n");
DBG(DBG_error0, "* Check the scanning head is *\n");
DBG(DBG_error0, "* unlocked and moving. *\n");
DBG(DBG_error0, "* *\n");
DBG(DBG_error0, "****************************************\n");
throw SaneException(SANE_STATUS_JAMMED, "scanning head is locked");
}
}
if (dev.model->is_cis) {
std::uint8_t min_gain = std::min({dev.frontend.get_gain(0),
dev.frontend.get_gain(1),
dev.frontend.get_gain(2)});
dev.frontend.set_gain(0, min_gain);
dev.frontend.set_gain(1, min_gain);
dev.frontend.set_gain(2, min_gain);
}
DBG(DBG_info, "%s: gain=(%d,%d,%d)\n", __func__,
dev.frontend.get_gain(0),
dev.frontend.get_gain(1),
dev.frontend.get_gain(2));
if (dev.model->asic_type == AsicType::GL841) {
gl841::gl841_stop_action(&dev);
} else {
scanner_stop_action(dev);
}
dev.cmd_set->move_back_home(&dev, true);
}
void sanei_genesys_calculate_zmod(bool two_table,
uint32_t exposure_time,

Wyświetl plik

@ -1466,131 +1466,10 @@ void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sens
scanner_offset_calibration(*dev, sensor, regs);
}
/* alternative coarse gain calibration
this on uses the settings from offset_calibration and
uses only one scanline
*/
/*
with offset and coarse calibration we only want to get our input range into
a reasonable shape. the fine calibration of the upper and lower bounds will
be done with shading.
*/
void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
float gain[3],coeff;
int code, lines;
// no gain nor offset for TI AFE
uint8_t reg0a = dev->interface->read_register(REG_0x0A);
if (((reg0a & REG_0x0A_SIFSEL) >> REG_0x0AS_SIFSEL) == 3) {
return;
}
/* coarse gain calibration is always done in color mode */
unsigned channels = 3;
if(dev->settings.xres<sensor.optical_res)
{
coeff = 0.9f;
} else {
coeff = 1.0f;
}
lines=10;
ScanSession session;
session.params.xres = sensor.optical_res;
session.params.yres = sensor.optical_res;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
try {
init_regs_for_scan_session(dev, sensor, &regs, session);
} catch (...) {
catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
throw;
}
sanei_genesys_set_motor_power(regs, false);
dev->interface->write_registers(regs);
std::vector<uint8_t> line(session.output_line_bytes);
set_fe(dev, sensor, AFE_SET);
begin_scan(dev, sensor, &regs, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("coarse_gain_calibration");
scanner_stop_action(*dev);
move_back_home(dev, true);
return;
}
// BUG: we probably want to read whole image, not just first line
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl124_gain.pnm", image);
}
/* average value on each channel */
for (unsigned ch = 0; ch < channels; ch++) {
auto width = image.get_width();
std::uint64_t total = 0;
for (std::size_t x = width / 4; x < (width * 3 / 4); x++) {
total += image.get_raw_channel(x, 0, ch);
}
float target_value = sensor.gain_white_ref * coeff;
float curr_output = total / (width / 2);
std::uint8_t out_gain = compute_frontend_gain(curr_output, target_value,
dev->frontend.layout.type);
dev->frontend.set_gain(ch, out_gain);
DBG(DBG_proc, "%s: channel %d, curr=%f, target=%f, out_gain:%d\n", __func__, ch,
curr_output, target_value, out_gain);
}
if (dev->model->is_cis) {
uint8_t gain0 = dev->frontend.get_gain(0);
if (gain0 > dev->frontend.get_gain(1)) {
gain0 = dev->frontend.get_gain(1);
}
if (gain0 > dev->frontend.get_gain(2)) {
gain0 = dev->frontend.get_gain(2);
}
dev->frontend.set_gain(0, gain0);
dev->frontend.set_gain(1, gain0);
dev->frontend.set_gain(2, gain0);
}
if (channels == 1) {
dev->frontend.set_gain(0, dev->frontend.get_gain(1));
dev->frontend.set_gain(2, dev->frontend.get_gain(1));
}
scanner_stop_action(*dev);
move_back_home(dev, true);
scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
// wait for lamp warmup by scanning the same line until difference

Wyświetl plik

@ -1821,6 +1821,8 @@ void CommandSetGl841::set_powersaving(Genesys_Device* dev, int delay /* in minut
void gl841_stop_action(Genesys_Device* dev)
{
// FIXME: figure out a way to merge this to scanner_stop_action()
DBG_HELPER(dbg);
Genesys_Register_Set local_reg;
unsigned int loop;
@ -2949,127 +2951,7 @@ void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sens
void CommandSetGl841::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
DBG_HELPER_ARGS(dbg, "dpi=%d", dpi);
int lines=1;
// feed to white strip if needed
if (dev->model->y_offset_calib_white > 0) {
unsigned move = static_cast<unsigned>(
(dev->model->y_offset_calib_white * (dev->motor.base_ydpi)) / MM_PER_INCH);
scanner_move(*dev, dev->model->default_method, move, Direction::FORWARD);
}
/* coarse gain calibration is allways done in color mode */
unsigned channels = 3;
unsigned resolution = sensor.get_register_hwdpi(dev->settings.xres);
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
unsigned num_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
ScanSession session;
session.params.xres = resolution;
session.params.yres = dev->settings.yres;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = num_pixels;
session.params.lines = lines;
session.params.depth = 16;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, calib_sensor);
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
dev->interface->write_registers(regs);
std::vector<uint8_t> line(session.output_total_bytes);
dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("coarse_gain_calibration");
gl841_stop_action(dev);
move_back_home(dev, true);
return;
}
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data)
sanei_genesys_write_pnm_file("gl841_gain.pnm", line.data(), 16, channels, num_pixels, lines);
/* average high level for each channel and compute gain
to reach the target code
we only use the central half of the CCD data */
for (unsigned ch = 0; ch < channels; ch++) {
unsigned max = 0;
for (std::size_t x = 0; x < image.get_width(); x++) {
auto value = image.get_raw_channel(x, 0, ch);
if (value > max) {
max = value;
}
}
float curr_output = max;
float target_value = 65535.0f;
std::uint8_t out_gain = compute_frontend_gain(curr_output, target_value,
dev->frontend.layout.type);
dev->frontend.set_gain(ch, out_gain);
DBG(DBG_proc, "%s: channel %d, curr=%f, target=%f, out_gain:%d\n", __func__, ch,
curr_output, target_value, out_gain);
if (target_value / curr_output > 30) {
DBG(DBG_error0, "****************************************\n");
DBG(DBG_error0, "* *\n");
DBG(DBG_error0, "* Extremely low Brightness detected. *\n");
DBG(DBG_error0, "* Check the scanning head is *\n");
DBG(DBG_error0, "* unlocked and moving. *\n");
DBG(DBG_error0, "* *\n");
DBG(DBG_error0, "****************************************\n");
throw SaneException(SANE_STATUS_JAMMED, "scanning head is locked");
}
}
if (dev->model->is_cis) {
uint8_t gain0 = dev->frontend.get_gain(0);
if (gain0 > dev->frontend.get_gain(1)) {
gain0 = dev->frontend.get_gain(1);
}
if (gain0 > dev->frontend.get_gain(2)) {
gain0 = dev->frontend.get_gain(2);
}
dev->frontend.set_gain(0, gain0);
dev->frontend.set_gain(1, gain0);
dev->frontend.set_gain(2, gain0);
}
if (channels == 1) {
dev->frontend.set_gain(0, dev->frontend.get_gain(1));
dev->frontend.set_gain(2, dev->frontend.get_gain(1));
}
DBG(DBG_info, "%s: gain=(%d,%d,%d)\n", __func__,
dev->frontend.get_gain(0),
dev->frontend.get_gain(1),
dev->frontend.get_gain(2));
gl841_stop_action(dev);
dev->cmd_set->move_back_home(dev, true);
scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
// wait for lamp warmup by scanning the same line until difference

Wyświetl plik

@ -1746,165 +1746,16 @@ SensorExposure CommandSetGl843::led_calibration(Genesys_Device* dev, const Genes
return calib_sensor.exposure;
}
/** @brief calibrate AFE offset
* Iterate doing scans at target dpi until AFE offset if correct. One
* color line is scanned at a time. Scanning head doesn't move.
* @param dev device to calibrate
*/
void CommandSetGl843::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs) const
{
scanner_offset_calibration(*dev, sensor, regs);
}
/* alternative coarse gain calibration
this on uses the settings from offset_calibration and
uses only one scanline
*/
/*
with offset and coarse calibration we only want to get our input range into
a reasonable shape. the fine calibration of the upper and lower bounds will
be done with shading.
*/
void CommandSetGl843::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
int dpihw;
float coeff;
int lines;
int resolution;
if (dev->frontend.layout.type != FrontendType::WOLFSON)
return;
dpihw = sensor.get_register_hwdpi(dpi);
// coarse gain calibration is always done in color mode
unsigned channels = 3;
/* follow CKSEL */
if (dev->model->sensor_id == SensorId::CCD_KVSS080) {
if(dev->settings.xres<sensor.optical_res)
{
coeff = 0.9f;
}
else
{
coeff=1.0;
}
}
else
{
coeff=1.0;
}
resolution=dpihw;
lines=10;
ScanFlag flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
if (dev->settings.scan_method == ScanMethod::TRANSPARENCY ||
dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
{
flags |= ScanFlag::USE_XPA;
}
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
dev->settings.scan_method);
ScanSession session;
session.params.xres = resolution;
session.params.yres = resolution;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = flags;
compute_session(dev, session, calib_sensor);
std::size_t pixels = session.output_pixels;
try {
init_regs_for_scan_session(dev, calib_sensor, &regs, session);
} catch (...) {
catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
throw;
}
sanei_genesys_set_motor_power(regs, false);
dev->interface->write_registers(regs);
dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
dev->cmd_set->begin_scan(dev, calib_sensor, &regs, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("coarse_gain_calibration");
scanner_stop_action(*dev);
move_back_home(dev, true);
return;
}
auto line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw);
scanner_stop_action_no_move(*dev, regs);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl843_gain.pnm", line);
}
// average value on each channel
for (unsigned ch = 0; ch < channels; ch++) {
std::vector<uint16_t> values;
// FIXME: start from the second line because the first line often has artifacts. Probably
// caused by unclean cleanup of previous scan
for (std::size_t x = pixels / 4; x < (pixels * 3 / 4); x++) {
values.push_back(line.get_raw_channel(x, 1, ch));
}
// pick target value at 95th percentile of all values. There may be a lot of black values
// in transparency scans for example
std::sort(values.begin(), values.end());
uint16_t curr_output = values[unsigned((values.size() - 1) * 0.95)];
float target_value = calib_sensor.gain_white_ref * coeff;
int code = compute_frontend_gain(curr_output, target_value, dev->frontend.layout.type);
dev->frontend.set_gain(ch, code);
DBG(DBG_proc, "%s: channel %d, max=%d, target=%d, setting:%d\n", __func__, ch, curr_output,
static_cast<int>(target_value), code);
}
if (dev->model->is_cis) {
uint8_t gain0 = dev->frontend.get_gain(0);
if (gain0 > dev->frontend.get_gain(1)) {
gain0 = dev->frontend.get_gain(1);
}
if (gain0 > dev->frontend.get_gain(2)) {
gain0 = dev->frontend.get_gain(2);
}
dev->frontend.set_gain(0, gain0);
dev->frontend.set_gain(1, gain0);
dev->frontend.set_gain(2, gain0);
}
if (channels == 1) {
dev->frontend.set_gain(0, dev->frontend.get_gain(1));
dev->frontend.set_gain(2, dev->frontend.get_gain(1));
}
scanner_stop_action(*dev);
move_back_home(dev, true);
scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
// wait for lamp warmup by scanning the same line until difference

Wyświetl plik

@ -1331,115 +1331,7 @@ void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sens
void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
DBG_HELPER(dbg);
float coeff;
int lines;
DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi);
// no gain nor offset for AKM AFE
uint8_t reg04 = dev->interface->read_register(REG_0x04);
if ((reg04 & REG_0x04_FESET) == 0x02) {
return;
}
/* coarse gain calibration is always done in color mode */
unsigned channels = 3;
/* follow CKSEL */
if(dev->settings.xres<sensor.optical_res)
{
coeff = 0.9f;
}
else
{
coeff=1.0;
}
lines=10;
ScanSession session;
session.params.xres = sensor.optical_res;
session.params.yres = sensor.optical_res;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
try {
init_regs_for_scan_session(dev, sensor, &regs, session);
} catch (...) {
catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
throw;
}
sanei_genesys_set_motor_power(regs, false);
dev->interface->write_registers(regs);
set_fe(dev, sensor, AFE_SET);
begin_scan(dev, sensor, &regs, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("coarse_gain_calibration");
scanner_stop_action(*dev);
move_back_home(dev, true);
return;
}
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl846_gain.pnm", image);
}
/* average value on each channel */
for (unsigned ch = 0; ch < channels; ch++) {
auto width = image.get_width();
std::uint64_t total = 0;
for (std::size_t x = width / 4; x < (width * 3 / 4); x++) {
total += image.get_raw_channel(x, 0, ch);
}
float target_value = sensor.gain_white_ref * coeff;
float curr_output = total / (width / 2);
std::uint8_t out_gain = compute_frontend_gain(curr_output, target_value,
dev->frontend.layout.type);
dev->frontend.set_gain(ch, out_gain);
DBG(DBG_proc, "%s: channel %d, curr=%f, target=%f, out_gain:%d\n", __func__, ch,
curr_output, target_value, out_gain);
}
if (dev->model->is_cis) {
uint8_t gain0 = dev->frontend.get_gain(0);
if (gain0 > dev->frontend.get_gain(1)) {
gain0 = dev->frontend.get_gain(1);
}
if (gain0 > dev->frontend.get_gain(2)) {
gain0 = dev->frontend.get_gain(2);
}
dev->frontend.set_gain(0, gain0);
dev->frontend.set_gain(1, gain0);
dev->frontend.set_gain(2, gain0);
}
scanner_stop_action(*dev);
move_back_home(dev, true);
scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
bool CommandSetGl846::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const

Wyświetl plik

@ -1372,118 +1372,7 @@ void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sens
void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, int dpi) const
{
DBG_HELPER_ARGS(dbg, "dpi = %d", dpi);
float coeff;
int lines;
// no gain nor offset for AKM AFE
uint8_t reg04 = dev->interface->read_register(REG_0x04);
if ((reg04 & REG_0x04_FESET) == 0x02) {
return;
}
/* coarse gain calibration is always done in color mode */
unsigned channels = 3;
/* follow CKSEL */
if(dev->settings.xres<sensor.optical_res)
{
coeff = 0.9f;
}
else
{
coeff=1.0;
}
lines=10;
ScanSession session;
session.params.xres = sensor.optical_res;
session.params.yres = sensor.optical_res;
session.params.startx = 0;
session.params.starty = 0;
session.params.pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
session.params.lines = lines;
session.params.depth = 8;
session.params.channels = channels;
session.params.scan_method = dev->settings.scan_method;
session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS;
session.params.color_filter = dev->settings.color_filter;
session.params.flags = ScanFlag::DISABLE_SHADING |
ScanFlag::DISABLE_GAMMA |
ScanFlag::SINGLE_LINE |
ScanFlag::IGNORE_STAGGER_OFFSET |
ScanFlag::IGNORE_COLOR_OFFSET;
compute_session(dev, session, sensor);
try {
init_regs_for_scan_session(dev, sensor, &regs, session);
} catch (...) {
catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); });
throw;
}
sanei_genesys_set_motor_power(regs, false);
dev->interface->write_registers(regs);
set_fe(dev, sensor, AFE_SET);
begin_scan(dev, sensor, &regs, true);
if (is_testing_mode()) {
dev->interface->test_checkpoint("coarse_gain_calibration");
scanner_stop_action(*dev);
move_back_home(dev, true);
return;
}
auto image = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
if (DBG_LEVEL >= DBG_data) {
sanei_genesys_write_pnm_file("gl847_gain.pnm", image);
}
/* average value on each channel */
for (unsigned ch = 0; ch < channels; ch++) {
auto width = image.get_width();
std::uint64_t total = 0;
for (std::size_t x = width / 4; x < (width * 3 / 4); x++) {
total += image.get_raw_channel(x, 0, ch);
}
float target_value = sensor.gain_white_ref * coeff;
float curr_output = total / (width / 2);
std::uint8_t out_gain = compute_frontend_gain(curr_output, target_value,
dev->frontend.layout.type);
dev->frontend.set_gain(ch, out_gain);
DBG(DBG_proc, "%s: channel %d, curr=%f, target=%f, out_gain:%d\n", __func__, ch,
curr_output, target_value, out_gain);
}
if (dev->model->is_cis) {
uint8_t gain0 = dev->frontend.get_gain(0);
if (gain0 > dev->frontend.get_gain(1)) {
gain0 = dev->frontend.get_gain(1);
}
if (gain0 > dev->frontend.get_gain(2)) {
gain0 = dev->frontend.get_gain(2);
}
dev->frontend.set_gain(0, gain0);
dev->frontend.set_gain(1, gain0);
dev->frontend.set_gain(2, gain0);
}
if (channels == 1) {
dev->frontend.set_gain(0, dev->frontend.get_gain(1));
dev->frontend.set_gain(2, dev->frontend.get_gain(1));
}
scanner_stop_action(*dev);
move_back_home(dev, true);
scanner_coarse_gain_calibration(*dev, sensor, regs, dpi);
}
bool CommandSetGl847::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const

Wyświetl plik

@ -311,6 +311,9 @@ float get_model_x_offset_ta(const Genesys_Device& dev, const Genesys_Settings& s
void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs);
void scanner_coarse_gain_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
Genesys_Register_Set& regs, unsigned dpi);
void scanner_clear_scan_and_feed_counts(Genesys_Device& dev);
extern void sanei_genesys_write_file(const char* filename, const std::uint8_t* data,