259 lines
5.7 KiB
C++
259 lines
5.7 KiB
C++
// Copyright 2004 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
|
|
*/
|
|
|
|
/*
|
|
* exposure.h: A superclass for all exposure classes.
|
|
*/
|
|
|
|
#ifndef __exposure_h__
|
|
#define __exposure_h__
|
|
|
|
#include "../pixel.h"
|
|
|
|
/*
|
|
* This class models a non-linear response function. More information can be
|
|
* found here:
|
|
*
|
|
* http://wearcam.org/comparametrics.pdf
|
|
*/
|
|
|
|
class exposure {
|
|
private:
|
|
static ale_real confidence_exponent;
|
|
pixel _multiplier;
|
|
ale_real _gain_multiplier;
|
|
static ale_real _gain_reference;
|
|
ale_real _black_level;
|
|
|
|
public:
|
|
|
|
/*
|
|
* confidence/uniform static mutators
|
|
*/
|
|
static void set_confidence(ale_real exponent) {
|
|
confidence_exponent = exponent;
|
|
}
|
|
|
|
/*
|
|
* confidence accessor
|
|
*/
|
|
static ale_real get_confidence() {
|
|
return confidence_exponent;
|
|
}
|
|
|
|
/*
|
|
* Event listener interface
|
|
*/
|
|
|
|
class listener {
|
|
friend class exposure;
|
|
private:
|
|
listener *next;
|
|
const char *name;
|
|
const exposure *target;
|
|
public:
|
|
virtual void trigger(pixel multiplier) = 0;
|
|
|
|
listener () {
|
|
next = NULL;
|
|
target = NULL;
|
|
}
|
|
|
|
virtual ~listener() {
|
|
if (target) {
|
|
target->remove_listener(this);
|
|
}
|
|
}
|
|
};
|
|
|
|
private:
|
|
mutable listener *listener_head;
|
|
public:
|
|
|
|
void add_listener(listener *l, const char *name) const {
|
|
|
|
/*
|
|
* This is a metafunction, so we consider it
|
|
* to leave the object constant.
|
|
*/
|
|
assert (l->next == NULL);
|
|
assert (l->target == NULL);
|
|
l->next = listener_head;
|
|
l->target = this;
|
|
l->name = name;
|
|
listener_head = l;
|
|
}
|
|
|
|
void remove_listener(listener *l) const {
|
|
|
|
assert (listener_head != NULL);
|
|
|
|
if (listener_head == l) {
|
|
listener_head = listener_head->next;
|
|
} else {
|
|
assert (listener_head->next != NULL);
|
|
|
|
listener *a = listener_head;
|
|
listener *b = listener_head->next;
|
|
|
|
while (b != l) {
|
|
assert (b->next != NULL);
|
|
a = b;
|
|
b = b->next;
|
|
}
|
|
|
|
a->next = b->next;
|
|
}
|
|
|
|
l->target = NULL;
|
|
}
|
|
|
|
void set_multiplier(pixel _multiplier) {
|
|
listener *cl = listener_head;
|
|
|
|
while(cl != NULL) {
|
|
cl->trigger(_multiplier / this->_multiplier);
|
|
cl = cl->next;
|
|
}
|
|
|
|
this->_multiplier = _multiplier;
|
|
}
|
|
|
|
void set_gain_multiplier(ale_real g) {
|
|
_gain_multiplier = g;
|
|
}
|
|
|
|
ale_real get_gain_multiplier() {
|
|
return _gain_multiplier;
|
|
}
|
|
|
|
void set_black_level(ale_real b) {
|
|
_black_level = b;
|
|
}
|
|
|
|
ale_real get_black_level() {
|
|
return _black_level;
|
|
}
|
|
|
|
static void set_gain_reference(ale_real r) {
|
|
_gain_reference = r;
|
|
}
|
|
|
|
static ale_real get_gain_reference() {
|
|
return _gain_reference;
|
|
}
|
|
|
|
pixel get_multiplier() const {
|
|
return _multiplier;
|
|
}
|
|
|
|
virtual ale_real confidence(unsigned int k, ale_real input,
|
|
ale_real confidence_floor = ale_real_confidence_floor) const {
|
|
|
|
ale_real _0 = (ale_real) 0;
|
|
ale_real _4 = (ale_real) 4;
|
|
ale_real _2 = (ale_real) 2;
|
|
ale_real _1 = (ale_real) 1;
|
|
|
|
if (confidence_exponent == _0)
|
|
return 1;
|
|
|
|
ale_real input_scaled = input / _multiplier[k];
|
|
|
|
ale_real unexponentiated = _1 - _4 * ((_1 / _2) - input_scaled)
|
|
* ((_1 / _2) - input_scaled);
|
|
|
|
// ale_real unexponentiated = _4 * ((_1 / _4) - (ale_real) ((_1 / _2) - input_scaled)
|
|
// * ((_1 / _2) - input_scaled));
|
|
|
|
// ale_real unexponentiated = 4 * input_scaled * (0.25 - pow(0.5 - input_scaled, 2));
|
|
|
|
ale_real exponentiated;
|
|
|
|
if (confidence_exponent != _1) {
|
|
|
|
if (unexponentiated < _0)
|
|
return confidence_floor;
|
|
|
|
exponentiated = pow(unexponentiated, confidence_exponent);
|
|
|
|
} else {
|
|
exponentiated = unexponentiated;
|
|
}
|
|
|
|
if (exponentiated < confidence_floor || !finite(exponentiated))
|
|
return confidence_floor;
|
|
|
|
return exponentiated;
|
|
}
|
|
|
|
/*
|
|
* This is a very hackish confidence function. It's zero at the
|
|
* extremes of camera response and maximal at the center.
|
|
*/
|
|
virtual pixel confidence(pixel input,
|
|
ale_real confidence_floor = ale_real_confidence_floor) const {
|
|
|
|
if (confidence_exponent != 0) {
|
|
return pixel(confidence(0, input[0], confidence_floor),
|
|
confidence(1, input[1], confidence_floor),
|
|
confidence(2, input[2], confidence_floor));
|
|
} else {
|
|
return pixel(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Confidence that the real value is lower or higher than the given
|
|
* value.
|
|
*
|
|
* XXX: This function now applies the one-sided condition only to
|
|
* responses greater than 50%. Should it be called
|
|
* 'upper_one_sided_confidence' instead?
|
|
*/
|
|
virtual pixel one_sided_confidence(pixel input, pixel sign) const {
|
|
if (confidence_exponent != 0) {
|
|
pixel result = confidence(input);
|
|
for (unsigned int k = 0; k < 3; k++) {
|
|
if (sign[k] > 0 && input[k] / _multiplier[k] > 1 / (ale_real) 2)
|
|
result[k] = 1;
|
|
}
|
|
return result;
|
|
} else {
|
|
return pixel(1, 1, 1);
|
|
}
|
|
}
|
|
|
|
virtual pixel linearize(pixel input) const = 0;
|
|
virtual pixel unlinearize(pixel input) const = 0;
|
|
|
|
exposure() {
|
|
listener_head = NULL;
|
|
_multiplier = pixel(1, 1, 1);
|
|
_gain_multiplier = 1;
|
|
_black_level = 0;
|
|
}
|
|
|
|
virtual ~exposure() {
|
|
}
|
|
};
|
|
|
|
#endif
|