Added 3D boxKDE
This commit is contained in:
262
math/boxkde/BoxGaus3D.h
Normal file
262
math/boxkde/BoxGaus3D.h
Normal file
@@ -0,0 +1,262 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
#include "BoxSizes.h"
|
||||
#include "Image3D.h"
|
||||
|
||||
template <class T>
|
||||
struct BoxGaus3D
|
||||
{
|
||||
void boxFilter(std::vector<T>& input, unsigned w, unsigned h, unsigned d, unsigned filterSize)
|
||||
{
|
||||
std::vector<T> buffer(input.size());
|
||||
|
||||
boxFilter(input.data(), buffer.data(), w, h, d, filterSize);
|
||||
|
||||
input.assign(buffer.begin(), buffer.end());
|
||||
}
|
||||
|
||||
void boxFilter(T* input, T* output, unsigned w, unsigned h, unsigned d, unsigned filterSize)
|
||||
{
|
||||
assertMsg((filterSize % 2 == 1), "filterSize must be odd");
|
||||
unsigned radius = filterSize / 2;
|
||||
|
||||
ImageView3D<T> in (w, h, d, input);
|
||||
ImageView3D<T> out(w, h, d, output);
|
||||
|
||||
boxBlur(in, out, radius, radius, radius);
|
||||
}
|
||||
|
||||
void approxGaus(Image3D<T>& input, _Point3<T> sigma, unsigned nFilt)
|
||||
{
|
||||
approxGaus(input.data(), input.getWidth(), input.getHeight(), input.getDepth(), sigma, nFilt);
|
||||
}
|
||||
|
||||
void approxGaus(std::vector<T>& input, unsigned w, unsigned h, unsigned d, _Point3<T> sigma, unsigned nFilt)
|
||||
{
|
||||
std::vector<T> buffer(input.size());
|
||||
|
||||
approxGaus(input.data(), buffer.data(), w, h, d, sigma, nFilt);
|
||||
|
||||
input.assign(buffer.begin(), buffer.end());
|
||||
}
|
||||
|
||||
void approxGaus(T* input, T* output, unsigned w, unsigned h, unsigned d, _Point3<T> sigma, unsigned nFilt)
|
||||
{
|
||||
ImageView3D<T> in (w, h, d, input);
|
||||
ImageView3D<T> out(w, h, d, output);
|
||||
|
||||
approxGaus(in, out, sigma, nFilt);
|
||||
}
|
||||
|
||||
void approxGaus(ImageView3D<T>& in, ImageView3D<T>& out, _Point3<T> sigma, unsigned nFilt)
|
||||
{
|
||||
BoxSizes<T> bsX(sigma.x, nFilt);
|
||||
BoxSizes<T> bsY(sigma.y, nFilt);
|
||||
BoxSizes<T> bsZ(sigma.z, nFilt);
|
||||
|
||||
assertMsg((nFilt % 2 == 1), "nFilt must be odd");
|
||||
|
||||
// if equal, we can save some cond's inside the loop
|
||||
if (bsX.m == bsY.m && bsX.m == bsZ.m)
|
||||
{
|
||||
const size_t m = bsX.m;
|
||||
|
||||
for (size_t i = 1; i <= m; i++)
|
||||
{
|
||||
if (i % 2) {
|
||||
boxBlur(in, out, bsX.wl, bsY.wl, bsZ.wl);
|
||||
} else {
|
||||
boxBlur(out, in, bsX.wl, bsY.wl, bsZ.wl);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 1; i <= nFilt - m; i++)
|
||||
{
|
||||
if (i % 2) {
|
||||
boxBlur(in, out, bsX.wu, bsY.wu, bsZ.wu);
|
||||
} else {
|
||||
boxBlur(out, in, bsX.wu, bsY.wu, bsZ.wu);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 1; i <= nFilt; i++)
|
||||
{
|
||||
const size_t rX = (i < bsX.m ? bsX.wl : bsX.wu);
|
||||
const size_t rY = (i < bsY.m ? bsY.wl : bsY.wu);
|
||||
const size_t rZ = (i < bsZ.m ? bsZ.wl : bsZ.wu);
|
||||
|
||||
if (i % 2) {
|
||||
boxBlur(in, out, rX, rY, rZ);
|
||||
} else{
|
||||
boxBlur(out, in, rX, rY, rZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void boxBlur(ImageView3D<T>& in, ImageView3D<T>& out, size_t rX, size_t rY, size_t rZ)
|
||||
{
|
||||
//box(in, out, r);
|
||||
boxBlurX(in, out, rX);
|
||||
boxBlurY(out, in, rY);
|
||||
boxBlurZ(in, out, rZ);
|
||||
}
|
||||
|
||||
void boxBlurX(const ImageView3D<T>& src, ImageView3D<T>& dst, size_t r)
|
||||
{
|
||||
T iarr = (T)1.0 / (r + r + 1);
|
||||
|
||||
for (size_t z = 0; z < src.getDepth(); z++)
|
||||
{
|
||||
for (size_t y = 0; y < src.getHeight(); y++)
|
||||
{
|
||||
auto srcView = src.getViewYZ(y, z);
|
||||
auto dstView = dst.getViewYZ(y, z);
|
||||
|
||||
boxBlur1D<SlicePlane::YZ>(srcView, dstView, src.getWidth(), r, iarr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void boxBlurY(const ImageView3D<T>& src, ImageView3D<T>& dst, size_t r)
|
||||
{
|
||||
T iarr = (T)1.0 / (r + r + 1);
|
||||
|
||||
for (size_t x = 0; x < src.getWidth(); x++)
|
||||
{
|
||||
for (size_t z = 0; z < src.getDepth(); z++)
|
||||
{
|
||||
auto srcView = src.getViewXZ(x, z);
|
||||
auto dstView = dst.getViewXZ(x, z);
|
||||
|
||||
boxBlur1D<SlicePlane::XZ>(srcView, dstView, src.getHeight(), r, iarr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void boxBlurZ(const ImageView3D<T>& src, ImageView3D<T>& dst, size_t r)
|
||||
{
|
||||
T iarr = (T)1.0 / (r + r + 1);
|
||||
|
||||
for (size_t x = 0; x < src.getWidth(); x++)
|
||||
{
|
||||
for (size_t y = 0; y < src.getHeight(); y++)
|
||||
{
|
||||
auto srcView = src.getViewXY(x, y);
|
||||
auto dstView = dst.getViewXY(x, y);
|
||||
|
||||
boxBlur1D<SlicePlane::XY>(srcView, dstView, src.getDepth(), r, iarr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<SlicePlane S>
|
||||
void boxBlur1D(const ImageView3D<T>::ConstLineView<S>& src, ImageView3D<T>::LineView<S>& dst, size_t len, size_t r, T iarr)
|
||||
{
|
||||
size_t li = 0; // left index
|
||||
size_t ri = r; // right index
|
||||
|
||||
T fv = src(0);
|
||||
T lv = src(len - 1);
|
||||
T val = (r + 1)*fv;
|
||||
|
||||
for (size_t i = 0; i < r; i++)
|
||||
val += src(i);
|
||||
|
||||
// <20>berhangbereich links vom Bild
|
||||
for (size_t i = 0; i <= r; i++)
|
||||
{
|
||||
val += src(ri++) - fv;
|
||||
dst(i) = val*iarr;
|
||||
}
|
||||
|
||||
// Bildbereich
|
||||
for (size_t i = r + 1; i < len - r; i++)
|
||||
{
|
||||
val += src(ri++) - src(li++);
|
||||
dst(i) = val*iarr;
|
||||
}
|
||||
|
||||
// <20>berhangbereich rechts vom Bild
|
||||
for (size_t i = len - r; i < len; i++)
|
||||
{
|
||||
val += lv - src(li++);
|
||||
dst(i) = val*iarr;
|
||||
}
|
||||
}
|
||||
|
||||
void box(const ImageView3D<T>& src, ImageView3D<T>& dst, size_t r)
|
||||
{
|
||||
T iarr = (T)1.0 / (r + r + 1);
|
||||
|
||||
ImageView3D<T> buffer(src);
|
||||
ImageView3D<T> buffer2(dst.getHeight(), dst.getDepth(), dst.getWidth(), dst.val_begin());
|
||||
|
||||
for (size_t i = 0; i < 3; i++)
|
||||
{
|
||||
for (size_t idx2 = 0; idx2 < buffer.getHeight(); idx2++)
|
||||
{
|
||||
for (size_t idx3 = 0; idx3 < buffer.getDepth(); idx3++)
|
||||
{
|
||||
box1D(buffer, buffer2, buffer.getWidth(), idx2, idx3, r, iarr);
|
||||
}
|
||||
}
|
||||
|
||||
// reinteprete buffer sizes after rotation and swap data pointers
|
||||
buffer = ImageView3D<T>(buffer.getHeight(), buffer.getDepth(), buffer.getWidth(), buffer.val_begin());
|
||||
buffer2 = ImageView3D<T>(buffer2.getHeight(), buffer2.getDepth(), buffer2.getWidth(), buffer2.val_begin());
|
||||
buffer.swap(buffer2);
|
||||
}
|
||||
|
||||
buffer.swap(dst);
|
||||
}
|
||||
|
||||
void box1D(const ImageView3D<T>& src, ImageView3D<T>& dst, size_t len, size_t idx2, size_t idx3, size_t r, T iarr)
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
// dst(idx2, idx3, i) = src(i, idx2, idx3);
|
||||
|
||||
size_t li = 0; // left index
|
||||
size_t ri = r; // right index
|
||||
|
||||
T fv = src(0, idx2, idx3);
|
||||
T lv = src(len - 1, idx2, idx3);
|
||||
T val = (r + 1)*fv;
|
||||
|
||||
for (size_t i = 0; i < r; i++)
|
||||
val += src(i, idx2, idx3);
|
||||
|
||||
// <20>berhangbereich links vom Bild
|
||||
for (size_t i = 0; i <= r; i++)
|
||||
{
|
||||
val += src(ri++, idx2, idx3) - fv;
|
||||
dst(idx2, idx3, i) = val*iarr;
|
||||
}
|
||||
|
||||
// Bildbereich
|
||||
for (size_t i = r + 1; i < len - r; i++)
|
||||
{
|
||||
val += src(ri++, idx2, idx3) - src(li++, idx2, idx3);
|
||||
dst(idx2, idx3, i) = val*iarr;
|
||||
}
|
||||
|
||||
// <20>berhangbereich rechts vom Bild
|
||||
for (size_t i = len - r; i < len; i++)
|
||||
{
|
||||
val += lv - src(li++, idx2, idx3);
|
||||
dst(idx2, idx3, i) = val*iarr;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template struct BoxGaus3D<float>;
|
||||
template struct BoxGaus3D<double>;
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "DataStructures.h"
|
||||
|
||||
template<typename T>
|
||||
struct BoxSizes
|
||||
|
||||
182
math/boxkde/Grid3D.h
Normal file
182
math/boxkde/Grid3D.h
Normal file
@@ -0,0 +1,182 @@
|
||||
#pragma once
|
||||
|
||||
//#include "DataStructures.h"
|
||||
#include "Image3D.h"
|
||||
|
||||
#include "../../geo/Point3.h"
|
||||
#include "../../geo/BBox3.h"
|
||||
|
||||
template<class T>
|
||||
struct Grid3D
|
||||
{
|
||||
static_assert(std::is_floating_point<T>::value, "Grid3D only supports float values");
|
||||
|
||||
public:
|
||||
const _BBox3<T> bb;
|
||||
const size_t numBinsX, numBinsY, numBinsZ;
|
||||
const T binSizeX, binSizeY, binSizeZ;
|
||||
private:
|
||||
Image3D<T> data;
|
||||
bool empty;
|
||||
|
||||
public:
|
||||
Grid3D(_BBox3<T> bb, size_t numBinsAll)
|
||||
: Grid3D(bb, numBinsAll, numBinsAll, numBinsAll)
|
||||
{}
|
||||
|
||||
Grid3D(_BBox3<T> bb, size_t numBinsX, size_t numBinsY, size_t numBinsZ)
|
||||
: bb(bb),
|
||||
numBinsX(numBinsX),
|
||||
numBinsY(numBinsY),
|
||||
numBinsZ(numBinsZ),
|
||||
binSizeX((bb.getSize().x + 1) / numBinsX),
|
||||
binSizeY((bb.getSize().y + 1) / numBinsY),
|
||||
binSizeZ((bb.getSize().z + 1) / numBinsZ),
|
||||
data(numBinsX, numBinsY, numBinsZ),
|
||||
empty(false)
|
||||
{
|
||||
}
|
||||
|
||||
Image3D<T>& image() { return data; }
|
||||
const Image3D<T>& image() const { return data; }
|
||||
|
||||
T& operator() (size_t x, size_t y, size_t z) { return data(x, y, z); }
|
||||
const T& operator() (size_t x, size_t y, size_t z) const { return data(x, y, z); }
|
||||
|
||||
void clear() { data.clear(); }
|
||||
|
||||
void fill(const std::vector<_Point3<T>>& samples)
|
||||
{
|
||||
assertMsg(!samples.empty(), "Samples must be non-empty");
|
||||
|
||||
if (!empty)
|
||||
data.clear();
|
||||
|
||||
const T weight = T(1.0) / samples.size();
|
||||
for (const auto& pt : samples)
|
||||
{
|
||||
add(pt.x, pt.y, pt.z, weight);
|
||||
}
|
||||
|
||||
empty = false;
|
||||
}
|
||||
|
||||
void fill(const std::vector<_Point3<T>>& samples, const std::vector<T>& weights)
|
||||
{
|
||||
assertMsg(!samples.empty(), "Samples must be non-empty");
|
||||
assertMsg(weights.size() == samples.size(), "Weights must have the same size as samples");
|
||||
|
||||
if (!empty)
|
||||
data.clear();
|
||||
|
||||
for (size_t i = 0; i < samples.size(); i++)
|
||||
{
|
||||
add(samples[i].x, samples[i].y, samples[i].z, weights[i]);
|
||||
}
|
||||
|
||||
empty = false;
|
||||
}
|
||||
|
||||
_Point3<size_t> add(_Point3<T> pt, T w)
|
||||
{
|
||||
return add(pt.x, pt.y, pt.z, w);
|
||||
}
|
||||
|
||||
_Point3<size_t> add(T x, T y, T z, T w)
|
||||
{
|
||||
if (assertCond(bb.contains(_Point3<T>(x, y, z))))
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Point " << "(" << x << "; " << y << "; " << z << ")" << " is out of bounds: "
|
||||
<< "(X: " << bb.getMin().x << " - " << bb.getMax().x << ";"
|
||||
<< " Y: " << bb.getMin().y << " - " << bb.getMax().y << ";"
|
||||
<< " Z: " << bb.getMin().z << " - " << bb.getMax().z << ")";
|
||||
assertThrow(ss.str());
|
||||
}
|
||||
return add_simple_bin(x, y, z, w);
|
||||
}
|
||||
|
||||
T fetch(T x, T y, T z) const
|
||||
{
|
||||
size_t bin_x = (size_t)((x - bb.getMin().x) / binSizeX);
|
||||
size_t bin_y = (size_t)((y - bb.getMin().y) / binSizeY);
|
||||
size_t bin_z = (size_t)((z - bb.getMin().z) / binSizeZ);
|
||||
|
||||
return data(bin_x, bin_y, bin_z);
|
||||
}
|
||||
|
||||
T maximum(_Point3<T>& pt) const
|
||||
{
|
||||
_Point3<size_t> gridPt;
|
||||
|
||||
T maxValue = image().maximum(gridPt);
|
||||
pt = asInputSpace(gridPt);
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
|
||||
// // Takes a point in input space and converts it to grid space coordinates
|
||||
//_Point3<size_t> asGridSpace(T x, T y, T z) const
|
||||
// {
|
||||
// size_t bin_x = (size_t)((x - bb.MinX) / binSizeX);
|
||||
// size_t bin_y = (size_t)((y - bb.MinY) / binSizeY);
|
||||
// size_t bin_z = (size_t)((z - bb.MinZ) / binSizeZ);
|
||||
|
||||
// if (bin_x == data.width) bin_x--;
|
||||
// if (bin_y == data.height) bin_y--;
|
||||
// if (bin_z == data.depth) bin_z--;
|
||||
|
||||
// return Point3D<size_t>(bin_x, bin_y, bin_z);
|
||||
// }
|
||||
|
||||
// // Takes a Size2D in input space and converts it to grid space coordiantes
|
||||
//_Point3<size_t> asGridSpace(Size3D<T> sz) const
|
||||
// {
|
||||
// return _Point3<size_t>(sz.sX / binSizeX, sz.sY / binSizeY, sz.sZ / binSizeZ);
|
||||
// }
|
||||
|
||||
// // Takes a Range2D in input space and converts it to grid space coordinates
|
||||
// Range3D<size_t> asGridSpace(Range3D<T> range) const
|
||||
// {
|
||||
// Point3D<size_t> startPt = asGridSpace(range.X.Start, range.Y.Start, range.Z.Start);
|
||||
|
||||
// size_t lengthX = range.X.Length / binSizeX;
|
||||
// size_t lengthY = range.Y.Length / binSizeY;
|
||||
// size_t lengthZ = range.Z.Length / binSizeZ;
|
||||
|
||||
// return Range3D<size_t>(startPt.X, lengthX, startPt.Y, lengthY, startPt.Z, lengthZ);
|
||||
// }
|
||||
|
||||
// Takes a point in grid space and converts it to input space coordinates
|
||||
_Point3<T> asInputSpace(_Point3<size_t> pt) const
|
||||
{
|
||||
return asInputSpace(pt.x, pt.y, pt.z);
|
||||
}
|
||||
|
||||
// Takes a point in grid space and converts it to input space coordinates
|
||||
_Point3<T> asInputSpace(size_t x, size_t y, size_t z) const
|
||||
{
|
||||
return _Point3<T>(x * binSizeX + bb.getMin().x + T(0.5)*binSizeX,
|
||||
y * binSizeY + bb.getMin().y + T(0.5)*binSizeY,
|
||||
z * binSizeZ + bb.getMin().z + T(0.5)*binSizeZ);
|
||||
}
|
||||
|
||||
private:
|
||||
_Point3<size_t> add_simple_bin(T x, T y, T z, T w)
|
||||
{
|
||||
size_t bin_x = (size_t)((x - bb.getMin().x) / binSizeX);
|
||||
size_t bin_y = (size_t)((y - bb.getMin().y) / binSizeY);
|
||||
size_t bin_z = (size_t)((z - bb.getMin().z) / binSizeZ);
|
||||
|
||||
//if (bin_x == data.width) bin_x--;
|
||||
//if (bin_y == data.height) bin_y--;
|
||||
//if (bin_z == data.depth) bin_z--;
|
||||
|
||||
data(bin_x, bin_y, bin_z) += w;
|
||||
|
||||
return _Point3<size_t>(bin_x, bin_y, bin_z);
|
||||
}
|
||||
};
|
||||
|
||||
template struct Grid3D<float>;
|
||||
template struct Grid3D<double>;
|
||||
208
math/boxkde/Image3D.h
Normal file
208
math/boxkde/Image3D.h
Normal file
@@ -0,0 +1,208 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
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>;
|
||||
Reference in New Issue
Block a user