DGtal  0.9.2
testArrayImageAdapter.cpp
1 
26 #include <cstddef>
27 #include <iostream>
28 #include <new>
29 #include <cmath>
30 
31 #include <DGtal/kernel/SpaceND.h>
32 #include <DGtal/kernel/domains/HyperRectDomain.h>
33 #include <DGtal/images/ImageContainerBySTLVector.h>
34 #include <DGtal/images/CConstImage.h>
35 #include <DGtal/images/CImage.h>
36 
37 #include <DGtal/images/ArrayImageAdapter.h>
38 
39 #include "DGtalCatch.h"
40 
41 using namespace DGtal;
42 using namespace std;
43 
44 template < typename TImage, typename TDomain >
45 void fillImageWithCounter ( TImage& anImage, TDomain const& aDomain )
46 {
47  size_t cnt = 0;
48  for ( auto const& point : aDomain )
49  anImage.setValue( point, cnt++ );
50 }
51 
52 template < typename TImage >
53 void fillImageWithCounter ( TImage& anImage )
54 {
55  fillImageWithCounter( anImage, anImage.domain() );
56 }
57 
58 template < typename TImage, typename TFunction, typename TDomain >
59 void fillImageWithPointFn ( TImage& anImage, TFunction const& aFunction, TDomain const& domain )
60 {
61  using Image = TImage;
62  using Value = typename Image::Value;
63  for ( auto const& point : domain )
64  {
65  Value value = 0;
66  for ( size_t i = 0; i < Image::dimension; ++i )
67  value += aFunction( i, point[i] );
68 
69  anImage.setValue(point, value);
70  }
71 }
72 
73 template < typename TImage, typename TFunction >
74 void fillImageWithPointFn ( TImage& anImage, TFunction const& aFunction )
75 {
76  fillImageWithPointFn ( anImage, aFunction, anImage.domain() );
77 }
78 
79 template < typename TImage, typename TFunction, typename TDomain >
80 void incrementImageWithPointFn ( TImage& anImage, TFunction const& aFunction, TDomain const& domain )
81 {
82  using Image = TImage;
83  using Value = typename Image::Value;
84  for ( auto const& point : domain )
85  {
86  Value value = anImage(point);
87  for ( size_t i = 0; i < Image::dimension; ++i )
88  value += aFunction( i, point[i] );
89 
90  anImage.setValue(point, value);
91  }
92 }
93 
94 template < typename TImage, typename TFunction >
95 void incrementImageWithPointFn ( TImage& anImage, TFunction const& aFunction )
96 {
97  incrementImageWithPointFn ( anImage, aFunction, anImage.domain() );
98 }
99 
100 template < typename TDomain, typename TValue, typename TFunction >
101 void fastFillImageWithPointFn ( ImageContainerBySTLVector<TDomain, TValue>& anImage, TFunction const& aFunction )
102 {
104  using Value = typename Image::Value;
105  auto imgit = anImage.begin();
106  for ( auto const& point : anImage.domain() )
107  {
108  Value value = 0;
109  for ( size_t i = 0; i < Image::dimension; ++i )
110  value += aFunction( i, point[i] );
111 
112  *(imgit++) = value;
113  }
114 }
115 
116 template < typename TIterator, typename TDomain, typename TFunction >
117 void fastFillImageWithPointFn ( ArrayImageAdapter<TIterator, TDomain>& anImage, TFunction const& aFunction )
118 {
119  using Image = ArrayImageAdapter<TIterator, TDomain>;
120  using Value = typename Image::Value;
121  for ( auto imgit = anImage.begin(); imgit != anImage.end(); ++imgit )
122  {
123  Value value = 0;
124  auto const point = imgit.getPoint();
125 
126  for ( size_t i = 0; i < Image::dimension; ++i )
127  value += aFunction( i, point[i] );
128 
129  *imgit = value;
130  }
131 }
132 
133 template < typename TImage >
134 void checkImage( TImage& anImage )
135 {
136  using Image = TImage;
137  using Value = typename Image::Value;
138  using Domain = typename Image::Domain;
139  using Point = typename Image::Point;
140  using Dimension = typename Point::Dimension;
141  using Coordinate = typename Point::Coordinate;
143 
144  // Checks CImage concept.
145  BOOST_CONCEPT_ASSERT( (DGtal::concepts::CImage<TImage>) );
146 
147  size_t nb = 0;
148  size_t nbok = 0;
149 
150  // Full domain
151  auto const domain = anImage.domain();
152 
153  // Sub domain
154  Point lowerPt = domain.lowerBound();
155  Point upperPt = domain.upperBound();
156  for ( Dimension i = 0; i < Domain::dimension; ++i )
157  {
158  lowerPt[i] = std::min( upperPt[i]-1, lowerPt[i] + 1 + static_cast<Coordinate>(i) );
159  upperPt[i] = std::max( lowerPt[i]+1, upperPt[i] - static_cast<Coordinate>(Domain::dimension - i) );
160  }
161  auto const sub_domain = Domain( lowerPt, upperPt );
162 
163  // Checks that sub domain is not empty and different of full domain
164  REQUIRE( (!sub_domain.isEmpty() && sub_domain.size() != domain.size()) );
165 
166  // Reference image
167  RefImage ref_image( domain );
168 
169  // The filling function
170  auto const fn = [] (size_t i, Coordinate x) { return cos( static_cast<Value>(pow(100, i)*x ) ); };
171 
172  // Fill with function
173  SECTION( "Filling with point dependant function" )
174  {
175  fillImageWithPointFn( ref_image, fn );
176  fillImageWithPointFn( anImage, fn );
177  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
178  }
179 
180  // Fill with counter
181  SECTION( "Filling with counter" )
182  {
183  fillImageWithCounter( ref_image );
184  fillImageWithCounter( anImage );
185  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
186  }
187 
188  // Fast filling with function
189  SECTION( "Fast filling with point dependant function" )
190  {
191  fastFillImageWithPointFn( ref_image, fn );
192  fastFillImageWithPointFn( anImage, fn );
193  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
194  }
195 
196  // Tests that need images to be initialized.
197  SECTION( "Tests on initialized images" )
198  {
199  fastFillImageWithPointFn( ref_image, fn );
200  fastFillImageWithPointFn( anImage, fn );
201  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
202 
203  // Increment with function
204  SECTION( "Incrementing with point dependant function" )
205  {
206  incrementImageWithPointFn( ref_image, fn );
207  incrementImageWithPointFn( anImage, fn );
208  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
209  }
210 
211  // Partial fill with counter
212  SECTION( "Partial filling with counter" )
213  {
214  auto sub_image = makeArrayImageAdapterFromImage( anImage, sub_domain );
215  fillImageWithCounter( ref_image, sub_domain );
216  fillImageWithCounter( sub_image );
217  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
218  }
219 
220  // Partial increment with function
221  SECTION( "Partial increment with point dependant function" )
222  {
223  auto sub_image = makeArrayImageAdapterFromImage( anImage, sub_domain );
224  incrementImageWithPointFn( ref_image, fn, sub_domain );
225  incrementImageWithPointFn( sub_image, fn );
226  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
227  }
228 
229  // Fast partial fill with function
230  SECTION( "Fast partial filling with point dependand function" )
231  {
232  auto sub_image = makeArrayImageAdapterFromImage( anImage, sub_domain );
233  fillImageWithPointFn( ref_image, fn, sub_domain );
234  fastFillImageWithPointFn( sub_image, fn );
235  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
236  }
237  }
238 }
239 
240 // Context for each image test
241 template < DGtal::Dimension N >
242 struct TestImage
243 {
244  using Space = SpaceND<N>;
246  using Value = double;
247 
248  template < typename TImage >
249  static
250  void checkThat( TImage & anImage )
251  {
252  checkImage(anImage);
253  }
254 
255  static const Domain domain;
256  static const Domain subDomain;
257 };
258 
259 // Context data for 3D image tests
260 using TestImage3D = TestImage<3>;
261 template <> const TestImage3D::Domain TestImage3D::domain{ {0, 1, 2}, {12, 8, 11} };
262 template <> const TestImage3D::Domain TestImage3D::subDomain{ {0, 2, 4}, {8, 7, 10} };
263 
264 // Test cases
265 TEST_CASE_METHOD( TestImage3D, "Checking ArrayImageAdapter with C-style array", "[CArray][FullDomain]" )
266 {
267  Value* data = new Value[domain.size()];
268  auto image = makeArrayImageAdapterFromIterator( data, domain );
269  checkThat(image);
270  delete[] data;
271 }
272 
273 TEST_CASE_METHOD( TestImage3D, "Checking ArrayImageAdapter with C-style array on sub-domain", "[CArray][SubDomain]" )
274 {
275  Value* data = new Value[domain.size()];
276  auto image = makeArrayImageAdapterFromIterator( data, domain, subDomain );
277  checkThat(image);
278  delete[] data;
279 }
280 
281 TEST_CASE_METHOD( TestImage3D, "Checking ArrayImageAdapter with ImageContainerBySTLVector", "[ImageSTL][FullDomain]" )
282 {
284  auto image_view = makeArrayImageAdapterFromImage( image );
285  checkThat(image_view);
286 }
287 
288 TEST_CASE_METHOD( TestImage3D, "Checking ArrayImageAdapter with ImageContainerBySTLVector on sub-domain", "[ImageSTL][SubDomain]" )
289 {
291  auto image_view = makeArrayImageAdapterFromImage( image, subDomain );
292  checkThat(image_view);
293 }
294 
Aim: implements association bewteen points lying in a digital domain and values.
Definition: Image.h:69
Aim: SpaceND is a utility class that defines the fundamental structure of a Digital Space in ND...
Definition: SpaceND.h:95
DGtal::uint32_t Dimension
Definition: Common.h:113
TImageContainer::Point Point
Definition: Image.h:83
STL namespace.
ArrayImageAdapter< TArrayIterator, TDomain > makeArrayImageAdapterFromIterator(TArrayIterator anArrayIterator, TDomain const &aFullDomain, TDomain const &aViewDomain)
ArrayImageAdapter< decltype(((TImage *) nullptr) ->begin()), TDomain > makeArrayImageAdapterFromImage(TImage &anImage, TDomain const &aViewDomain)
DGtal is the top-level namespace which contains all DGtal functions and types.
const Domain & domain() const
TImageContainer::Value Value
Definition: Image.h:84
Aim: Defines the concept describing a read/write image, having an output iterator.
Definition: CImage.h:102
TImageContainer::Domain Domain
Definition: Image.h:82