genesys: Deduplicate offset calibration

pixma-axis-driver
Povilas Kanapickas 2020-03-14 23:19:26 +02:00
rodzic 255da97fcb
commit e0bec6723d
6 zmienionych plików z 330 dodań i 777 usunięć

Wyświetl plik

@ -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, &regs, 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, &regs, 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, &regs, 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, &regs, 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,

Wyświetl plik

@ -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, &regs, 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, &regs, 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, &regs, 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, &regs, 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);
}

Wyświetl plik

@ -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, &regs, 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, &regs, 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, &regs, 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, &regs, 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);
}

Wyświetl plik

@ -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, &regs, 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, &regs, 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, &regs, 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, &regs, 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,

Wyświetl plik

@ -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, &regs, 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, &regs, 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, &regs, 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, &regs, 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,

Wyświetl plik

@ -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,