ale/d2/render/psf/psf_calibrate.h
2022-07-30 14:46:04 -03:00

334 lines
10 KiB
C++

// Copyright 2003 David Hilvert <dhilvert@auricle.dyndns.org>,
// <dhilvert@ugcs.caltech.edu>
/* 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