mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-08 04:31:08 -06:00
345 lines
11 KiB
C++
345 lines
11 KiB
C++
/*****************************************************************************************
|
|
* *
|
|
* OpenSpace *
|
|
* *
|
|
* Copyright (c) 2014-2022 *
|
|
* *
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
|
* software and associated documentation files (the "Software"), to deal in the Software *
|
|
* without restriction, including without limitation the rights to use, copy, modify, *
|
|
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
|
* permit persons to whom the Software is furnished to do so, subject to the following *
|
|
* conditions: *
|
|
* *
|
|
* The above copyright notice and this permission notice shall be included in all copies *
|
|
* or substantial portions of the Software. *
|
|
* *
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
|
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
|
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
|
****************************************************************************************/
|
|
|
|
#include <openspace/util/histogram.h>
|
|
|
|
#include <ghoul/logging/logmanager.h>
|
|
#include <ghoul/misc/assert.h>
|
|
#include <cmath>
|
|
|
|
namespace {
|
|
constexpr const char* _loggerCat = "Histogram";
|
|
} // namespace
|
|
|
|
namespace openspace {
|
|
|
|
Histogram::Histogram(float minValue, float maxValue, int numBins, float* data)
|
|
: _numBins(numBins)
|
|
, _minValue(minValue)
|
|
, _maxValue(maxValue)
|
|
, _data(data)
|
|
{
|
|
if (!data) {
|
|
_data = new float[numBins];
|
|
for (int i = 0; i < numBins; ++i) {
|
|
_data[i] = 0.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
Histogram::~Histogram() {
|
|
delete[] _data;
|
|
}
|
|
|
|
int Histogram::numBins() const {
|
|
return _numBins;
|
|
}
|
|
|
|
float Histogram::minValue() const {
|
|
return _minValue;
|
|
}
|
|
|
|
float Histogram::maxValue() const {
|
|
return _maxValue;
|
|
}
|
|
|
|
bool Histogram::isValid() const {
|
|
return _numBins != -1;
|
|
}
|
|
|
|
bool Histogram::add(float value, float repeat) {
|
|
if (value < _minValue || value > _maxValue) {
|
|
// Out of range
|
|
return false;
|
|
}
|
|
|
|
const float normalizedValue = (value - _minValue) / (_maxValue - _minValue);
|
|
const int binIndex = static_cast<int>(std::min(
|
|
static_cast<float>(floor(normalizedValue * _numBins)),
|
|
_numBins - 1.f
|
|
)); // [0, _numBins - 1]
|
|
|
|
_data[binIndex] += repeat;
|
|
_numValues = static_cast<int>(_numValues + repeat);
|
|
|
|
return true;
|
|
}
|
|
|
|
void Histogram::changeRange(float minValue, float maxValue){
|
|
if (minValue > _minValue && maxValue < _maxValue) {
|
|
return;
|
|
}
|
|
|
|
float* oldData = _data;
|
|
float oldMin = _minValue;
|
|
float oldMax = _maxValue;
|
|
|
|
float* newData = new float[_numBins]{0.0};
|
|
for(int i=0; i<_numBins; i++){
|
|
float unNormalizedValue = i*(oldMax-oldMin)+oldMin;
|
|
float normalizedValue = (unNormalizedValue - _minValue) /
|
|
(_maxValue - _minValue); // [0.0, 1.0]
|
|
int binIndex = static_cast<int>(std::min(
|
|
static_cast<float>(floor(normalizedValue * _numBins)),
|
|
_numBins - 1.f
|
|
)); // [0, _numBins - 1]
|
|
|
|
newData[binIndex] = oldData[i];
|
|
}
|
|
|
|
_data = newData;
|
|
delete oldData;
|
|
|
|
_minValue = minValue;
|
|
_maxValue = maxValue;
|
|
|
|
}
|
|
|
|
bool Histogram::add(const Histogram& histogram) {
|
|
if (_minValue == histogram.minValue() &&
|
|
_maxValue == histogram.maxValue() &&
|
|
_numBins == histogram.numBins())
|
|
{
|
|
const float* data = histogram.data();
|
|
for (int i = 0; i < _numBins; i++) {
|
|
_data[i] += data[i];
|
|
}
|
|
_numValues += histogram._numValues;
|
|
return true;
|
|
}
|
|
else {
|
|
LERROR("Dimension mismatch");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Histogram::addRectangle(float lowBin, float highBin, float value) {
|
|
if (lowBin == highBin) {
|
|
return true;
|
|
}
|
|
|
|
if (lowBin > highBin) {
|
|
std::swap(lowBin, highBin);
|
|
}
|
|
if (lowBin < _minValue || highBin > _maxValue) {
|
|
// Out of range
|
|
return false;
|
|
}
|
|
|
|
const float normalizedLowBin = (lowBin - _minValue) / (_maxValue - _minValue);
|
|
const float normalizedHighBin = (highBin - _minValue) / (_maxValue - _minValue);
|
|
|
|
const float lowBinIndex = normalizedLowBin * _numBins;
|
|
const float highBinIndex = normalizedHighBin * _numBins;
|
|
|
|
const int fillLow = static_cast<int>(floor(lowBinIndex));
|
|
const int fillHigh = static_cast<int>(ceil(highBinIndex));
|
|
|
|
for (int i = fillLow; i < fillHigh; i++) {
|
|
_data[i] += value;
|
|
}
|
|
|
|
if (lowBinIndex > fillLow) {
|
|
const float diff = lowBinIndex - fillLow;
|
|
_data[fillLow] -= diff * value;
|
|
}
|
|
if (highBinIndex < fillHigh) {
|
|
const float diff = -highBinIndex + fillHigh;
|
|
_data[fillHigh - 1] -= diff * value;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
float Histogram::interpolate(float bin) const {
|
|
const float normalizedBin = (bin - _minValue) / (_maxValue - _minValue);
|
|
const float binIndex = normalizedBin * _numBins - 0.5f; // Center
|
|
|
|
const float interpolator = binIndex - floor(binIndex);
|
|
int binLow = static_cast<int>(floor(binIndex));
|
|
int binHigh = static_cast<int>(ceil(binIndex));
|
|
|
|
// Clamp bins
|
|
if (binLow < 0) {
|
|
binLow = 0;
|
|
}
|
|
if (binHigh >= _numBins) {
|
|
binHigh = _numBins - 1;
|
|
}
|
|
|
|
return (1.f - interpolator) * _data[binLow] + interpolator * _data[binHigh];
|
|
}
|
|
|
|
float Histogram::sample(int binIndex) const {
|
|
ghoul_assert(binIndex >= 0 && binIndex < _numBins, "binIndex out of range");
|
|
|
|
return _data[binIndex];
|
|
}
|
|
|
|
const float* Histogram::data() const {
|
|
return _data;
|
|
}
|
|
|
|
std::vector<std::pair<float,float>> Histogram::getDecimated(int) const {
|
|
// Return a copy of _data decimated as in Ljung 2004
|
|
return std::vector<std::pair<float,float>>();
|
|
}
|
|
|
|
void Histogram::normalize() {
|
|
float sum = 0.0;
|
|
for (int i = 0; i < _numBins; i++) {
|
|
sum += _data[i];
|
|
}
|
|
for (int i = 0; i < _numBins; i++) {
|
|
_data[i] /= sum;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Will create an internal array for histogram equalization.
|
|
* Old histogram value is the index of the array, and the new equalized
|
|
* value will be the value at the index.
|
|
*/
|
|
void Histogram::generateEqualizer() {
|
|
float previousCdf = 0.0f;
|
|
_equalizer = std::vector<float>(_numBins, 0.0f);
|
|
for (int i = 0; i < _numBins; i++) {
|
|
const float probability = _data[i] / static_cast<float>(_numValues);
|
|
const float cdf = std::min(1.0f, previousCdf + probability);
|
|
_equalizer[i] = cdf * (_numBins-1);
|
|
previousCdf = cdf;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Will return a equalized histogram
|
|
*/
|
|
Histogram Histogram::equalize() {
|
|
Histogram equalizedHistogram(_minValue, _maxValue, _numBins);
|
|
|
|
for (int i = 0; i < _numBins; i++) {
|
|
equalizedHistogram._data[static_cast<int>(_equalizer[i])] += _data[i];
|
|
}
|
|
equalizedHistogram._numValues = _numValues;
|
|
return equalizedHistogram;
|
|
}
|
|
|
|
/*
|
|
* Given a value within the domain of this histogram (_minValue < value < maxValue),
|
|
* this method will use its equalizer to return a histogram equalized result.
|
|
*/
|
|
float Histogram::equalize(float value) const {
|
|
// if (value < _minValue || value > _maxValue) {
|
|
// LWARNING(
|
|
// "Equalized value is is not within domain of histogram. min: " +
|
|
// std::to_string(_minValue) + " max: " + std::to_string(_maxValue) +
|
|
// " val: " + std::to_string(value)
|
|
// );
|
|
// }
|
|
float normalizedValue = (value-_minValue)/(_maxValue-_minValue);
|
|
int bin = static_cast<int>(floor(normalizedValue * _numBins));
|
|
// If value == _maxValues then bin == _numBins, which is a invalid index.
|
|
bin = std::min(_numBins-1, bin);
|
|
bin = std::max(0, bin);
|
|
|
|
return _equalizer[bin];
|
|
}
|
|
|
|
float Histogram::entropy() {
|
|
float entropy = 0.f;
|
|
for (int i = 0; i < _numBins; ++i) {
|
|
if (_data[i] != 0) {
|
|
entropy -= (_data[i] / static_cast<float>(_numValues)) *
|
|
(log2(_data[i]) / static_cast<float>(_numValues));
|
|
}
|
|
}
|
|
return entropy;
|
|
}
|
|
|
|
std::vector<char> Histogram::getBinaryData() const {
|
|
std::vector<char> dataVector(
|
|
reinterpret_cast<char*>(_data),
|
|
reinterpret_cast<char*>(_data + _numValues)
|
|
);
|
|
return dataVector;
|
|
}
|
|
|
|
void Histogram::print() const {
|
|
//for (int i = 0; i < _numBins; i++) {
|
|
// //float low = _minValue + float(i) / _numBins * (_maxValue - _minValue);
|
|
// //float high = low + (_maxValue - _minValue) / float(_numBins);
|
|
// // std::cout << i << " [" << low << ", " << high << "]"
|
|
// // << " " << _data[i] << std::endl;
|
|
// std::cout << _data[i]/static_cast<float>(_numValues) << ", ";
|
|
//}
|
|
//std::cout << std::endl;
|
|
//// std::cout << std::endl << std::endl << std::endl<< "==============" << std::endl;
|
|
}
|
|
|
|
float Histogram::highestBinValue(bool equalized, int overBins){
|
|
int highestBin = 0;
|
|
float highestValue = 0;
|
|
|
|
for (int i = 0; i < _numBins; i++) {
|
|
float value = 0;
|
|
int num = 0;
|
|
for (int j=0; j<overBins; j++) {
|
|
if (i - j > 0) {
|
|
value += _data[i-j];
|
|
num++;
|
|
}
|
|
if (i + j < _numBins) {
|
|
value += _data[i+j];
|
|
num++;
|
|
}
|
|
}
|
|
|
|
value += _data[i];
|
|
value /= static_cast<float>(++num);
|
|
|
|
if (value > highestValue) {
|
|
highestBin = i;
|
|
highestValue = value;
|
|
}
|
|
}
|
|
|
|
|
|
if (!equalized) {
|
|
float low = _minValue + static_cast<float>(highestBin) /
|
|
_numBins * (_maxValue - _minValue);
|
|
float high = low + (_maxValue - _minValue) / static_cast<float>(_numBins);
|
|
return (high+low) / 2.f;
|
|
}
|
|
else {
|
|
return highestBin / static_cast<float>(_numBins);
|
|
// return equalize((high+low)/2.0);
|
|
}
|
|
}
|
|
|
|
float Histogram::binWidth() {
|
|
return (_maxValue - _minValue) / _numBins;
|
|
}
|
|
|
|
} // namespace openspace
|