Commit 86dfa80bf728ed221ec9acc53c1b5d406248bd51

Authored by David Mayerich
1 parent dbeb83f2

added 2D gaussian filter (CPU implementation), and added the ability to split an…

…d merge stim::image by channel
Showing 2 changed files with 67 additions and 6 deletions   Show diff stats
stim/image/image.h
@@ -54,7 +54,7 @@ class image{ @@ -54,7 +54,7 @@ class image{
54 54
55 size_t bytes(){ return size() * sizeof(T); } 55 size_t bytes(){ return size() * sizeof(T); }
56 56
57 - inline size_t idx(size_t x, size_t y, size_t c = 0){ 57 + inline size_t idx(size_t x, size_t y, size_t c = 0) const {
58 return y * R[0] * R[1] + x * R[0] + c; 58 return y * R[0] * R[1] + x * R[0] + c;
59 } 59 }
60 60
@@ -125,6 +125,11 @@ public: @@ -125,6 +125,11 @@ public:
125 free(img); 125 free(img);
126 } 126 }
127 127
  128 + ///Resize an image
  129 + void resize(size_t x, size_t y, size_t c = 1) {
  130 + allocate(x, y, c);
  131 + }
  132 +
128 stim::image<T>& operator=(const stim::image<T>& I){ 133 stim::image<T>& operator=(const stim::image<T>& I){
129 init(); 134 init();
130 if(&I == this) //handle self-assignment 135 if(&I == this) //handle self-assignment
@@ -340,7 +345,7 @@ public: @@ -340,7 +345,7 @@ public:
340 345
341 /// Return an image representing a specified channel 346 /// Return an image representing a specified channel
342 /// @param c is the channel to be returned 347 /// @param c is the channel to be returned
343 - image<T> channel(size_t c){ 348 + image<T> channel(size_t c) const {
344 image<T> r(X(), Y(), 1); //create a new image 349 image<T> r(X(), Y(), 1); //create a new image
345 for(size_t x = 0; x < X(); x++){ 350 for(size_t x = 0; x < X(); x++){
346 for(size_t y = 0; y < Y(); y++){ 351 for(size_t y = 0; y < Y(); y++){
@@ -351,7 +356,7 @@ public: @@ -351,7 +356,7 @@ public:
351 } 356 }
352 357
353 /// Returns an std::vector containing each channel as a separate image 358 /// Returns an std::vector containing each channel as a separate image
354 - std::vector<image<T>> split() { 359 + std::vector<image<T>> split() const {
355 std::vector<image<T>> r; //create an image array 360 std::vector<image<T>> r; //create an image array
356 r.resize(C()); //create images for each channel 361 r.resize(C()); //create images for each channel
357 362
@@ -361,6 +366,15 @@ public: @@ -361,6 +366,15 @@ public:
361 return r; 366 return r;
362 } 367 }
363 368
  369 + /// Merge a series of single-channel images into a multi-channel image
  370 + void merge(std::vector<image<T>>& list) {
  371 + size_t x = list[0].width(); //calculate the size of the image
  372 + size_t y = list[0].height();
  373 + allocate(x, y, list.size()); //re-allocate the image
  374 + for (size_t c = 0; c < list.size(); c++) //for each channel
  375 + set_channel(list[c].channel(0).data(), c); //insert the channel into the output image
  376 + }
  377 +
364 T& operator()(size_t x, size_t y, size_t c = 0){ 378 T& operator()(size_t x, size_t y, size_t c = 0){
365 return img[idx(x, y, c)]; 379 return img[idx(x, y, c)];
366 } 380 }
@@ -394,15 +408,15 @@ public: @@ -394,15 +408,15 @@ public:
394 } 408 }
395 } 409 }
396 410
397 - size_t channels(){ 411 + size_t channels() const{
398 return C(); 412 return C();
399 } 413 }
400 414
401 - size_t width(){ 415 + size_t width() const{
402 return X(); 416 return X();
403 } 417 }
404 418
405 - size_t height(){ 419 + size_t height() const{
406 return Y(); 420 return Y();
407 } 421 }
408 422
stim/math/filters/gauss2.h 0 → 100644
  1 +#ifndef STIM_CUDA_GAUSS2_H
  2 +#define STIM_CUDA_GAUSS2_H
  3 +
  4 +#include <stim/image/image.h>
  5 +#include <stim/math/filters/sepconv2.h>
  6 +#include <stim/math/constants.h>
  7 +
  8 +namespace stim {
  9 +
  10 + template<typename T>
  11 + T gauss1d(T x, T mu, T std) {
  12 + return ((T)1 / (T)sqrt(stim::TAU * std * std) * exp(-(x - mu)*(x - mu) / (2 * std*std)));
  13 + }
  14 + ///Perform a 2D gaussian convolution on an input image.
  15 + ///@param in is a pointer to the input image
  16 + ///@param stdx is the standard deviation (in pixels) along the x axis
  17 + ///@param stdy is the standard deviation (in pixels) along the y axis
  18 + ///@param nstds specifies the number of standard deviations of the Gaussian that will be kept in the kernel
  19 + template<typename T, typename K = T>
  20 + stim::image<T> cpu_gauss2(const stim::image<T>& in, K stdx, K stdy, size_t nstds = 3) {
  21 + size_t kx = stdx * nstds * 2; //calculate the kernel sizes
  22 + size_t ky = stdy * nstds * 2;
  23 + size_t X = in.width() - kx + 1; //calculate the size of the output image
  24 + size_t Y = in.height() - ky + 1;
  25 + stim::image<T> r(X, Y, in.channels()); //create an output image
  26 +
  27 + K* gx = (K*)malloc(kx * sizeof(K)); //allocate space for the gaussian kernels
  28 + K* gy = (K*)malloc(ky * sizeof(K));
  29 + K mux = (K)kx / (K)2; //calculate the mean of the gaussian (center of the kernel)
  30 + K muy = (K)ky / (K)2;
  31 + for (size_t xi = 0; xi < kx; xi++) //evaluate the kernels
  32 + gx[xi] = gauss1d((K)xi, mux, stdx);
  33 + for (size_t yi = 0; yi < ky; yi++)
  34 + gy[yi] = gauss1d((K)yi, muy, stdy);
  35 +
  36 + std::vector<stim::image<T>> IN = in.split(); //split the input image into channels
  37 + std::vector<stim::image<T>> R = r.split(); //split the output image into channels
  38 + for (size_t c = 0; c < in.channels(); c++) //for each channel
  39 + cpu_sepconv2(R[c].data(), IN[c].data(), gx, gy, IN[c].width(), IN[c].height(), kx, ky);
  40 +
  41 + r.merge(R); //merge the blurred channels into the final image
  42 + return r;
  43 + }
  44 +}
  45 +
  46 +
  47 +#endif
0 \ No newline at end of file 48 \ No newline at end of file