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*****************************************************************************/
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...
Use the X11 console to display images on unix-like OS. Thus to enable this class X11 should be instal...
Definition vpDisplayX.h:132
void init(vpImage< unsigned char > &I, int win_x=-1, int win_y=-1, const std::string &win_title="")
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()