Skip to content

Commit e745fe6

Browse files
committed
Merge branch 4.x
2 parents ed9e79d + 8eec886 commit e745fe6

File tree

3 files changed

+160
-6
lines changed

3 files changed

+160
-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: 141 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,94 @@ 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+
cols.resize(scores.rows);
166+
167+
// backtrack along best path
168+
for (int i = bundleGrad.rows - 1; i >= 0; i--)
169+
{
170+
cols(i) = index_max_location;
171+
index_max_location = fromLocations(i, index_max_location);
172+
}
173+
}
174+
175+
struct HistTrackerImpl : public OLSTracker
89176
{
90177
Mat vtx;
91178
Mat tris;
@@ -95,15 +182,18 @@ struct OLSTrackerImpl : public OLSTracker
95182
double tau;
96183
uchar sobelThresh;
97184

98-
OLSTrackerImpl(InputArray _pts3d, InputArray _tris, int histBins, uchar _sobelThesh)
185+
bool useGOS;
186+
187+
HistTrackerImpl(InputArray _pts3d, InputArray _tris, int histBins, uchar _sobelThesh, bool _useGOS)
99188
{
100189
CV_Assert(_tris.getMat().checkVector(3, CV_32S) > 0);
101190
CV_Assert(_pts3d.getMat().checkVector(3, CV_32F) > 0);
102191
vtx = _pts3d.getMat();
103192
tris = _tris.getMat();
104193

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

108198
bgHist.create(histBins, histBins);
109199
}
@@ -129,7 +219,7 @@ struct OLSTrackerImpl : public OLSTracker
129219

130220
double s = bhattacharyyaCoeff(fgHist, hist);
131221
// handle object clutter as in eq. (5)
132-
if((1.0 - s) > tau)
222+
if(s > tau)
133223
s = 1.0 - bhattacharyyaCoeff(bgHist, hist);
134224
scores(i, j) = float(s);
135225
start = j;
@@ -138,6 +228,36 @@ struct OLSTrackerImpl : public OLSTracker
138228
}
139229
}
140230

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

190310
Mat_<float> scores(lineBundle.size());
191311
computeAppearanceScores(bundleHSV, bundleGrad, scores);
192-
findCorrespondenciesOLS(scores, cols);
312+
313+
if(useGOS)
314+
{
315+
Mat_<float> bgScores(scores.size());
316+
computeBackgroundScores(bundleHSV, bundleGrad, bgScores);
317+
findCorrespondenciesGOS(bundleGrad, scores, bgScores, imgLoc, cols);
318+
}
319+
else
320+
{
321+
findCorrespondenciesOLS(scores, cols);
322+
}
193323

194324
convertCorrespondencies(cols, imgLoc, pts2d, pts3d, cols > -1);
195325

@@ -224,7 +354,12 @@ struct OLSTrackerImpl : public OLSTracker
224354

225355
Ptr<OLSTracker> OLSTracker::create(InputArray pts3d, InputArray tris, int histBins, uchar sobelThesh)
226356
{
227-
return makePtr<OLSTrackerImpl>(pts3d, tris, histBins, sobelThesh);
357+
return makePtr<HistTrackerImpl>(pts3d, tris, histBins, sobelThesh, false);
358+
}
359+
360+
Ptr<OLSTracker> GOSTracker::create(InputArray pts3d, InputArray tris, int histBins, uchar sobelThesh)
361+
{
362+
return makePtr<HistTrackerImpl>(pts3d, tris, histBins, sobelThesh, true);
228363
}
229364

230365
} // namespace rapid

0 commit comments

Comments
 (0)