kopia lustrzana https://gitlab.com/sane-project/backends
genesys: Deduplicate offset calibration
rodzic
255da97fcb
commit
e0bec6723d
|
@ -1272,6 +1272,324 @@ void scanner_search_strip(Genesys_Device& dev, bool forward, bool black)
|
|||
}
|
||||
}
|
||||
|
||||
static int dark_average_channel(const Image& image, unsigned black, unsigned channel)
|
||||
{
|
||||
auto channels = get_pixel_channels(image.get_format());
|
||||
|
||||
unsigned avg[3];
|
||||
|
||||
// computes average values on black margin
|
||||
for (unsigned ch = 0; ch < channels; ch++) {
|
||||
avg[ch] = 0;
|
||||
unsigned count = 0;
|
||||
// FIXME: start with the second line because the black pixels often have noise on the first
|
||||
// line; the cause is probably incorrectly cleaned up previous scan
|
||||
for (std::size_t y = 1; y < image.get_height(); y++) {
|
||||
for (unsigned j = 0; j < black; j++) {
|
||||
avg[ch] += image.get_raw_channel(j, y, ch);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
avg[ch] /= count;
|
||||
}
|
||||
DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, ch, avg[ch]);
|
||||
}
|
||||
DBG(DBG_info, "%s: average = %d\n", __func__, avg[channel]);
|
||||
return avg[channel];
|
||||
}
|
||||
|
||||
bool should_calibrate_only_active_area(const Genesys_Device& dev,
|
||||
const Genesys_Settings& settings)
|
||||
{
|
||||
if (settings.scan_method == ScanMethod::TRANSPARENCY ||
|
||||
settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
|
||||
{
|
||||
if (dev.model->model_id == ModelId::CANON_4400F && settings.xres >= 4800) {
|
||||
return true;
|
||||
}
|
||||
if (dev.model->model_id == ModelId::CANON_8600F && settings.xres == 4800) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
float get_model_x_offset_ta(const Genesys_Device& dev, const Genesys_Settings& settings)
|
||||
{
|
||||
if (dev.model->model_id == ModelId::CANON_8600F && settings.xres == 4800) {
|
||||
return 85.0f;
|
||||
}
|
||||
if (dev.model->model_id == ModelId::CANON_4400F && settings.xres == 4800) {
|
||||
return dev.model->x_offset_ta - 10.0;
|
||||
}
|
||||
return dev.model->x_offset_ta;
|
||||
}
|
||||
|
||||
void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
|
||||
Genesys_Register_Set& regs)
|
||||
{
|
||||
DBG_HELPER(dbg);
|
||||
|
||||
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) {
|
||||
std::uint8_t reg0a = dev.interface->read_register(gl124::REG_0x0A);
|
||||
if (((reg0a & gl124::REG_0x0A_SIFSEL) >> gl124::REG_0x0AS_SIFSEL) == 3) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned target_pixels = dev.model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
|
||||
unsigned start_pixel = 0;
|
||||
unsigned black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
|
||||
|
||||
DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
|
||||
|
||||
unsigned channels = 3;
|
||||
unsigned lines = 1;
|
||||
unsigned resolution = sensor.optical_res;
|
||||
|
||||
const Genesys_Sensor* calib_sensor = &sensor;
|
||||
if (dev.model->asic_type == AsicType::GL843) {
|
||||
lines = 8;
|
||||
|
||||
// compute divider factor to compute final pixels number
|
||||
resolution = sensor.get_register_hwdpi(dev.settings.xres);
|
||||
unsigned factor = sensor.optical_res / resolution;
|
||||
|
||||
calib_sensor = &sanei_genesys_find_sensor(&dev, resolution, channels,
|
||||
dev.settings.scan_method);
|
||||
|
||||
target_pixels = dev.model->x_size_calib_mm * resolution / MM_PER_INCH;
|
||||
black_pixels = calib_sensor->black_pixels / factor;
|
||||
|
||||
if (should_calibrate_only_active_area(dev, dev.settings)) {
|
||||
float offset = get_model_x_offset_ta(dev, dev.settings);
|
||||
offset /= calib_sensor->get_ccd_size_divisor_for_dpi(resolution);
|
||||
start_pixel = static_cast<int>((offset * resolution) / MM_PER_INCH);
|
||||
|
||||
float size = dev.model->x_size_ta;
|
||||
size /= calib_sensor->get_ccd_size_divisor_for_dpi(resolution);
|
||||
target_pixels = static_cast<int>((size * resolution) / MM_PER_INCH);
|
||||
}
|
||||
|
||||
if (dev.model->model_id == ModelId::CANON_4400F &&
|
||||
dev.settings.scan_method == ScanMethod::FLATBED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
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 = resolution;;
|
||||
session.params.startx = start_pixel;
|
||||
session.params.starty = 0;
|
||||
session.params.pixels = target_pixels;
|
||||
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.model->asic_type == AsicType::GL843 ? ColorFilter::RED
|
||||
: dev.settings.color_filter;
|
||||
session.params.flags = flags;
|
||||
compute_session(&dev, session, *calib_sensor);
|
||||
|
||||
dev.cmd_set->init_regs_for_scan_session(&dev, *calib_sensor, ®s, session);
|
||||
|
||||
unsigned output_pixels = session.output_pixels;
|
||||
|
||||
sanei_genesys_set_motor_power(regs, false);
|
||||
|
||||
int top[3], bottom[3];
|
||||
int topavg[3], bottomavg[3], avg[3];
|
||||
|
||||
// init gain and offset
|
||||
for (unsigned ch = 0; ch < 3; ch++)
|
||||
{
|
||||
bottom[ch] = 10;
|
||||
dev.frontend.set_offset(ch, bottom[ch]);
|
||||
dev.frontend.set_gain(ch, 0);
|
||||
}
|
||||
dev.cmd_set->set_fe(&dev, *calib_sensor, AFE_SET);
|
||||
|
||||
// scan with bottom AFE settings
|
||||
dev.interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting first line reading\n", __func__);
|
||||
|
||||
dev.cmd_set->begin_scan(&dev, *calib_sensor, ®s, true);
|
||||
|
||||
if (is_testing_mode()) {
|
||||
dev.interface->test_checkpoint("offset_calibration");
|
||||
if (dev.model->asic_type == AsicType::GL843) {
|
||||
scanner_stop_action_no_move(dev, regs);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Image first_line;
|
||||
if (dev.model->asic_type == AsicType::GL843) {
|
||||
first_line = read_unshuffled_image_from_scanner(&dev, session,
|
||||
session.output_total_bytes_raw);
|
||||
scanner_stop_action_no_move(dev, regs);
|
||||
} else {
|
||||
first_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
|
||||
}
|
||||
|
||||
if (DBG_LEVEL >= DBG_data) {
|
||||
char fn[40];
|
||||
std::snprintf(fn, 40, "gl843_bottom_offset_%03d_%03d_%03d.pnm",
|
||||
bottom[0], bottom[1], bottom[2]);
|
||||
sanei_genesys_write_pnm_file(fn, first_line);
|
||||
}
|
||||
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
bottomavg[ch] = dark_average_channel(first_line, black_pixels, ch);
|
||||
DBG(DBG_io2, "%s: bottom avg %d=%d\n", __func__, ch, bottomavg[ch]);
|
||||
}
|
||||
|
||||
// now top value
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
top[ch] = 255;
|
||||
dev.frontend.set_offset(ch, top[ch]);
|
||||
}
|
||||
dev.cmd_set->set_fe(&dev, *calib_sensor, AFE_SET);
|
||||
|
||||
// scan with top AFE values
|
||||
dev.interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
|
||||
dev.cmd_set->begin_scan(&dev, *calib_sensor, ®s, true);
|
||||
|
||||
Image second_line;
|
||||
if (dev.model->asic_type == AsicType::GL843) {
|
||||
second_line = read_unshuffled_image_from_scanner(&dev, session,
|
||||
session.output_total_bytes_raw);
|
||||
scanner_stop_action_no_move(dev, regs);
|
||||
} else {
|
||||
second_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
|
||||
}
|
||||
|
||||
for (unsigned ch = 0; ch < 3; ch++){
|
||||
topavg[ch] = dark_average_channel(second_line, black_pixels, ch);
|
||||
DBG(DBG_io2, "%s: top avg %d=%d\n", __func__, ch, topavg[ch]);
|
||||
}
|
||||
|
||||
unsigned pass = 0;
|
||||
|
||||
std::vector<std::uint8_t> debug_image;
|
||||
std::size_t debug_image_lines = 0;
|
||||
std::string debug_image_info;
|
||||
|
||||
// loop until acceptable level
|
||||
while ((pass < 32) && ((top[0] - bottom[0] > 1) ||
|
||||
(top[1] - bottom[1] > 1) ||
|
||||
(top[2] - bottom[2] > 1)))
|
||||
{
|
||||
pass++;
|
||||
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
if (top[ch] - bottom[ch] > 1) {
|
||||
dev.frontend.set_offset(ch, (top[ch] + bottom[ch]) / 2);
|
||||
}
|
||||
}
|
||||
dev.cmd_set->set_fe(&dev, *calib_sensor, AFE_SET);
|
||||
|
||||
// scan with no move
|
||||
dev.interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
dev.cmd_set->begin_scan(&dev, *calib_sensor, ®s, true);
|
||||
|
||||
if (dev.model->asic_type == AsicType::GL843) {
|
||||
second_line = read_unshuffled_image_from_scanner(&dev, session,
|
||||
session.output_total_bytes_raw);
|
||||
scanner_stop_action_no_move(dev, regs);
|
||||
} else {
|
||||
second_line = read_unshuffled_image_from_scanner(&dev, session, session.output_total_bytes);
|
||||
}
|
||||
|
||||
if (DBG_LEVEL >= DBG_data) {
|
||||
char title[100];
|
||||
std::snprintf(title, 100, "lines: %d pixels_per_line: %d offsets[0..2]: %d %d %d\n",
|
||||
lines, output_pixels,
|
||||
dev.frontend.get_offset(0),
|
||||
dev.frontend.get_offset(1),
|
||||
dev.frontend.get_offset(2));
|
||||
debug_image_info += title;
|
||||
std::copy(second_line.get_row_ptr(0),
|
||||
second_line.get_row_ptr(0) + second_line.get_row_bytes() * second_line.get_height(),
|
||||
std::back_inserter(debug_image));
|
||||
debug_image_lines += lines;
|
||||
}
|
||||
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
avg[ch] = dark_average_channel(second_line, black_pixels, ch);
|
||||
DBG(DBG_info, "%s: avg[%d]=%d offset=%d\n", __func__, ch, avg[ch],
|
||||
dev.frontend.get_offset(ch));
|
||||
}
|
||||
|
||||
// compute new boundaries
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
if (topavg[ch] >= avg[ch]) {
|
||||
topavg[ch] = avg[ch];
|
||||
top[ch] = dev.frontend.get_offset(ch);
|
||||
} else {
|
||||
bottomavg[ch] = avg[ch];
|
||||
bottom[ch] = dev.frontend.get_offset(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DBG_LEVEL >= DBG_data) {
|
||||
sanei_genesys_write_file("gl_offset_all_desc.txt",
|
||||
reinterpret_cast<const std::uint8_t*>(debug_image_info.data()),
|
||||
debug_image_info.size());
|
||||
sanei_genesys_write_pnm_file("gl_offset_all.pnm",
|
||||
debug_image.data(), session.params.depth, channels, output_pixels,
|
||||
debug_image_lines);
|
||||
}
|
||||
|
||||
DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
|
||||
dev.frontend.get_offset(0),
|
||||
dev.frontend.get_offset(1),
|
||||
dev.frontend.get_offset(2));
|
||||
}
|
||||
|
||||
|
||||
void sanei_genesys_calculate_zmod(bool two_table,
|
||||
uint32_t exposure_time,
|
||||
|
|
|
@ -1460,179 +1460,10 @@ SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genes
|
|||
return { exp[0], exp[1], exp[2] };
|
||||
}
|
||||
|
||||
/**
|
||||
* average dark pixels of a 8 bits scan
|
||||
*/
|
||||
static int
|
||||
dark_average (uint8_t * data, unsigned int pixels, unsigned int lines,
|
||||
unsigned int channels, unsigned int black)
|
||||
{
|
||||
unsigned int i, j, k, average, count;
|
||||
unsigned int avg[3];
|
||||
uint8_t val;
|
||||
|
||||
/* computes average value on black margin */
|
||||
for (k = 0; k < channels; k++)
|
||||
{
|
||||
avg[k] = 0;
|
||||
count = 0;
|
||||
for (i = 0; i < lines; i++)
|
||||
{
|
||||
for (j = 0; j < black; j++)
|
||||
{
|
||||
val = data[i * channels * pixels + j + k];
|
||||
avg[k] += val;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count)
|
||||
avg[k] /= count;
|
||||
DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]);
|
||||
}
|
||||
average = 0;
|
||||
for (i = 0; i < channels; i++)
|
||||
average += avg[i];
|
||||
average /= channels;
|
||||
DBG(DBG_info, "%s: average = %d\n", __func__, average);
|
||||
return average;
|
||||
}
|
||||
|
||||
|
||||
void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
||||
Genesys_Register_Set& regs) const
|
||||
{
|
||||
DBG_HELPER(dbg);
|
||||
unsigned channels;
|
||||
int pass = 0, avg;
|
||||
int topavg, bottomavg, lines;
|
||||
int top, bottom, black_pixels;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/* offset calibration is always done in color mode */
|
||||
channels = 3;
|
||||
lines=1;
|
||||
unsigned pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
|
||||
black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
|
||||
DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
|
||||
|
||||
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 = pixels;
|
||||
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);
|
||||
|
||||
init_regs_for_scan_session(dev, sensor, ®s, session);
|
||||
|
||||
sanei_genesys_set_motor_power(regs, false);
|
||||
|
||||
/* init gain */
|
||||
dev->frontend.set_gain(0, 0);
|
||||
dev->frontend.set_gain(1, 0);
|
||||
dev->frontend.set_gain(2, 0);
|
||||
|
||||
/* scan with no move */
|
||||
bottom = 10;
|
||||
dev->frontend.set_offset(0, bottom);
|
||||
dev->frontend.set_offset(1, bottom);
|
||||
dev->frontend.set_offset(2, bottom);
|
||||
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting first line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
|
||||
if (is_testing_mode()) {
|
||||
dev->interface->test_checkpoint("offset_calibration");
|
||||
return;
|
||||
}
|
||||
|
||||
auto first_line = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
|
||||
|
||||
if (DBG_LEVEL >= DBG_data)
|
||||
{
|
||||
char title[30];
|
||||
std::snprintf(title, 30, "gl124_offset%03d.pnm", bottom);
|
||||
sanei_genesys_write_pnm_file(title, first_line);
|
||||
}
|
||||
|
||||
bottomavg = dark_average(first_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
|
||||
|
||||
/* now top value */
|
||||
top = 255;
|
||||
dev->frontend.set_offset(0, top);
|
||||
dev->frontend.set_offset(1, top);
|
||||
dev->frontend.set_offset(2, top);
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
|
||||
auto second_line = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
|
||||
|
||||
topavg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
|
||||
|
||||
/* loop until acceptable level */
|
||||
while ((pass < 32) && (top - bottom > 1))
|
||||
{
|
||||
pass++;
|
||||
|
||||
/* settings for new scan */
|
||||
dev->frontend.set_offset(0, (top + bottom) / 2);
|
||||
dev->frontend.set_offset(1, (top + bottom) / 2);
|
||||
dev->frontend.set_offset(2, (top + bottom) / 2);
|
||||
|
||||
// scan with no move
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
second_line = read_unshuffled_image_from_scanner(dev, session, session.output_line_bytes);
|
||||
|
||||
if (DBG_LEVEL >= DBG_data) {
|
||||
char title[30];
|
||||
std::snprintf(title, 30, "gl124_offset%03d.pnm", dev->frontend.get_offset(1));
|
||||
sanei_genesys_write_pnm_file(title, second_line);
|
||||
}
|
||||
|
||||
avg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
|
||||
|
||||
/* compute new boundaries */
|
||||
if (topavg == avg)
|
||||
{
|
||||
topavg = avg;
|
||||
top = dev->frontend.get_offset(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomavg = avg;
|
||||
bottom = dev->frontend.get_offset(1);
|
||||
}
|
||||
}
|
||||
DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
|
||||
dev->frontend.get_offset(0),
|
||||
dev->frontend.get_offset(1),
|
||||
dev->frontend.get_offset(2));
|
||||
scanner_offset_calibration(*dev, sensor, regs);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1170,18 +1170,6 @@ void CommandSetGl843::init_regs_for_scan_session(Genesys_Device* dev, const Gene
|
|||
DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read);
|
||||
}
|
||||
|
||||
static float get_model_x_offset_ta(const Genesys_Device& dev,
|
||||
const Genesys_Settings& settings)
|
||||
{
|
||||
if (dev.model->model_id == ModelId::CANON_8600F && settings.xres == 4800) {
|
||||
return 85.0f;
|
||||
}
|
||||
if (dev.model->model_id == ModelId::CANON_4400F && settings.xres == 4800) {
|
||||
return dev.model->x_offset_ta - 10.0;
|
||||
}
|
||||
return dev.model->x_offset_ta;
|
||||
}
|
||||
|
||||
ScanSession CommandSetGl843::calculate_scan_session(const Genesys_Device* dev,
|
||||
const Genesys_Sensor& sensor,
|
||||
const Genesys_Settings& settings) const
|
||||
|
@ -1482,22 +1470,6 @@ void CommandSetGl843::move_back_home(Genesys_Device* dev, bool wait_until_home)
|
|||
scanner_move_back_home(*dev, wait_until_home);
|
||||
}
|
||||
|
||||
static bool should_calibrate_only_active_area(const Genesys_Device& dev,
|
||||
const Genesys_Settings& settings)
|
||||
{
|
||||
if (settings.scan_method == ScanMethod::TRANSPARENCY ||
|
||||
settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED)
|
||||
{
|
||||
if (dev.model->model_id == ModelId::CANON_4400F && settings.xres >= 4800) {
|
||||
return true;
|
||||
}
|
||||
if (dev.model->model_id == ModelId::CANON_8600F && settings.xres == 4800) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// init registers for shading calibration shading calibration is done at dpihw
|
||||
void CommandSetGl843::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
||||
Genesys_Register_Set& regs) const
|
||||
|
@ -1774,38 +1746,6 @@ SensorExposure CommandSetGl843::led_calibration(Genesys_Device* dev, const Genes
|
|||
return calib_sensor.exposure;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* average dark pixels of a 8 bits scan of a given channel
|
||||
*/
|
||||
static int dark_average_channel(const Image& image, unsigned black, unsigned channel)
|
||||
{
|
||||
auto channels = get_pixel_channels(image.get_format());
|
||||
|
||||
unsigned avg[3];
|
||||
|
||||
// computes average values on black margin
|
||||
for (unsigned ch = 0; ch < channels; ch++) {
|
||||
avg[ch] = 0;
|
||||
unsigned count = 0;
|
||||
// FIXME: start with the second line because the black pixels often have noise on the first
|
||||
// line; the cause is probably incorrectly cleaned up previous scan
|
||||
for (std::size_t y = 1; y < image.get_height(); y++) {
|
||||
for (unsigned j = 0; j < black; j++) {
|
||||
avg[ch] += image.get_raw_channel(j, y, ch);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count > 0) {
|
||||
avg[ch] /= count;
|
||||
}
|
||||
DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, ch, avg[ch]);
|
||||
}
|
||||
DBG(DBG_info, "%s: average = %d\n", __func__, avg[channel]);
|
||||
return avg[channel];
|
||||
}
|
||||
|
||||
/** @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.
|
||||
|
@ -1814,220 +1754,7 @@ static int dark_average_channel(const Image& image, unsigned black, unsigned cha
|
|||
void CommandSetGl843::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
||||
Genesys_Register_Set& regs) const
|
||||
{
|
||||
DBG_HELPER(dbg);
|
||||
|
||||
if (dev->frontend.layout.type != FrontendType::WOLFSON)
|
||||
return;
|
||||
|
||||
unsigned channels;
|
||||
int pass, resolution, lines;
|
||||
int topavg[3], bottomavg[3], avg[3];
|
||||
int top[3], bottom[3], black_pixels, pixels, factor, dpihw;
|
||||
|
||||
/* offset calibration is always done in color mode */
|
||||
channels = 3;
|
||||
lines = 8;
|
||||
|
||||
// compute divider factor to compute final pixels number
|
||||
dpihw = sensor.get_register_hwdpi(dev->settings.xres);
|
||||
factor = sensor.optical_res / dpihw;
|
||||
resolution = dpihw;
|
||||
|
||||
const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels,
|
||||
dev->settings.scan_method);
|
||||
|
||||
int target_pixels = dev->model->x_size_calib_mm * resolution / MM_PER_INCH;
|
||||
int start_pixel = 0;
|
||||
black_pixels = calib_sensor.black_pixels / factor;
|
||||
|
||||
if (should_calibrate_only_active_area(*dev, dev->settings)) {
|
||||
float offset = get_model_x_offset_ta(*dev, dev->settings);
|
||||
offset /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution);
|
||||
start_pixel = static_cast<int>((offset * resolution) / MM_PER_INCH);
|
||||
|
||||
float size = dev->model->x_size_ta;
|
||||
size /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution);
|
||||
target_pixels = static_cast<int>((size * resolution) / MM_PER_INCH);
|
||||
}
|
||||
|
||||
if (dev->model->model_id == ModelId::CANON_4400F &&
|
||||
dev->settings.scan_method == ScanMethod::FLATBED)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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 = resolution;
|
||||
session.params.startx = start_pixel;
|
||||
session.params.starty = 0;
|
||||
session.params.pixels = target_pixels;
|
||||
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 = ColorFilter::RED;
|
||||
session.params.flags = flags;
|
||||
compute_session(dev, session, calib_sensor);
|
||||
pixels = session.output_pixels;
|
||||
|
||||
DBG(DBG_io, "%s: dpihw =%d\n", __func__, dpihw);
|
||||
DBG(DBG_io, "%s: factor =%d\n", __func__, factor);
|
||||
DBG(DBG_io, "%s: resolution =%d\n", __func__, resolution);
|
||||
DBG(DBG_io, "%s: pixels =%d\n", __func__, pixels);
|
||||
DBG(DBG_io, "%s: black_pixels=%d\n", __func__, black_pixels);
|
||||
init_regs_for_scan_session(dev, calib_sensor, ®s, session);
|
||||
|
||||
sanei_genesys_set_motor_power(regs, false);
|
||||
|
||||
// init gain and offset
|
||||
for (unsigned ch = 0; ch < 3; ch++)
|
||||
{
|
||||
bottom[ch] = 10;
|
||||
dev->frontend.set_offset(ch, bottom[ch]);
|
||||
dev->frontend.set_gain(ch, 0);
|
||||
}
|
||||
dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
|
||||
|
||||
// scan with bottom AFE settings
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting first line reading\n", __func__);
|
||||
|
||||
dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true);
|
||||
|
||||
if (is_testing_mode()) {
|
||||
dev->interface->test_checkpoint("offset_calibration");
|
||||
scanner_stop_action_no_move(*dev, regs);
|
||||
return;
|
||||
}
|
||||
|
||||
auto first_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)
|
||||
{
|
||||
char fn[40];
|
||||
std::snprintf(fn, 40, "gl843_bottom_offset_%03d_%03d_%03d.pnm",
|
||||
bottom[0], bottom[1], bottom[2]);
|
||||
sanei_genesys_write_pnm_file(fn, first_line);
|
||||
}
|
||||
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
bottomavg[ch] = dark_average_channel(first_line, black_pixels, ch);
|
||||
DBG(DBG_io2, "%s: bottom avg %d=%d\n", __func__, ch, bottomavg[ch]);
|
||||
}
|
||||
|
||||
// now top value
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
top[ch] = 255;
|
||||
dev->frontend.set_offset(ch, top[ch]);
|
||||
}
|
||||
dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
|
||||
|
||||
// scan with top AFE values
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
|
||||
dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true);
|
||||
auto second_line = read_unshuffled_image_from_scanner(dev, session,
|
||||
session.output_total_bytes_raw);
|
||||
scanner_stop_action_no_move(*dev, regs);
|
||||
|
||||
for (unsigned ch = 0; ch < 3; ch++){
|
||||
topavg[ch] = dark_average_channel(second_line, black_pixels, ch);
|
||||
DBG(DBG_io2, "%s: top avg %d=%d\n", __func__, ch, topavg[ch]);
|
||||
}
|
||||
|
||||
pass = 0;
|
||||
|
||||
std::vector<uint8_t> debug_image;
|
||||
size_t debug_image_lines = 0;
|
||||
std::string debug_image_info;
|
||||
|
||||
/* loop until acceptable level */
|
||||
while ((pass < 32)
|
||||
&& ((top[0] - bottom[0] > 1)
|
||||
|| (top[1] - bottom[1] > 1) || (top[2] - bottom[2] > 1)))
|
||||
{
|
||||
pass++;
|
||||
|
||||
// settings for new scan
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
if (top[ch] - bottom[ch] > 1) {
|
||||
dev->frontend.set_offset(ch, (top[ch] + bottom[ch]) / 2);
|
||||
}
|
||||
}
|
||||
dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET);
|
||||
|
||||
// scan with no move
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true);
|
||||
second_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)
|
||||
{
|
||||
char title[100];
|
||||
std::snprintf(title, 100, "lines: %d pixels_per_line: %d offsets[0..2]: %d %d %d\n",
|
||||
lines, pixels,
|
||||
dev->frontend.get_offset(0),
|
||||
dev->frontend.get_offset(1),
|
||||
dev->frontend.get_offset(2));
|
||||
debug_image_info += title;
|
||||
std::copy(second_line.get_row_ptr(0),
|
||||
second_line.get_row_ptr(0) + second_line.get_row_bytes() * second_line.get_height(),
|
||||
std::back_inserter(debug_image));
|
||||
debug_image_lines += lines;
|
||||
}
|
||||
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
avg[ch] = dark_average_channel(second_line, black_pixels, ch);
|
||||
DBG(DBG_info, "%s: avg[%d]=%d offset=%d\n", __func__, ch, avg[ch],
|
||||
dev->frontend.get_offset(ch));
|
||||
}
|
||||
|
||||
// compute new boundaries
|
||||
for (unsigned ch = 0; ch < 3; ch++) {
|
||||
if (topavg[ch] >= avg[ch]) {
|
||||
topavg[ch] = avg[ch];
|
||||
top[ch] = dev->frontend.get_offset(ch);
|
||||
} else {
|
||||
bottomavg[ch] = avg[ch];
|
||||
bottom[ch] = dev->frontend.get_offset(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DBG_LEVEL >= DBG_data)
|
||||
{
|
||||
sanei_genesys_write_file("gl843_offset_all_desc.txt",
|
||||
reinterpret_cast<const std::uint8_t*>(debug_image_info.data()),
|
||||
debug_image_info.size());
|
||||
sanei_genesys_write_pnm_file("gl843_offset_all.pnm",
|
||||
debug_image.data(), session.params.depth, channels, pixels,
|
||||
debug_image_lines);
|
||||
}
|
||||
|
||||
DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
|
||||
dev->frontend.get_offset(0),
|
||||
dev->frontend.get_offset(1),
|
||||
dev->frontend.get_offset(2));
|
||||
scanner_offset_calibration(*dev, sensor, regs);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1322,176 +1322,10 @@ void CommandSetGl846::update_home_sensor_gpio(Genesys_Device& dev) const
|
|||
dev.interface->write_register(REG_0x6C, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* average dark pixels of a 8 bits scan
|
||||
*/
|
||||
static int
|
||||
dark_average (uint8_t * data, unsigned int pixels, unsigned int lines,
|
||||
unsigned int channels, unsigned int black)
|
||||
{
|
||||
unsigned int i, j, k, average, count;
|
||||
unsigned int avg[3];
|
||||
uint8_t val;
|
||||
|
||||
/* computes average value on black margin */
|
||||
for (k = 0; k < channels; k++)
|
||||
{
|
||||
avg[k] = 0;
|
||||
count = 0;
|
||||
for (i = 0; i < lines; i++)
|
||||
{
|
||||
for (j = 0; j < black; j++)
|
||||
{
|
||||
val = data[i * channels * pixels + j + k];
|
||||
avg[k] += val;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count)
|
||||
avg[k] /= count;
|
||||
DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]);
|
||||
}
|
||||
average = 0;
|
||||
for (i = 0; i < channels; i++)
|
||||
average += avg[i];
|
||||
average /= channels;
|
||||
DBG(DBG_info, "%s: average = %d\n", __func__, average);
|
||||
return average;
|
||||
}
|
||||
|
||||
void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
||||
Genesys_Register_Set& regs) const
|
||||
{
|
||||
DBG_HELPER(dbg);
|
||||
unsigned channels;
|
||||
int pass = 0, avg;
|
||||
int topavg, bottomavg, lines;
|
||||
int top, bottom, black_pixels;
|
||||
|
||||
// no gain nor offset for AKM AFE
|
||||
uint8_t reg04 = dev->interface->read_register(REG_0x04);
|
||||
if ((reg04 & REG_0x04_FESET) == 0x02) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* offset calibration is always done in color mode */
|
||||
channels = 3;
|
||||
lines=1;
|
||||
unsigned pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
|
||||
black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
|
||||
DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
|
||||
|
||||
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 = pixels;
|
||||
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);
|
||||
|
||||
init_regs_for_scan_session(dev, sensor, ®s, session);
|
||||
|
||||
sanei_genesys_set_motor_power(regs, false);
|
||||
|
||||
/* init gain */
|
||||
dev->frontend.set_gain(0, 0);
|
||||
dev->frontend.set_gain(1, 0);
|
||||
dev->frontend.set_gain(2, 0);
|
||||
|
||||
/* scan with no move */
|
||||
bottom = 10;
|
||||
dev->frontend.set_offset(0, bottom);
|
||||
dev->frontend.set_offset(1, bottom);
|
||||
dev->frontend.set_offset(2, bottom);
|
||||
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting first line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
|
||||
if (is_testing_mode()) {
|
||||
dev->interface->test_checkpoint("offset_calibration");
|
||||
return;
|
||||
}
|
||||
|
||||
auto first_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
|
||||
if (DBG_LEVEL >= DBG_data)
|
||||
{
|
||||
char fn[30];
|
||||
std::snprintf(fn, 30, "gl846_offset%03d.pnm", bottom);
|
||||
sanei_genesys_write_pnm_file(fn, first_line);
|
||||
}
|
||||
|
||||
bottomavg = dark_average(first_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
|
||||
|
||||
/* now top value */
|
||||
top = 255;
|
||||
dev->frontend.set_offset(0, top);
|
||||
dev->frontend.set_offset(1, top);
|
||||
dev->frontend.set_offset(2, top);
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
auto second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
|
||||
|
||||
topavg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
|
||||
|
||||
/* loop until acceptable level */
|
||||
while ((pass < 32) && (top - bottom > 1))
|
||||
{
|
||||
pass++;
|
||||
|
||||
/* settings for new scan */
|
||||
dev->frontend.set_offset(0, (top + bottom) / 2);
|
||||
dev->frontend.set_offset(1, (top + bottom) / 2);
|
||||
dev->frontend.set_offset(2, (top + bottom) / 2);
|
||||
|
||||
// scan with no move
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
|
||||
|
||||
if (DBG_LEVEL >= DBG_data) {
|
||||
char fn[30];
|
||||
std::snprintf(fn, 30, "gl846_offset%03d.pnm", dev->frontend.get_offset(1));
|
||||
sanei_genesys_write_pnm_file(fn, second_line);
|
||||
}
|
||||
|
||||
avg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
|
||||
|
||||
/* compute new boundaries */
|
||||
if (topavg == avg)
|
||||
{
|
||||
topavg = avg;
|
||||
top = dev->frontend.get_offset(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomavg = avg;
|
||||
bottom = dev->frontend.get_offset(1);
|
||||
}
|
||||
}
|
||||
DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
|
||||
dev->frontend.get_offset(0),
|
||||
dev->frontend.get_offset(1),
|
||||
dev->frontend.get_offset(2));
|
||||
scanner_offset_calibration(*dev, sensor, regs);
|
||||
}
|
||||
|
||||
void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
||||
|
|
|
@ -1363,175 +1363,10 @@ void CommandSetGl847::update_home_sensor_gpio(Genesys_Device& dev) const
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* average dark pixels of a 8 bits scan
|
||||
*/
|
||||
static int
|
||||
dark_average (uint8_t * data, unsigned int pixels, unsigned int lines,
|
||||
unsigned int channels, unsigned int black)
|
||||
{
|
||||
unsigned int i, j, k, average, count;
|
||||
unsigned int avg[3];
|
||||
uint8_t val;
|
||||
|
||||
/* computes average value on black margin */
|
||||
for (k = 0; k < channels; k++)
|
||||
{
|
||||
avg[k] = 0;
|
||||
count = 0;
|
||||
for (i = 0; i < lines; i++)
|
||||
{
|
||||
for (j = 0; j < black; j++)
|
||||
{
|
||||
val = data[i * channels * pixels + j + k];
|
||||
avg[k] += val;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count)
|
||||
avg[k] /= count;
|
||||
DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]);
|
||||
}
|
||||
average = 0;
|
||||
for (i = 0; i < channels; i++)
|
||||
average += avg[i];
|
||||
average /= channels;
|
||||
DBG(DBG_info, "%s: average = %d\n", __func__, average);
|
||||
return average;
|
||||
}
|
||||
|
||||
void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
||||
Genesys_Register_Set& regs) const
|
||||
{
|
||||
DBG_HELPER(dbg);
|
||||
unsigned channels;
|
||||
int pass = 0, avg;
|
||||
int topavg, bottomavg, lines;
|
||||
int top, bottom, black_pixels;
|
||||
|
||||
// no gain nor offset for AKM AFE
|
||||
uint8_t reg04 = dev->interface->read_register(REG_0x04);
|
||||
if ((reg04 & REG_0x04_FESET) == 0x02) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* offset calibration is always done in color mode */
|
||||
channels = 3;
|
||||
lines=1;
|
||||
unsigned pixels = dev->model->x_size_calib_mm * sensor.optical_res / MM_PER_INCH;
|
||||
black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res;
|
||||
DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels);
|
||||
|
||||
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 = pixels;
|
||||
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);
|
||||
|
||||
init_regs_for_scan_session(dev, sensor, ®s, session);
|
||||
|
||||
sanei_genesys_set_motor_power(regs, false);
|
||||
|
||||
/* init gain */
|
||||
dev->frontend.set_gain(0, 0);
|
||||
dev->frontend.set_gain(1, 0);
|
||||
dev->frontend.set_gain(2, 0);
|
||||
|
||||
/* scan with no move */
|
||||
bottom = 10;
|
||||
dev->frontend.set_offset(0, bottom);
|
||||
dev->frontend.set_offset(1, bottom);
|
||||
dev->frontend.set_offset(2, bottom);
|
||||
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting first line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
|
||||
if (is_testing_mode()) {
|
||||
dev->interface->test_checkpoint("offset_calibration");
|
||||
return;
|
||||
}
|
||||
|
||||
auto first_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
|
||||
if (DBG_LEVEL >= DBG_data) {
|
||||
char fn[30];
|
||||
std::snprintf(fn, 30, "gl847_offset%03d.pnm", bottom);
|
||||
sanei_genesys_write_pnm_file(fn, first_line);
|
||||
}
|
||||
|
||||
bottomavg = dark_average(first_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg);
|
||||
|
||||
/* now top value */
|
||||
top = 255;
|
||||
dev->frontend.set_offset(0, top);
|
||||
dev->frontend.set_offset(1, top);
|
||||
dev->frontend.set_offset(2, top);
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
auto second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
|
||||
|
||||
topavg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg);
|
||||
|
||||
/* loop until acceptable level */
|
||||
while ((pass < 32) && (top - bottom > 1))
|
||||
{
|
||||
pass++;
|
||||
|
||||
/* settings for new scan */
|
||||
dev->frontend.set_offset(0, (top + bottom) / 2);
|
||||
dev->frontend.set_offset(1, (top + bottom) / 2);
|
||||
dev->frontend.set_offset(2, (top + bottom) / 2);
|
||||
|
||||
// scan with no move
|
||||
set_fe(dev, sensor, AFE_SET);
|
||||
dev->interface->write_registers(regs);
|
||||
DBG(DBG_info, "%s: starting second line reading\n", __func__);
|
||||
begin_scan(dev, sensor, ®s, true);
|
||||
second_line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes);
|
||||
|
||||
if (DBG_LEVEL >= DBG_data) {
|
||||
char fn[30];
|
||||
std::snprintf(fn, 30, "gl847_offset%03d.pnm", dev->frontend.get_offset(1));
|
||||
sanei_genesys_write_pnm_file(fn, second_line);
|
||||
}
|
||||
|
||||
avg = dark_average(second_line.get_row_ptr(0), pixels, lines, channels, black_pixels);
|
||||
DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1));
|
||||
|
||||
/* compute new boundaries */
|
||||
if (topavg == avg)
|
||||
{
|
||||
topavg = avg;
|
||||
top = dev->frontend.get_offset(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
bottomavg = avg;
|
||||
bottom = dev->frontend.get_offset(1);
|
||||
}
|
||||
}
|
||||
DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__,
|
||||
dev->frontend.get_offset(0),
|
||||
dev->frontend.get_offset(1),
|
||||
dev->frontend.get_offset(2));
|
||||
scanner_offset_calibration(*dev, sensor, regs);
|
||||
}
|
||||
|
||||
void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor,
|
||||
|
|
|
@ -303,6 +303,14 @@ void scanner_move_back_home_ta(Genesys_Device& dev);
|
|||
*/
|
||||
void scanner_search_strip(Genesys_Device& dev, bool forward, bool black);
|
||||
|
||||
bool should_calibrate_only_active_area(const Genesys_Device& dev,
|
||||
const Genesys_Settings& settings);
|
||||
|
||||
float get_model_x_offset_ta(const Genesys_Device& dev, const Genesys_Settings& settings);
|
||||
|
||||
void scanner_offset_calibration(Genesys_Device& dev, const Genesys_Sensor& sensor,
|
||||
Genesys_Register_Set& regs);
|
||||
|
||||
void scanner_clear_scan_and_feed_counts(Genesys_Device& dev);
|
||||
|
||||
extern void sanei_genesys_write_file(const char* filename, const std::uint8_t* data,
|
||||
|
|
Ładowanie…
Reference in New Issue