Commit 018b00d675350835a968dba69361027a39b9f3b7
1 parent
85025dd1
adapted bsds500 files to the stim library, tested cPb
Showing
12 changed files
with
805 additions
and
0 deletions
Show diff stats
1 | +#ifndef STIM_CUDA_ARRAY_ATAN2_H | ||
2 | +#define STIM_CUDA_ARRAY_ATAN2_H | ||
3 | + | ||
4 | +#include <iostream> | ||
5 | +#include <cuda.h> | ||
6 | +#include <cmath> | ||
7 | +#include <stim/cuda/cudatools.h> | ||
8 | + | ||
9 | +namespace stim{ | ||
10 | + namespace cuda{ | ||
11 | + | ||
12 | + template<typename T> | ||
13 | + __global__ void cuda_atan2(T* y, T* x, T* r, unsigned int N){ | ||
14 | + | ||
15 | + //calculate the 1D index for this thread | ||
16 | + int idx = blockIdx.x * blockDim.x + threadIdx.x; | ||
17 | + | ||
18 | + if(idx < N){ | ||
19 | + r[idx] = atan2(y[idx], x[idx]); | ||
20 | + } | ||
21 | + | ||
22 | + } | ||
23 | + | ||
24 | + template<typename T> | ||
25 | + void gpu_atan2(T* y, T* x, T* r, unsigned int N){ | ||
26 | + | ||
27 | + //get the maximum number of threads per block for the CUDA device | ||
28 | + int threads = stim::maxThreadsPerBlock(); | ||
29 | + | ||
30 | + //calculate the number of blocks | ||
31 | + int blocks = N / threads + 1; | ||
32 | + | ||
33 | + //call the kernel to do the multiplication | ||
34 | + cuda_atan2 <<< blocks, threads >>>(y, x, r, N); | ||
35 | + | ||
36 | + } | ||
37 | + | ||
38 | + template<typename T> | ||
39 | + void cpu_atan2(T* y, T* x, T* cpu_r, unsigned int N){ | ||
40 | + | ||
41 | + //allocate memory on the GPU for the array | ||
42 | + T* gpu_x; | ||
43 | + T* gpu_y; | ||
44 | + T* gpu_r; | ||
45 | + HANDLE_ERROR( cudaMalloc( &gpu_x, N * sizeof(T) ) ); | ||
46 | + HANDLE_ERROR( cudaMalloc( &gpu_y, N * sizeof(T) ) ); | ||
47 | + HANDLE_ERROR( cudaMalloc( &gpu_r, N * sizeof(T) ) ); | ||
48 | + | ||
49 | + //copy the array to the GPU | ||
50 | + HANDLE_ERROR( cudaMemcpy( gpu_x, x, N * sizeof(T), cudaMemcpyHostToDevice) ); | ||
51 | + HANDLE_ERROR( cudaMemcpy( gpu_y, y, N * sizeof(T), cudaMemcpyHostToDevice) ); | ||
52 | + | ||
53 | + //call the GPU version of this function | ||
54 | + gpu_atan2<T>(gpu_y, gpu_x ,gpu_r, N); | ||
55 | + | ||
56 | + //copy the array back to the CPU | ||
57 | + HANDLE_ERROR( cudaMemcpy( cpu_r, gpu_r, N * sizeof(T), cudaMemcpyDeviceToHost) ); | ||
58 | + | ||
59 | + //free allocated memory | ||
60 | + cudaFree(gpu_x); | ||
61 | + cudaFree(gpu_y); | ||
62 | + cudaFree(gpu_r); | ||
63 | + | ||
64 | + } | ||
65 | + | ||
66 | + } | ||
67 | +} | ||
68 | + | ||
69 | + | ||
70 | + | ||
71 | +#endif | ||
0 | \ No newline at end of file | 72 | \ No newline at end of file |
1 | +#ifndef STIM_CUDA_PB_CUH | ||
2 | +#define STIM_CUDA_PB_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +//#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | + | ||
9 | +#include "dG1_conv2.cuh" | ||
10 | +#include <stim/cuda/arraymath/array_abs.cuh> | ||
11 | +#include <stim/cuda/arraymath/array_divide.cuh> | ||
12 | +#include <stim/cuda/arraymath/array_atan.cuh> | ||
13 | +#include <stim/cuda/arraymath/array_atan2.cuh> | ||
14 | +#include <stim/cuda/arraymath/array_cos.cuh> | ||
15 | +#include <stim/cuda/arraymath/array_sin.cuh> | ||
16 | +#include <stim/cuda/arraymath/array_multiply.cuh> | ||
17 | +#include <stim/cuda/arraymath/array_add.cuh> | ||
18 | + | ||
19 | + | ||
20 | + | ||
21 | + | ||
22 | + | ||
23 | + | ||
24 | +#define SIGMA_N 3 | ||
25 | + | ||
26 | +//void array_abs(float* img, unsigned int N); | ||
27 | +//void array_multiply(float* lhs, float rhs, unsigned int N); | ||
28 | +//void array_cos(float* ptr1, float* cpu_out, unsigned int N); | ||
29 | +//void array_sin(float* ptr1, float* cpu_out, unsigned int N); | ||
30 | +//void array_atan(float* ptr1, float* cpu_out, unsigned int N); | ||
31 | +//void array_divide(float* ptr1, float* ptr2,float* cpu_quotient, unsigned int N); | ||
32 | +//void array_multiply(float* ptr1, float* ptr2, float* product, unsigned int N); | ||
33 | +//void array_add(float* ptr1, float* ptr2, float* sum, unsigned int N); | ||
34 | + | ||
35 | +/// This function uses odd-symmetric gaussian derivative filter to evaluate | ||
36 | +/// the max probability of a contour on one scale, given an one-channel image | ||
37 | + | ||
38 | +/// @param img is an one-channel image | ||
39 | +/// @param r is an array of radii for different scaled discs(filters) | ||
40 | +/// @param sigma_n is the number of standard deviations used to define the sigma | ||
41 | + | ||
42 | +stim::image<float> Pb(stim::image<float> image, int sigma){ | ||
43 | + | ||
44 | + unsigned int w = image.width(); // get the width of picture | ||
45 | + unsigned int h = image.height(); // get the height of picture | ||
46 | + unsigned N = w * h; // get the number of pixels of picture | ||
47 | + | ||
48 | + stim::image<float> I(w, h, 1, 2); // allocate space for return image of dG1_conv2 | ||
49 | + stim::image<float> theta(w, h); // allocate space for theta matrix | ||
50 | + stim::image<float> cos(w, h); // allocate space for cos(theta) | ||
51 | + stim::image<float> sin(w, h); // allocate space for sin(theta) | ||
52 | + stim::image<float> temp(w, h); // allocate space for temp | ||
53 | + stim::image<float> Ix(w, h); // allocate space for Ix | ||
54 | + stim::image<float> Iy(w, h); // allocate space for Iy | ||
55 | + stim::image<float> Pb(w, h); // allocate space for Pb | ||
56 | + | ||
57 | + I = dG1_conv2(image, sigma); // calculate the Ix, Iy | ||
58 | + Ix = I.channel(0); | ||
59 | + stim::cuda::cpu_abs(Ix.data(), N); //get |Ix|; | ||
60 | + //stim::cpu2image(Ix.data(), "data_output/Pb_Ix_0924.bmp", w, h, stim::cmBrewer); | ||
61 | + Iy = I.channel(1); | ||
62 | + stim::cuda::cpu_abs(Iy.data(), N); //get |Iy|; | ||
63 | + //stim::cpu2image(Iy.data(), "data_output/Pb_Iy_0924.bmp", w, h, stim::cmBrewer); | ||
64 | + | ||
65 | + //stim::cuda::cpu_divide(Iy.data(), Ix.data(), theta.data(), N); //temp = Iy./Ix | ||
66 | + stim::cuda::cpu_atan2(Iy.data(), Ix.data(), theta.data(), N); //temp = Iy./Ix | ||
67 | + //stim::cuda::cpu_atan(temp.data(), theta.data(), N); //theta = atan(temp) | ||
68 | + stim::cuda::cpu_cos(theta.data(), cos.data(), N); //cos = cos(theta) | ||
69 | + stim::cuda::cpu_sin(theta.data(), sin.data(), N); //sin = sin(theta) | ||
70 | + stim::cuda::cpu_multiply(Ix.data(), cos.data(), Ix.data(), N); //Ix = Ix.*cos | ||
71 | + stim::cuda::cpu_multiply(Iy.data(), sin.data(), Iy.data(), N); //Iy = Iy.*sin | ||
72 | + stim::cuda::cpu_add(Ix.data(), Iy.data(), Pb.data(), N); //Pb = Ix + Iy; | ||
73 | + | ||
74 | + float max = Pb.maxv(); // get the maximum of Pb used for normalization | ||
75 | + stim::cuda::cpu_multiply(Pb.data(), 1/max, N); // normalize the Pb | ||
76 | + | ||
77 | + //stim::cpu2image(Pb.data(), "data_output/Pb_0924.bmp", w, h, stim::cmBrewer); show the Pb(optional) | ||
78 | + | ||
79 | + return Pb; | ||
80 | + | ||
81 | +} | ||
82 | + | ||
83 | +#endif |
1 | +#ifndef STIM_CUDA_CPB_CUH | ||
2 | +#define STIM_CUDA_CPB_CUH | ||
3 | + | ||
4 | +#include <cmath> | ||
5 | +#include <sstream> | ||
6 | + | ||
7 | +#include <stim/image/image.h> | ||
8 | +#include <stim/visualization/colormap.h> | ||
9 | +#include <stim/cuda/arraymath/array_multiply.cuh> | ||
10 | +#include <stim/cuda/arraymath/array_add.cuh> | ||
11 | + | ||
12 | +//BSDS500 files | ||
13 | +#include "Pb.cuh" | ||
14 | + | ||
15 | +//void array_multiply(float* lhs, float rhs, unsigned int N); | ||
16 | +//void array_add(float* ptr1, float* ptr2, float* sum, unsigned int N); | ||
17 | + | ||
18 | +/// This function evaluates the cPb given an multi-channel image | ||
19 | + | ||
20 | +/// @param img is the multi-channel image | ||
21 | +/// @param r is an array of radii for different scaled discs(filters) | ||
22 | +/// @param alpha is is an array of weights for different scaled discs(filters) | ||
23 | +/// @param s is the number of scales | ||
24 | + | ||
25 | +stim::image<float> cPb(stim::image<float> img, int* sigma, float* alpha, int s){ | ||
26 | + | ||
27 | + unsigned int w = img.width(); // get the width of picture | ||
28 | + unsigned int h = img.height(); // get the height of picture | ||
29 | + unsigned int c = img.channels(); // get the channels of picture | ||
30 | + | ||
31 | + | ||
32 | + stim::image<float> cPb(w, h, 1); // allocate space for cPb | ||
33 | + unsigned size = cPb.size(); // get the size of cPb | ||
34 | + memset ( cPb.data(), 0, size * sizeof(float)); // initialize all the pixels of cPb to 0 | ||
35 | + | ||
36 | + | ||
37 | + unsigned int N = w * h; // get the number of pixels | ||
38 | + | ||
39 | + //std::ostringstream ss; // (optional) set the stream to designate the test result file | ||
40 | + | ||
41 | + stim::image<float> temp; // set the temporary image to store the addtion result | ||
42 | + | ||
43 | + for (int i = 0; i < c; i++){ | ||
44 | + for (int j = 0; j < s; j++){ | ||
45 | + | ||
46 | + //ss << "data_output/cPb_slice"<< i*s + j << ".bmp"; // set the name for test result file (optional) | ||
47 | + //std::string sss = ss.str(); | ||
48 | + | ||
49 | + // get the gaussian gradient by convolving each image slice with the mask | ||
50 | + temp = Pb(img.channel(i), sigma[i*s + j]); | ||
51 | + | ||
52 | + // output the test result of each slice (optional) | ||
53 | + //stim::cpu2image(temp.data(), sss, w, h, stim::cmBrewer); | ||
54 | + | ||
55 | + // multiply each gaussian gradient with its weight | ||
56 | + stim::cuda::cpu_multiply(temp.data(), alpha[i*s + j], N); | ||
57 | + | ||
58 | + // add up all the weighted gaussian gradients | ||
59 | + stim::cuda::cpu_add(cPb.data(), temp.data(), cPb.data(), N); | ||
60 | + | ||
61 | + //ss.str(""); //(optional) clear the space for stream | ||
62 | + | ||
63 | + } | ||
64 | + } | ||
65 | + | ||
66 | + float max = cPb.maxv(); // get the maximum of cPb used for normalization | ||
67 | + stim::cuda::cpu_multiply(cPb.data(), 1/max, N); // normalize the cPb | ||
68 | + | ||
69 | + // output the test result of cPb (optional) | ||
70 | + //stim::cpu2image(cPb.data(), "data_output/cPb_0916.bmp", w, h, stim::cmBrewer); | ||
71 | + | ||
72 | + return cPb; | ||
73 | +} | ||
74 | + | ||
75 | +#endif |
1 | +#ifndef STIM_CUDA_DG1_CONV2_CUH | ||
2 | +#define STIM_CUDA_DG1_CONV2_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +//#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | + | ||
9 | +#include <stim/cuda/templates/conv2sep.cuh> | ||
10 | + | ||
11 | +#define SIGMA_N 3 | ||
12 | + | ||
13 | +/// This function generates the first-order gaussian derivative filter gx gy, | ||
14 | +/// convolves the image with gx gy, | ||
15 | +/// and returns an image class which channel(0) is Ix and channel(1) is Iy | ||
16 | + | ||
17 | +/// @param img is the one-channel image | ||
18 | +/// @param sigma is the parameter for gaussian function | ||
19 | + | ||
20 | +//void conv2_sep(float* img, unsigned int x, unsigned int y, float* kernel0, unsigned int k0, float* kernel1, unsigned int k1); | ||
21 | +//void array_abs(float* img, unsigned int N); | ||
22 | + | ||
23 | +stim::image<float> dG1_conv2(stim::image<float> image, int sigma){ | ||
24 | + | ||
25 | + unsigned int w = image.width(); // get the width of picture | ||
26 | + unsigned int h = image.height(); // get the height of picture | ||
27 | + | ||
28 | + int r = SIGMA_N * sigma; | ||
29 | + int winsize = 2 * SIGMA_N * sigma + 1; // set the winsdow size of filter | ||
30 | + | ||
31 | + stim::image<float> I(w, h, 1, 2); // allocate space for return image class | ||
32 | + stim::image<float> Ix(w, h); // allocate space for Ix | ||
33 | + stim::image<float> Iy(w, h); // allocate space for Iy | ||
34 | + Ix = image; // initialize Ix | ||
35 | + Iy = image; // initialize Iy | ||
36 | + | ||
37 | + float* array_x1; | ||
38 | + array_x1 = new float[winsize]; //allocate space for the 1D x-oriented gaussian derivative filter array_x1 for gx | ||
39 | + float* array_y1; | ||
40 | + array_y1 = new float[winsize]; //allocate space for the 1D y-oriented gaussian derivative filter array_y1 for gx | ||
41 | + float* array_x2; | ||
42 | + array_x2 = new float[winsize]; //allocate space for the 1D x-oriented gaussian derivative filter array_x2 for gy | ||
43 | + float* array_y2; | ||
44 | + array_y2 = new float[winsize]; //allocate space for the 1D y-oriented gaussian derivative filter array_y2 for gy | ||
45 | + | ||
46 | + | ||
47 | + for (int i = 0; i < winsize; i++){ | ||
48 | + | ||
49 | + int x = i - r; //range of x | ||
50 | + int y = i - r; //range of y | ||
51 | + | ||
52 | + // create the 1D x-oriented gaussian derivative filter array_x1 for gx | ||
53 | + array_x1[i] = (-1) * x * exp((-1)*(pow(x, 2))/(2*pow(sigma, 2))); | ||
54 | + // create the 1D y-oriented gaussian derivative filter array_y1 for gx | ||
55 | + array_y1[i] = exp((-1)*(pow(y, 2))/(2*pow(sigma, 2))); | ||
56 | + // create the 1D x-oriented gaussian derivative filter array_x2 for gy | ||
57 | + array_x2[i] = exp((-1)*(pow(x, 2))/(2*pow(sigma, 2))); | ||
58 | + // create the 1D y-oriented gaussian derivative filter array_y2 for gy | ||
59 | + array_y2[i] = (-1) * y * exp((-1)*(pow(y, 2))/(2*pow(sigma, 2))); | ||
60 | + } | ||
61 | + | ||
62 | + //stim::cpu2image(array_x1, "data_output/array_x1_0915.bmp", winsize, 1, stim::cmBrewer); // (optional) show the mask result | ||
63 | + //stim::cpu2image(array_y1, "data_output/array_y1_0915.bmp", winsize, 1, stim::cmBrewer); // (optional) show the mask result | ||
64 | + //stim::cpu2image(array_x2, "data_output/array_x2_0915.bmp", winsize, 1, stim::cmBrewer); // (optional) show the mask result | ||
65 | + //stim::cpu2image(array_y2, "data_output/array_y2_0915.bmp", winsize, 1, stim::cmBrewer); // (optional) show the mask result | ||
66 | + | ||
67 | + // get Ix by convolving the image with gx | ||
68 | + //conv2_sep(Ix.data(), w, h, array_x1, winsize, array_y1, winsize); | ||
69 | + stim::cuda::cpu_conv2sep(Ix.data(), w, h, array_x1, winsize, array_y1, winsize); | ||
70 | + | ||
71 | + //stim::cpu2image(Ix.data(), "data_output/Ix_0915.bmp", w, h, stim::cmBrewer); | ||
72 | + // get Iy by convolving the image with gy | ||
73 | + //conv2_sep(Iy.data(), w, h, array_x2, winsize, array_y2, winsize); | ||
74 | + stim::cuda::cpu_conv2sep(Iy.data(), w, h, array_x2, winsize, array_y2, winsize); | ||
75 | + | ||
76 | + //stim::cpu2image(Iy.data(), "data_output/Iy_0915.bmp", w, h, stim::cmBrewer); | ||
77 | + | ||
78 | + delete [] array_x1; //free the memory of array_x1 | ||
79 | + delete [] array_y1; //free the memory of array_y1 | ||
80 | + delete [] array_x2; //free the memory of array_x2 | ||
81 | + delete [] array_y2; //free the memory of array_y2 | ||
82 | + | ||
83 | + I.set_channel(0, Ix.data()); | ||
84 | + I.set_channel(1, Iy.data()); | ||
85 | + | ||
86 | + return I; | ||
87 | + | ||
88 | +} | ||
89 | + | ||
90 | +#endif | ||
0 | \ No newline at end of file | 91 | \ No newline at end of file |
1 | +#ifndef STIM_CUDA_DG1_THETA_CONV2_CUH | ||
2 | +#define STIM_CUDA_DG1_THETA_CONV2_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | + | ||
9 | +#define PI 3.1415926 | ||
10 | +#define SIGMA_N 3 | ||
11 | + | ||
12 | +//void array_multiply(float* lhs, float rhs, unsigned int N); | ||
13 | +//void array_add(float* ptr1, float* ptr2, float* sum, unsigned int N); | ||
14 | +//void array_abs(float* img, unsigned int N); | ||
15 | + | ||
16 | +/// This function evaluates the theta-dependent odd symmetric gaussian derivative gradient of an one-channel image | ||
17 | + | ||
18 | +/// @param img is the one-channel image | ||
19 | +/// @param r is an array of radii for different scaled discs(filters) | ||
20 | +/// @param sigma_n is the number of standard deviations used to define the sigma | ||
21 | +/// @param theta is angle used for computing the gradient | ||
22 | + | ||
23 | +stim::image<float> dG1_theta_conv2(stim::image<float> image, int sigma, float theta){ | ||
24 | + | ||
25 | + float theta_r = (theta * PI)/180; //change angle unit from degree to rad | ||
26 | + | ||
27 | + unsigned int w = image.width(); // get the width of picture | ||
28 | + unsigned int h = image.height(); // get the height of picture | ||
29 | + | ||
30 | + int r = SIGMA_N * sigma; | ||
31 | + unsigned N = w * h; // get the number of pixels of picture | ||
32 | + | ||
33 | + int winsize = 2 * SIGMA_N * sigma + 1; // set the winsdow size of filter | ||
34 | + | ||
35 | + stim::image<float> I(w, h, 1, 2); // allocate space for return image of dG1_conv2 | ||
36 | + stim::image<float> Ix(w, h); // allocate space for Ix | ||
37 | + stim::image<float> Iy(w, h); // allocate space for Iy | ||
38 | + stim::image<float> dG1_theta(w, h); // allocate space for Pb | ||
39 | + | ||
40 | + I = dG1_conv2(image, sigma); // calculate the Ix, Iy | ||
41 | + Ix = I.channel(0); | ||
42 | + Iy = I.channel(1); | ||
43 | + | ||
44 | + array_multiply(Ix.data(), cos(theta_r), N); //Ix = Ix*cos(theta_r) | ||
45 | + array_multiply(Iy.data(), sin(theta_r), N); //Iy = Iy*sin(theta_r) | ||
46 | + array_add(Ix.data(), Iy.data(), dG1_theta.data(), N); //dG1_theta = Ix + Iy; | ||
47 | + array_abs(dG1_theta.data(), N); | ||
48 | + | ||
49 | + //stim::cpu2image(I.channel(0).data(), "data_output/dG1_theta_x_0919.bmp", w, h, stim::cmBrewer); | ||
50 | + //stim::cpu2image(I.channel(1).data(), "data_output/dG1_theta_y_0919.bmp", w, h, stim::cmBrewer); | ||
51 | + //stim::cpu2image(dG1_theta.data(), "data_output/dG1_theta_0919.bmp", w, h, stim::cmBrewer); | ||
52 | + | ||
53 | + return dG1_theta; | ||
54 | + | ||
55 | +} | ||
56 | + | ||
57 | +#endif | ||
0 | \ No newline at end of file | 58 | \ No newline at end of file |
1 | +#ifndef STIM_CUDA_DG2_CONV2_CUH | ||
2 | +#define STIM_CUDA_DG2_CONV2_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +//#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | +#define SIGMA_N 3 | ||
9 | + | ||
10 | +/// This function generates the second-order gaussian derivative filter gxx gyy, | ||
11 | +/// convolves the image with gxx gyy, | ||
12 | +/// and returns an image class which channel(0) is Ixx and channel(1) is Iyy | ||
13 | + | ||
14 | +/// @param img is the one-channel image | ||
15 | +/// @param sigma is the parameter for gaussian function | ||
16 | + | ||
17 | +//void conv2_sep(float* img, unsigned int x, unsigned int y, float* kernel0, unsigned int k0, float* kernel1, unsigned int k1); | ||
18 | +//void array_abs(float* img, unsigned int N); | ||
19 | + | ||
20 | +stim::image<float> dG2_conv2(stim::image<float> image, int sigma){ | ||
21 | + | ||
22 | + unsigned int w = image.width(); // get the width of picture | ||
23 | + unsigned int h = image.height(); // get the height of picture | ||
24 | + unsigned N = w * h; // get the number of pixels of picture | ||
25 | + | ||
26 | + int winsize = 2 * SIGMA_N * sigma + 1; // set the winsdow size of filter | ||
27 | + int r = SIGMA_N * sigma; | ||
28 | + | ||
29 | + stim::image<float> I(w, h, 1, 2); // allocate space for return image class | ||
30 | + stim::image<float> Ixx(w, h); // allocate space for Ixx | ||
31 | + stim::image<float> Iyy(w, h); // allocate space for Iyy | ||
32 | + Ixx = image; // initialize Ixx | ||
33 | + Iyy = image; // initialize Iyy | ||
34 | + | ||
35 | + float* array_x1; | ||
36 | + array_x1 = new float[winsize]; //allocate space for the 1D x-oriented gaussian derivative filter array_x1 for gxx | ||
37 | + float* array_y1; | ||
38 | + array_y1 = new float[winsize]; //allocate space for the 1D y-oriented gaussian derivative filter array_y1 for gxx | ||
39 | + float* array_x2; | ||
40 | + array_x2 = new float[winsize]; //allocate space for the 1D x-oriented gaussian derivative filter array_x2 for gyy | ||
41 | + float* array_y2; | ||
42 | + array_y2 = new float[winsize]; //allocate space for the 1D y-oriented gaussian derivative filter array_y2 for gyy | ||
43 | + | ||
44 | + | ||
45 | + for (int i = 0; i < winsize; i++){ | ||
46 | + | ||
47 | + int x = i - r; //range of x | ||
48 | + int y = i - r; //range of y | ||
49 | + | ||
50 | + // create the 1D x-oriented gaussian derivative filter array_x1 for gxx | ||
51 | + array_x1[i] = (-1) * (1 - pow(x, 2)) * exp((-1)*(pow(x, 2))/(2*pow(sigma, 2))); | ||
52 | + // create the 1D y-oriented gaussian derivative filter array_y1 for gxx | ||
53 | + array_y1[i] = exp((-1)*(pow(y, 2))/(2*pow(sigma, 2))); | ||
54 | + // create the 1D x-oriented gaussian derivative filter array_x2 for gyy | ||
55 | + array_x2[i] = exp((-1)*(pow(x, 2))/(2*pow(sigma, 2))); | ||
56 | + // create the 1D y-oriented gaussian derivative filter array_y2 for gyy | ||
57 | + array_y2[i] = (-1) * (1 - pow(y, 2)) * exp((-1)*(pow(y, 2))/(2*pow(sigma, 2))); | ||
58 | + } | ||
59 | + | ||
60 | + //stim::cpu2image(array_x1, "data_output/array_x1_0915.bmp", winsize, 1, stim::cmBrewer); // (optional) show the mask result | ||
61 | + //stim::cpu2image(array_y1, "data_output/array_y1_0915.bmp", winsize, 1, stim::cmBrewer); // (optional) show the mask result | ||
62 | + //stim::cpu2image(array_x2, "data_output/array_x2_0915.bmp", winsize, 1, stim::cmBrewer); // (optional) show the mask result | ||
63 | + //stim::cpu2image(array_y2, "data_output/array_y2_0915.bmp", winsize, 1, stim::cmBrewer); // (optional) show the mask result | ||
64 | + | ||
65 | + // get Ixx by convolving the image with gxx | ||
66 | + conv2_sep(Ixx.data(), w, h, array_x1, winsize, array_y1, winsize); | ||
67 | + | ||
68 | + //stim::cpu2image(Ixx.data(), "data_output/Ixx_0915.bmp", w, h, stim::cmBrewer); | ||
69 | + // get Iyy by convolving the image with gyy | ||
70 | + conv2_sep(Iyy.data(), w, h, array_x2, winsize, array_y2, winsize); | ||
71 | + | ||
72 | + //stim::cpu2image(Iyy.data(), "data_output/Iyy_0915.bmp", w, h, stim::cmBrewer); | ||
73 | + | ||
74 | + delete [] array_x1; //free the memory of array_x1 | ||
75 | + delete [] array_y1; //free the memory of array_y1 | ||
76 | + delete [] array_x2; //free the memory of array_x2 | ||
77 | + delete [] array_y2; //free the memory of array_y2 | ||
78 | + | ||
79 | + I.set_channel(0, Ixx.data()); | ||
80 | + I.set_channel(1, Iyy.data()); | ||
81 | + | ||
82 | + return I; | ||
83 | + | ||
84 | +} | ||
85 | + | ||
86 | +#endif | ||
0 | \ No newline at end of file | 87 | \ No newline at end of file |
1 | +#ifndef STIM_CUDA_DG2_D2X_THETA_CONV2_CUH | ||
2 | +#define STIM_CUDA_DG2_D2X_THETA_CONV2_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | + | ||
9 | +#define SIGMA_N 3 | ||
10 | + | ||
11 | +/// This function evaluates the theta-dependent even-symmetric gaussian derivative gradient of an one-channel image | ||
12 | + | ||
13 | +/// @param img is the one-channel image | ||
14 | +/// @param r is an array of radii for different scaled discs(filters) | ||
15 | +/// @param sigma_n is the number of standard deviations used to define the sigma | ||
16 | +/// @param theta is angle used for computing the gradient | ||
17 | + | ||
18 | +//void conv2(float* img, float* mask, float* cpu_copy, unsigned int w, unsigned int h, unsigned int M); | ||
19 | +//void array_abs(float* img, unsigned int N); | ||
20 | + | ||
21 | +stim::image<float> dG2_d2x_theta_conv2(stim::image<float> image, int sigma, float theta){ | ||
22 | + | ||
23 | + unsigned int w = image.width(); // get the width of picture | ||
24 | + unsigned int h = image.height(); // get the height of picture | ||
25 | + unsigned N = w * h; // get the number of pixels of picture | ||
26 | + | ||
27 | + int r = SIGMA_N * sigma; // set the radius of filter | ||
28 | + int winsize = 2 * SIGMA_N * sigma + 1; // set the winsdow size of filter | ||
29 | + | ||
30 | + stim::image<float> I(w, h, 1, 2); // allocate space for return image class | ||
31 | + stim::image<float> dG2_d2x_theta(w, h); // allocate space for dG2_d2x_theta | ||
32 | + stim::image<float> mask_x(winsize, winsize); // allocate space for x-axis-oriented filter | ||
33 | + stim::image<float> mask_r(winsize, winsize); // allocate space for theta-oriented filter | ||
34 | + | ||
35 | + for (int j = 0; j < winsize; j++){ | ||
36 | + for (int i = 0; i< winsize; i++){ | ||
37 | + | ||
38 | + int x = i - r; //range of x | ||
39 | + int y = j - r; //range of y | ||
40 | + | ||
41 | + // create the x-oriented gaussian derivative filter mask_x | ||
42 | + mask_x.data()[j*winsize + i] = (-1) * (1 - pow(x, 2)) * exp((-1)*(pow(x, 2))/(2*pow(sigma, 2))) * exp((-1)*(pow(y, 2))/(2*pow(sigma, 2))); | ||
43 | + | ||
44 | + } | ||
45 | + } | ||
46 | + | ||
47 | + mask_r = mask_x.rotate(theta, r, r); | ||
48 | + //mask_r = mask_x.rotate(45, r, r); | ||
49 | + //stim::cpu2image(mask_r.data(), "data_output/mask_r_0919.bmp", winsize, winsize, stim::cmBrewer); | ||
50 | + | ||
51 | + // do the 2D convolution with image and mask | ||
52 | + conv2(image.data(), mask_r.data(), dG2_d2x_theta.data(), w, h, winsize); | ||
53 | + array_abs(dG2_d2x_theta.data(), N); | ||
54 | + | ||
55 | + //stim::cpu2image(dG2_d2x_theta.data(), "data_output/dG2_d2x_theta_0919.bmp", w, h, stim::cmGrayscale); | ||
56 | + | ||
57 | + return dG2_d2x_theta; | ||
58 | +} | ||
59 | + | ||
60 | +#endif | ||
0 | \ No newline at end of file | 61 | \ No newline at end of file |
1 | +#ifndef STIM_CUDA_KMEANS_CUH | ||
2 | +#define STIM_CUDA_KMEANS_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +//#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | +#include <opencv2/opencv.hpp> | ||
9 | +#include <iostream> | ||
10 | + | ||
11 | +/// This function use cvkmeans to cluster given textons | ||
12 | + | ||
13 | +/// @param testons is a multi-channel image | ||
14 | +/// @param K is the number of clusters | ||
15 | + | ||
16 | +stim::image<float> kmeans(stim::image<float> textons, unsigned int K){ | ||
17 | + | ||
18 | + unsigned int w = textons.width(); // get the width of picture | ||
19 | + unsigned int h = textons.height(); // get the height of picture | ||
20 | + unsigned int feature_n = textons.channels(); // get the spectrum of picture | ||
21 | + unsigned int N = w * h; // get the number of pixels | ||
22 | + | ||
23 | + float* sample1 = (float*) malloc(sizeof(float) * N * feature_n); //allocate the space for textons | ||
24 | + | ||
25 | + //reallocate a multi-channel texton image to a single-channel image | ||
26 | + for(unsigned int c = 0; c < feature_n; c++){ | ||
27 | + | ||
28 | + stim::image<float> temp; | ||
29 | + temp = textons.channel(c); | ||
30 | + | ||
31 | + for(unsigned int j = 0; j < N; j++){ | ||
32 | + | ||
33 | + sample1[c + j * feature_n] = temp.data()[j]; | ||
34 | + } | ||
35 | + } | ||
36 | + | ||
37 | + | ||
38 | + cv::Mat sample2(N, feature_n, CV_32F, sample1); //copy image to cv::mat | ||
39 | + | ||
40 | + //(optional) show the test result | ||
41 | + //imshow("sample2", sample2); | ||
42 | + | ||
43 | + | ||
44 | + cv::TermCriteria criteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 10, 0.1); // set stop-criteria for kmeans iteration | ||
45 | + cv::Mat labels(N, 1, CV_8U, cvScalarAll(0)); // allocate space for kmeans output | ||
46 | + cv::Mat centers; // allocate space for kmeans output | ||
47 | + | ||
48 | + unsigned int test_times = 2; // set the number of times of trying kmeans, it will return the best result | ||
49 | + | ||
50 | + cv::kmeans(sample2, K, labels, criteria, test_times, cv::KMEANS_PP_CENTERS, centers); // kmeans clustering | ||
51 | + | ||
52 | + //(optional) show the test result | ||
53 | + //imwrite( "data_output/labels_1D.bmp", labels); | ||
54 | + | ||
55 | + stim::image<float> texture(w, h, 1, 1); // allocate space for texture | ||
56 | + | ||
57 | + for(unsigned int i = 0; i < N; i++){ // reshape the labels from iD array to image | ||
58 | + | ||
59 | + texture.data()[i] = labels.at<int>(i); | ||
60 | + | ||
61 | + } | ||
62 | + | ||
63 | + //texture.save("data_output/kmeans_test0924_2.bmp"); | ||
64 | + | ||
65 | + //(optional) show the test result | ||
66 | + //stim::cpu2image(texture.data(), "data_output/kmeans_test.bmp", w, h, stim::cmBrewer); | ||
67 | + | ||
68 | + return texture; | ||
69 | + | ||
70 | +} | ||
71 | + | ||
72 | +#endif | ||
0 | \ No newline at end of file | 73 | \ No newline at end of file |
1 | +#ifndef STIM_CUDA_LAPLACIAN_CONV2_CUH | ||
2 | +#define STIM_CUDA_LAPLACIAN_CONV2_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | + | ||
9 | +#define PI 3.1415926 | ||
10 | +#define SIGMA_N 3 | ||
11 | + | ||
12 | +//void array_multiply(float* lhs, float rhs, unsigned int N); | ||
13 | +//void array_add(float* ptr1, float* ptr2, float* sum, unsigned int N); | ||
14 | +//void array_abs(float* img, unsigned int N); | ||
15 | + | ||
16 | +/// This function evaluates the center-surround(Laplacian of Gaussian) gaussian derivative gradient of an one-channel image | ||
17 | + | ||
18 | +/// @param img is the one-channel image | ||
19 | +/// @param r is an array of radii for different scaled discs(filters) | ||
20 | +/// @param sigma_n is the number of standard deviations used to define the sigma | ||
21 | + | ||
22 | +stim::image<float> laplacian_conv2(stim::image<float> image, int sigma){ | ||
23 | + | ||
24 | + unsigned int w = image.width(); // get the width of picture | ||
25 | + unsigned int h = image.height(); // get the height of picture | ||
26 | + unsigned N = w * h; // get the number of pixels of picture | ||
27 | + | ||
28 | + int winsize = 2 * SIGMA_N * sigma + 1; // set the winsdow size of filter | ||
29 | + | ||
30 | + stim::image<float> I(w, h, 1, 2); // allocate space for return image of dG2_conv2 | ||
31 | + stim::image<float> Ixx(w, h); // allocate space for Ixx | ||
32 | + stim::image<float> Iyy(w, h); // allocate space for Iyy | ||
33 | + stim::image<float> laplacian(w, h); // allocate space for Pb | ||
34 | + | ||
35 | + I = dG2_conv2(image, sigma); // calculate the Ixx, Iyy | ||
36 | + Ixx = I.channel(0); | ||
37 | + Iyy = I.channel(1); | ||
38 | + | ||
39 | + array_add(Ixx.data(), Iyy.data(), laplacian.data(), N); //laplacian = Ixx + Iyy; | ||
40 | + array_abs(laplacian.data(), N); | ||
41 | + | ||
42 | + //stim::cpu2image(laplacian.data(), "data_output/laplacian_0919.bmp", w, h, stim::cmBrewer); | ||
43 | + | ||
44 | + return laplacian; | ||
45 | + | ||
46 | +} | ||
47 | + | ||
48 | +#endif |
1 | +#ifndef STIM_CUDA_TPB_CUH | ||
2 | +#define STIM_CUDA_TPB_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | +#include <sstream> | ||
9 | + | ||
10 | + | ||
11 | +//void array_multiply(float* lhs, float rhs, unsigned int N); | ||
12 | +//void array_add(float* ptr1, float* ptr2, float* sum, unsigned int N); | ||
13 | +//void chi_grad(float* img, float* cpu_copy, unsigned int w, unsigned int h, int r, unsigned int bin_n, unsigned int bin_size, float theta); | ||
14 | + | ||
15 | +/// This function evaluates the tPb given a grayscale image | ||
16 | + | ||
17 | +/// @param img is the multi-channel image | ||
18 | +/// @param theta_n is the number of angles used for computing oriented chi-gradient | ||
19 | +/// @param r is an array of radii for different scaled discs(filters) | ||
20 | +/// @param alpha is is an array of weights for different scaled discs(filters) | ||
21 | +/// @param s is the number of scales | ||
22 | +/// @param K is the number of clusters | ||
23 | + | ||
24 | +stim::image<float> tPb(stim::image<float> img, int* r, float* alpha, unsigned int theta_n, unsigned int bin_n, int s, unsigned K){ | ||
25 | + | ||
26 | + unsigned int w = img.width(); // get the width of picture | ||
27 | + unsigned int h = img.height(); // get the height of picture | ||
28 | + unsigned int N = w * h; // get the number of pixels | ||
29 | + | ||
30 | + stim::image<float> img_textons(w, h, 1, theta_n*2+1); // allocate space for img_textons | ||
31 | + stim::image<float> img_texture(w, h, 1, 1); // allocate space for img_texture | ||
32 | + stim::image<float> tPb_theta(w, h, 1, 1); // allocate space for tPb_theta | ||
33 | + stim::image<float> tPb(w, h, 1, 1); // allocate space for tPb | ||
34 | + unsigned size = tPb_theta.size(); // get the size of tPb_theta | ||
35 | + memset (tPb.data(), 0, size * sizeof(float)); // initialize all the pixels of tPb to 0 | ||
36 | + stim::image<float> temp(w, h, 1, 1); // set the temporary image to store the addtion result | ||
37 | + | ||
38 | + std::ostringstream ss; // (optional) set the stream to designate the test result file | ||
39 | + | ||
40 | + | ||
41 | + img_textons = textons(img, theta_n); | ||
42 | + | ||
43 | + img_texture = kmeans(img_textons, K); // changing kmeans result into float type is required | ||
44 | + | ||
45 | + stim::cpu2image(img_texture.data(), "data_output/texture.bmp", w, h, stim::cmBrewer); | ||
46 | + | ||
47 | + | ||
48 | + unsigned int max1 = img_texture.maxv(); // get the maximum of Pb used for normalization | ||
49 | + unsigned int bin_size = (max1 + 1)/bin_n; // (whether"+1" or not depends on kmeans result) | ||
50 | + | ||
51 | + for (int i = 0; i < theta_n; i++){ | ||
52 | + | ||
53 | + float theta = 180 * ((float)i/theta_n); // calculate the even-splited angle for each tPb_theta | ||
54 | + | ||
55 | + memset (tPb_theta.data(), 0, size * sizeof(float)); // initialize all the pixels of tPb_theta to 0 | ||
56 | + | ||
57 | + //ss << "data_output/0922tPb_theta"<< theta << ".bmp"; // set the name for test result file (optional) | ||
58 | + //std::string sss = ss.str(); | ||
59 | + | ||
60 | + for (int j = 0; j < s; j++){ | ||
61 | + | ||
62 | + // get the chi-gradient by convolving each image slice with the mask | ||
63 | + chi_grad(img_texture.data(), temp.data(), w, h, r[j], bin_n, bin_size, theta); | ||
64 | + | ||
65 | + float max2 = temp.maxv(); // get the maximum of tPb_theta used for normalization | ||
66 | + array_multiply(temp.data(), 1/max2, N); // normalize the tPb_theta | ||
67 | + | ||
68 | + //output the test result of each slice (optional) | ||
69 | + //stim::cpu2image(temp.data(), "data_output/tPb_slice0924_2.bmp", w, h, stim::cmBrewer); | ||
70 | + | ||
71 | + // multiply each chi-gradient with its weight | ||
72 | + array_multiply(temp.data(), alpha[j], N); | ||
73 | + | ||
74 | + // add up all the weighted chi-gradients | ||
75 | + array_add(tPb_theta.data(), temp.data(), tPb_theta.data(), N); | ||
76 | + | ||
77 | + | ||
78 | + } | ||
79 | + | ||
80 | + //ss.str(""); //(optional) clear the space for stream | ||
81 | + | ||
82 | + for(unsigned long ti = 0; ti < N; ti++){ | ||
83 | + | ||
84 | + if(tPb_theta.data()[ti] > tPb.data()[ti]){ //get the maximum value among all tPb_theta for ith pixel | ||
85 | + tPb.data()[ti] = tPb_theta.data()[ti]; | ||
86 | + } | ||
87 | + | ||
88 | + else{ | ||
89 | + } | ||
90 | + } | ||
91 | + } | ||
92 | + | ||
93 | + float max3 = tPb.maxv(); // get the maximum of tPb used for normalization | ||
94 | + array_multiply(tPb.data(), 1/max3, N); // normalize the tPb | ||
95 | + | ||
96 | + //output the test result of tPb (optional) | ||
97 | + //stim::cpu2image(tPb.data(), "data_output/tPb_0922.bmp", w, h, stim::cmBrewer); | ||
98 | + | ||
99 | + return tPb; | ||
100 | +} | ||
101 | + | ||
102 | +#endif | ||
0 | \ No newline at end of file | 103 | \ No newline at end of file |
1 | +#ifndef STIM_CUDA_TEXONS_CUH | ||
2 | +#define STIM_CUDA_TEXONS_CUH | ||
3 | + | ||
4 | +#include <stim/image/image.h> | ||
5 | +//#include <cmath> | ||
6 | +#include <stim/visualization/colormap.h> | ||
7 | +//#include <stim/image/image_contour_detection.h> | ||
8 | +#include <sstream> | ||
9 | + | ||
10 | +/// This function convolve the grayscale image with a set of oriented Gaussian | ||
11 | +/// derivative filters, and return a texton image with (theta_n*2+1) channels | ||
12 | + | ||
13 | +/// @param image is an one-channel grayscale image | ||
14 | +/// @param theta_n is the number of angles used for computing the gradient | ||
15 | + | ||
16 | +stim::image<float> textons(stim::image<float> image, unsigned int theta_n){ | ||
17 | + | ||
18 | + unsigned int w = image.width(); // get the width of picture | ||
19 | + unsigned int h = image.height(); // get the height of picture | ||
20 | + unsigned N = w * h; // get the number of pixels of picture | ||
21 | + | ||
22 | + stim::image<float> textons(w, h, 1, theta_n*2+1); // allocate space for textons | ||
23 | + stim::image<float> temp(w, h); // allocate space for temp | ||
24 | + | ||
25 | + int sigma = 1; // set sigma for odd-symmetric, even-symmetric and center-surround filter filter | ||
26 | + | ||
27 | + //std::ostringstream ss1, ss2; // (optional) set the stream to designate the test result file | ||
28 | + | ||
29 | + for (unsigned int i = 0; i < theta_n; i++){ | ||
30 | + | ||
31 | + //ss1 << "data_output/textons_channel_"<< i << ".bmp"; // set the name for test result file (optional) | ||
32 | + //std::string sss1 = ss1.str(); | ||
33 | + //ss2 << "data_output/textons_channel_"<< i+theta_n << ".bmp"; // set the name for test result file (optional) | ||
34 | + //std::string sss2 = ss2.str(); | ||
35 | + | ||
36 | + float theta = 180 * ((float)i/theta_n); // calculate the even-splited angle for each oriented filter | ||
37 | + | ||
38 | + temp = dG1_theta_conv2(image, sigma, theta); // return dG1_theta_conv2 to temp | ||
39 | + //stim::cpu2image(temp.data(), sss1, w, h, stim::cmBrewer); | ||
40 | + textons.set_channel(i, temp.data()); // copy temp to ith channel of textons | ||
41 | + | ||
42 | + temp = dG2_d2x_theta_conv2(image, sigma, theta); // return dG2_d2x_theta_conv2 to temp | ||
43 | + //stim::cpu2image(temp.data(), sss2, w, h, stim::cmBrewer); | ||
44 | + textons.set_channel(i + theta_n, temp.data()); // copy temp to (i+theta_n)th channel of textons | ||
45 | + | ||
46 | + //ss1.str(""); //(optional) clear the space for stream | ||
47 | + //ss2.str(""); //(optional) clear the space for stream | ||
48 | + | ||
49 | + } | ||
50 | + | ||
51 | + temp = laplacian_conv2(image, sigma); // return laplacian_conv2 to temp | ||
52 | + //stim::cpu2image(temp.data(), "data_output/textons_channel_16.bmp", w, h, stim::cmBrewer); | ||
53 | + textons.set_channel(theta_n*2, temp.data()); // copy temp to (theta_n*2)th channel of textons | ||
54 | + | ||
55 | + return textons; | ||
56 | + | ||
57 | +} | ||
58 | + | ||
59 | +#endif | ||
60 | + | ||
61 | + | ||
0 | \ No newline at end of file | 62 | \ No newline at end of file |