Visual Servoing Platform version 3.5.0
testImageTemplateMatching.cpp
1/****************************************************************************
2 *
3 * ViSP, open source Visual Servoing Platform software.
4 * Copyright (C) 2005 - 2019 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 http://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/vpIoTools.h>
43#include <visp3/core/vpImageTools.h>
44#include <visp3/io/vpVideoReader.h>
45#include <visp3/io/vpParseArgv.h>
46#include <visp3/gui/vpDisplayX.h>
47#include <visp3/gui/vpDisplayGDI.h>
48#include <visp3/gui/vpDisplayOpenCV.h>
49
50#if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x040000)
51# include <opencv2/imgproc.hpp>
52#endif
53
54// List of allowed command line options
55#define GETOPTARGS "cdi:th"
56
57namespace
58{
59 void usage(const char *name, const char *badparam, std::string ipath)
60 {
61 fprintf(stdout, "\n\
62 Test vpImageTools::templateMatching().\n\
63 \n\
64 SYNOPSIS\n\
65 %s [-i <VISP_IMAGES directory>] \n\
66 [-c] [-t] \n\
67 [-h]\n \
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", ipath.c_str());
84
85 if (badparam)
86 fprintf(stdout, "\nERROR: Bad parameter [%s]\n", badparam);
87 }
88
89 bool getOptions(int argc, const char **argv, std::string &ipath, bool &click,
90 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], NULL, ipath);
102 return false;
103 break;
104 case 't':
105 doTemplateMatching = true;
106 break;
107
108 case 'c':
109 click = true;
110 break;
111 case 'd':
112 break;
113
114 default:
115 usage(argv[0], optarg_, ipath);
116 return false;
117 break;
118 }
119 }
120
121 if ((c == 1) || (c == -1)) {
122 // standalone param or error
123 usage(argv[0], NULL, ipath);
124 std::cerr << "ERROR: " << std::endl;
125 std::cerr << " Bad argument " << optarg_ << std::endl << std::endl;
126 return false;
127 }
128
129 return true;
130 }
131}
132
133int main(int argc, const char **argv)
134{
135#if defined(VISP_HAVE_OPENCV) && (VISP_HAVE_OPENCV_VERSION >= 0x030000)
136 {
137 const int h = 5, w = 5;
139 I[0][0] = 1; I[0][1] = 2; I[0][2] = 2; I[0][3] = 4; I[0][4] = 1;
140 I[1][0] = 3; I[1][1] = 4; I[1][2] = 1; I[1][3] = 5; I[1][4] = 2;
141 I[2][0] = 2; I[2][1] = 3; I[2][2] = 3; I[2][3] = 2; I[2][4] = 4;
142 I[3][0] = 4; I[3][1] = 1; I[3][2] = 5; I[3][3] = 4; I[3][4] = 6;
143 I[4][0] = 6; I[4][1] = 3; I[4][2] = 2; I[4][3] = 1; I[4][4] = 3;
144
145 vpImage<double> II, IIsq;
146 vpImageTools::integralImage(I, II, IIsq);
147 std::cout << "I:\n" << I << std::endl;
148 std::cout << "II:\n" << II << std::endl;
149 std::cout << "IIsq:\n" << IIsq << std::endl;
150
151 cv::Mat mat(h, w, CV_64F);
152 for (int i = 0; i < h; i++) {
153 for (int j = 0; j < w; j++) {
154 mat.at<double>(i,j) = I[i][j];
155 }
156 }
157
158 cv::Mat sum, sqsum;
159 cv::integral(mat, sum, sqsum);
160 std::cout << "mat:\n" << mat << std::endl;
161 std::cout << "sum:\n" << sum << std::endl;
162 std::cout << "sqsum:\n" << sqsum << std::endl;
163
164 for (int i = 0; i < h; i++) {
165 for (int j = 0; j < w; j++) {
166 if ( !vpMath::equal(II[i][j], sum.at<double>(i,j), std::numeric_limits<double>::epsilon()) ) {
167 std::cerr << "Error vpImageTools::integralImage(II), reference: " << std::setprecision(17)
168 << sum.at<double>(i,j) << " ; compute: " << II[i][j] << std::endl;
169 return EXIT_FAILURE;
170 }
171
172 if ( !vpMath::equal(IIsq[i][j], sqsum.at<double>(i,j), std::numeric_limits<double>::epsilon()) ) {
173 std::cerr << "Error vpImageTools::integralImage(IIsq), reference: " << std::setprecision(17)
174 << sqsum.at<double>(i,j) << " ; compute: " << IIsq[i][j] << std::endl;
175 return EXIT_FAILURE;
176 }
177 }
178 }
179 }
180#endif
181
182 try {
183 std::string env_ipath;
184 std::string opt_ipath;
185 std::string ipath;
186 std::string filename;
187 bool click = false;
188 bool doTemplateMatching = false;
189
190 // Get the visp-images-data package path or VISP_INPUT_IMAGE_PATH
191 // environment variable value
193
194 // Set the default input path
195 if (!env_ipath.empty()) {
196 ipath = env_ipath;
197 }
198
199 // Read the command line options
200 if (!getOptions(argc, argv, opt_ipath, click, doTemplateMatching)) {
201 exit(EXIT_FAILURE);
202 }
203
204 // Get the option values
205 if (!opt_ipath.empty()) {
206 ipath = opt_ipath;
207 }
208
209 // Compare ipath and env_ipath. If they differ, we take into account
210 // the input path comming from the command line option
211 if (!opt_ipath.empty() && !env_ipath.empty()) {
212 if (ipath != env_ipath) {
213 std::cout << std::endl << "WARNING: " << std::endl;
214 std::cout << " Since -i <visp image path=" << ipath << "> "
215 << " is different from VISP_IMAGE_PATH=" << env_ipath << std::endl
216 << " we skip the environment variable." << std::endl;
217 }
218 }
219
220 // Test if an input path is set
221 if (opt_ipath.empty() && env_ipath.empty()) {
222 usage(argv[0], NULL, ipath);
223 std::cerr << std::endl << "ERROR:" << std::endl;
224 std::cerr << " Use -i <visp image path> option or set VISP_INPUT_IMAGE_PATH " << std::endl
225 << " environment variable to specify the location of the " << std::endl
226 << " image path where test images are located." << std::endl
227 << std::endl;
228 exit(EXIT_FAILURE);
229 }
230
231 //
232 // Here starts really the test
233 //
234
235 // Load cube sequence
236 filename = vpIoTools::createFilePath(ipath, "mbt/cube/image%04d.pgm");
237
238 vpVideoReader reader;
239 reader.setFileName(filename);
240 vpImage<unsigned char> I, I_template;
241 reader.open(I);
242 vpRect template_roi( vpImagePoint(201, 310), vpImagePoint(201+152-1, 310+138-1) );
243 vpImageTools::crop(I, template_roi, I_template);
244
245 if (doTemplateMatching) {
246#if defined(VISP_HAVE_X11) || defined(VISP_HAVE_GDI) || defined(VISP_HAVE_OPENCV)
247
248#if defined(VISP_HAVE_X11)
249 vpDisplayX d;
250#elif defined(VISP_HAVE_GDI)
251 vpDisplayGDI d;
252#elif defined(VISP_HAVE_OPENCV)
254#endif
255
256 d.init(I, 0, 0, "Image");
257
258 vpImage<double> I_score;
259 std::vector<double> benchmark_vec;
260 bool quit = false;
261 while (!reader.end() && !quit) {
262 reader.acquire(I);
263
265
266 std::stringstream ss;
267 ss << "Frame: " << reader.getFrameIndex();
268 vpDisplay::displayText(I, 20, 20, ss.str(), vpColor::red);
269
270 //Basic template matching
271 double t_proc = vpTime::measureTimeMs();
272 const unsigned int step_u = 5, step_v = 5;
273 vpImageTools::templateMatching(I, I_template, I_score, step_u, step_v);
274
275 vpImagePoint max_loc;
276 double max_correlation = -1.0;
277 I_score.getMinMaxLoc(NULL, &max_loc, NULL, &max_correlation);
278 t_proc = vpTime::measureTimeMs() - t_proc;
279 benchmark_vec.push_back(t_proc);
280
281 ss.str("");
282 ss << "Template matching: " << t_proc << " ms";
283 vpDisplay::displayText(I, 40, 20, ss.str(), vpColor::red);
284
285 ss.str("");
286 ss << "Max correlation: " << max_correlation;
287 vpDisplay::displayText(I, 60, 20, ss.str(), vpColor::red);
288
289 vpDisplay::displayRectangle(I, max_loc, I_template.getWidth(), I_template.getHeight(), vpColor::red, false, 1);
290
292
294 if (vpDisplay::getClick(I, button, click)) {
295 switch (button) {
297 quit = !click;
298 break;
299
301 click = !click;
302 break;
303
304 default:
305 break;
306 }
307 }
308 }
309
310 if (!benchmark_vec.empty()) {
311 std::cout << "Processing time, Mean: " << vpMath::getMean(benchmark_vec) << " ms ; Median: "
312 << vpMath::getMedian(benchmark_vec) << " ms ; Std: "
313 << vpMath::getStdev(benchmark_vec) << " ms" << std::endl;
314 }
315#endif
316 } else {
317 //ctest case
318 //Basic template matching
319 const unsigned int step_u = 5, step_v = 5;
320 vpImage<double> I_score, I_score_gold;
321
322 double t = vpTime::measureTimeMs();
323 vpImageTools::templateMatching(I, I_template, I_score, step_u, step_v, true);
324 t = vpTime::measureTimeMs() - t;
325
326 double t_gold = vpTime::measureTimeMs();
327 vpImageTools::templateMatching(I, I_template, I_score_gold, step_u, step_v, false);
328 t_gold = vpTime::measureTimeMs() - t_gold;
329
330 std::cout << "Template matching: " << t << " ms" << std::endl;
331 std::cout << "Template matching (gold): " << t_gold << " ms" << std::endl;
332
333 for (unsigned int i = 0; i < I_score.getHeight(); i++) {
334 for (unsigned int j = 0; j < I_score.getWidth(); j++) {
335 if ( !vpMath::equal(I_score[i][j], I_score_gold[i][j], 1e-9) ) {
336 std::cerr << "Issue with template matching, gold: " << std::setprecision(17) << I_score_gold[i][j]
337 << " ; compute: " << I_score[i][j] << std::endl;
338 return EXIT_FAILURE;
339 }
340 }
341 }
342 }
343
344 } catch (const vpException &e) {
345 std::cerr << "\nCatch an exception: " << e << std::endl;
346 return EXIT_FAILURE;
347 }
348
349 return EXIT_SUCCESS;
350}
static const vpColor red
Definition: vpColor.h:217
Display for windows using GDI (available on any windows 32 platform).
Definition: vpDisplayGDI.h:129
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
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 emited by ViSP classes.
Definition: vpException.h:72
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
Definition: vpImagePoint.h:88
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)
Definition: vpImageTools.h:305
static void integralImage(const vpImage< unsigned char > &I, vpImage< double > &II, vpImage< double > &IIsq)
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:974
unsigned int getWidth() const
Definition: vpImage.h:246
unsigned int getHeight() const
Definition: vpImage.h:188
static std::string getViSPImagesDataPath()
Definition: vpIoTools.cpp:1365
static std::string createFilePath(const std::string &parent, const std::string &child)
Definition: vpIoTools.cpp:1670
static double getMedian(const std::vector< double > &v)
Definition: vpMath.cpp:261
static double getStdev(const std::vector< double > &v, bool useBesselCorrection=false)
Definition: vpMath.cpp:291
static bool equal(double x, double y, double s=0.001)
Definition: vpMath.h:295
static double getMean(const std::vector< double > &v)
Definition: vpMath.cpp:241
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:69
Defines a rectangle in the plane.
Definition: vpRect.h:80
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()