// Copyright 2002, 2004, 2007 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 __incremental_h__ #define __incremental_h__ #include "invariant.h" #include "../render.h" #include "../transformation.h" #include "../image.h" #include "../point.h" /* * Class for incremental renderers. */ class incremental : public render { protected: image_weighted_avg *accum_image; invariant *inv; /* * Set extents of image and weight according to a new image to be * merged. This function should remove only superfluous undefined * areas. */ void set_extents_by_map(unsigned int frame_num, transformation t) { assert (accum_image != NULL); ale_pos extend_offset_i = accum_image->offset()[0]; ale_pos extend_offset_j = accum_image->offset()[1]; int extend_top = 0; int extend_bottom = 0; int extend_left = 0; int extend_right = 0; ale_pos zero = 0; ale_pos infinity = 1 / zero; assert (!finite(infinity)); assert (!isnan(infinity)); assert (infinity > 0); point min, max; min[0] = min[1] = infinity; max[0] = max[1] = -infinity; for (unsigned int i = 0; i < t.unscaled_height(); i++) for (unsigned int j = 0; j < t.unscaled_width(); j++) { if (is_excluded_f(i, j, frame_num)) continue; point p = t.transform_unscaled(point(i, j)); if (is_excluded_r(accum_image->offset(), p, frame_num)) continue; if (p[0] < min[0]) { min[0] = p[0]; } if (p[0] > max[0]) { max[0] = p[0]; } if (p[1] < min[1]) { min[1] = p[1]; } if (p[1] > max[1]) { max[1] = p[1]; } } if (!finite(max[0]) || !finite(max[1]) || !finite(min[0]) || !finite(min[1])) return; extend_top = (int) ceil(extend_offset_i - floor(min[0])); extend_left = (int) ceil(extend_offset_j - floor(min[1])); extend_bottom = (int) ceil(ceil(max[0]) - (ale_pos) (accum_image->height() - 1 + extend_offset_i)); extend_right = (int) ceil(ceil(max[1]) - (ale_pos) (accum_image->width() - 1 + extend_offset_j)); accum_image->_extend(extend_top, extend_bottom, extend_left, extend_right); } void increase_extents_by_map(unsigned int frame_num, transformation t) { assert (accum_image != NULL); ale_pos extend_offset_i = accum_image->offset()[0]; ale_pos extend_offset_j = accum_image->offset()[1]; int extend_top = 0; int extend_bottom = 0; int extend_left = 0; int extend_right = 0; double zero = 0; double infinity = 1 / zero; assert (!finite(infinity)); assert (!isnan(infinity)); assert (infinity > 0); point min, max; min[0] = min[1] = infinity; max[0] = max[1] = -infinity; for (unsigned int i = 0; i < t.unscaled_height(); i++) for (unsigned int j = 0; j < t.unscaled_width(); j++) { if (is_excluded_f(i, j, frame_num)) continue; point p = t.transform_unscaled(point(i, j)); if (is_excluded_r(point(0, 0), p, frame_num)) continue; if (p[0] < min[0]) { min[0] = p[0]; } if (p[0] > max[0]) { max[0] = p[0]; } if (p[1] < min[1]) { min[1] = p[1]; } if (p[1] > max[1]) { max[1] = p[1]; } } if (!finite(max[0]) || !finite(max[1]) || !finite(min[0]) || !finite(min[1])) return; if (ceil(min[0]) < extend_offset_i) extend_top = (int) ceil(extend_offset_i - floor(min[0])); if (ceil(min[1]) < extend_offset_j) extend_left = (int) ceil(extend_offset_j - floor(min[1])); if (floor(max[0]) > accum_image->height() - 1 + extend_offset_i) extend_bottom = (int) ceil(ceil(max[0]) - (ale_pos) (accum_image->height() - 1 + extend_offset_i)); if (floor(max[1]) > accum_image->width() - 1 + extend_offset_j) extend_right = (int) ceil(ceil(max[1]) - (ale_pos) (accum_image->width() - 1 + extend_offset_j)); accum_image->_extend(extend_top, extend_bottom, extend_left, extend_right); } /* * Merge operation for a single pixel in the accumulated image. */ void _merge_pixel(int frame, const image *delta, transformation t, int i, int j, const filter::ssfe *_ssfe) { if (_ssfe->ex_is_honored() && is_excluded_r(i, j, frame)) return; if (accum_image->accumulate_norender(i, j)) return; /* * Pixel value to be merged, and the associated * confidence */ pixel value, confidence; if (exposure::get_confidence() != 0) { _ssfe->filtered(i, j, frame, &value, &confidence, ((pixel) accum_image->get_pixel(i, j)), accum_image->get_weights()->get_pixel(i, j)); } else { _ssfe->filtered(i, j, frame, &value, &confidence); } accum_image->accumulate(i, j, frame, value, confidence); } /* * Merge part of a delta frame with part of the accumulated image using * the specified transformation. */ class merge : public thread::decompose_domain { incremental *instance; int frame; const image *delta; transformation t; invariant *inv; image_weighted_avg *accum_image; protected: void prepare_subdomains(unsigned int N) { ale_pos_disable_casting(); ale_real_disable_casting(); ale_accum_disable_casting(); } void subdomain_algorithm(unsigned int thread, int i_min, int i_max, int j_min, int j_max) { point offset = accum_image->offset(); assert (accum_image != NULL); assert (delta != NULL); const filter::ssfe *_ssfe = inv->ssfe(); for (int i = i_min; i < i_max; i++) for (int j = j_min; j < j_max; j++) { #if 0 /* * This is untested, but it should work, and is less * verbose than what follows. */ instance->_merge_pixel(frame, delta, t, i, j, _ssfe); #else if (_ssfe->ex_is_honored() && instance->is_excluded_r(i, j, frame)) continue; if (accum_image->accumulate_norender(i, j)) continue; /* * Pixel value to be merged, and the associated * confidence */ pixel value, confidence; if (exposure::get_confidence() != 0) { _ssfe->filtered(i, j, frame, &value, &confidence, ((pixel) accum_image->get_pixel(i, j)), accum_image->get_weights()->get_pixel(i, j)); } else { _ssfe->filtered(i, j, frame, &value, &confidence); } accum_image->accumulate(i, j, frame, value, confidence); #endif } } void finish_subdomains(unsigned int N) { ale_pos_enable_casting(); ale_real_enable_casting(); ale_accum_enable_casting(); } public: merge(incremental *_instance, int _frame, const image *_delta, transformation _t) : decompose_domain(0, _instance->accum_image->height(), 0, _instance->accum_image->width()), t(_t) { instance = _instance; frame = _frame; delta = _delta; t = _t; inv = instance->inv; accum_image = instance->accum_image; } }; void _merge(int frame, const image *delta, transformation t) { ui::get()->d2_incremental_start(); point offset = accum_image->offset(); assert (accum_image != NULL); assert (delta != NULL); const filter::ssfe *_ssfe = inv->ssfe(); _ssfe->set_parameters(t, delta, offset); merge m(this, frame, delta, t); m.run(); ui::get()->d2_incremental_stop(); } public: /* * Constructor */ incremental(invariant *inv) { this->inv = inv; accum_image = NULL; } /* * Invariant */ const invariant *get_invariant() const { return inv; } /* * Result of rendering. */ virtual const image *get_image() const { assert (accum_image != NULL); return accum_image; } /* * Definition map. Unit-depth image whose pixels are nonzero where * the image is defined. */ virtual const image *get_defined() const { assert (accum_image != NULL); return accum_image->get_weights(); } /* * Perform the current rendering step. */ virtual void step() { /* * Dynamic invariants are not incrementally updated. */ if (inv->ssfe()->get_scaled_filter()->is_dynamic()) { /* * Create a trivial image for the case where there is * no chain suffix. */ if (accum_image == NULL) accum_image = new image_weighted_simple(1, 1, 3, inv); return; } assert (get_step() >= -1); if (get_step() == 0) { transformation t = align::of(0); const image *im = image_rw::open(0); ui::get()->rendering(); if (inv->is_median()) accum_image = new image_weighted_median(1, 1, 3); else accum_image = new image_weighted_simple(1, 1, 3, inv); set_extents_by_map(0, t); _merge(0, im, t); image_rw::close(0); } else if (align::match(get_step())) { transformation t = align::of(get_step()); ui::get()->rendering(); if (is_extend()) increase_extents_by_map(get_step(), t); const image *im = image_rw::open(get_step()); _merge(get_step(), im, t); image_rw::close(get_step()); } } virtual void init_point_renderer(unsigned int h, unsigned int w, unsigned int d) { assert(accum_image == NULL); if (inv->is_median()) accum_image = new image_weighted_median(h, w, d); else accum_image = new image_weighted_simple(h, w, d, inv); assert(accum_image); } virtual void point_render(unsigned int i, unsigned int j, unsigned int f, transformation t) { const image *im = d2::image_rw::get_open(f); const filter::ssfe *_ssfe = inv->ssfe(); _ssfe->set_parameters(t, im, accum_image->offset()); _merge_pixel(f, im, t, i, j, _ssfe); } virtual void finish_point_rendering() { return; } void free_memory() { delete accum_image; accum_image = NULL; } }; #endif