Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testImageTemplateMatching.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * Test vpImageTools::templateMatching().
32 */
33
39
40#include <visp3/core/vpImage.h>
41#include <visp3/core/vpImageTools.h>
42#include <visp3/core/vpIoTools.h>
43#include <visp3/gui/vpDisplayGDI.h>
44#include <visp3/gui/vpDisplayOpenCV.h>
45#include <visp3/gui/vpDisplayX.h>
46#include <visp3/io/vpParseArgv.h>
47#include <visp3/io/vpVideoReader.h>
48
49// List of allowed command line options
50#define GETOPTARGS "cdi:th"
51
52#ifdef ENABLE_VISP_NAMESPACE
53using namespace VISP_NAMESPACE_NAME;
54#endif
55
56namespace
57{
58void usage(const char *name, const char *badparam, std::string ipath)
59{
60 fprintf(stdout, "\n\
61 Test vpImageTools::templateMatching().\n\
62 \n\
63 SYNOPSIS\n\
64 %s [-i <VISP_IMAGES directory>] \n\
65 [-c] [-t] \n\
66 [-h]\n \
67 ",
68 name);
69
70 fprintf(stdout, "\n\
71 OPTIONS: Default\n\
72 -i <VISP_IMAGES directory> %s\n\
73 Set VISP_IMAGES input path.\n\
74 Setting the VISP_INPUT_IMAGE_PATH environment\n\
75 variable produces the same behaviour than using\n\
76 this option.\n\
77 \n\
78 -c \n\
79 Mouse click.\n\
80 -t \n\
81 Perform template matching on cube sequence.\n\
82 -h\n\
83 Print the help.\n\n",
84 ipath.c_str());
85
86 if (badparam)
87 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
88}
89
90bool getOptions(int argc, const char **argv, std::string &ipath, bool &click, bool &doTemplateMatching)
91{
92 const char *optarg_;
93 int c;
94 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
95
96 switch (c) {
97 case 'i':
98 ipath = optarg_;
99 break;
100 case 'h':
101 usage(argv[0], nullptr, ipath);
102 return false;
103 case 't':
104 doTemplateMatching = true;
105 break;
106
107 case 'c':
108 click = true;
109 break;
110 case 'd':
111 break;
112
113 default:
114 usage(argv[0], optarg_, ipath);
115 return false;
116 }
117 }
118
119 if ((c == 1) || (c == -1)) {
120 // standalone param or error
121 usage(argv[0], nullptr, ipath);
122 std::cerr << "ERROR: " << std::endl;
123 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
124 return false;
125 }
126
127 return true;
128}
129} // namespace
130
131int main(int argc, const char **argv)
132{
133#if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(HAVE_OPENCV_IMGPROC)
134 {
135 const int h = 5, w = 5;
137 I[0][0] = 1;
138 I[0][1] = 2;
139 I[0][2] = 2;
140 I[0][3] = 4;
141 I[0][4] = 1;
142 I[1][0] = 3;
143 I[1][1] = 4;
144 I[1][2] = 1;
145 I[1][3] = 5;
146 I[1][4] = 2;
147 I[2][0] = 2;
148 I[2][1] = 3;
149 I[2][2] = 3;
150 I[2][3] = 2;
151 I[2][4] = 4;
152 I[3][0] = 4;
153 I[3][1] = 1;
154 I[3][2] = 5;
155 I[3][3] = 4;
156 I[3][4] = 6;
157 I[4][0] = 6;
158 I[4][1] = 3;
159 I[4][2] = 2;
160 I[4][3] = 1;
161 I[4][4] = 3;
162
163 vpImage<double> II, IIsq;
164 vpImageTools::integralImage(I, II, IIsq);
165 std::cout << "I:\n" << I << std::endl;
166 std::cout << "II:\n" << II << std::endl;
167 std::cout << "IIsq:\n" << IIsq << std::endl;
168
169 cv::Mat mat(h, w, CV_64F);
170 for (int i = 0; i < h; i++) {
171 for (int j = 0; j < w; j++) {
172 mat.at<double>(i, j) = I[i][j];
173 }
174 }
175
176 cv::Mat sum, sqsum;
177 cv::integral(mat, sum, sqsum);
178 std::cout << "mat:\n" << mat << std::endl;
179 std::cout << "sum:\n" << sum << std::endl;
180 std::cout << "sqsum:\n" << sqsum << std::endl;
181
182 for (int i = 0; i < h; i++) {
183 for (int j = 0; j < w; j++) {
184 if (!vpMath::equal(II[i][j], sum.at<double>(i, j), std::numeric_limits<double>::epsilon())) {
185 std::cerr << "Error vpImageTools::integralImage(II), reference: " << std::setprecision(17)
186 << sum.at<double>(i, j) << " ; compute: " << II[i][j] << std::endl;
187 return EXIT_FAILURE;
188 }
189
190 if (!vpMath::equal(IIsq[i][j], sqsum.at<double>(i, j), std::numeric_limits<double>::epsilon())) {
191 std::cerr << "Error vpImageTools::integralImage(IIsq), reference: " << std::setprecision(17)
192 << sqsum.at<double>(i, j) << " ; compute: " << IIsq[i][j] << std::endl;
193 return EXIT_FAILURE;
194 }
195 }
196 }
197 }
198#endif
199
200try {
201 std::string env_ipath;
202 std::string opt_ipath;
203 std::string ipath;
204 std::string filename;
205 bool click = false;
206 bool doTemplateMatching = false;
207
208#if defined(VISP_HAVE_DATASET)
209#if VISP_HAVE_DATASET_VERSION >= 0x030600
210 std::string ext("png");
211#else
212 std::string ext("pgm");
213#endif
214#else
215 // We suppose that the user will download a recent dataset
216 std::string ext("png");
217#endif
218
219 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
220 // environment variable value
222
223 // Set the default input path
224 if (!env_ipath.empty()) {
225 ipath = env_ipath;
226 }
227
228 // Read the command line options
229 if (!getOptions(argc, argv, opt_ipath, click, doTemplateMatching)) {
230 exit(EXIT_FAILURE);
231 }
232
233 // Get the option values
234 if (!opt_ipath.empty()) {
235 ipath = opt_ipath;
236 }
237
238 // Compare ipath and env_ipath. If they differ, we take into account
239 // the input path coming from the command line option
240 if (!opt_ipath.empty() && !env_ipath.empty()) {
241 if (ipath != env_ipath) {
242 std::cout << std::endl << "WARNING: " << std::endl;
243 std::cout << " Since -i <visp image path=" << ipath << "> "
244 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
245 << " we skip the environment variable." << std::endl;
246 }
247 }
248
249 // Test if an input path is set
250 if (opt_ipath.empty() && env_ipath.empty()) {
251 usage(argv[0], nullptr, ipath);
252 std::cerr << std::endl << "ERROR:" << std::endl;
253 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
254 << " environment variable to specify the location of the " << std::endl
255 << " image path where test images are located." << std::endl
256 << std::endl;
257 exit(EXIT_FAILURE);
258 }
259
260 //
261 // Here starts really the test
262 //
263
264 // Load cube sequence
265 filename = vpIoTools::createFilePath(ipath, "mbt/cube/image%04d." + ext);
266
267 vpVideoReader reader;
268 reader.setFileName(filename);
269 vpImage<unsigned char> I, I_template;
270 reader.open(I);
271 vpRect template_roi(vpImagePoint(201, 310), vpImagePoint(201 + 152 - 1, 310 + 138 - 1));
272 vpImageTools::crop(I, template_roi, I_template);
273
274 if (doTemplateMatching) {
275#if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV)
276
277#if defined(VISP_HAVE_X11)
279#elif defined(VISP_HAVE_GDI)
281#elif defined(HAVE_OPENCV_HIGHGUI)
283#endif
284
285 d.init(I, 0, 0, "Image");
286
287 vpImage<double> I_score;
288 std::vector<double> benchmark_vec;
289 bool quit = false;
290 while (!reader.end() && !quit) {
291 reader.acquire(I);
292
294
295 std::stringstream ss;
296 ss << "Frame: " << reader.getFrameIndex();
297 vpDisplay::displayText(I, 20, 20, ss.str(), vpColor::red);
298
299 // Basic template matching
300 double t_proc = vpTime::measureTimeMs();
301 const unsigned int step_u = 5, step_v = 5;
302 vpImageTools::templateMatching(I, I_template, I_score, step_u, step_v);
303
304 vpImagePoint max_loc;
305 double max_correlation = -1.0;
306 I_score.getMinMaxLoc(nullptr, &max_loc, nullptr, &max_correlation);
307 t_proc = vpTime::measureTimeMs() - t_proc;
308 benchmark_vec.push_back(t_proc);
309
310 ss.str("");
311 ss << "Template matching: " << t_proc << " ms";
312 vpDisplay::displayText(I, 40, 20, ss.str(), vpColor::red);
313
314 ss.str("");
315 ss << "Max correlation: " << max_correlation;
316 vpDisplay::displayText(I, 60, 20, ss.str(), vpColor::red);
317
318 vpDisplay::displayRectangle(I, max_loc, I_template.getWidth(), I_template.getHeight(), vpColor::red, false, 1);
319
321
323 if (vpDisplay::getClick(I, button, click)) {
324 switch (button) {
326 quit = !click;
327 break;
328
330 click = !click;
331 break;
332
333 default:
334 break;
335 }
336 }
337 }
338
339 if (!benchmark_vec.empty()) {
340 std::cout << "Processing time, Mean: " << vpMath::getMean(benchmark_vec)
341 << " ms ; Median: " << vpMath::getMedian(benchmark_vec)
342 << " ms ; Std: " << vpMath::getStdev(benchmark_vec) << " ms" << std::endl;
343 }
344#endif
345 }
346 else {
347 // ctest case
348 // Basic template matching
349 const unsigned int step_u = 5, step_v = 5;
350 vpImage<double> I_score, I_score_gold;
351
352 double t = vpTime::measureTimeMs();
353 vpImageTools::templateMatching(I, I_template, I_score, step_u, step_v, true);
355
356 double t_gold = vpTime::measureTimeMs();
357 vpImageTools::templateMatching(I, I_template, I_score_gold, step_u, step_v, false);
358 t_gold = vpTime::measureTimeMs() - t_gold;
359
360 std::cout << "Template matching: " << t << " ms" << std::endl;
361 std::cout << "Template matching (gold): " << t_gold << " ms" << std::endl;
362
363 for (unsigned int i = 0; i < I_score.getHeight(); i++) {
364 for (unsigned int j = 0; j < I_score.getWidth(); j++) {
365 if (!vpMath::equal(I_score[i][j], I_score_gold[i][j], 1e-9)) {
366 std::cerr << "Issue with template matching, gold: " << std::setprecision(17) << I_score_gold[i][j]
367 << " ; compute: " << I_score[i][j] << std::endl;
368 return EXIT_FAILURE;
369 }
370 }
371 }
372 }
373
374}
375catch (const vpException &e) {
376 std::cerr << "\nCatch an exception: " << e << std::endl;
377 return EXIT_FAILURE;
378}
379
380return EXIT_SUCCESS;
381}
static const vpColor red
Definition vpColor.h:198
Display for windows using GDI (available on any windows 32 platform).
The vpDisplayOpenCV allows to display image using the OpenCV library. Thus to enable this class OpenC...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition vpDisplayX.h:135
static bool getClick(const vpImage< unsigned char > &I, bool blocking=true)
static void display(const vpImage< unsigned char > &I)
static void flush(const vpImage< unsigned char > &I)
static void displayRectangle(const vpImage< unsigned char > &I, const vpImagePoint &topLeft, unsigned int width, unsigned int height, const vpColor &color, bool fill=false, unsigned int thickness=1)
static void displayText(const vpImage< unsigned char > &I, const vpImagePoint &ip, const std::string &s, const vpColor &color)
error that can be emitted by ViSP classes.
Definition vpException.h:60
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
static void templateMatching(const vpImage< unsigned char > &I, const vpImage< unsigned char > &I_tpl, vpImage< double > &I_score, unsigned int step_u, unsigned int step_v, bool useOptimized=true)
static void crop(const vpImage< Type > &I, double roi_top, double roi_left, unsigned int roi_height, unsigned int roi_width, vpImage< Type > &crop, unsigned int v_scale=1, unsigned int h_scale=1)
static void integralImage(const vpImage< unsigned char > &I, vpImage< double > &II, vpImage< double > &IIsq)
Definition of the vpImage class member functions.
Definition vpImage.h:131
void getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal=nullptr, Type *maxVal=nullptr) const
Get the position of the minimum and/or the maximum pixel value within the bitmap and the correspondin...
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:181
static std::string getViSPImagesDataPath()
static std::string createFilePath(const std::string &parent, const std::string &child)
static double getMedian(const std::vector< double > &v)
Definition vpMath.cpp:343
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
Definition vpMath.cpp:374
static bool equal(double x, double y, double threshold=0.001)
Definition vpMath.h:470
static double getMean(const std::vector< double > &v)
Definition vpMath.cpp:323
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Defines a rectangle in the plane.
Definition vpRect.h:79
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
void open(vpImage< vpRGBa > &I) VP_OVERRIDE
void setFileName(const std::string &filename)
long getFrameIndex() const
void acquire(vpImage< vpRGBa > &I) VP_OVERRIDE
VISP_EXPORT double measureTimeMs()