Skip to content

Commit 25f3c85

Browse files
committed
rapid: add global optimal search implementation
also fix error in LOS regarding tau
1 parent 029c283 commit 25f3c85

File tree

3 files changed

+158
-6
lines changed

3 files changed

+158
-6
lines changed

modules/rapid/doc/rapid.bib

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,14 @@ @article{seo2013optimal
2727
year={2013},
2828
publisher={IEEE}
2929
}
30+
31+
@article{wang2015global,
32+
title={Global optimal searching for textureless 3D object tracking},
33+
author={Wang, Guofeng and Wang, Bin and Zhong, Fan and Qin, Xueying and Chen, Baoquan},
34+
journal={The Visual Computer},
35+
volume={31},
36+
number={6},
37+
pages={979--988},
38+
year={2015},
39+
publisher={Springer}
40+
}

modules/rapid/include/opencv2/rapid.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ class CV_EXPORTS_W OLSTracker : public Tracker
149149
public:
150150
CV_WRAP static Ptr<OLSTracker> create(InputArray pts3d, InputArray tris, int histBins = 8, uchar sobelThesh = 10);
151151
};
152+
153+
/** implements "Global optimal searching for textureless 3D object tracking" @cite wang2015global
154+
*/
155+
class CV_EXPORTS_W GOSTracker : public Tracker
156+
{
157+
public:
158+
CV_WRAP static Ptr<OLSTracker> create(InputArray pts3d, InputArray tris, int histBins = 4, uchar sobelThesh = 10);
159+
};
152160
//! @}
153161
} /* namespace rapid */
154162
} /* namespace cv */

modules/rapid/src/histogram.cpp

Lines changed: 139 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,92 @@ static void findCorrespondenciesOLS(const cv::Mat_<float>& scores, cv::Mat_<int>
8585
}
8686
}
8787

88-
struct OLSTrackerImpl : public OLSTracker
88+
static float computeEdgeWeight(const cv::Vec2s& curCandiPoint, const cv::Vec2s& preCandiPoint)
89+
{
90+
float spatial_dist = (float)cv::norm(curCandiPoint - preCandiPoint, cv::NORM_L2SQR);
91+
return std::exp(-spatial_dist/1000.0f);
92+
}
93+
94+
static void findCorrespondenciesGOS(Mat& bundleGrad, Mat_<float>& fgScores, Mat_<float>& bgScores,
95+
const Mat_<Vec2s>& imgLocations, Mat_<int>& cols)
96+
{
97+
// combine scores
98+
Mat_<float> scores;
99+
exp((fgScores + bgScores)/10.0f, scores);
100+
101+
Mat_<int> fromLocations(scores.size());
102+
fromLocations = 0;
103+
104+
// source node
105+
bool hasCandidate = false;
106+
for(int j=0; j<bundleGrad.cols; j++)
107+
{
108+
if(bundleGrad.at<uchar>(0, j))
109+
{
110+
hasCandidate = true;
111+
fromLocations(0, j) = j;
112+
}
113+
}
114+
// fall back to using center as candidate
115+
if(!hasCandidate)
116+
{
117+
fromLocations(0, bundleGrad.cols/2) = bundleGrad.cols/2;
118+
}
119+
120+
int index_max_location = 0; // index in preceding line for backtracking
121+
122+
// the other layers
123+
for(int i=1; i<bundleGrad.rows; i++)
124+
{
125+
hasCandidate = false;
126+
for(int j=0; j<bundleGrad.cols; j++)
127+
{
128+
if(bundleGrad.at<uchar>(i, j))
129+
hasCandidate = true;
130+
}
131+
if(!hasCandidate)
132+
{
133+
bundleGrad.at<uchar>(i, bundleGrad.cols/2) = 255;
134+
}
135+
136+
for(int j=0; j<bundleGrad.cols; j++)
137+
{
138+
// search for max combined score
139+
float max_energy = -INFINITY;
140+
int location = bundleGrad.cols/2;
141+
142+
if(bundleGrad.at<uchar>(i, j))
143+
{
144+
for(int k=0; k<bundleGrad.cols; k++)
145+
{
146+
if(bundleGrad.at<uchar>(i - 1, k))
147+
{
148+
float edge_weight = computeEdgeWeight(imgLocations(i, j), imgLocations(i - 1, k));
149+
float energy = scores(i, j) + scores(i-1, k) + edge_weight;
150+
if(max_energy < energy)
151+
{
152+
max_energy = energy;
153+
location = k;
154+
}
155+
}
156+
}
157+
158+
scores(i, j) = max_energy; // update the score
159+
fromLocations(i, j) = location;
160+
index_max_location = j;
161+
}
162+
}
163+
}
164+
165+
// backtrack along best path
166+
for (int i = bundleGrad.rows - 1; i >= 0; i--)
167+
{
168+
cols(i) = index_max_location;
169+
index_max_location = fromLocations(i, index_max_location);
170+
}
171+
}
172+
173+
struct HistTrackerImpl : public OLSTracker
89174
{
90175
Mat vtx;
91176
Mat tris;
@@ -95,15 +180,18 @@ struct OLSTrackerImpl : public OLSTracker
95180
double tau;
96181
uchar sobelThresh;
97182

98-
OLSTrackerImpl(InputArray _pts3d, InputArray _tris, int histBins, uchar _sobelThesh)
183+
bool useGOS;
184+
185+
HistTrackerImpl(InputArray _pts3d, InputArray _tris, int histBins, uchar _sobelThesh, bool _useGOS)
99186
{
100187
CV_Assert(_tris.getMat().checkVector(3, CV_32S) > 0);
101188
CV_Assert(_pts3d.getMat().checkVector(3, CV_32F) > 0);
102189
vtx = _pts3d.getMat();
103190
tris = _tris.getMat();
104191

105-
tau = 1.0; // currently does not work as intended. effectively disable
192+
tau = 0.7; // this is 1 - tau compared to OLS paper
106193
sobelThresh = _sobelThesh;
194+
useGOS = _useGOS;
107195

108196
bgHist.create(histBins, histBins);
109197
}
@@ -129,7 +217,7 @@ struct OLSTrackerImpl : public OLSTracker
129217

130218
double s = bhattacharyyaCoeff(fgHist, hist);
131219
// handle object clutter as in eq. (5)
132-
if((1.0 - s) > tau)
220+
if(s > tau)
133221
s = 1.0 - bhattacharyyaCoeff(bgHist, hist);
134222
scores(i, j) = float(s);
135223
start = j;
@@ -138,6 +226,36 @@ struct OLSTrackerImpl : public OLSTracker
138226
}
139227
}
140228

229+
void computeBackgroundScores(const Mat& bundleHSV, const Mat& bundleGrad, Mat_<float>& scores)
230+
{
231+
scores.resize(bundleHSV.rows);
232+
scores = 0;
233+
234+
Mat_<float> hist(fgHist.size());
235+
236+
for (int i = 0; i < bundleHSV.rows; i++)
237+
{
238+
int end = bundleHSV.cols - 1;
239+
for (int j = bundleHSV.cols - 1; j >= 0; j--)
240+
{
241+
if (bundleGrad.at<uchar>(i, j))
242+
{
243+
// compute the histogram between last candidate point to current candidate point
244+
hist = 0;
245+
calcHueSatHist(bundleHSV({i, i + 1}, {j, end}), hist);
246+
hist /= std::max(sum(hist), 1.0f);
247+
248+
double s = 1 - bhattacharyyaCoeff(fgHist, hist);
249+
if (s <= tau)
250+
s = bhattacharyyaCoeff(bgHist, hist);
251+
252+
scores(i, j) = float(s);
253+
end = j;
254+
}
255+
}
256+
}
257+
}
258+
141259
void updateFgBgHist(const Mat_<Vec3b>& hsv, const Mat_<int>& cols)
142260
{
143261
fgHist = 0;
@@ -189,7 +307,17 @@ struct OLSTrackerImpl : public OLSTracker
189307

190308
Mat_<float> scores(lineBundle.size());
191309
computeAppearanceScores(bundleHSV, bundleGrad, scores);
192-
findCorrespondenciesOLS(scores, cols);
310+
311+
if(useGOS)
312+
{
313+
Mat_<float> bgScores(scores.size());
314+
computeBackgroundScores(bundleHSV, bundleGrad, bgScores);
315+
findCorrespondenciesGOS(bundleGrad, scores, bgScores, imgLoc, cols);
316+
}
317+
else
318+
{
319+
findCorrespondenciesOLS(scores, cols);
320+
}
193321

194322
convertCorrespondencies(cols, imgLoc, pts2d, pts3d, cols > -1);
195323

@@ -224,7 +352,12 @@ struct OLSTrackerImpl : public OLSTracker
224352

225353
Ptr<OLSTracker> OLSTracker::create(InputArray pts3d, InputArray tris, int histBins, uchar sobelThesh)
226354
{
227-
return makePtr<OLSTrackerImpl>(pts3d, tris, histBins, sobelThesh);
355+
return makePtr<HistTrackerImpl>(pts3d, tris, histBins, sobelThesh, false);
356+
}
357+
358+
Ptr<OLSTracker> GOSTracker::create(InputArray pts3d, InputArray tris, int histBins, uchar sobelThesh)
359+
{
360+
return makePtr<HistTrackerImpl>(pts3d, tris, histBins, sobelThesh, true);
228361
}
229362

230363
} // namespace rapid

0 commit comments

Comments
 (0)