This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Indoor/math/boxkde/Image2D.h
2018-01-17 10:26:16 +01:00

188 lines
5.4 KiB
C++

#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>;