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 54  
55 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 58 return y * R[0] * R[1] + x * R[0] + c;
59 59 }
60 60  
... ... @@ -125,6 +125,11 @@ public:
125 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 133 stim::image<T>& operator=(const stim::image<T>& I){
129 134 init();
130 135 if(&I == this) //handle self-assignment
... ... @@ -340,7 +345,7 @@ public:
340 345  
341 346 /// Return an image representing a specified channel
342 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 349 image<T> r(X(), Y(), 1); //create a new image
345 350 for(size_t x = 0; x < X(); x++){
346 351 for(size_t y = 0; y < Y(); y++){
... ... @@ -351,7 +356,7 @@ public:
351 356 }
352 357  
353 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 360 std::vector<image<T>> r; //create an image array
356 361 r.resize(C()); //create images for each channel
357 362  
... ... @@ -361,6 +366,15 @@ public:
361 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 378 T& operator()(size_t x, size_t y, size_t c = 0){
365 379 return img[idx(x, y, c)];
366 380 }
... ... @@ -394,15 +408,15 @@ public:
394 408 }
395 409 }
396 410  
397   - size_t channels(){
  411 + size_t channels() const{
398 412 return C();
399 413 }
400 414  
401   - size_t width(){
  415 + size_t width() const{
402 416 return X();
403 417 }
404 418  
405   - size_t height(){
  419 + size_t height() const{
406 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 48 \ No newline at end of file
... ...