// Copyright 2003 David Hilvert , // /* This file is part of the Anti-Lamenessing Engine. The Anti-Lamenessing Engine is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The Anti-Lamenessing Engine is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the Anti-Lamenessing Engine; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __psf_calibrate_h__ #define __psf_calibrate_h__ #include "../../image.h" #include "../../render.h" #include "../ipc.h" class psf_calibrate : public ipc { private: double *psf_match_args; public: psf_calibrate(render *input, unsigned int iterations, int _inc, psf *lresponse, psf *nlresponse, double *psf_match_args) : ipc(input, iterations, _inc, lresponse, nlresponse, 1, 0, 0) { fprintf(stderr, "\nIPC Calibration module.\n\n"); fprintf(stderr, "This module is designed for use with a calibration script.\n\n"); this->psf_match_args = psf_match_args; } void _ip_frame(ale_accum *diff, unsigned int *count, int m) { /* * Get alignment information for frame m. */ transformation t = align::of(m); /* * We create real and simulated input-frame data structures * REAL and SIMULATED, as well as simulated input-frame weights * SIM_WEIGHTS, used to track the weights of contributions to each * simulated input-frame pixel component. */ const image *real = image_rw::open(m); image *simulated = new_image_ale_real( real->height(), real->width(), 3); /* * Calculate the simulated input frame SIMULATED from the image * approximation APPROXIMATION, iterating over image * approximation pixels and tracking contributions to simulated * frame pixels in the data structure SIM_WEIGHTS. */ image *sim_weights = new_image_ale_real( simulated->height(), simulated->width(), 3); for (unsigned int i = 0; i < approximation->height(); i++) for (unsigned int j = 0; j < approximation->width(); j++) { /* * Obtain the position Q and dimensions D of * image approximation pixel (i, j) in the coordinate * system of the simulated frame. */ point p = point(i + approximation->offset()[0], j + approximation->offset()[1]); point q; ale_pos d[2]; t.unscaled_map_area_inverse(p, &q, d); /* * Iterate over all simulated frame pixels influenced * by the scene pixel (i, j), as determined by the * response function. */ for (int ii = (int) floor(q[0] - d[0] + (ale_pos) lresponse->min_i()); ii <= ceil(q[0] + d[0] + (ale_pos) lresponse->max_i()); ii++) for (int jj = (int) floor(q[1] - d[1] + (ale_pos) lresponse->min_j()); jj <= ceil(q[1] + d[1] + (ale_pos) lresponse->max_j()); jj++) { ale_pos top = q[0] - d[0]; ale_pos bot = q[0] + d[0]; ale_pos lef = q[1] - d[1]; ale_pos rig = q[1] + d[1]; if (ii >= (int) 0 && ii < (int) real->height() && jj >= (int) 0 && jj < (int) real->width()) { psf::psf_result r = (*lresponse)(top - ii, bot - ii, lef - jj, rig - jj, lresponse->select(ii, jj)); sim_weights->set_pixel(ii, jj, (pixel) sim_weights->get_pixel(ii, jj) + r.weight()); simulated->set_pixel(ii, jj, (pixel) simulated->get_pixel(ii, jj) + r(approximation->get_pixel(i, j))); } } } /* * Normalize SIMULATED by SIM_WEIGHTS */ for (unsigned int i = 0; i < simulated->height(); i++) for (unsigned int j = 0; j < simulated->width(); j++) simulated->set_pixel(i, j, (pixel) simulated->get_pixel(i, j) / (pixel) sim_weights->get_pixel(i, j)); delete sim_weights; /* * If NLRESPONSE is defined, then redefine SIMULATED to account * for this. */ if (nlresponse != NULL) { image *nlsimulated = new_image_ale_real( simulated->height(), simulated->width(), 3); image *nlsim_weights = new_image_ale_real( simulated->height(), simulated->width(), 3); for (unsigned int i = 0; i < simulated->height(); i++) for (unsigned int j = 0; j < simulated->width(); j++) { for (int ii = (int) floor(i - 0.5 + nlresponse->min_i()); ii <= ceil(i + 0.5 + nlresponse->max_i()); ii++) for (int jj = (int) floor(j - 0.5 + nlresponse->min_j()); jj <= ceil(j + 0.5 + nlresponse->max_j()); jj++) { ale_pos top = i - 0.5; ale_pos bot = i + 0.5; ale_pos lef = j - 0.5; ale_pos rig = j + 0.5; if (ii >= (int) 0 && ii < (int) nlsimulated->height() && jj >= (int) 0 && jj < (int) nlsimulated->width()) { psf::psf_result r = (*nlresponse)(top - ii, bot - ii, lef - jj, rig - jj, nlresponse->select(ii, jj)); nlsim_weights->set_pixel(ii, jj, (pixel) nlsim_weights->get_pixel(ii, jj) + r.weight()); nlsimulated->set_pixel(ii, jj, (pixel) nlsimulated->get_pixel(ii, jj) + r(real->exp().unlinearize(simulated->get_pixel(i, j)))); } } } /* * Normalize nlsimulated. */ for (unsigned int i = 0; i < simulated->height(); i++) for (unsigned int j = 0; j < simulated->width(); j++) nlsimulated->set_pixel(i, j, (pixel) nlsimulated->get_pixel(i, j) / nlsim_weights->get_pixel(i, j)); /* * Linearize nlsimulated */ for (unsigned int i = 0; i < simulated->height(); i++) for (unsigned int j = 0; j < simulated->width(); j++) nlsimulated->set_pixel(i, j, real->exp().linearize(nlsimulated->get_pixel(i, j))); delete simulated; delete nlsim_weights; simulated = nlsimulated; } /* * For each SIMULATED pixel, calculate the difference from * the corresponding REAL pixel, and update the sum of squares * of differences. */ ale_real margin_i1 = lresponse->min_i() + (nlresponse ? nlresponse->min_i() : ale_real_0); ale_real margin_i2 = lresponse->max_i() + (nlresponse ? nlresponse->max_i() : ale_real_0); ale_real margin_j1 = lresponse->min_j() + (nlresponse ? nlresponse->min_j() : ale_real_0); ale_real margin_j2 = lresponse->max_j() + (nlresponse ? nlresponse->max_j() : ale_real_0); for (unsigned int i = 0; i < simulated->height(); i++) for (unsigned int j = 0; j < simulated->width(); j++) { /* * Establish margins. This is designed to reduce the * influence of boundary conditions. */ point p; p = t.transform_unscaled(point(i + margin_i1, j + margin_j1)); if (p[0] < 0 || p[0] > approximation->height() || p[1] < 0 || p[1] > approximation->width()) continue; p = t.transform_unscaled(point(i + margin_i1, j + margin_j2)); if (p[0] < 0 || p[0] > approximation->height() || p[1] < 0 || p[1] > approximation->width()) continue; p = t.transform_unscaled(point(i + margin_i2, j + margin_j1)); if (p[0] < 0 || p[0] > approximation->height() || p[1] < 0 || p[1] > approximation->width()) continue; p = t.transform_unscaled(point(i + margin_i2, j + margin_j2)); if (p[0] < 0 || p[0] > approximation->height() || p[1] < 0 || p[1] > approximation->width()) continue; /* * Real and simulated responses */ pixel comp_real = real->get_pixel(i, j); pixel comp_simu = simulated->get_pixel(i, j); for (unsigned int k = 0; k < simulated->depth(); k++) { if (!finite(comp_simu[k])) continue; /* * Error calculation */ if ((comp_real[k] < 1.0 || comp_simu[k] < 1.0 ) && (comp_real[k] > 0 || comp_simu[k] > 0) && ((*count) < ULONG_MAX)) { /* * real and simulated are distinguishable * within the dynamic range of the program * inputs, so calculate the error for this * channel. */ (*diff) += pow(comp_simu[k] - comp_real[k], 2); (*count)++; } } } image_rw::close(m); delete simulated; } void _ip() { /* * Input images 0 through count()-2 are frames captured with * the device to be calibrated, so we combine the difference * values for all of these frames against the calibration image * count()-1. */ ale_accum diff = 0; unsigned int channel_count = 0; approximation = image_rw::copy(image_rw::count() - 1, "PSF_CALIBRATE reference"); #if 0 fprintf(stderr, "[%f %f %f %f %f %f] ", psf_match_args[0], psf_match_args[1], psf_match_args[2], psf_match_args[3], psf_match_args[4], psf_match_args[5]); #endif for (unsigned int i = 0; i < approximation->height(); i++) for (unsigned int j = 0; j < approximation->width(); j++) { approximation->set_pixel(i, j, (pixel) approximation->get_pixel(i, j) * pixel(psf_match_args[0], psf_match_args[1], psf_match_args[2])); approximation->set_pixel(i, j, (pixel) approximation->get_pixel(i, j) + pixel(psf_match_args[3], psf_match_args[4], psf_match_args[5])); } for (unsigned int m = 0; m < image_rw::count() - 1; m++) { _ip_frame(&diff, &channel_count, m); } diff = pow(diff / (ale_accum) channel_count, 0.5); fprintf(stderr, "\n\nPSF Error:: %e\n\n", (double) diff); delete approximation; } void free_memory() { } }; #endif