vil_cartesian_differential_invariants.hxx
Go to the documentation of this file.
1 #ifndef vil_cartesian_differential_invariants_hxx_
2 #define vil_cartesian_differential_invariants_hxx_
3 //:
4 // \file
5 // \brief Find Cartesian differential invariants
6 // \author Ian Scott
7 // Based on some Matlab code by K. Walker 1999.
8 
10 #include <vil/vil_image_view.h>
13 #include <vil/vil_transpose.h>
14 #include <vil/vil_plane.h>
15 #include <cassert>
16 #ifdef _MSC_VER
17 # include <vcl_msvc_warnings.h>
18 #endif
19 
20 //: Compute 1st, 2nd, and 3rd order C.d.i.s of an image.
21 // The input must be 1 plane, the output will be 8 planes.
22 template <class S, class T>
24  const vil_image_view<S>& src, vil_image_view<T>& dest, double scale,
25  unsigned max_kernel_width /*=0*/)
26 {
27  assert(src.nplanes()==1);
28 
29  unsigned filt_n=int(3*scale + 0.5)*2+1;
30 
31  if (max_kernel_width!=0 && filt_n > max_kernel_width)
32  filt_n = (max_kernel_width | 1); // make sure it is an odd number
33 
34  const std::ptrdiff_t filt_c=filt_n/2;
35 
36  std::vector<double> filt_0(filt_n), filt_2(filt_n), filt_1(filt_n), filt_3(filt_n);
37  vil_gauss_filter_gen_ntap(scale, 0, filt_0);
38  vil_gauss_filter_gen_ntap(scale, 1, filt_1);
39  vil_gauss_filter_gen_ntap(scale, 2, filt_2);
40  vil_gauss_filter_gen_ntap(scale, 3, filt_3);
41 
43 
44  // Filter all the x directions
45  vil_image_view<T> LX, LXx, LXxx, LXxxx;
46  vil_convolve_1d(src, LX, &filt_0[filt_c], -filt_c, filt_c, double(), bo, bo);
47  vil_convolve_1d(src, LXx, &filt_1[filt_c], -filt_c, filt_c, double(), bo, bo);
48  vil_convolve_1d(src, LXxx, &filt_2[filt_c], -filt_c, filt_c, double(), bo, bo);
49  vil_convolve_1d(src, LXxxx, &filt_3[filt_c], -filt_c, filt_c, double(), bo, bo);
50 
51  // Now calculate the full values.
52  vil_image_view<T> Lx, Ly, Lxx, Lxy, Lyy, Lxxx, Lxxy, Lxyy, Lyyy;
53 
54  // construct first order partial derivatives
56  &filt_0[filt_c], -filt_c, filt_c, double(), bo, bo);
58  &filt_1[filt_c], -filt_c, filt_c, double(), bo, bo);
59 
60  // construct second order partial derivatives
61  vil_convolve_1d(vil_transpose(LXxx), Lxx,
62  &filt_0[filt_c], -filt_c, filt_c, double(), bo, bo);
64  &filt_1[filt_c], -filt_c, filt_c, double(), bo, bo);
66  &filt_2[filt_c], -filt_c, filt_c, double(), bo, bo);
67 
68  // construct third order partial derivatives
69  vil_convolve_1d(vil_transpose(LXxxx), Lxxx,
70  &filt_0[filt_c], -filt_c, filt_c, double(), bo, bo);
71  vil_convolve_1d(vil_transpose(LXxx), Lxxy,
72  &filt_1[filt_c], -filt_c, filt_c, double(), bo, bo);
73  vil_convolve_1d(vil_transpose(LXx), Lxyy,
74  &filt_2[filt_c], -filt_c, filt_c, double(), bo, bo);
76  &filt_3[filt_c], -filt_c, filt_c, double(), bo, bo);
77 
78  dest.set_size(src.ni(), src.nj(), 8);
79  for (unsigned j=0;j<dest.ni();++j)
80  {
81  for (unsigned i=0;i<dest.nj();++i)
82  {
83  // I1 = LiLi=LxLx+LyLy
84  // cdi(1,:,:)=(Lx.*Lx)+(Ly.*Ly);
85  dest(j,i,0)= Lx(i,j)*Lx(i,j)
86  +Ly(i,j)*Ly(i,j);
87 
88  // LiLijLj=LxxLxLx+2LxLxyLy+LyyLyLy
89  // cdi(2,:,:)=(Lxx.*Lx.*Lx)+(2.*Lx.*Lxy.*Ly)+(Lyy.*Ly.*Ly);
90  dest(j,i,1)= Lxx(i,j)*Lx(i,j)*Lx(i,j)
91  +T(2)*Lx(i,j)*Lxy(i,j)*Ly(i,j)
92  +Lyy(i,j)*Ly(i,j)*Ly(i,j);
93 
94  // %LiiLjLj-LijLiLj=LxxLyLy-2LxyLxLy+LyyLxLx
95  // cdi(3,:,:)=(Lxx.*Ly.*Ly)-(2.*Lxy.*Lx.*Ly)+(Lyy.*Lx.*Lx);
96  dest(j,i,2)= Lxx(i,j)*Ly(i,j)*Ly(i,j)
97  -T(2)*Lxy(i,j)*Lx(i,j)*Ly(i,j)
98  +Lyy(i,j)*Lx(i,j)*Lx(i,j);
99 
100 
101  // %-eijLjkLiLk=LxxLxLy+LxyLyLy-LyyLxLy-LxyLxLx
102  // cdi(4,:,:)=(Lxx.*Lx.*Ly)+(Lxy.*Ly.*Ly)-(Lyy.*Lx.*Ly)-(Lxy.*Lx.*Lx);
103  dest(j,i,3)= Lxx(i,j)*Lx(i,j)*Ly(i,j)
104  +Lxy(i,j)*Ly(i,j)*Ly(i,j)
105  -Lyy(i,j)*Lx(i,j)*Ly(i,j)
106  -Lxy(i,j)*Lx(i,j)*Lx(i,j);
107 
108  // %eij(LjklLiLkLl-LjkkLiLlLl)=(2LxyyLxLxLy)-(2LxxyLxLyLy)-(LxxyLxLyLy)-(LyyyLxLxLx)+(LxyyLyLxLx)+(LxxxLyLyLy)
109  // cdi(5,:,:) = (2.*Lxyy.*Lx.*Lx.*Ly)-(2.*Lxxy.*Lx.*Ly.*Ly)-(Lxxy.*Lx.*Ly.*Ly)
110  // -(Lyyy.*Lx.*Lx.*Lx)+(Lxyy.*Ly.*Lx.*Lx)+(Lxxx.*Ly.*Ly.*Ly);
111  dest(j,i,4)= T(2)*Lxyy(i,j)*Lx(i,j)*Lx(i,j)*Ly(i,j)
112  -T(2)*Lxxy(i,j)*Lx(i,j)*Ly(i,j)*Ly(i,j)
113  -Lxxy(i,j)*Lx(i,j)*Ly(i,j)*Ly(i,j)
114  -Lyyy(i,j)*Lx(i,j)*Lx(i,j)*Lx(i,j)
115  +Lxyy(i,j)*Ly(i,j)*Lx(i,j)*Lx(i,j)
116  +Lxxx(i,j)*Ly(i,j)*Ly(i,j)*Ly(i,j);
117 
118 
119  // %LiijLjLkLk-LijkLiLjLk=(LxxxLxLyLy)-(2LxxyLxLxLy)+(LxxyLyLyLy)+(LxyyLxLxLx)-(2LxyyLxLyLy)+(LyyylxLxLy)
120  // cdi(6,:,:) = (Lxxx.*Lx.*Ly.*Ly)-(2.*Lxxy.*Lx.*Lx.*Ly)+(Lxxy.*Ly.*Ly.*Ly)
121  // +(Lxyy.*Lx.*Lx.*Lx)-(2.*Lxyy.*Lx.*Ly.*Ly)+(Lyyy.*Lx.*Lx.*Ly);
122  dest(j,i,5)= Lxxx(i,j)*Lx(i,j)*Ly(i,j)*Ly(i,j)
123  -T(2)*Lxxy(i,j)*Lx(i,j)*Lx(i,j)*Ly(i,j)
124  +Lxxy(i,j)*Ly(i,j)*Ly(i,j)*Ly(i,j)
125  +Lxyy(i,j)*Lx(i,j)*Lx(i,j)*Lx(i,j)
126  -T(2)*Lxyy(i,j)*Lx(i,j)*Ly(i,j)*Ly(i,j)
127  +Lyyy(i,j)*Lx(i,j)*Lx(i,j)*Ly(i,j);
128 
129 
130  // %-eijLjklLiLkLl=(LxxxLxLxLy)+(2LxxyLxLyLy)+(LxyyLyLyLy)-(LyyyLxLyLy)-(2LxyyLxLxLy)-(LxxyLxLxLx)
131  // cdi(7,:,:) = (Lxxx.*Lx.*Lx.*Ly)+(2.*Lxxy.*Lx.*Ly.*Ly)+(Lxyy.*Ly.*Ly.*Ly)
132  // -(Lyyy.*Lx.*Ly.*Ly)-(2.*Lxyy.*Lx.*Lx.*Ly)-(Lxxy.*Lx.*Lx.*Lx);
133  dest(j,i,6)= Lxxx(i,j)*Lx(i,j)*Lx(i,j)*Ly(i,j)
134  +T(2)*Lxxy(i,j)*Lx(i,j)*Ly(i,j)*Ly(i,j)
135  +Lxyy(i,j)*Ly(i,j)*Ly(i,j)*Ly(i,j)
136  -Lyyy(i,j)*Lx(i,j)*Ly(i,j)*Ly(i,j)
137  -T(2)*Lxyy(i,j)*Lx(i,j)*Lx(i,j)*Ly(i,j)
138  -Lxxy(i,j)*Lx(i,j)*Lx(i,j)*Lx(i,j);
139 
140 
141  // %LijkLiLjLk=(LxxxLxLxLx)+(LyyyLyLyLy)+(3LxxyLxLxLy)+(3LxyyLxLyLy)
142  // cdi(8,:,:)=(Lxxx.*Lx.*Lx.*Lx)+(Lyyy.*Ly.*Ly.*Ly)+(3.*Lxxy.*Lx.*Lx.*Ly)+(3.*Lxyy.*Lx.*Ly.*Ly);
143  dest(j,i,7)= Lxxx(i,j)*Lx(i,j)*Lx(i,j)*Lx(i,j)
144  +Lyyy(i,j)*Ly(i,j)*Ly(i,j)*Ly(i,j)
145  +T(3)*Lxxy(i,j)*Lx(i,j)*Lx(i,j)*Ly(i,j)
146  +T(3)*Lxyy(i,j)*Lx(i,j)*Ly(i,j)*Ly(i,j);
147  }
148  }
149 }
150 
151 
152 //: Compute 1st, 2nd, and 3rd order C.d.i.s of an image.
153 template <class S, class T>
155  const vil_image_view<S>& src, vil_image_view<T>& dest, double scale, unsigned max_kernel_width /*=0*/)
156 {
157  dest.set_size(src.ni(), src.nj(), src.nplanes()*8);
158  assert(dest.planestep() >= int(dest.ni() * dest.nj()));
159 
160  for (unsigned p=0; p < src.nplanes(); ++p)
161  {
162  vil_image_view<T> destplanes = vil_planes(dest, p*8, 1, 8);
163 #ifndef NDEBUG
164  vil_image_view<T> check = destplanes;
165 #endif
166  vil_cartesian_differential_invariants_3_1plane(vil_plane(src, p), destplanes, scale, max_kernel_width);
167  assert(destplanes == check);
168  }
169 }
170 
171 #undef VIL_CARTESIAN_DIFFERENTIAL_INVARIANTS_INSTANTIATE
172 #define VIL_CARTESIAN_DIFFERENTIAL_INVARIANTS_INSTANTIATE(S, T) \
173 template void \
174 vil_cartesian_differential_invariants_3( const vil_image_view< S >& src, \
175  vil_image_view< T >& dest, double, unsigned )
176 
177 #endif // vil_cartesian_differential_invariants_hxx_
void vil_gauss_filter_gen_ntap(double sd, unsigned diff, std::vector< double > &filter)
Generate an n-tap FIR filter from a Gaussian function.
Smooths images.
Extend the signal to be constant beyond the boundary.
void vil_cartesian_differential_invariants_3(const vil_image_view< S > &src, vil_image_view< T > &dest, double scale, unsigned max_kernel_width=0)
Compute up to 3rd order C.d.i. of an image.
Concrete view of image data of type T held in memory.
Definition: vil_fwd.h:13
void set_size(unsigned ni, unsigned nj) override
resize current planes to ni x nj.
vil_convolve_boundary_option
Available options for boundary behavior.
unsigned ni() const
Width.
unsigned nj() const
Height.
std::ptrdiff_t planestep() const
Add this to your pixel pointer to get pixel on next plane.
A base class reference-counting view of some image data.
Find Cartesian differential Invariants.
void vil_cartesian_differential_invariants_3_1plane(const vil_image_view< S > &src, vil_image_view< T > &dest, double scale, unsigned max_kernel_width)
Compute 1st, 2nd, and 3rd order C.d.i.s of an image.
vil_image_view< T > vil_plane(const vil_image_view< T > &im, unsigned p)
Return a view of im's plane p.
Definition: vil_plane.h:20
void vil_convolve_1d(const vil_image_view< srcT > &src_im, vil_image_view< destT > &dest_im, const kernelT *kernel, std::ptrdiff_t k_lo, std::ptrdiff_t k_hi, accumT ac, vil_convolve_boundary_option start_option, vil_convolve_boundary_option end_option)
Convolve kernel[i] (i in [k_lo,k_hi]) with srcT in i-direction.
unsigned nplanes() const
Number of planes.
vil_image_view< T > vil_planes(const vil_image_view< T > &im, unsigned first, int skip, unsigned n)
Return a view of a selection of im's planes.
Definition: vil_plane.h:35
1D Convolution with cunning boundary options
vil_image_view< T > vil_transpose(const vil_image_view< T > &v)
Create a view which appears as the transpose of this view.
Definition: vil_transpose.h:16