test_core.cpp
Go to the documentation of this file.
1 /*
2 * ECVL - European Computer Vision Library
3 * Version: 0.3.4
4 * copyright (c) 2021, Università degli Studi di Modena e Reggio Emilia (UNIMORE), AImageLab
5 * Authors:
6 * Costantino Grana (costantino.grana@unimore.it)
7 * Federico Bolelli (federico.bolelli@unimore.it)
8 * Michele Cancilla (michele.cancilla@unimore.it)
9 * Laura Canalini (laura.canalini@unimore.it)
10 * Stefano Allegretti (stefano.allegretti@unimore.it)
11 * All rights reserved.
12 */
13 
14 #include <gtest/gtest.h>
15 
16 #ifdef ECVL_GPU
17 #include <cuda_runtime.h>
18 #include "test_cuda.h"
19 #include "ecvl/core/cuda/common.h"
20 #endif
21 
22 #include "ecvl/core.h"
23 
24 using namespace ecvl;
25 
26 namespace
27 {
28 class TCore : public ::testing::Test
29 {
30 protected:
31  Image out;
32 
33 #define ECVL_TUPLE(type, ...) \
34  Image g2_##type = Image({ 2, 2, 1 }, DataType::type, "xyc", ColorType::GRAY); \
35  View<DataType::type> g2_##type##_v;
36  //Image g3_##type = Image({ 3, 3, 1 }, DataType::type, "xyc", ColorType::GRAY); \
37  //View<DataType::type> g3_##type##_v; \
38 
40 #undef ECVL_TUPLE
41 
42  void SetUp() override
43  {
44 #define ECVL_TUPLE(type, ...) \
45  g2_##type##_v = g2_##type; \
46  g2_##type##_v({ 0,0,0 }) = 50; g2_##type##_v({ 1,0,0 }) = 32; \
47  g2_##type##_v({ 0,1,0 }) = 14; g2_##type##_v({ 1,1,0 }) = 60;
48 
50 #undef ECVL_TUPLE
51  }
52 };
53 
54 using CoreImage = TCore;
55 using CoreArithmetics = TCore;
56 
57 TEST(Core, CreateEmptyImage)
58 {
59  Image img;
60  EXPECT_EQ(img.dims_.size(), 0);
61  EXPECT_EQ(img.strides_.size(), 0);
62  EXPECT_EQ(img.data_, nullptr);
63 }
64 
65 TEST(Core, CreateImageWithFiveDims)
66 {
67  Image img({ 1, 2, 3, 4, 5 }, DataType::uint8, "xyzoo", ColorType::none);
68  EXPECT_EQ(img.dims_.size(), 5);
69  int sdims = vsize(img.dims_);
70  for (int i = 0; i < sdims; i++) {
71  EXPECT_EQ(img.dims_[i], i + 1);
72  }
73  EXPECT_EQ(img.strides_.size(), 5);
74 }
75 
76 #define ECVL_TUPLE(type, ...) \
77 TEST_F(CoreImage, Move##type) \
78 { \
79  Image img(std::move(g2_##type)); \
80  View<DataType::type> img_v(img); \
81  EXPECT_TRUE(img_v({ 0,0,0 }) == 50); EXPECT_TRUE(img_v({ 1,0,0 }) == 32); \
82  EXPECT_TRUE(img_v({ 0,1,0 }) == 14); EXPECT_TRUE(img_v({ 1,1,0 }) == 60); \
83 } \
84 \
85 TEST_F(CoreImage, Copy##type) \
86 { \
87  Image img(g2_##type); \
88  View<DataType::type> img_v(img); \
89  EXPECT_TRUE(img_v({ 0,0,0 }) == 50); EXPECT_TRUE(img_v({ 1,0,0 }) == 32); \
90  EXPECT_TRUE(img_v({ 0,1,0 }) == 14); EXPECT_TRUE(img_v({ 1,1,0 }) == 60); \
91 } \
92 \
93 TEST_F(CoreImage, CopyNonContiguousXYZC##type) \
94 { \
95  Image src({ 2, 3, 3, 1 }, DataType::type, "xyzc", ColorType::GRAY); \
96  View<DataType::type> src_v(src, { 0, 0, 0, 0 }, { 2, 2, 2, 1 }); \
97  src_v({ 0,0,0,0 }) = 50; src_v({ 0,0,1,0 }) = 32; \
98  src_v({ 0,1,0,0 }) = 14; src_v({ 0,1,1,0 }) = 60; \
99  src_v({ 1,0,0,0 }) = 54; src_v({ 1,0,1,0 }) = 41; \
100  src_v({ 1,1,0,0 }) = 97; src_v({ 1,1,1,0 }) = 79; \
101  Image dst(src_v); \
102  View<DataType::type> dst_v(dst); \
103  EXPECT_TRUE(dst_v({ 0,0,0,0 }) == 50); EXPECT_TRUE(dst_v({ 0,0,1,0 }) == 32); \
104  EXPECT_TRUE(dst_v({ 0,1,0,0 }) == 14); EXPECT_TRUE(dst_v({ 0,1,1,0 }) == 60); \
105  EXPECT_TRUE(dst_v({ 1,0,0,0 }) == 54); EXPECT_TRUE(dst_v({ 1,0,1,0 }) == 41); \
106  EXPECT_TRUE(dst_v({ 1,1,0,0 }) == 97); EXPECT_TRUE(dst_v({ 1,1,1,0 }) == 79); \
107 } \
108 \
109 TEST_F(CoreImage, RearrangeXYZC##type) \
110 { \
111  Image img({ 3, 4, 3, 2 }, DataType::type, "cxyz", ColorType::RGB); \
112  View<DataType::type> view(img); \
113  auto it = view.Begin(); \
114  for (uint8_t i = 0; i < 24 * 3; ++i) { \
115  *reinterpret_cast<TypeInfo_t<DataType::type>*>(it.ptr_) = i; \
116  ++it; \
117  } \
118  Image img2; \
119  RearrangeChannels(img, img2, "xyzc"); \
120  View<DataType::type> view2(img2); \
121  \
122  EXPECT_TRUE(view2({ 2, 0, 1, 0 }) == 42); \
123  EXPECT_TRUE(view2({ 3, 1, 1, 2 }) == 59); \
124  EXPECT_TRUE(view2({ 0, 2, 0, 1 }) == 25); \
125  EXPECT_TRUE(view2({ 1, 2, 0, 1 }) == 28); \
126 } \
127 TEST_F(CoreImage, CopyNonContiguousXYO##type) \
128 { \
129  Image src({ 2, 3, 3 }, DataType::type, "xyo", ColorType::GRAY); \
130  View<DataType::type> src_v(src, { 0, 0, 0 }, { 2, 2, 2 }); \
131  src_v({ 0,0,0 }) = 50; src_v({ 0,0,1 }) = 32; \
132  src_v({ 0,1,0 }) = 14; src_v({ 0,1,1 }) = 60; \
133  src_v({ 1,0,0 }) = 54; src_v({ 1,0,1 }) = 41; \
134  src_v({ 1,1,0 }) = 97; src_v({ 1,1,1 }) = 79; \
135  Image dst(src_v); \
136  View<DataType::type> dst_v(dst); \
137  EXPECT_TRUE(dst_v({ 0,0,0 }) == 50); EXPECT_TRUE(dst_v({ 0,0,1 }) == 32); \
138  EXPECT_TRUE(dst_v({ 0,1,0 }) == 14); EXPECT_TRUE(dst_v({ 0,1,1 }) == 60); \
139  EXPECT_TRUE(dst_v({ 1,0,0 }) == 54); EXPECT_TRUE(dst_v({ 1,0,1 }) == 41); \
140  EXPECT_TRUE(dst_v({ 1,1,0 }) == 97); EXPECT_TRUE(dst_v({ 1,1,1 }) == 79); \
141 } \
142 \
143 TEST_F(CoreImage, RearrangeXYO##type) \
144 { \
145  Image img({ 6, 4, 3 }, DataType::type, "oxy", ColorType::RGB); \
146  View<DataType::type> view(img); \
147  auto it = view.Begin(); \
148  for (uint8_t i = 0; i < 24 * 3; ++i) { \
149  *reinterpret_cast<TypeInfo_t<DataType::type>*>(it.ptr_) = i; \
150  ++it; \
151  } \
152  Image img2; \
153  RearrangeChannels(img, img2, "xyo"); \
154  View<DataType::type> view2(img2); \
155  \
156  EXPECT_TRUE(view2({ 3, 1, 0 }) == 42); \
157  EXPECT_TRUE(view2({ 1, 2, 5 }) == 59); \
158  EXPECT_TRUE(view2({ 0, 1, 1 }) == 25); \
159  EXPECT_TRUE(view2({ 0, 1, 4 }) == 28); \
160 } \
161 \
162 TEST_F(CoreImage, ToFpga##type) \
163 { \
164  Image tmp(g2_##type); \
165  EXPECT_THROW(tmp.To(Device::FPGA), std::runtime_error); \
166 } \
167 \
168 \
169 \
170 TEST_F(CoreArithmetics, AddScalar##type) \
171 { \
172  g2_##type.Add(10); \
173  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 60); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 42); \
174  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 24); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 70); \
175  g2_##type.Add(10, false); \
176  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 70); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 52); \
177  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 34); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 80); \
178 } \
179 \
180 TEST_F(CoreArithmetics, AddImage##type) \
181 { \
182  g2_##type.Add(g2_##type); \
183  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 100); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 64); \
184  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 28); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 120); \
185 } \
186 \
187 TEST_F(CoreArithmetics, AddImageNonSaturate##type) \
188 { \
189  g2_##type.Add(g2_##type, false); \
190  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 100); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 64); \
191  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 28); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 120); \
192 } \
193 \
194 TEST_F(CoreArithmetics, SubScalar##type) \
195 { \
196  g2_##type.Sub(10); \
197  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 40); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 22); \
198  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 4); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 50); \
199 } \
200 \
201 TEST_F(CoreArithmetics, SubScalarNonSaturate##type) \
202 { \
203  g2_##type.Sub(10, false); \
204  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 40); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 22); \
205  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 4); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 50); \
206 } \
207 \
208 TEST_F(CoreArithmetics, SubImage##type) \
209 { \
210  g2_##type.Sub(g2_##type); \
211  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 0); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 0); \
212  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 0); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 0); \
213 } \
214 \
215 TEST_F(CoreArithmetics, MulScalar##type) \
216 { \
217  g2_##type.Mul(2); \
218  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 100); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 64); \
219  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 28); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 120); \
220 } \
221 \
222 TEST_F(CoreArithmetics, MulScalarNonSaturate##type) \
223 { \
224  g2_##type.Mul(2, false); \
225  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 100); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 64); \
226  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 28); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 120); \
227 } \
228 \
229 TEST_F(CoreArithmetics, MulImage##type) \
230 { \
231  Image tmp(g2_##type); \
232  View<DataType::type> tmp_v(tmp); \
233  auto i = tmp.Begin<uint8_t>(), e = tmp.End<uint8_t>(); \
234  for (; i != e; ++i) { \
235  *reinterpret_cast<TypeInfo_t<DataType::type>*>(i.ptr_) = 2; \
236  } \
237  g2_##type.Mul(tmp); \
238  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 100); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 64); \
239  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 28); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 120); \
240 } \
241 \
242 TEST_F(CoreArithmetics, DivScalar##type) \
243 { \
244  g2_##type.Div(2); \
245  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 25); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 16); \
246  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 7); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 30); \
247 } \
248 \
249 TEST_F(CoreArithmetics, DivScalarNonSaturate##type) \
250 { \
251  g2_##type.Div(2, false); \
252  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 25); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 16); \
253  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 7); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 30); \
254 } \
255 \
256 TEST_F(CoreArithmetics, DivImage##type) \
257 { \
258  Image tmp(g2_##type); \
259  View<DataType::type> tmp_v(tmp); \
260  auto i = tmp.Begin<uint8_t>(), e = tmp.End<uint8_t>(); \
261  for (; i != e; ++i) { \
262  *reinterpret_cast<TypeInfo_t<DataType::type>*>(i.ptr_) = 2; \
263  } \
264  g2_##type.Div(tmp); \
265  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == 25); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == 16); \
266  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == 7); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == 30); \
267 } \
268 \
269 TEST_F(CoreArithmetics, SetTo0##type) \
270 { \
271  g2_##type.SetTo(0); \
272  View<DataType::type> my_view(g2_##type); \
273  auto i = my_view.Begin(), e = my_view.End(); \
274  for (; i != e; ++i) { \
275  EXPECT_TRUE(*i == static_cast<TypeInfo_t<DataType::type>>(0)); \
276  } \
277 } \
278 \
279 TEST_F(CoreArithmetics, SetTo10_##type) \
280 { \
281  g2_##type.SetTo(10.); \
282  View<DataType::type> my_view(g2_##type); \
283  auto i = my_view.Begin(), e = my_view.End(); \
284  for (; i != e; ++i) { \
285  EXPECT_TRUE(*i == static_cast<TypeInfo_t<DataType::type>>(10.)); \
286  } \
287 } \
288 \
289 TEST_F(CoreArithmetics, SetTo10_f##type) \
290 { \
291  g2_##type.SetTo(10.f); \
292  View<DataType::type> my_view(g2_##type); \
293  auto i = my_view.Begin(), e = my_view.End(); \
294  for (; i != e; ++i) { \
295  EXPECT_TRUE(*i == static_cast<TypeInfo_t<DataType::type>>(10.f)); \
296  } \
297 } \
298 \
299 TEST_F(CoreArithmetics, SetTo10##type) \
300 { \
301  g2_##type.SetTo(10); \
302  View<DataType::type> my_view(g2_##type); \
303  auto i = my_view.Begin(), e = my_view.End(); \
304  for (; i != e; ++i) { \
305  EXPECT_TRUE(*i == static_cast<TypeInfo_t<DataType::type>>(10)); \
306  } \
307 } \
308 \
309 TEST_F(CoreArithmetics, ConvertTo##type) \
310 { \
311  { \
312  Image img({ 2, 2, 1 }, DataType::type, "xyc", ColorType::GRAY); \
313  img.SetTo(std::numeric_limits<TypeInfo_t<DataType::type>>::max()); \
314  ConvertTo(img, out, DataType::uint8, true); \
315  View<DataType::type> img_v(img); \
316  EXPECT_TRUE(out.elemtype_ == DataType::uint8); \
317  View<DataType::uint8> out_v(out); \
318  auto i = img_v.Begin(), e = img_v.End(); \
319  auto o_i = out_v.Begin(); \
320  for (; i != e; ++i, ++o_i) { \
321  EXPECT_TRUE(*o_i == saturate_cast<TypeInfo_t<DataType::uint8>>(*i)); \
322  } \
323  } \
324  { \
325  Image img({ 2, 2, 1 }, DataType::type, "xyc", ColorType::GRAY); \
326  img.SetTo(std::numeric_limits<TypeInfo_t<DataType::type>>::max()); \
327  ConvertTo(img, out, DataType::int16, true); \
328  View<DataType::type> img_v(img); \
329  EXPECT_TRUE(out.elemtype_ == DataType::int16); \
330  View<DataType::int16> out_v(out); \
331  auto i = img_v.Begin(), e = img_v.End(); \
332  auto o_i = out_v.Begin(); \
333  for (; i != e; ++i, ++o_i) { \
334  EXPECT_TRUE(*o_i == saturate_cast<TypeInfo_t<DataType::int16>>(*i)); \
335  } \
336  } \
337 }
338 
340 #undef ECVL_TUPLE
341 
342 #define ECVL_TUPLE(type, ...) \
343 TEST_F(CoreArithmetics, Neg##type) \
344 { \
345  g2_##type.Neg(); \
346  EXPECT_TRUE(g2_##type##_v({ 0,0,0 }) == -50); EXPECT_TRUE(g2_##type##_v({ 1,0,0 }) == -32); \
347  EXPECT_TRUE(g2_##type##_v({ 0,1,0 }) == -14); EXPECT_TRUE(g2_##type##_v({ 1,1,0 }) == -60); \
348 }
349 
351 #undef ECVL_TUPLE
352 
353 #ifdef ECVL_GPU
354 #define ECVL_TUPLE(type, ...) \
355 TEST_F(CoreImage, CpuToGpu##type) \
356 { \
357  Image tmp(g2_##type); \
358  tmp.To(Device::GPU); \
359  uint8_t res_h; \
360  uint8_t* res_d; \
361  checkCudaError(cudaMalloc(&res_d, 1)); \
362  RunTestCpuToGpuKernel##type(tmp.data_, res_d); \
363  checkCudaError(cudaMemcpy(&res_h, res_d, 1, cudaMemcpyDeviceToHost)); \
364  checkCudaError(cudaFree(res_d)); \
365  EXPECT_TRUE(res_h == 1); \
366 } \
367 \
368 TEST_F(CoreImage, GpuToCpu##type) { \
369  Image gpu_img({ 2, 2, 1 }, DataType::type, "xyc", ColorType::GRAY, { 1, 1, 1 }, Device::GPU); \
370  RunTestGpuToCpuKernel##type(gpu_img.data_); \
371  checkCudaError(cudaDeviceSynchronize()); \
372  gpu_img.To(Device::CPU); \
373  View<DataType::type> img_v(gpu_img); \
374  EXPECT_TRUE(img_v({ 0,0,0 }) == 50); EXPECT_TRUE(img_v({ 1,0,0 }) == 32); \
375  EXPECT_TRUE(img_v({ 0,1,0 }) == 14); EXPECT_TRUE(img_v({ 1,1,0 }) == 60); \
376 }
378 #undef ECVL_TUPLE
379 #endif
380 
381 #if 0 // TODO Functions reimplementation needed
382 TEST_F(CoreArithmetics, Anduint8)
383 {
384  Image tmp(g2_uint8);
385  View<DataType::uint8> tmp_v(tmp);
386  tmp_v({ 0,0,0 }) = 49; tmp_v({ 1,0,0 }) = 31;
387  tmp_v({ 0,1,0 }) = 13; tmp_v({ 1,1,0 }) = 59;
388  And(g2_uint8, tmp, out);
389  View<DataType::uint8> out_v(out);
390  EXPECT_TRUE(out_v({ 0,0,0 }) == 48); EXPECT_TRUE(out_v({ 1,0,0 }) == 0);
391  EXPECT_TRUE(out_v({ 0,1,0 }) == 12); EXPECT_TRUE(out_v({ 1,1,0 }) == 56);
392 }
393 
394 TEST_F(CoreArithmetics, Oruint8)
395 {
396  Image tmp(g2_uint8);
397  View<DataType::uint8> tmp_v(tmp);
398  tmp_v({ 0,0,0 }) = 49; tmp_v({ 1,0,0 }) = 31;
399  tmp_v({ 0,1,0 }) = 13; tmp_v({ 1,1,0 }) = 59;
400  Or(g2_uint8, tmp, out);
401  View<DataType::uint8> out_v(out);
402  EXPECT_TRUE(out_v({ 0,0,0 }) == 51); EXPECT_TRUE(out_v({ 1,0,0 }) == 63);
403  EXPECT_TRUE(out_v({ 0,1,0 }) == 15); EXPECT_TRUE(out_v({ 1,1,0 }) == 63);
404 }
405 #endif // 0
406 }
Image class.
Definition: image.h:72
uint8_t * data_
Pointer to Image data.
Definition: image.h:168
int vsize(const std::vector< T > &v)
Definition: image.h:34
std::vector< int > strides_
Vector of Image strides.
Definition: image.h:125
std::vector< int > dims_
Definition: image.h:123
TEST(DatasetParser, LoadNonExistingDataset)