00001 #ifndef CVD_INC_TENSOR_VOTE_H
00002 #define CVD_INC_TENSOR_VOTE_H
00003
00004 #include <cvd/image.h>
00005 #include <TooN/TooN.h>
00006 #include <TooN/helpers.h>
00007 #include <vector>
00008 #include <utility>
00009
00010 namespace CVD
00011 {
00012
00013 #ifndef DOXYGEN_IGNORE_INTERNAL
00014 namespace TensorVoting
00015 {
00016 struct TV_coord
00017 {
00018 ptrdiff_t o;
00019 int x;
00020 int y;
00021 };
00022
00023 std::vector<std::pair<TV_coord, TooN::Matrix<2> > > compute_a_tensor_kernel(int radius, double cutoff, double angle, double sigma, double ratio, int row_stride);
00024 inline unsigned int quantize_half_angle(double r, int num_divs)
00025 {
00026 return ((int)floor((r/M_PI+100) * num_divs + 0.5)) % num_divs;
00027 }
00028 }
00029
00030 #endif
00031
00080 template<class C> Image<TooN::Matrix<2> > dense_tensor_vote_gradients(const SubImage<C>& image, double sigma, double ratio, double cutoff=0.001, unsigned int num_divs = 4096)
00081 {
00082 using TooN::Matrix;
00083 using std::pair;
00084 using std::vector;
00085 using TensorVoting::TV_coord;
00086
00087 Matrix<2> zero;
00088 TooN::Zero(zero);
00089 Image<Matrix<2> > field(image.size(), zero);
00090
00091
00092
00093
00094
00095
00096 int kernel_radius = (int)ceil(sigma * sqrt(-log(cutoff)));
00097
00098
00099
00100 vector<vector<pair<TV_coord, Matrix<2> > > > kernels;
00101 for(unsigned int i=0; i < num_divs; i++)
00102 {
00103 double angle = M_PI * i / num_divs;
00104 kernels.push_back(TensorVoting::compute_a_tensor_kernel(kernel_radius, cutoff, angle, sigma, ratio, field.row_stride()));
00105 }
00106
00107
00108 for(int y= kernel_radius; y < field.size().y - kernel_radius; y++)
00109 for(int x= kernel_radius; x < field.size().x - kernel_radius; x++)
00110 {
00111 double gx = ((double)image[y][x+1] - image[y][x-1])/2.;
00112 double gy = ((double)image[y+1][x] - image[y-1][x])/2.;
00113
00114 double scale = sqrt(gx*gx + gy*gy);
00115 unsigned int direction = TensorVoting::quantize_half_angle(M_PI/2 + atan2(gy,gx), num_divs);
00116
00117 const vector<pair<TV_coord, Matrix<2> > >& kernel = kernels[direction];
00118
00119 Matrix<2>* p = &field[y][x];
00120
00121
00122 for(unsigned int i=0; i < kernel.size(); i++)
00123 {
00124 p[kernel[i].first.o][0][0] += kernel[i].second[0][0] * scale;
00125 p[kernel[i].first.o][0][1] += kernel[i].second[0][1] * scale;
00126 p[kernel[i].first.o][1][1] += kernel[i].second[1][1] * scale;
00127 }
00128 }
00129
00130
00131 for(int y= 1; y < field.size().y-1; y++)
00132 {
00133 for(int x= 1; x < field.size().x-1; x++)
00134 {
00135
00136 if(y >= kernel_radius && y < field.size().y - kernel_radius && x == kernel_radius)
00137 x = field.size().x - kernel_radius;
00138
00139 double gx = ((double)image[y][x+1] - image[y][x-1])/2.;
00140 double gy = ((double)image[y+1][x] - image[y-1][x])/2.;
00141
00142 double scale = sqrt(gx*gx + gy*gy);
00143 unsigned int direction = TensorVoting::quantize_half_angle(M_PI/2 + atan(gy / gx), num_divs);
00144
00145 const vector<pair<TV_coord, Matrix<2> > >& kernel = kernels[direction];
00146
00147 Matrix<2>* p = &field[y][x];
00148
00149
00150 for(unsigned int i=0; i < kernel.size(); i++)
00151 {
00152 if(kernel[i].first.y+y >= 0 && kernel[i].first.y+y < field.size().y && kernel[i].first.x+x >= 0 && kernel[i].first.x+x < field.size().x)
00153 {
00154 p[kernel[i].first.o][0][0] += kernel[i].second[0][0] * scale;
00155 p[kernel[i].first.o][0][1] += kernel[i].second[0][1] * scale;
00156 p[kernel[i].first.o][1][1] += kernel[i].second[1][1] * scale;
00157 }
00158 }
00159 }
00160 }
00161
00162
00163 for(Image<Matrix<2> >:: iterator i=field.begin(); i != field.end(); i++)
00164 (*i)[1][0] = (*i)[0][1];
00165
00166 return field;
00167 }
00168
00169
00170 #ifdef CVD_EXPERIMENTAL
00171
00172 template<class C> Image<TooN::Matrix<2> > dense_tensor_vote_gradients_fast(const SubImage<C>& image, double sigma, double ratio, double cutoff=0.001, int num_divs = 4096)
00173 {
00174 using TooN::Matrix;
00175 using std::pair;
00176 using std::make_pair;
00177 using std::vector;
00178
00179 Matrix<2> zero;
00180 TooN::Zero(zero);
00181 Image<Matrix<2> > ffield(image.size(), zero);
00182 Image<__m128> field(image.size());
00183 field.zero();
00184
00185
00186
00187 int kernel_radius = (int)ceil(sigma * sqrt(-log(cutoff)));
00188 vector<vector<pair<int, Matrix<2> > > > matrix_kernels;
00189 for(unsigned int i=0; i < num_divs; i++)
00190 {
00191 double angle = M_PI * i / num_divs;
00192 matrix_kernels.push_back(TensorVoting::compute_a_tensor_kernel(kernel_radius, cutoff, angle, sigma, ratio, field.row_stride()));
00193 }
00194
00195
00196
00197
00198 vector<vector<int> > kernel_offsets;
00199 vector<Image<__m128> > kernel_values;
00200 for(unsigned int i=0; i < matrix_kernels.size(); i++)
00201 {
00202 vector<int> off(matrix_kernels[i].size());
00203 Image<__m128> val(ImageRef(matrix_kernels[i].size(), 1));
00204
00205 for(unsigned int j=0; j < matrix_kernels[i].size(); j++)
00206 {
00207 off[j] = matrix_kernels[i][j].first;
00208 Matrix<2>& m = matrix_kernels[i][j].second;
00209 val.data()[j] = _mm_setr_ps(m[0][0], m[0][1], m[1][0], m[1][1]);
00210 }
00211
00212 kernel_offsets.push_back(off);
00213 kernel_values.push_back(val);
00214 }
00215
00216 for(int y= kernel_radius; y < field.size().y - kernel_radius; y++)
00217 for(int x= kernel_radius; x < field.size().x - kernel_radius; x++)
00218 {
00219 float gx = ((float)image[y][x+1] - image[y][x-1])/2.;
00220 float gy = ((float)image[y+1][x] - image[y-1][x])/2.;
00221
00222 float scale = sqrt(gx*gx + gy*gy);
00223 unsigned int direction = TensorVoting::quantize_half_angle(M_PI/2 + atan(gy / gx), num_divs);
00224
00225 const vector<int> & off = kernel_offsets[direction];
00226 __m128* val = kernel_values[direction].data();
00227 __m128* p = &field[y][x];
00228 __m128 s = _mm_set1_ps(scale);
00229
00230 for(unsigned int i=0; i < off.size(); i++)
00231 p[off[i]] = _mm_add_ps(p[off[i]], _mm_mul_ps(val[i], s));
00232 }
00233
00234 for(int y=0; y < field.size().y; y++)
00235 for(int x=0; x < field.size().x; x++)
00236 {
00237 float f[4];
00238 _mm_storeu_ps(f, field[y][x]);
00239 ffield[y][x][0][0] = f[0];
00240 ffield[y][x][0][1] = f[1];
00241 ffield[y][x][1][0] = f[2];
00242 ffield[y][x][1][1] = f[3];
00243 }
00244
00245 return ffield;
00246 }
00247 #endif
00248
00249 }
00250
00251
00252 #endif