DGtal  1.5.beta
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 ( Dimension 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 ( Dimension 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 {
103  typedef ImageContainerBySTLVector<TDomain, TValue> Image; // 'typedef' instead of 'using' because of g++ 4.7.4 bug.
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 ( Dimension 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  typedef ArrayImageAdapter<TIterator, TDomain> Image; // 'typedef' instead of 'using' because of g++ 4.7.4 bug.
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 ( Dimension 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 Coordinate = typename Point::Coordinate;
142 
143  // Checks CImage concept.
144  BOOST_CONCEPT_ASSERT( (DGtal::concepts::CImage<TImage>) );
145 
146  // Full domain
147  auto const domain = anImage.domain();
148 
149  // Sub domain
150  Point lowerPt = domain.lowerBound();
151  Point upperPt = domain.upperBound();
152  for ( Dimension i = 0; i < Domain::dimension; ++i )
153  {
154  lowerPt[i] = std::min( upperPt[i]-1, lowerPt[i] + 1 + static_cast<Coordinate>(i) );
155  upperPt[i] = std::max( lowerPt[i]+1, upperPt[i] - static_cast<Coordinate>(Domain::dimension - i) );
156  }
157  auto const sub_domain = Domain( lowerPt, upperPt );
158 
159  // Checks that sub domain is not empty and different of full domain
160  REQUIRE( (!sub_domain.isEmpty() && sub_domain.size() != domain.size()) );
161 
162  // Reference image
163  RefImage ref_image( domain );
164 
165  // The filling function
166  auto const fn = [] (size_t i, Coordinate x) { return cos( static_cast<Value>(pow(100, i)*x ) ); };
167 
168  // Fill with function
169  SECTION( "Filling with point dependant function" )
170  {
171  fillImageWithPointFn( ref_image, fn );
172  fillImageWithPointFn( anImage, fn );
173  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
174  }
175 
176  // Fill with counter
177  SECTION( "Filling with counter" )
178  {
179  fillImageWithCounter( ref_image );
180  fillImageWithCounter( anImage );
181  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
182  }
183 
184  // Fast filling with function
185  SECTION( "Fast filling with point dependant function" )
186  {
187  fastFillImageWithPointFn( ref_image, fn );
188  fastFillImageWithPointFn( anImage, fn );
189  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
190  }
191 
192  // Tests that need images to be initialized.
193  SECTION( "Tests on initialized images" )
194  {
195  fastFillImageWithPointFn( ref_image, fn );
196  fastFillImageWithPointFn( anImage, fn );
197  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
198 
199  // Increment with function
200  SECTION( "Incrementing with point dependant function" )
201  {
202  incrementImageWithPointFn( ref_image, fn );
203  incrementImageWithPointFn( anImage, fn );
204  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
205  }
206 
207  // Partial fill with counter
208  SECTION( "Partial filling with counter" )
209  {
210  auto sub_image = makeArrayImageAdapterFromImage( anImage, sub_domain );
211  fillImageWithCounter( ref_image, sub_domain );
212  fillImageWithCounter( sub_image );
213  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
214  }
215 
216  // Partial increment with function
217  SECTION( "Partial increment with point dependant function" )
218  {
219  auto sub_image = makeArrayImageAdapterFromImage( anImage, sub_domain );
220  incrementImageWithPointFn( ref_image, fn, sub_domain );
221  incrementImageWithPointFn( sub_image, fn );
222  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
223  }
224 
225  // Fast partial fill with function
226  SECTION( "Fast partial filling with point dependand function" )
227  {
228  auto sub_image = makeArrayImageAdapterFromImage( anImage, sub_domain );
229  fillImageWithPointFn( ref_image, fn, sub_domain );
230  fastFillImageWithPointFn( sub_image, fn );
231  REQUIRE( std::equal( ref_image.begin(), ref_image.end(), anImage.begin() ) );
232  }
233  }
234 }
235 
236 // Context for each image test
237 template < DGtal::Dimension N >
238 struct TestImage
239 {
240  using Space = SpaceND<N>;
242  using Value = double;
243 
244  template < typename TImage >
245  static
246  void checkThat( TImage & anImage )
247  {
248  checkImage(anImage);
249  }
250 
251  static const Domain domain;
252  static const Domain subDomain;
253 };
254 
255 // Context data for 3D image tests
256 using TestImage3D = TestImage<3>;
257 using Point3D = TestImage3D::Domain::Point;
258 template <> const TestImage3D::Domain TestImage3D::domain{ Point3D{0, 1, 2}, Point3D{12, 8, 11} };
259 template <> const TestImage3D::Domain TestImage3D::subDomain{ Point3D{0, 2, 4}, Point3D{8, 7, 10} };
260 
261 // Test cases
262 TEST_CASE_METHOD( TestImage3D, "Checking ArrayImageAdapter with C-style array", "[CArray][FullDomain]" )
263 {
264  Value* data = new Value[domain.size()];
265  auto image = makeArrayImageAdapterFromIterator( data, domain );
266  checkThat(image);
267  delete[] data;
268 }
269 
270 TEST_CASE_METHOD( TestImage3D, "Checking ArrayImageAdapter with C-style array on sub-domain", "[CArray][SubDomain]" )
271 {
272  Value* data = new Value[domain.size()];
273  auto image = makeArrayImageAdapterFromIterator( data, domain, subDomain );
274  checkThat(image);
275  delete[] data;
276 }
277 
278 TEST_CASE_METHOD( TestImage3D, "Checking ArrayImageAdapter with ImageContainerBySTLVector", "[ImageSTL][FullDomain]" )
279 {
281  auto image_view = makeArrayImageAdapterFromImage( image );
282  checkThat(image_view);
283 }
284 
285 TEST_CASE_METHOD( TestImage3D, "Checking ArrayImageAdapter with ImageContainerBySTLVector on sub-domain", "[ImageSTL][SubDomain]" )
286 {
288  auto image_view = makeArrayImageAdapterFromImage( image, subDomain );
289  checkThat(image_view);
290 }
291 
const Point & lowerBound() const
const Point & upperBound() const
const Domain & domain() const
Aim: implements association bewteen points lying in a digital domain and values.
Definition: Image.h:70
TImageContainer::Point Point
Definition: Image.h:83
TImageContainer::Domain Domain
Definition: Image.h:82
TImageContainer::Value Value
Definition: Image.h:84
DGtal is the top-level namespace which contains all DGtal functions and types.
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::uint32_t Dimension
Definition: Common.h:136
Aim: Defines the concept describing a read/write image, having an output iterator.
Definition: CImage.h:103
int max(int a, int b)
MyPointD Point
Definition: testClone2.cpp:383
bool checkImage(const Image &a, const Image &b)
TEST_CASE_METHOD(Fixture_object_diamond_with_hole, "Basic Graph functions", "[interface]")
Domain domain
Image image(domain)
ImageContainerBySTLVector< Domain, Value > Image
SECTION("Testing constant forward iterators")
HyperRectDomain< Space > Domain
REQUIRE(domain.isInside(aPoint))