#pragma once #include #include #include "BoxSizes.h" #include "Image3D.h" template struct BoxGaus3D { void boxFilter(std::vector& input, unsigned w, unsigned h, unsigned d, unsigned filterSize) { std::vector 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 in (w, h, d, input); ImageView3D out(w, h, d, output); boxBlur(in, out, radius, radius, radius); } void approxGaus(Image3D& input, _Point3 sigma, unsigned nFilt) { approxGaus(input.data(), input.getWidth(), input.getHeight(), input.getDepth(), sigma, nFilt); } void approxGaus(std::vector& input, unsigned w, unsigned h, unsigned d, _Point3 sigma, unsigned nFilt) { std::vector 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 sigma, unsigned nFilt) { ImageView3D in (w, h, d, input); ImageView3D out(w, h, d, output); approxGaus(in, out, sigma, nFilt); } void approxGaus(ImageView3D& in, ImageView3D& out, _Point3 sigma, unsigned nFilt) { BoxSizes bsX(sigma.x, nFilt); BoxSizes bsY(sigma.y, nFilt); BoxSizes 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& in, ImageView3D& 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& src, ImageView3D& 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(srcView, dstView, src.getWidth(), r, iarr); } } } void boxBlurY(const ImageView3D& src, ImageView3D& 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(srcView, dstView, src.getHeight(), r, iarr); } } } void boxBlurZ(const ImageView3D& src, ImageView3D& 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(srcView, dstView, src.getDepth(), r, iarr); } } } template void boxBlur1D(const typename ImageView3D::template ConstLineView& src, typename ImageView3D::template LineView& 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); // Ü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; } // Ü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& src, ImageView3D& dst, size_t r) { T iarr = (T)1.0 / (r + r + 1); ImageView3D buffer(src); ImageView3D 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(buffer.getHeight(), buffer.getDepth(), buffer.getWidth(), buffer.val_begin()); buffer2 = ImageView3D(buffer2.getHeight(), buffer2.getDepth(), buffer2.getWidth(), buffer2.val_begin()); buffer.swap(buffer2); } buffer.swap(dst); } void box1D(const ImageView3D& src, ImageView3D& 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); // Ü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; } // Ü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; template struct BoxGaus3D;