Visual Servoing Platform version 3.6.0
Loading...
Searching...
No Matches
testImageTemplateMatching.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 * Test vpImageTools::templateMatching().
33 *
34*****************************************************************************/
40
41#include <visp3/core/vpImage.h>
42#include <visp3/core/vpImageTools.h>
43#include <visp3/core/vpIoTools.h>
44#include <visp3/gui/vpDisplayGDI.h>
45#include <visp3/gui/vpDisplayOpenCV.h>
46#include <visp3/gui/vpDisplayX.h>
47#include <visp3/io/vpParseArgv.h>
48#include <visp3/io/vpVideoReader.h>
49
50// List of allowed command line options
51#define GETOPTARGS "cdi:th"
52
53namespace
54{
55void usage(const char *name, const char *badparam, std::string ipath)
56{
57 fprintf(stdout, "\n\
58 Test vpImageTools::templateMatching().\n\
59 \n\
60 SYNOPSIS\n\
61 %s [-i <VISP_IMAGES directory>] \n\
62 [-c] [-t] \n\
63 [-h]\n \
64 ",
65 name);
66
67 fprintf(stdout, "\n\
68 OPTIONS: Default\n\
69 -i <VISP_IMAGES directory> %s\n\
70 Set VISP_IMAGES input path.\n\
71 Setting the VISP_INPUT_IMAGE_PATH environment\n\
72 variable produces the same behaviour than using\n\
73 this option.\n\
74 \n\
75 -c \n\
76 Mouse click.\n\
77 -t \n\
78 Perform template matching on cube sequence.\n\
79 -h\n\
80 Print the help.\n\n",
81 ipath.c_str());
82
83 if (badparam)
84 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
85}
86
87bool getOptions(int argc, const char **argv, std::string &ipath, bool &click, bool &doTemplateMatching)
88{
89 const char *optarg_;
90 int c;
91 while ((c = vpParseArgv::parse(argc, argv, GETOPTARGS, &optarg_)) > 1) {
92
93 switch (c) {
94 case 'i':
95 ipath = optarg_;
96 break;
97 case 'h':
98 usage(argv[0], NULL, ipath);
99 return false;
100 break;
101 case 't':
102 doTemplateMatching = true;
103 break;
104
105 case 'c':
106 click = true;
107 break;
108 case 'd':
109 break;
110
111 default:
112 usage(argv[0], optarg_, ipath);
113 return false;
114 break;
115 }
116 }
117
118 if ((c == 1) || (c == -1)) {
119 // standalone param or error
120 usage(argv[0], NULL, ipath);
121 std::cerr << "ERROR: " << std::endl;
122 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
123 return false;
124 }
125
126 return true;
127}
128} // namespace
129
130int main(int argc, const char **argv)
131{
132#if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x030000) && defined(HAVE_OPENCV_IMGPROC)
133 {
134 const int h = 5, w = 5;
136 I[0][0] = 1;
137 I[0][1] = 2;
138 I[0][2] = 2;
139 I[0][3] = 4;
140 I[0][4] = 1;
141 I[1][0] = 3;
142 I[1][1] = 4;
143 I[1][2] = 1;
144 I[1][3] = 5;
145 I[1][4] = 2;
146 I[2][0] = 2;
147 I[2][1] = 3;
148 I[2][2] = 3;
149 I[2][3] = 2;
150 I[2][4] = 4;
151 I[3][0] = 4;
152 I[3][1] = 1;
153 I[3][2] = 5;
154 I[3][3] = 4;
155 I[3][4] = 6;
156 I[4][0] = 6;
157 I[4][1] = 3;
158 I[4][2] = 2;
159 I[4][3] = 1;
160 I[4][4] = 3;
161
162 vpImage<double> II, IIsq;
163 vpImageTools::integralImage(I, II, IIsq);
164 std::cout << "I:\n" << I << std::endl;
165 std::cout << "II:\n" << II << std::endl;
166 std::cout << "IIsq:\n" << IIsq << std::endl;
167
168 cv::Mat mat(h, w, CV_64F);
169 for (int i = 0; i < h; i++) {
170 for (int j = 0; j < w; j++) {
171 mat.at<double>(i, j) = I[i][j];
172 }
173 }
174
175 cv::Mat sum, sqsum;
176 cv::integral(mat, sum, sqsum);
177 std::cout << "mat:\n" << mat << std::endl;
178 std::cout << "sum:\n" << sum << std::endl;
179 std::cout << "sqsum:\n" << sqsum << std::endl;
180
181 for (int i = 0; i < h; i++) {
182 for (int j = 0; j < w; j++) {
183 if (!vpMath::equal(II[i][j], sum.at<double>(i, j), std::numeric_limits<double>::epsilon())) {
184 std::cerr << "Error vpImageTools::integralImage(II), reference: " << std::setprecision(17)
185 << sum.at<double>(i, j) << " ; compute: " << II[i][j] << std::endl;
186 return EXIT_FAILURE;
187 }
188
189 if (!vpMath::equal(IIsq[i][j], sqsum.at<double>(i, j), std::numeric_limits<double>::epsilon())) {
190 std::cerr << "Error vpImageTools::integralImage(IIsq), reference: " << std::setprecision(17)
191 << sqsum.at<double>(i, j) << " ; compute: " << IIsq[i][j] << std::endl;
192 return EXIT_FAILURE;
193 }
194 }
195 }
196 }
197#endif
198
199 try {
200 std::string env_ipath;
201 std::string opt_ipath;
202 std::string ipath;
203 std::string filename;
204 bool click = false;
205 bool doTemplateMatching = false;
206
207#if VISP_HAVE_DATASET_VERSION >= 0x030600
208 std::string ext("png");
209#else
210 std::string ext("pgm");
211#endif
212
213 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
214 // environment variable value
216
217 // Set the default input path
218 if (!env_ipath.empty()) {
219 ipath = env_ipath;
220 }
221
222 // Read the command line options
223 if (!getOptions(argc, argv, opt_ipath, click, doTemplateMatching)) {
224 exit(EXIT_FAILURE);
225 }
226
227 // Get the option values
228 if (!opt_ipath.empty()) {
229 ipath = opt_ipath;
230 }
231
232 // Compare ipath and env_ipath. If they differ, we take into account
233 // the input path comming from the command line option
234 if (!opt_ipath.empty() && !env_ipath.empty()) {
235 if (ipath != env_ipath) {
236 std::cout << std::endl << "WARNING: " << std::endl;
237 std::cout << " Since -i <visp image path=" << ipath << "> "
238 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
239 << " we skip the environment variable." << std::endl;
240 }
241 }
242
243 // Test if an input path is set
244 if (opt_ipath.empty() && env_ipath.empty()) {
245 usage(argv[0], NULL, ipath);
246 std::cerr << std::endl << "ERROR:" << std::endl;
247 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
248 << " environment variable to specify the location of the " << std::endl
249 << " image path where test images are located." << std::endl
250 << std::endl;
251 exit(EXIT_FAILURE);
252 }
253
254 //
255 // Here starts really the test
256 //
257
258 // Load cube sequence
259 filename = vpIoTools::createFilePath(ipath, "mbt/cube/image%04d." + ext);
260
261 vpVideoReader reader;
262 reader.setFileName(filename);
263 vpImage<unsigned char> I, I_template;
264 reader.open(I);
265 vpRect template_roi(vpImagePoint(201, 310), vpImagePoint(201 + 152 - 1, 310 + 138 - 1));
266 vpImageTools::crop(I, template_roi, I_template);
267
268 if (doTemplateMatching) {
269#if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV)
270
271#if defined(VISP_HAVE_X11)
272 vpDisplayX d;
273#elif defined(VISP_HAVE_GDI)
274 vpDisplayGDI d;
275#elif defined(HAVE_OPENCV_HIGHGUI)
277#endif
278
279 d.init(I, 0, 0, "Image");
280
281 vpImage<double> I_score;
282 std::vector<double> benchmark_vec;
283 bool quit = false;
284 while (!reader.end() && !quit) {
285 reader.acquire(I);
286
288
289 std::stringstream ss;
290 ss << "Frame: " << reader.getFrameIndex();
291 vpDisplay::displayText(I, 20, 20, ss.str(), vpColor::red);
292
293 // Basic template matching
294 double t_proc = vpTime::measureTimeMs();
295 const unsigned int step_u = 5, step_v = 5;
296 vpImageTools::templateMatching(I, I_template, I_score, step_u, step_v);
297
298 vpImagePoint max_loc;
299 double max_correlation = -1.0;
300 I_score.getMinMaxLoc(NULL, &max_loc, NULL, &max_correlation);
301 t_proc = vpTime::measureTimeMs() - t_proc;
302 benchmark_vec.push_back(t_proc);
303
304 ss.str("");
305 ss << "Template matching: " << t_proc << " ms";
306 vpDisplay::displayText(I, 40, 20, ss.str(), vpColor::red);
307
308 ss.str("");
309 ss << "Max correlation: " << max_correlation;
310 vpDisplay::displayText(I, 60, 20, ss.str(), vpColor::red);
311
312 vpDisplay::displayRectangle(I, max_loc, I_template.getWidth(), I_template.getHeight(), vpColor::red, false, 1);
313
315
317 if (vpDisplay::getClick(I, button, click)) {
318 switch (button) {
320 quit = !click;
321 break;
322
324 click = !click;
325 break;
326
327 default:
328 break;
329 }
330 }
331 }
332
333 if (!benchmark_vec.empty()) {
334 std::cout << "Processing time, Mean: " << vpMath::getMean(benchmark_vec)
335 << " ms ; Median: " << vpMath::getMedian(benchmark_vec)
336 << " ms ; Std: " << vpMath::getStdev(benchmark_vec) << " ms" << std::endl;
337 }
338#endif
339 } else {
340 // ctest case
341 // Basic template matching
342 const unsigned int step_u = 5, step_v = 5;
343 vpImage<double> I_score, I_score_gold;
344
345 double t = vpTime::measureTimeMs();
346 vpImageTools::templateMatching(I, I_template, I_score, step_u, step_v, true);
347 t = vpTime::measureTimeMs() - t;
348
349 double t_gold = vpTime::measureTimeMs();
350 vpImageTools::templateMatching(I, I_template, I_score_gold, step_u, step_v, false);
351 t_gold = vpTime::measureTimeMs() - t_gold;
352
353 std::cout << "Template matching: " << t << " ms" << std::endl;
354 std::cout << "Template matching (gold): " << t_gold << " ms" << std::endl;
355
356 for (unsigned int i = 0; i < I_score.getHeight(); i++) {
357 for (unsigned int j = 0; j < I_score.getWidth(); j++) {
358 if (!vpMath::equal(I_score[i][j], I_score_gold[i][j], 1e-9)) {
359 std::cerr << "Issue with template matching, gold: " << std::setprecision(17) << I_score_gold[i][j]
360 << " ; compute: " << I_score[i][j] << std::endl;
361 return EXIT_FAILURE;
362 }
363 }
364 }
365 }
366
367 } catch (const vpException &e) {
368 std::cerr << "\nCatch an exception: " << e << std::endl;
369 return EXIT_FAILURE;
370 }
371
372 return EXIT_SUCCESS;
373}
static const vpColor red
Definition vpColor.h:211
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...
void init(vpImage< unsigned char > &I, int winx=-1, int winy=-1, const std::string &title="")
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition vpDisplayX.h:132
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:59
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:135
void getMinMaxLoc(vpImagePoint *minLoc, vpImagePoint *maxLoc, Type *minVal=NULL, Type *maxVal=NULL) const
Get the position of the minimum and/or the maximum pixel value within the bitmap and the correspondin...
Definition vpImage.h:1223
unsigned int getWidth() const
Definition vpImage.h:242
unsigned int getHeight() const
Definition vpImage.h:184
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:314
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
Definition vpMath.cpp:345
static bool equal(double x, double y, double threshold=0.001)
Definition vpMath.h:369
static double getMean(const std::vector< double > &v)
Definition vpMath.cpp:294
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Defines a rectangle in the plane.
Definition vpRect.h:76
Class that enables to manipulate easily a video file or a sequence of images. As it inherits from the...
void acquire(vpImage< vpRGBa > &I)
void open(vpImage< vpRGBa > &I)
void setFileName(const std::string &filename)
long getFrameIndex() const
VISP_EXPORT double measureTimeMs()