ref #39 smoothing is refactored
KDE smoothing algorithmisch mal geschrieben, jetzt noch testen
This commit is contained in:
188
math/boxkde/Image2D.h
Normal file
188
math/boxkde/Image2D.h
Normal file
@@ -0,0 +1,188 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "DataStructures.h"
|
||||
|
||||
enum struct LineDirection { X, Y };
|
||||
|
||||
template <typename TValue>
|
||||
struct ImageView2D
|
||||
{
|
||||
static_assert(std::is_arithmetic<TValue>::value, "Image only supports integers or floats");
|
||||
|
||||
// forward declaration
|
||||
//enum struct LineDirection;
|
||||
template<LineDirection D> struct LineView;
|
||||
template<LineDirection D> struct ConstLineView;
|
||||
|
||||
size_t width, height, size;
|
||||
protected:
|
||||
TValue* values; // contains image data row-wise
|
||||
|
||||
public:
|
||||
ImageView2D()
|
||||
: width(0), height(0), size(0), values(nullptr)
|
||||
{ }
|
||||
|
||||
ImageView2D(size_t width, size_t height)
|
||||
: width(width), height(height), size(width*height), values(nullptr)
|
||||
{ }
|
||||
|
||||
ImageView2D(size_t width, size_t height, TValue* data)
|
||||
: width(width), height(height), size(width*height), values(data)
|
||||
{ }
|
||||
|
||||
inline TValue& operator() (size_t x, size_t y) { return values[indexFromCoord(x, y)]; }
|
||||
inline const TValue& operator() (size_t x, size_t y) const { return values[indexFromCoord(x, y)]; }
|
||||
|
||||
TValue* val_begin() { return values; }
|
||||
TValue* val_end () { return values + size; }
|
||||
|
||||
const TValue* val_begin() const { return values; }
|
||||
const TValue* val_end () const { return values + size; }
|
||||
|
||||
inline size_t indexFromCoord(size_t x, size_t y) const
|
||||
{
|
||||
assertMsg(x < width && y < height, "(x,y) out of bounds");
|
||||
return y * width + x;
|
||||
}
|
||||
|
||||
Point2D<size_t> coordFromIndex(size_t index) const
|
||||
{
|
||||
assertMsg(index < size, "Index out of bounds");
|
||||
return Point2D<size_t>(index % width, index / width);
|
||||
}
|
||||
|
||||
Point2D<size_t> maximum() const
|
||||
{
|
||||
size_t maxValueIndex = std::distance(val_begin(), std::max_element(val_begin(), val_end()));
|
||||
return coordFromIndex(maxValueIndex);
|
||||
}
|
||||
|
||||
TValue maximum(Point2D<size_t>& pt) const
|
||||
{
|
||||
size_t maxValueIndex = std::distance(val_begin(), std::max_element(val_begin(), val_end()));
|
||||
pt = coordFromIndex(maxValueIndex);
|
||||
return values[maxValueIndex];
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
fill(TValue(0));
|
||||
}
|
||||
|
||||
void fill(TValue value)
|
||||
{
|
||||
std::fill(val_begin(), val_end(), value);
|
||||
}
|
||||
|
||||
void assign(const ImageView2D<TValue>& other)
|
||||
{
|
||||
assertMsg(size == other.size, "Other must be of the same size as this");
|
||||
std::copy(other.val_begin(), other.val_end(), val_begin());
|
||||
}
|
||||
|
||||
TValue sum() const
|
||||
{
|
||||
return std::accumulate(val_begin(), val_end(), TValue(0));
|
||||
}
|
||||
|
||||
// Returns a transposed view of this image without copying any data.
|
||||
ImageView2D<TValue> transpose() const
|
||||
{
|
||||
return ImageView2D<TValue>(height, width, values);
|
||||
}
|
||||
|
||||
// Returns the value at (x,y). Throws if out of bounds.
|
||||
const TValue& at(size_t x, size_t y) const
|
||||
{
|
||||
return values[indexFromCoord(x, y)];
|
||||
}
|
||||
|
||||
// Returns the value at (x,y) but falls back to default if out of bounds.
|
||||
const TValue& get(size_t x, size_t y, TValue dflt = 0) const
|
||||
{
|
||||
if (x >= width || y >= height)
|
||||
return dflt;
|
||||
else
|
||||
return values[indexFromCoord(x, y)];
|
||||
}
|
||||
|
||||
std::vector<Point2D<size_t>> findLocalMaxima(int radiusX = 1, int radiusY = 1) const
|
||||
{
|
||||
std::vector<Point2D<size_t>> result;
|
||||
findLocalMaxima(result, radiusX, radiusY);
|
||||
return result;
|
||||
}
|
||||
|
||||
void findLocalMaxima(std::vector<Point2D<size_t>>& result, int radiusX = 1, int radiusY = 1) const
|
||||
{
|
||||
assertMsg(radiusX > 0, "Search radius must be greater than 0.");
|
||||
|
||||
for (size_t y = 0; y < height; y++)
|
||||
{
|
||||
for (size_t x = 0; x < width; x++)
|
||||
{
|
||||
TValue val = at(x, y);
|
||||
bool lclMax = true;
|
||||
|
||||
for (int ry = -radiusY; ry <= radiusY; ry++)
|
||||
{
|
||||
for (int rx = -radiusX; rx <= radiusX; rx++)
|
||||
{
|
||||
TValue other = get(x + rx, y + ry);
|
||||
if (!(rx == 0 && ry == 0) && val <= other)
|
||||
{
|
||||
lclMax = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lclMax)
|
||||
{
|
||||
result.emplace_back(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class TValue>
|
||||
struct Image2D : public ImageView2D<TValue>
|
||||
{
|
||||
static_assert(std::is_arithmetic<TValue>::value, "Image only supports integers or floats");
|
||||
|
||||
std::vector<TValue> values_vec;
|
||||
|
||||
Image2D()
|
||||
{
|
||||
}
|
||||
|
||||
Image2D(size_t width, size_t height)
|
||||
: ImageView2D<TValue>(width, height), values_vec(width * height)
|
||||
{
|
||||
this->values = values_vec.data();
|
||||
}
|
||||
|
||||
Image2D(size_t width, size_t height, std::vector<TValue>& data)
|
||||
: ImageView2D<TValue>(width, height), values_vec(data)
|
||||
{
|
||||
assertMsg(data.size() == width*height, "Sizes must be the same");
|
||||
this->values = values_vec.data();
|
||||
}
|
||||
|
||||
|
||||
std::vector<TValue>& data() { return values_vec; }
|
||||
const std::vector<TValue>& data() const { return values_vec; }
|
||||
};
|
||||
|
||||
|
||||
template struct ImageView2D<float>;
|
||||
template struct ImageView2D<double>;
|
||||
|
||||
template struct Image2D<float>;
|
||||
template struct Image2D<double>;
|
||||
Reference in New Issue
Block a user