Commit 86dfa80bf728ed221ec9acc53c1b5d406248bd51
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 |
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 |