Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
testImageLoadSave.cpp
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2023 by Inria. All rights reserved.
5 *
6 * This software is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 * See the file LICENSE.txt at the root directory of this source
11 * distribution for additional information about the GNU GPL.
12 *
13 * For using ViSP with software that can not be combined with the GNU
14 * GPL, please contact Inria about acquiring a ViSP Professional
15 * Edition License.
16 *
17 * See https://visp.inria.fr for more information.
18 *
19 * This software was developed at:
20 * Inria Rennes - Bretagne Atlantique
21 * Campus Universitaire de Beaulieu
22 * 35042 Rennes Cedex
23 * France
24 *
25 * If you have questions regarding the use of this file, please contact
26 * Inria at visp@inria.fr
27 *
28 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30 *
31 * Description:
32 * Check that the different image I/O backends work correctly.
33 *
34*****************************************************************************/
35
36#include <visp3/core/vpConfig.h>
37
38#if defined(VISP_HAVE_CATCH2) && (VISP_HAVE_DATASET_VERSION >= 0x030500)
39#define CATCH_CONFIG_ENABLE_BENCHMARKING
40#define CATCH_CONFIG_RUNNER
41#include <catch.hpp>
42
43#include <thread>
44#include <visp3/core/vpIoTools.h>
45#include <visp3/io/vpImageIo.h>
46
47static const std::string ipath = vpIoTools::getViSPImagesDataPath();
48static const std::string path = ipath + "/Solvay/Solvay_conference_1927_Version2_640x440";
49
50static const double ccThreshPNG = 1.0;
51static const double ccThreshJPG = 0.99;
52
53static const std::vector<vpImageIo::vpImageIoBackendType> backends
54{
55#if defined(VISP_HAVE_JPEG) && defined(VISP_HAVE_PNG)
57#endif
58#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGCODECS)
60#endif
62};
63static const std::vector<std::string> backendNamesJpeg
64{
65#if defined(VISP_HAVE_JPEG)
66 "libjpeg",
67#endif
68#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGCODECS)
69 "OpenCV",
70#endif
71 "simd", "stb"
72};
73static std::vector<std::string> backendNamesPng
74{
75#if defined(VISP_HAVE_PNG)
76 "libpng",
77#endif
78#if defined(VISP_HAVE_OPENCV) && defined(HAVE_OPENCV_IMGCODECS)
79 "OpenCV",
80#endif
81 "simd", "stb"
82};
83
84static const unsigned int imgWidth = 640;
85static const unsigned int imgHeight = 440;
86
87namespace
88{
89double computePearsonCC(const vpImage<unsigned char> &I1, const vpImage<unsigned char> &I2)
90{
91 double m1 = I1.getSum() / I1.getSize();
92 double m2 = I2.getSum() / I2.getSize();
93
94 double num = 0, den1 = 0, den2 = 0;
95 for (unsigned int i = 0; i < I1.getSize(); i++) {
96 double x1 = I1.bitmap[i];
97 double x2 = I2.bitmap[i];
98 double x1_m = x1 - m1;
99 double x2_m = x2 - m2;
100 num += x1_m * x2_m;
101 den1 += x1_m * x1_m;
102 den2 += x2_m * x2_m;
103 }
104
105 return num / (std::sqrt(den1) * std::sqrt(den2));
106}
107
108double computePearsonCC(const vpImage<vpRGBa> &I1, const vpImage<vpRGBa> &I2)
109{
110 double m1 = I1.getSum() / (3 * I1.getSize());
111 double m2 = I2.getSum() / (3 * I2.getSize());
112
113 double num = 0, den1 = 0, den2 = 0;
114 for (unsigned int i = 0; i < I1.getSize(); i++) {
115 double x1 = I1.bitmap[i].R + I1.bitmap[i].G + I1.bitmap[i].B;
116 double x2 = I2.bitmap[i].R + I2.bitmap[i].G + I2.bitmap[i].B;
117 double x1_m = x1 - m1;
118 double x2_m = x2 - m2;
119 num += x1_m * x2_m;
120 den1 += x1_m * x1_m;
121 den2 += x2_m * x2_m;
122 }
123
124 return num / (std::sqrt(den1) * std::sqrt(den2));
125}
126} // namespace
127
128TEST_CASE("Test grayscale JPEG image loading", "[image_I/O]")
129{
131 vpImageIo::read(I_ref, path + ".jpg");
132
133 for (size_t j = 0; j < backends.size(); j++) {
135
136 SECTION(backendNamesJpeg[j] + " backend")
137 {
138 CHECK_NOTHROW(vpImageIo::read(I, path + ".jpg", backends[j]));
139 double cc = computePearsonCC(I_ref, I);
140 std::cout << backendNamesJpeg[j] << " backend Pearson correlation coefficient: " << cc << std::endl;
141 CHECK(cc >= Approx(ccThreshJPG));
142 CHECK(I.getWidth() == imgWidth);
143 CHECK(I.getHeight() == imgHeight);
144 };
145 }
146}
147
148TEST_CASE("Test RGBA JPEG image loading", "[image_I/O]")
149{
150 vpImage<vpRGBa> I_ref;
151 vpImageIo::read(I_ref, path + ".jpg");
152
153 for (size_t j = 0; j < backends.size(); j++) {
155
156 SECTION(backendNamesJpeg[j] + " backend")
157 {
158 CHECK_NOTHROW(vpImageIo::read(I, path + ".jpg", backends[j]));
159 double cc = computePearsonCC(I_ref, I);
160 std::cout << backendNamesJpeg[j] << " backend Pearson correlation coefficient: " << cc << std::endl;
161 CHECK(cc >= Approx(ccThreshJPG));
162 CHECK(I.getWidth() == imgWidth);
163 CHECK(I.getHeight() == imgHeight);
164 };
165 }
166}
167
168TEST_CASE("Test grayscale PNG image loading", "[image_I/O]")
169{
171 vpImageIo::read(I_ref, path + ".png");
172
173 for (size_t j = 0; j < backends.size(); j++) {
175
176 SECTION(backendNamesPng[j] + " backend")
177 {
178 CHECK_NOTHROW(vpImageIo::read(I, path + ".png", backends[j]));
179 double cc = computePearsonCC(I_ref, I);
180 std::cout << backendNamesPng[j] << " backend Pearson correlation coefficient: " << cc << std::endl;
181 CHECK(cc == Approx(ccThreshPNG));
182 CHECK(I.getWidth() == imgWidth);
183 CHECK(I.getHeight() == imgHeight);
184 };
185 }
186}
187
188TEST_CASE("Test RGBA PNG image loading", "[image_I/O]")
189{
190 vpImage<vpRGBa> I_ref;
191 vpImageIo::read(I_ref, path + ".png");
192
193 for (size_t j = 0; j < backends.size(); j++) {
195
196 SECTION(backendNamesPng[j] + " backend")
197 {
198 CHECK_NOTHROW(vpImageIo::read(I, path + ".png", backends[j]));
199 double cc = computePearsonCC(I_ref, I);
200 std::cout << backendNamesPng[j] << " backend Pearson correlation coefficient: " << cc << std::endl;
201 CHECK(cc == Approx(ccThreshPNG));
202 CHECK(I.getWidth() == imgWidth);
203 CHECK(I.getHeight() == imgHeight);
204 };
205 }
206}
207
208TEST_CASE("Test grayscale JPEG image saving", "[image_I/O]")
209{
211 std::string directory_filename_tmp =
212 tmp_dir + "/vpIoTools_perfImageLoadSave_" + vpTime::getDateTime("%Y-%m-%d_%H.%M.%S");
213 vpIoTools::makeDirectory(directory_filename_tmp);
214 REQUIRE(vpIoTools::checkDirectory(directory_filename_tmp));
215
217 vpImageIo::read(I, path + ".png");
218
219 for (size_t j = 0; j < backends.size(); j++) {
220 SECTION(backendNamesJpeg[j] + " backend")
221 {
222 CHECK_NOTHROW(vpImageIo::write(I, directory_filename_tmp + "/ViSP_tmp_perf_write.jpg", backends[j]));
224 vpImageIo::read(I_read, directory_filename_tmp + "/ViSP_tmp_perf_write.jpg");
225 double cc = computePearsonCC(I_read, I);
226 std::cout << backendNamesPng[j] << " backend Pearson correlation coefficient: " << cc << std::endl;
227 CHECK(cc >= Approx(ccThreshJPG));
228 };
229 }
230
231 REQUIRE(vpIoTools::remove(directory_filename_tmp));
232}
233
234TEST_CASE("Test RGBA JPEG image saving", "[image_I/O]")
235{
237 std::string directory_filename_tmp =
238 tmp_dir + "/vpIoTools_perfImageLoadSave_" + vpTime::getDateTime("%Y-%m-%d_%H.%M.%S");
239 vpIoTools::makeDirectory(directory_filename_tmp);
240 REQUIRE(vpIoTools::checkDirectory(directory_filename_tmp));
241
243 vpImageIo::read(I, path + ".png");
244
245 for (size_t j = 0; j < backends.size(); j++) {
246 SECTION(backendNamesJpeg[j] + " backend")
247 {
248 CHECK_NOTHROW(vpImageIo::write(I, directory_filename_tmp + "/ViSP_tmp_perf_write.jpg", backends[j]));
249 vpImage<vpRGBa> I_read;
250 vpImageIo::read(I_read, directory_filename_tmp + "/ViSP_tmp_perf_write.jpg");
251 double cc = computePearsonCC(I_read, I);
252 std::cout << backendNamesPng[j] << " backend Pearson correlation coefficient: " << cc << std::endl;
253 CHECK(cc >= Approx(ccThreshJPG));
254 };
255 }
256
257 REQUIRE(vpIoTools::remove(directory_filename_tmp));
258}
259
260TEST_CASE("Test grayscale PNG image saving", "[image_I/O]")
261{
263 std::string directory_filename_tmp =
264 tmp_dir + "/vpIoTools_perfImageLoadSave_" + vpTime::getDateTime("%Y-%m-%d_%H.%M.%S");
265 vpIoTools::makeDirectory(directory_filename_tmp);
266 REQUIRE(vpIoTools::checkDirectory(directory_filename_tmp));
267
269 vpImageIo::read(I, path + ".png");
270
271 for (size_t j = 0; j < backends.size(); j++) {
272 SECTION(backendNamesPng[j] + " backend")
273 {
274 CHECK_NOTHROW(vpImageIo::write(I, directory_filename_tmp + "/ViSP_tmp_perf_write.png", backends[j]));
276 vpImageIo::read(I_read, directory_filename_tmp + "/ViSP_tmp_perf_write.png");
277 double cc = computePearsonCC(I_read, I);
278 std::cout << backendNamesPng[j] << " backend Pearson correlation coefficient: " << cc << std::endl;
279 CHECK(cc == Approx(ccThreshPNG));
280 };
281 }
282
283 REQUIRE(vpIoTools::remove(directory_filename_tmp));
284}
285
286TEST_CASE("Test RGBA PNG image saving", "[image_I/O]")
287{
289 std::string directory_filename_tmp =
290 tmp_dir + "/vpIoTools_perfImageLoadSave_" + vpTime::getDateTime("%Y-%m-%d_%H.%M.%S");
291 vpIoTools::makeDirectory(directory_filename_tmp);
292 REQUIRE(vpIoTools::checkDirectory(directory_filename_tmp));
293
295 vpImageIo::read(I, path + ".png");
296
297 for (size_t j = 0; j < backends.size(); j++) {
298 SECTION(backendNamesPng[j] + " backend")
299 {
300 CHECK_NOTHROW(vpImageIo::write(I, directory_filename_tmp + "/ViSP_tmp_perf_write.png", backends[j]));
301 vpImage<vpRGBa> I_read;
302 vpImageIo::read(I_read, directory_filename_tmp + "/ViSP_tmp_perf_write.png");
303 double cc = computePearsonCC(I_read, I);
304 std::cout << backendNamesPng[j] << " backend Pearson correlation coefficient: " << cc << std::endl;
305 CHECK(cc == Approx(ccThreshPNG));
306 };
307 }
308
309 REQUIRE(vpIoTools::remove(directory_filename_tmp));
310}
311
312int main(int argc, char *argv[])
313{
314 Catch::Session session; // There must be exactly one instance
315
316 // Let Catch (using Clara) parse the command line
317 session.applyCommandLine(argc, argv);
318
319 int numFailed = session.run();
320
321 // numFailed is clamped to 255 as some unices only use the lower 8 bits.
322 // This clamping has already been applied, so just return it here
323 // You can also do any post run clean-up here
324 return numFailed;
325}
326#else
327#include <iostream>
328
329int main() { return EXIT_SUCCESS; }
330#endif
@ IO_STB_IMAGE_BACKEND
Use embedded stb_image library.
Definition vpImageIo.h:126
@ IO_SIMDLIB_BACKEND
Use embedded simd library.
Definition vpImageIo.h:125
@ IO_SYSTEM_LIB_BACKEND
Use system libraries like libpng or libjpeg.
Definition vpImageIo.h:123
@ IO_OPENCV_BACKEND
Use OpenCV.
Definition vpImageIo.h:124
static void read(vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
static void write(const vpImage< unsigned char > &I, const std::string &filename, int backend=IO_DEFAULT_BACKEND)
Definition of the vpImage class member functions.
Definition vpImage.h:135
unsigned int getWidth() const
Definition vpImage.h:242
double getSum() const
Definition vpImage.h:1885
unsigned int getSize() const
Definition vpImage.h:223
Type * bitmap
points toward the bitmap
Definition vpImage.h:139
unsigned int getHeight() const
Definition vpImage.h:184
static std::string getViSPImagesDataPath()
static std::string getTempPath()
static bool checkDirectory(const std::string &dirname)
static void makeDirectory(const std::string &dirname)
static bool remove(const std::string &filename)
static std::string makeTempDirectory(const std::string &dirname)
VISP_EXPORT std::string getDateTime(const std::string &format="%Y/%m/%d %H:%M:%S")