Imagine++
Algos.h
1 // ===========================================================================
2 // Imagine++ Libraries
3 // Copyright (C) Imagine
4 // For detailed information: http://imagine.enpc.fr/software
5 // ===========================================================================
6 
7 namespace Imagine {
10 
11  // ===============================================
12  // Scalings
13 
22  template <typename T, int dim>
23  Image<T,dim> scaleUp(const Image<T,dim>&I,int fact)
24  {
25  Image<T,dim> I1(I.sizes() * fact);
26  // coordinates aware iterator
27  for (CoordsIterator<dim> r = I.coordsBegin() ; r != I.coordsEnd() ; ++r) {
28  Coords<dim> o=*r;
29  T b=I(o);
30  for (CoordsIterator<dim> zr(o * fact, o * fact + Coords<dim>(fact-1));zr!=I.coordsEnd();++zr){
31  I1(*zr)=b;
32  }
33  }
34  return I1;
35  }
44  template <typename T, int dim>
45  Image<T,dim> scaleDown(const Image<T,dim>&I,int fact)
46  {
47  Image<T,dim> I1(I.sizes()/fact);
48  // coordinates aware iterator
49  for (CoordsIterator<dim> r = I1.coordsBegin() ; r != I1.coordsEnd() ; ++r)
50  I1(*r)=I((*r)*fact);
51  return I1;
52  }
61  template <typename T, int dim>
62  Image<T,dim> reduce(const Image<T,dim>&I, int fact)
63  {
64  typedef typename PixelTraits<T>::template CastPixel<double>::value_type doubleT;
65  Coords<dim> d=I.sizes()/fact;
66  double nb=pow(double(fact),dim);
67  Image<T,dim> Ir(d);
68  for (CoordsIterator<dim> r = Ir.coordsBegin() ; r != Ir.coordsEnd() ; ++r) {
69  doubleT p(0.);
70  for (CoordsIterator<dim> r2((*r)*fact,((*r)*fact+Coords<dim>(fact-1))); r2!=CoordsIterator<dim>(); ++r2) {
71  p+=doubleT(I(*r2));
72  }
73  Ir(*r)=T(p/nb);
74  }
75  return Ir;
76  }
87  template <typename T, int dim>
88  Image<T,dim> reduce(const Image<T,dim>&I,Coords<dim> nd,bool keepRatio=false)
89  {
90  typedef typename PixelTraits<T>::template CastPixel<double>::value_type doubleT;
91  Image<doubleT,dim> oI(I);
92  Coords<dim> od=I.sizes();
94  std::pair<double,double> mM = range(f);
95  assert(mM.first>=1);
96  if (keepRatio) {
97  f.fill(mM.second);
98  nd=Coords<dim>(FVector<double,dim>(od)/mM.second);
99  }
100  inPlaceBlur(oI,1.5*(sqrt(f)-.99)); // Todo: better filtering
101  Image<T,dim> nI(nd);
102  for (CoordsIterator<dim> r = nI.coordsBegin() ; r != nI.coordsEnd() ; ++r) {
104  nI(*r)=T(oI.interpolate(x));
105  }
106  return nI;
107  }
109  template <typename T> Image<T,2> inline reduce(const Image<T,2>&I,int w,int h,bool keepRatio=false) { return reduce(I,Coords<2>(w,h),keepRatio); } // Reduce image (given dimensions), 3D alias.
111  template <typename T> Image<T,3> inline reduce(const Image<T,3>&I,int w,int h,int d,bool keepRatio=false) { return reduce(I,Coords<3>(w,h,d),keepRatio); }
120  template <typename T,int dim>
121  inline Image<T,dim> reduce(const Image<T,dim>&I,double fact)
122  {
124  return reduce(I,nd);
125  }
136  template <typename T,int dim>
137  Image<T,dim> enlarge(const Image<T,dim>&I,Coords<dim> nd,bool keepRatio=false)
138  {
139  typedef typename PixelTraits<T>::template CastPixel<double> doubleT;
140  Coords<dim> od=I.sizes();
142  std::pair<double,double> mM = range(f);
143  assert(mM.second<=1);
144  if (keepRatio) {
145  f.fill(mM.second);
146  nd=Coords<dim>(FVector<double,dim>(od)/mM.second);
147  }
148  Image<T,dim> nI(nd);
149  for (CoordsIterator<dim> r = nI.coordsBegin() ; r != nI.coordsEnd() ; ++r) {
151  nI(*r)=T(I.interpolate(x));
152  }
153  return nI;
154  }
156  template <typename T> Image<T,2> inline enlarge(const Image<T,2>&I,int w,int h,bool keepRatio=false) { return enlarge(I,Coords<2>(w,h),keepRatio); }
158  template <typename T> Image<T,3> inline enlarge(const Image<T,3>&I,int w,int h,int d,bool keepRatio=false) { return enlarge(I,Coords<3>(w,h,d),keepRatio); }
167  template <typename T,int dim>
168  inline Image<T,dim> enlarge(const Image<T,dim>&I,double fact)
169  {
171  return enlarge(I,nd);
172  }
173 
174  // ===============================================
175  // Deriche
176 
188  template <typename T,int dim>
189  void inPlaceDeriche(Image<T,dim>&I,typename PixelTraits<T>::scalar_type sigma, int order, int d, bool neumann = true) {
190  // Checks parameter values
191  assert(sigma>0 && order>=0 && order<3 && d>=0 && d<dim);
192 
193  // Computes coefficients of the recursive filter
194  const typename PixelTraits<T>::scalar_type
195  alpha = 1.695f/sigma,
196  ea = std::exp(alpha),
197  ema = std::exp(-alpha),
198  em2a = ema*ema,
199  b1 = 2*ema,
200  b2 = -em2a;
201 
202  typename PixelTraits<T>::scalar_type ek,ekn,parity,a1,a2,a3,a4,g0,sumg1,sumg0;
203 
204  switch(order) {
205 
206  // first-order derivative
207  case 1:
208  ek = -(1-ema)*(1-ema)*(1-ema)/(2*(ema+1)*ema);
209  a1 = a4 = 0;
210  a2 = ek*ema;
211  a3 = -ek*ema;
212  parity = -1;
213  if (neumann) {
214  sumg1 = (ek*ea) / ((ea-1)*(ea-1));
215  g0 = 0;
216  sumg0 = g0 + sumg1;
217  }
218  else
219  g0 = sumg0 = sumg1 = 0;
220  break;
221 
222  // second-order derivative
223  case 2:
224  ekn = ( -2*(-1+3*ea-3*ea*ea+ea*ea*ea)/(3*ea+1+3*ea*ea+ea*ea*ea) );
225  ek = -(em2a-1)/(2*alpha*ema);
226  a1 = ekn;
227  a2 = -ekn*(1+ek*alpha)*ema;
228  a3 = ekn*(1-ek*alpha)*ema;
229  a4 = -ekn*em2a;
230  parity = 1;
231  if (neumann) {
232  sumg1 = ekn/2;
233  g0 = ekn;
234  sumg0 = g0 + sumg1;
235  }
236  else
237  g0 = sumg0 = sumg1 = 0;
238  break;
239 
240  // smoothing
241  default:
242  ek = (1-ema)*(1-ema) / (1+2*alpha*ema - em2a);
243  a1 = ek;
244  a2 = ek*ema*(alpha-1);
245  a3 = ek*ema*(alpha+1);
246  a4 = -ek*em2a;
247  parity = 1;
248  if (neumann) {
249  sumg1 = ek*(alpha*ea+ea-1) / ((ea-1)*(ea-1));
250  g0 = ek;
251  sumg0 = g0 + sumg1;
252  }
253  else
254  g0 = sumg0 = sumg1 = 0;
255  break;
256  }
257 
258  // filter init
259  T *Y = new T[I.size(d)];
260  const size_t offset = I.stride(d);
261  const size_t nb = I.size(d);
262 
263  // Iterates on dimensions other than d
264  Coords<dim> beg(0), end = I.sizes() - Coords<dim>(1);
265  end[d]=0;
266  for (CoordsIterator<dim> p(beg,end); p != CoordsIterator<dim>(); ++p) {
267  T *ima = &(I(*p));
268  T I2 = *ima; ima += offset;
269  T I1 = *ima; ima += offset;
270  T Y2 = *(Y++) = sumg0*I2;
271  T Y1 = *(Y++) = g0*I1 + sumg1*I2;
272  for (size_t i=2; i<nb; i++) {
273  I1 = *ima; ima+=offset;
274  T Y0 = *(Y++) = a1*I1 + a2*I2 + b1*Y1 + b2*Y2;
275  I2=I1; Y2=Y1; Y1=Y0;
276  }
277  ima -= offset;
278  I2 = *ima;
279  Y2 = Y1 = (parity*sumg1)*I2;
280  *ima = *(--Y)+Y2;
281  ima-=offset;
282  I1 = *ima;
283  *ima = *(--Y)+Y1;
284  for (size_t i=nb-3; ; i--) {
285  T Y0 = a3*I1+a4*I2+b1*Y1+b2*Y2;
286  ima-=offset;
287  I2=I1;
288  I1=*ima;
289  *ima=*(--Y)+Y0;
290  Y2=Y1;
291  Y1=Y0;
292  if (i==0)
293  break;
294  }
295  }
296  delete [] Y;
297 
298  }
311  template <typename T,int dim>
312  Image<T,dim> deriche(const Image<T,dim>&I,typename PixelTraits<T>::scalar_type sigma, int order, int d, bool neumann = true) {
313  Image<T,dim> J=I.clone();
314  inPlaceDeriche(J,sigma,order,d,neumann);
315  return J;
316  }
325  template <typename T,int dim>
326  void inPlaceBlur(Image<T,dim>&I,const FVector<typename PixelTraits<T>::scalar_type,dim>& sigmas, bool neumann = true) {
327  for (int i=0;i<dim;i++) {
328  inPlaceDeriche(I,sigmas[i], 0, i, neumann);
329  }
330  }
339  template <typename T,int dim>
340  void inPlaceBlur(Image<T,dim>&I,typename PixelTraits<T>::scalar_type sigma, bool neumann = true) {
341  inPlaceBlur(I,FVector<typename PixelTraits<T>::scalar_type,dim>(sigma),neumann);
342  }
352  template <typename T,int dim>
353  Image<T,dim> blur(const Image<T,dim>&I,typename PixelTraits<T>::scalar_type sigma, bool neumann = true) {
354  Image<T,dim> J=I.clone();
355  inPlaceBlur(J,sigma,neumann);
356  return J;
357  }
367  template <typename T,int dim>
368  Image<T,dim> blur(const Image<T,dim>&I,const FVector<typename PixelTraits<T>::scalar_type,dim>& sigmas, bool neumann = true) {
369  Image<T,dim> J=I.clone();
370  inPlaceBlur(J,sigmas,neumann);
371  return J;
372  }
373 
375 }
PixelTraits< T >::template CastPixel< V >::value_type interpolate(const FVector< V, dim > &c) const
Interpolation.
Definition: Image.h:198
Coordinates.
Definition: Coords.h:16
Vector of fixed size.
Definition: FVector.h:17
FVector & fill(const T &v)
Filling.
Definition: FVector.h:75
Image< T, dim > scaleDown(const Image< T, dim > &I, int fact)
Down scaling: fast naive version.
Definition: Algos.h:45
Iterator on Coordinates.
Definition: Coords.h:83
CoordsIterator< dim > coordsEnd() const
End coords iterator.
Definition: MultiArray.h:379
FArray< size_t, dim > stride() const
Stride.
Definition: MultiArray.h:253
Image< T, dim > blur(const Image< T, dim > &I, typename PixelTraits< T >::scalar_type sigma, bool neumann=true)
Blur.
Definition: Algos.h:353
Image.
Definition: Image.h:24
Image< T, dim > deriche(const Image< T, dim > &I, typename PixelTraits< T >::scalar_type sigma, int order, int d, bool neumann=true)
Deriche filter.
Definition: Algos.h:312
Coords< dim > sizes() const
Sizes.
Definition: MultiArray.h:211
int size(int i) const
ith size.
Definition: MultiArray.h:225
Image clone() const
Cloning.
Definition: Image.h:146
Image< T, dim > reduce(const Image< T, dim > &I, int fact)
Reduce image (integer factor).
Definition: Algos.h:62
Imagine++ namespace.
Definition: Array.h:7
void inPlaceDeriche(Image< T, dim > &I, typename PixelTraits< T >::scalar_type sigma, int order, int d, bool neumann=true)
In place Deriche filter.
Definition: Algos.h:189
void inPlaceBlur(Image< T, dim > &I, const FVector< typename PixelTraits< T >::scalar_type, dim > &sigmas, bool neumann=true)
In Place Blur (anisotropic).
Definition: Algos.h:326
Image< T, dim > scaleUp(const Image< T, dim > &I, int fact)
Up scaling: fast naive version.
Definition: Algos.h:23
CoordsIterator< dim > coordsBegin() const
Begin coords iterator.
Definition: MultiArray.h:371
Image< T, dim > enlarge(const Image< T, dim > &I, Coords< dim > nd, bool keepRatio=false)
Enlarge image (given dimensions).
Definition: Algos.h:137