Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpKltOpencv.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 * Wrapper for the KLT (Kanade-Lucas-Tomasi) feature tracker implemented
32 * with opencv.
33 */
34
41
42#include <visp3/core/vpConfig.h>
43
44#if defined(HAVE_OPENCV_HIGHGUI) && defined(HAVE_OPENCV_IMGPROC) && defined(HAVE_OPENCV_VIDEO)
45
46#include <string>
47
48#include <visp3/core/vpDisplay.h>
49#include <visp3/core/vpTrackingException.h>
50#include <visp3/klt/vpKltOpencv.h>
51
57{
58 m_termcrit = cv::TermCriteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 20, 0.03);
59}
60
68
91
93
94void vpKltOpencv::initTracking(const cv::Mat &I, const cv::Mat &mask)
95{
97
98 I.copyTo(m_gray);
99
100 for (size_t i = 0; i < 2; i++) {
101 m_points[i].clear();
102 }
103
104 m_points_id.clear();
105
106 cv::goodFeaturesToTrack(m_gray, m_points[1], m_maxCount, m_qualityLevel, m_minDistance, mask, m_blockSize, false,
107 m_harris_k);
108
109 if (m_points[1].size() > 0) {
110 cv::cornerSubPix(m_gray, m_points[1], cv::Size(m_winSize, m_winSize), cv::Size(-1, -1), m_termcrit);
111
112 for (size_t i = 0; i < m_points[1].size(); i++)
113 m_points_id.push_back(m_next_points_id++);
114 }
115}
116
117void vpKltOpencv::track(const cv::Mat &I)
118{
119 if (m_points[1].size() == 0)
120 throw vpTrackingException(vpTrackingException::fatalError, "Not enough key points to track.");
121
122 std::vector<float> err;
123 int flags = 0;
124
125 cv::swap(m_prevGray, m_gray);
126
127 if (m_initial_guess) {
128 flags |= cv::OPTFLOW_USE_INITIAL_FLOW;
129 m_initial_guess = false;
130 }
131 else {
132 std::swap(m_points[1], m_points[0]);
133 }
134
135 // cvtColor(I, m_gray, cv::COLOR_BGR2GRAY);
136 I.copyTo(m_gray);
137
138 if (m_prevGray.empty()) {
139 m_gray.copyTo(m_prevGray);
140 }
141
142 std::vector<uchar> status;
143
144 cv::calcOpticalFlowPyrLK(m_prevGray, m_gray, m_points[0], m_points[1], status, err, cv::Size(m_winSize, m_winSize),
146
147 // Remove points that are lost
148 for (int i = static_cast<int>(status.size()) - 1; i >= 0; i--) {
149 if (status[static_cast<size_t>(i)] == 0) { // point is lost
150 m_points[0].erase(m_points[0].begin() + i);
151 m_points[1].erase(m_points[1].begin() + i);
152 m_points_id.erase(m_points_id.begin() + i);
153 }
154 }
155}
156
157void vpKltOpencv::getFeature(const int &index, long &id, float &x, float &y) const
158{
159 if (static_cast<size_t>(index) >= m_points[1].size()) {
160 throw(vpException(vpException::badValue, "Feature [%d] doesn't exist", index));
161 }
162
163 x = m_points[1][static_cast<size_t>(index)].x;
164 y = m_points[1][static_cast<size_t>(index)].y;
165 id = m_points_id[static_cast<size_t>(index)];
166}
167
168void vpKltOpencv::display(const vpImage<unsigned char> &I, const vpColor &color, unsigned int thickness) const
169{
170 vpKltOpencv::display(I, m_points[1], m_points_id, color, thickness);
171}
172
173void vpKltOpencv::display(const vpImage<unsigned char> &I, const std::vector<cv::Point2f> &features,
174 const vpColor &color, unsigned int thickness)
175{
176 vpImagePoint ip;
177 for (size_t i = 0; i < features.size(); i++) {
178 ip.set_u(vpMath::round(features[i].x));
179 ip.set_v(vpMath::round(features[i].y));
180 vpDisplay::displayCross(I, ip, 10 + thickness, color, thickness);
181 }
182}
183
184void vpKltOpencv::display(const vpImage<vpRGBa> &I, const std::vector<cv::Point2f> &features, const vpColor &color,
185 unsigned int thickness)
186{
187 vpImagePoint ip;
188 for (size_t i = 0; i < features.size(); i++) {
189 ip.set_u(vpMath::round(features[i].x));
190 ip.set_v(vpMath::round(features[i].y));
191 vpDisplay::displayCross(I, ip, 10 + thickness, color, thickness);
192 }
193}
194
195void vpKltOpencv::display(const vpImage<unsigned char> &I, const std::vector<cv::Point2f> &features,
196 const std::vector<long> &featuresid, const vpColor &color, unsigned int thickness)
197{
198 vpImagePoint ip;
199 for (size_t i = 0; i < features.size(); i++) {
200 ip.set_u(vpMath::round(features[i].x));
201 ip.set_v(vpMath::round(features[i].y));
202 vpDisplay::displayCross(I, ip, 10, color, thickness);
203
204 std::ostringstream id;
205 id << featuresid[i];
206 ip.set_u(vpMath::round(features[i].x + 5));
207 vpDisplay::displayText(I, ip, id.str(), color);
208 }
209}
210
211void vpKltOpencv::display(const vpImage<vpRGBa> &I, const std::vector<cv::Point2f> &features,
212 const std::vector<long> &featuresid, const vpColor &color, unsigned int thickness)
213{
214 vpImagePoint ip;
215 for (size_t i = 0; i < features.size(); i++) {
216 ip.set_u(vpMath::round(features[i].x));
217 ip.set_v(vpMath::round(features[i].y));
218 vpDisplay::displayCross(I, ip, 10, color, thickness);
219
220 std::ostringstream id;
221 id << featuresid[i];
222 ip.set_u(vpMath::round(features[i].x + 5));
223 vpDisplay::displayText(I, ip, id.str(), color);
224 }
225}
226
227void vpKltOpencv::setInitialGuess(const std::vector<cv::Point2f> &guess_pts)
228{
229 if (guess_pts.size() != m_points[1].size()) {
231 "Cannot set initial guess: size feature vector [%d] "
232 "and guess vector [%d] doesn't match",
233 m_points[1].size(), guess_pts.size()));
234 }
235
236 m_points[1] = guess_pts;
237 m_initial_guess = true;
238}
239
240void vpKltOpencv::setInitialGuess(const std::vector<cv::Point2f> &init_pts, const std::vector<cv::Point2f> &guess_pts,
241 const std::vector<long> &fid)
242{
243 if (guess_pts.size() != init_pts.size()) {
245 "Cannot set initial guess: size init vector [%d] and "
246 "guess vector [%d] doesn't match",
247 init_pts.size(), guess_pts.size()));
248 }
249
250 m_points[0] = init_pts;
251 m_points[1] = guess_pts;
252 m_points_id = fid;
253 m_initial_guess = true;
254}
255
256void vpKltOpencv::initTracking(const cv::Mat &I, const std::vector<cv::Point2f> &pts)
257{
258 m_initial_guess = false;
259 m_points[1] = pts;
261 m_points_id.clear();
262 for (size_t i = 0; i < m_points[1].size(); i++) {
263 m_points_id.push_back(m_next_points_id++);
264 }
265
266 I.copyTo(m_gray);
267}
268
269void vpKltOpencv::initTracking(const cv::Mat &I, const std::vector<cv::Point2f> &pts, const std::vector<long> &ids)
270{
271 m_initial_guess = false;
272 m_points[1] = pts;
273 m_points_id.clear();
274
275 if (ids.size() != pts.size()) {
277 for (size_t i = 0; i < m_points[1].size(); i++)
278 m_points_id.push_back(m_next_points_id++);
279 }
280 else {
281 long max = 0;
282 for (size_t i = 0; i < m_points[1].size(); i++) {
283 m_points_id.push_back(ids[i]);
284 if (ids[i] > max)
285 max = ids[i];
286 }
287 m_next_points_id = max + 1;
288 }
289
290 I.copyTo(m_gray);
291}
292
293void vpKltOpencv::addFeature(const float &x, const float &y)
294{
295 cv::Point2f f(x, y);
296 m_points[1].push_back(f);
297 m_points_id.push_back(m_next_points_id++);
298}
299
300void vpKltOpencv::addFeature(const long &id, const float &x, const float &y)
301{
302 cv::Point2f f(x, y);
303 m_points[1].push_back(f);
304 m_points_id.push_back(id);
305 if (id >= m_next_points_id)
306 m_next_points_id = id + 1;
307}
308
309void vpKltOpencv::addFeature(const cv::Point2f &f)
310{
311 m_points[1].push_back(f);
312 m_points_id.push_back(m_next_points_id++);
313}
314
315void vpKltOpencv::suppressFeature(const int &index)
316{
317 if (static_cast<size_t>(index) >= m_points[1].size()) {
318 throw(vpException(vpException::badValue, "Feature [%d] doesn't exist", index));
319 }
320
321 m_points[1].erase(m_points[1].begin() + index);
322 m_points_id.erase(m_points_id.begin() + index);
323}
324END_VISP_NAMESPACE
325#else
326
327// Work around to avoid visp_klt library empty when OpenCV is not installed or used
328class VISP_EXPORT dummy_vpKltOpencv
329{
330public:
331 dummy_vpKltOpencv() { }
332};
333
334#if !defined(VISP_BUILD_SHARED_LIBS)
335// Work around to avoid warning: libvisp_klt.a(vpKltOpenCV.cpp.o) has no symbols
336void dummy_vpKltOpenCV_fct() { }
337#endif
338
339#endif
Class to define RGB colors available for display functionalities.
Definition vpColor.h:157
static void displayCross(const vpImage< unsigned char > &I, const vpImagePoint &ip, unsigned int size, const vpColor &color, 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
@ badValue
Used to indicate that a value is not in the allowed range.
Definition vpException.h:73
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
void set_u(double u)
void set_v(double v)
Definition of the vpImage class member functions.
Definition vpImage.h:131
virtual ~vpKltOpencv()
std::vector< long > m_points_id
Keypoint id.
void display(const vpImage< unsigned char > &I, const vpColor &color=vpColor::red, unsigned int thickness=1) const
int m_useHarrisDetector
true to use Harris detector
int m_maxCount
Max number of keypoints.
int m_blockSize
Block size.
void track(const cv::Mat &I)
double m_minDistance
Mins distance between keypoints.
vpKltOpencv & operator=(const vpKltOpencv &copy)
cv::TermCriteria m_termcrit
Term criteria.
double m_minEigThreshold
Min eigen threshold.
void getFeature(const int &index, long &id, float &x, float &y) const
int m_pyrMaxLevel
Pyramid max level.
std::vector< cv::Point2f > m_points[2]
Previous [0] and current [1] keypoint location.
double m_qualityLevel
Quality level.
void suppressFeature(const int &index)
bool m_initial_guess
true when initial guess is provided
cv::Mat m_gray
Gray image.
void setInitialGuess(const std::vector< cv::Point2f > &guess_pts)
void addFeature(const float &x, const float &y)
double m_harris_k
Harris parameter.
void initTracking(const cv::Mat &I, const cv::Mat &mask=cv::Mat())
int m_winSize
Window criteria.
long m_next_points_id
Id for the newt keypoint.
cv::Mat m_prevGray
Previous gray image.
static int round(double x)
Definition vpMath.h:413
Error that can be emitted by the vpTracker class and its derivatives.
@ fatalError
Tracker fatal error.