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/Image3D.h

230 lines
7.1 KiB
C++

#pragma once
#include <cassert>
#include <numeric>
#include <vector>
#include "../../geo/Point3.h"
enum struct SlicePlane { XY, XZ, YZ };
template <class TValue>
struct ImageView3D
{
static_assert(std::is_arithmetic<TValue>::value, "ImageView3D only supports integers or floats");
// forward declaration
template<SlicePlane S> struct LineView;
template<SlicePlane S> struct ConstLineView;
private:
size_t width, height, depth, size; // TODO private
protected:
TValue* values; // contains image data row-wise
public:
ImageView3D()
: width(0), height(0), depth(0), size(0), values(nullptr)
{
}
ImageView3D(size_t width, size_t height, size_t depth)
: width(width), height(height), depth(depth), size(width*height*depth), values(nullptr)
{
}
ImageView3D(size_t width, size_t height, size_t depth, TValue* data)
: width(width), height(height), depth(depth), size(width*height*depth), values(data)
{
}
TValue& operator() (size_t x, size_t y, size_t z) { return values[indexFromCoord(x, y, z)]; }
const TValue& operator() (size_t x, size_t y, size_t z) const { return values[indexFromCoord(x, y, z)]; }
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; }
size_t getWidth() const { return width; }
size_t getHeight() const { return height; }
size_t getDepth() const { return depth; }
size_t indexFromCoord(size_t x, size_t y, size_t z) const
{
assertMsg(x < width && y < height && z < depth, "(x,y,z) out of bounds");
return z*width*height + y*width + x;
}
_Point3<size_t> coordFromIndex(size_t index) const
{
assertMsg(index < size, "Index out of bounds");
size_t z = index / (width*height);
size_t y = (index - z*width*height) / width;
size_t x = index - y*width - z*width*height;
return _Point3<size_t>(x, y, z);
}
TValue minimum() const
{
size_t minValueIndex = std::distance(val_begin(), std::min_element(val_begin(), val_end()));
return values[minValueIndex];
}
_Point3<size_t> maximum() const
{
size_t maxValueIndex = std::distance(val_begin(), std::max_element(val_begin(), val_end()));
return coordFromIndex(maxValueIndex);
}
TValue maximum(_Point3<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()
{
std::fill(val_begin(), val_end(), TValue(0));
}
void assign(const ImageView3D<TValue>& other)
{
assertMsg(size == other.size, "Other must be of 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));
}
void swap(ImageView3D<TValue>& other)
{
TValue* tmp = other.values;
other.values = this->values;
this->values = tmp;
}
// Returns the value at (x,y). Throws if out of bounds.
const TValue& at(size_t x, size_t y, size_t z) const
{
return values[indexFromCoord(x, y, z)];
}
// Returns the value at (x,y) but falls back to default if out of bounds.
const TValue& get(size_t x, size_t y, size_t z, TValue dflt = 0) const
{
if (x >= width || y >= height || z >= depth)
return dflt;
else
return values[indexFromCoord(x, y, z)];
}
public:
typedef LineView<SlicePlane::XY> LineViewXY;
typedef LineView<SlicePlane::XZ> LineViewXZ;
typedef LineView<SlicePlane::YZ> LineViewYZ;
typedef ConstLineView<SlicePlane::XY> ConstLineViewXY;
typedef ConstLineView<SlicePlane::XZ> ConstLineViewXZ;
typedef ConstLineView<SlicePlane::YZ> ConstLineViewYZ;
LineViewXY getViewXY(size_t fixedX, size_t fixedY) { return LineViewXY(*this, fixedX, fixedY); }
LineViewXZ getViewXZ(size_t fixedX, size_t fixedZ) { return LineViewXZ(*this, fixedX, fixedZ); }
LineViewYZ getViewYZ(size_t fixedY, size_t fixedZ) { return LineViewYZ(*this, fixedY, fixedZ); }
ConstLineViewXY getViewXY(size_t fixedX, size_t fixedY) const { return ConstLineViewXY(*this, fixedX, fixedY); }
ConstLineViewXZ getViewXZ(size_t fixedX, size_t fixedZ) const { return ConstLineViewXZ(*this, fixedX, fixedZ); }
ConstLineViewYZ getViewYZ(size_t fixedY, size_t fixedZ) const { return ConstLineViewYZ(*this, fixedY, fixedZ); }
template<SlicePlane S>
struct LineView
{
size_t fixIdx1, fixIdx2;
ImageView3D<TValue>& img;
LineView(ImageView3D<TValue>& img, size_t fixedIndex1, size_t fixedIndex2)
: fixIdx1(fixedIndex1), fixIdx2(fixedIndex2), img(img)
{}
TValue& operator() (size_t idx)
{
switch (S)
{
case SlicePlane::XY: return img(fixIdx1, fixIdx2, idx);
case SlicePlane::XZ: return img(fixIdx1, idx, fixIdx2);
case SlicePlane::YZ: return img(idx, fixIdx1, fixIdx2);
default: assert(false); abort();
}
}
};
template<SlicePlane S>
struct ConstLineView
{
size_t fixIdx1, fixIdx2;
const ImageView3D<TValue>& img;
ConstLineView(const ImageView3D<TValue>& img, size_t fixedIndex1, size_t fixedIndex2)
: fixIdx1(fixedIndex1), fixIdx2(fixedIndex2), img(img)
{}
const TValue& operator() (size_t idx)
{
switch (S)
{
case SlicePlane::XY: return img(fixIdx1, fixIdx2, idx);
case SlicePlane::XZ: return img(fixIdx1, idx, fixIdx2);
case SlicePlane::YZ: return img(idx, fixIdx1, fixIdx2);
default: assert(false); abort();
}
}
const TValue& operator() (size_t idx) const
{
switch (S)
{
case SlicePlane::XY: return img(fixIdx1, fixIdx2, idx);
case SlicePlane::XZ: return img(fixIdx1, idx, fixIdx2);
case SlicePlane::YZ: return img(idx, fixIdx1, fixIdx2);
default: assert(false); abort();
}
}
};
};
template <class TValue>
struct Image3D : public ImageView3D<TValue>
{
std::vector<TValue> values_vec;
public:
Image3D(size_t width, size_t height, size_t depth)
: ImageView3D<TValue>(width, height, depth), values_vec(width * height * depth)
{
this->values = values_vec.data();
}
Image3D(size_t width, size_t height, size_t depth, std::vector<TValue>& data)
: ImageView3D<TValue>(width, height, depth), values_vec(data)
{
assertMsg(data.size() == width*height*depth, "Data must be of the same size as this");
this->values = values_vec.data();
}
std::vector<TValue>& data() { return values_vec; }
const std::vector<TValue>& data() const { return values_vec; }
};
template struct ImageView3D<float>;
//template struct ImageView3D<double>;
template struct Image3D<float>;
//template struct Image3D<double>;