Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
f95e71ea
Commit
f95e71ea
authored
Aug 15, 2011
by
Alexey Spizhevoy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added saving of matches graph into opencv_stitching (in DOT format)
parent
7820c343
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
282 additions
and
192 deletions
+282
-192
main.cpp
modules/stitching/main.cpp
+21
-0
matchers.hpp
modules/stitching/matchers.hpp
+99
-100
motion_estimators.cpp
modules/stitching/motion_estimators.cpp
+65
-0
motion_estimators.hpp
modules/stitching/motion_estimators.hpp
+95
-91
util.hpp
modules/stitching/util.hpp
+2
-1
No files found.
modules/stitching/main.cpp
View file @
f95e71ea
...
...
@@ -48,6 +48,7 @@
// 3) Automatic Panoramic Image Stitching using Invariant Features.
// Matthew Brown and David G. Lowe. 2007.
#include <fstream>
#include "precomp.hpp"
#include "util.hpp"
#include "warpers.hpp"
...
...
@@ -83,6 +84,10 @@ void printUsage()
" Bundle adjustment cost function. The default is 'focal_ray'.
\n
"
" --wave_correct (no|yes)
\n
"
" Perform wave effect correction. The default is 'yes'.
\n
"
" --save_graph <file_name>
\n
"
" Save matches graph represented in DOT language to <file_name> file.
\n
"
" Labels description: Nm is number of matches, Ni is number of inliers,
\n
"
" C is confidence.
\n
"
"
\n
Compositing Flags:
\n
"
" --warp (plane|cylindrical|spherical)
\n
"
" Warp surface type. The default is 'spherical'.
\n
"
...
...
@@ -114,6 +119,8 @@ double compose_megapix = -1;
int
ba_space
=
BundleAdjuster
::
FOCAL_RAY_SPACE
;
float
conf_thresh
=
1.
f
;
bool
wave_correct
=
true
;
bool
save_graph
=
false
;
std
::
string
save_graph_to
;
int
warp_type
=
Warper
::
SPHERICAL
;
int
expos_comp_type
=
ExposureCompensator
::
GAIN_BLOCKS
;
float
match_conf
=
0.65
f
;
...
...
@@ -209,6 +216,12 @@ int parseCmdArgs(int argc, char** argv)
}
i
++
;
}
else
if
(
string
(
argv
[
i
])
==
"--save_graph"
)
{
save_graph
=
true
;
save_graph_to
=
argv
[
i
+
1
];
i
++
;
}
else
if
(
string
(
argv
[
i
])
==
"--warp"
)
{
if
(
string
(
argv
[
i
+
1
])
==
"plane"
)
...
...
@@ -378,6 +391,14 @@ int main(int argc, char* argv[])
matcher
.
releaseMemory
();
LOGLN
(
"Pairwise matching, time: "
<<
((
getTickCount
()
-
t
)
/
getTickFrequency
())
<<
" sec"
);
// Check if we should save matches graph
if
(
save_graph
)
{
LOGLN
(
"Saving matches graph..."
);
ofstream
f
(
save_graph_to
.
c_str
());
f
<<
matchesGraphAsString
(
img_names
,
pairwise_matches
,
conf_thresh
);
}
// Leave only images we are sure are from the same panorama
vector
<
int
>
indices
=
leaveBiggestComponent
(
features
,
pairwise_matches
,
conf_thresh
);
vector
<
Mat
>
img_subset
;
...
...
modules/stitching/matchers.hpp
View file @
f95e71ea
...
...
@@ -38,102 +38,102 @@
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_MATCHERS_HPP__
#define __OPENCV_MATCHERS_HPP__
#include "precomp.hpp"
struct
ImageFeatures
{
int
img_idx
;
cv
::
Size
img_size
;
std
::
vector
<
cv
::
KeyPoint
>
keypoints
;
cv
::
Mat
descriptors
;
};
class
FeaturesFinder
{
public
:
virtual
~
FeaturesFinder
()
{}
void
operator
()(
const
cv
::
Mat
&
image
,
ImageFeatures
&
features
);
virtual
void
releaseMemory
()
{}
protected
:
virtual
void
find
(
const
cv
::
Mat
&
image
,
ImageFeatures
&
features
)
=
0
;
};
class
SurfFeaturesFinder
:
public
FeaturesFinder
{
public
:
SurfFeaturesFinder
(
bool
try_use_gpu
=
true
,
double
hess_thresh
=
300.0
,
int
num_octaves
=
3
,
int
num_layers
=
4
,
int
num_octaves_descr
=
4
,
int
num_layers_descr
=
2
);
void
releaseMemory
();
protected
:
void
find
(
const
cv
::
Mat
&
image
,
ImageFeatures
&
features
);
cv
::
Ptr
<
FeaturesFinder
>
impl_
;
};
struct
MatchesInfo
{
MatchesInfo
();
MatchesInfo
(
const
MatchesInfo
&
other
);
const
MatchesInfo
&
operator
=
(
const
MatchesInfo
&
other
);
int
src_img_idx
,
dst_img_idx
;
// Images indices (optional)
std
::
vector
<
cv
::
DMatch
>
matches
;
std
::
vector
<
uchar
>
inliers_mask
;
// Geometrically consistent matches mask
int
num_inliers
;
// Number of geometrically consistent matches
cv
::
Mat
H
;
// Estimated homography
double
confidence
;
// Confidence two images are from the same panorama
};
class
FeaturesMatcher
{
public
:
virtual
~
FeaturesMatcher
()
{}
void
operator
()(
const
ImageFeatures
&
features1
,
const
ImageFeatures
&
features2
,
MatchesInfo
&
matches_info
)
{
match
(
features1
,
features2
,
matches_info
);
}
void
operator
()(
const
std
::
vector
<
ImageFeatures
>
&
features
,
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
);
bool
isThreadSafe
()
const
{
return
is_thread_safe_
;
}
virtual
void
releaseMemory
()
{}
protected
:
FeaturesMatcher
(
bool
is_thread_safe
=
false
)
:
is_thread_safe_
(
is_thread_safe
)
{}
virtual
void
match
(
const
ImageFeatures
&
features1
,
const
ImageFeatures
&
features2
,
MatchesInfo
&
matches_info
)
=
0
;
bool
is_thread_safe_
;
};
class
BestOf2NearestMatcher
:
public
FeaturesMatcher
{
public
:
BestOf2NearestMatcher
(
bool
try_use_gpu
=
true
,
float
match_conf
=
0.55
f
,
int
num_matches_thresh1
=
6
,
int
num_matches_thresh2
=
6
);
void
releaseMemory
();
protected
:
void
match
(
const
ImageFeatures
&
features1
,
const
ImageFeatures
&
features2
,
MatchesInfo
&
matches_info
);
int
num_matches_thresh1_
;
int
num_matches_thresh2_
;
cv
::
Ptr
<
FeaturesMatcher
>
impl_
;
};
#endif // __OPENCV_MATCHERS_HPP__
\ No newline at end of file
//M*/
#ifndef __OPENCV_MATCHERS_HPP__
#define __OPENCV_MATCHERS_HPP__
#include "precomp.hpp"
struct
ImageFeatures
{
int
img_idx
;
cv
::
Size
img_size
;
std
::
vector
<
cv
::
KeyPoint
>
keypoints
;
cv
::
Mat
descriptors
;
};
class
FeaturesFinder
{
public
:
virtual
~
FeaturesFinder
()
{}
void
operator
()(
const
cv
::
Mat
&
image
,
ImageFeatures
&
features
);
virtual
void
releaseMemory
()
{}
protected
:
virtual
void
find
(
const
cv
::
Mat
&
image
,
ImageFeatures
&
features
)
=
0
;
};
class
SurfFeaturesFinder
:
public
FeaturesFinder
{
public
:
SurfFeaturesFinder
(
bool
try_use_gpu
=
true
,
double
hess_thresh
=
300.0
,
int
num_octaves
=
3
,
int
num_layers
=
4
,
int
num_octaves_descr
=
4
,
int
num_layers_descr
=
2
);
void
releaseMemory
();
protected
:
void
find
(
const
cv
::
Mat
&
image
,
ImageFeatures
&
features
);
cv
::
Ptr
<
FeaturesFinder
>
impl_
;
};
struct
MatchesInfo
{
MatchesInfo
();
MatchesInfo
(
const
MatchesInfo
&
other
);
const
MatchesInfo
&
operator
=
(
const
MatchesInfo
&
other
);
int
src_img_idx
,
dst_img_idx
;
// Images indices (optional)
std
::
vector
<
cv
::
DMatch
>
matches
;
std
::
vector
<
uchar
>
inliers_mask
;
// Geometrically consistent matches mask
int
num_inliers
;
// Number of geometrically consistent matches
cv
::
Mat
H
;
// Estimated homography
double
confidence
;
// Confidence two images are from the same panorama
};
class
FeaturesMatcher
{
public
:
virtual
~
FeaturesMatcher
()
{}
void
operator
()(
const
ImageFeatures
&
features1
,
const
ImageFeatures
&
features2
,
MatchesInfo
&
matches_info
)
{
match
(
features1
,
features2
,
matches_info
);
}
void
operator
()(
const
std
::
vector
<
ImageFeatures
>
&
features
,
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
);
bool
isThreadSafe
()
const
{
return
is_thread_safe_
;
}
virtual
void
releaseMemory
()
{}
protected
:
FeaturesMatcher
(
bool
is_thread_safe
=
false
)
:
is_thread_safe_
(
is_thread_safe
)
{}
virtual
void
match
(
const
ImageFeatures
&
features1
,
const
ImageFeatures
&
features2
,
MatchesInfo
&
matches_info
)
=
0
;
bool
is_thread_safe_
;
};
class
BestOf2NearestMatcher
:
public
FeaturesMatcher
{
public
:
BestOf2NearestMatcher
(
bool
try_use_gpu
=
true
,
float
match_conf
=
0.55
f
,
int
num_matches_thresh1
=
6
,
int
num_matches_thresh2
=
6
);
void
releaseMemory
();
protected
:
void
match
(
const
ImageFeatures
&
features1
,
const
ImageFeatures
&
features2
,
MatchesInfo
&
matches_info
);
int
num_matches_thresh1_
;
int
num_matches_thresh2_
;
cv
::
Ptr
<
FeaturesMatcher
>
impl_
;
};
#endif // __OPENCV_MATCHERS_HPP__
modules/stitching/motion_estimators.cpp
View file @
f95e71ea
...
...
@@ -40,6 +40,7 @@
//
//M*/
#include <algorithm>
#include <sstream>
#include "autocalib.hpp"
#include "motion_estimators.hpp"
#include "util.hpp"
...
...
@@ -407,6 +408,70 @@ void waveCorrect(vector<Mat> &rmats)
//////////////////////////////////////////////////////////////////////////////
string
matchesGraphAsString
(
vector
<
string
>
&
pathes
,
vector
<
MatchesInfo
>
&
pairwise_matches
,
float
conf_threshold
)
{
stringstream
str
;
str
<<
"graph matches_graph{
\n
"
;
set
<
int
>
added_imgs
;
// Add matches
for
(
size_t
i
=
0
;
i
<
pairwise_matches
.
size
();
++
i
)
{
if
(
pairwise_matches
[
i
].
src_img_idx
<
pairwise_matches
[
i
].
dst_img_idx
&&
pairwise_matches
[
i
].
confidence
>
conf_threshold
)
{
string
name_src
=
pathes
[
pairwise_matches
[
i
].
src_img_idx
];
size_t
prefix_len
=
name_src
.
find_last_of
(
"/
\\
"
);
if
(
prefix_len
!=
string
::
npos
)
prefix_len
++
;
else
prefix_len
=
0
;
name_src
=
name_src
.
substr
(
prefix_len
,
name_src
.
size
()
-
prefix_len
);
string
name_dst
=
pathes
[
pairwise_matches
[
i
].
dst_img_idx
];
prefix_len
=
name_dst
.
find_last_of
(
"/
\\
"
);
if
(
prefix_len
!=
string
::
npos
)
prefix_len
++
;
else
prefix_len
=
0
;
name_dst
=
name_dst
.
substr
(
prefix_len
,
name_dst
.
size
()
-
prefix_len
);
added_imgs
.
insert
(
pairwise_matches
[
i
].
src_img_idx
);
added_imgs
.
insert
(
pairwise_matches
[
i
].
dst_img_idx
);
str
<<
"
\"
"
<<
name_src
<<
"
\"
--
\"
"
<<
name_dst
<<
"
\"
"
<<
"[label=
\"
Nm="
<<
pairwise_matches
[
i
].
matches
.
size
()
<<
", Ni="
<<
pairwise_matches
[
i
].
num_inliers
<<
", C="
<<
pairwise_matches
[
i
].
confidence
<<
"
\"
];
\n
"
;
}
}
// Add unmatched images
for
(
size_t
i
=
0
;
i
<
pairwise_matches
.
size
();
++
i
)
{
if
(
pairwise_matches
[
i
].
src_img_idx
<
pairwise_matches
[
i
].
dst_img_idx
)
{
if
(
added_imgs
.
find
(
pairwise_matches
[
i
].
src_img_idx
)
==
added_imgs
.
end
())
{
added_imgs
.
insert
(
pairwise_matches
[
i
].
src_img_idx
);
string
name
=
pathes
[
pairwise_matches
[
i
].
src_img_idx
];
size_t
prefix_len
=
name
.
find_last_of
(
"/
\\
"
);
if
(
prefix_len
!=
string
::
npos
)
prefix_len
++
;
else
prefix_len
=
0
;
name
=
name
.
substr
(
prefix_len
,
name
.
size
()
-
prefix_len
);
str
<<
"
\"
"
<<
name
<<
"
\"
;
\n
"
;
}
if
(
added_imgs
.
find
(
pairwise_matches
[
i
].
dst_img_idx
)
==
added_imgs
.
end
())
{
added_imgs
.
insert
(
pairwise_matches
[
i
].
dst_img_idx
);
string
name
=
pathes
[
pairwise_matches
[
i
].
dst_img_idx
];
size_t
prefix_len
=
name
.
find_last_of
(
"/
\\
"
);
if
(
prefix_len
!=
string
::
npos
)
prefix_len
++
;
else
prefix_len
=
0
;
name
=
name
.
substr
(
prefix_len
,
name
.
size
()
-
prefix_len
);
str
<<
"
\"
"
<<
name
<<
"
\"
;
\n
"
;
}
}
}
str
<<
"}"
;
return
str
.
str
();
}
vector
<
int
>
leaveBiggestComponent
(
vector
<
ImageFeatures
>
&
features
,
vector
<
MatchesInfo
>
&
pairwise_matches
,
float
conf_threshold
)
{
...
...
modules/stitching/motion_estimators.hpp
View file @
f95e71ea
...
...
@@ -38,94 +38,98 @@
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#ifndef __OPENCV_MOTION_ESTIMATORS_HPP__
#define __OPENCV_MOTION_ESTIMATORS_HPP__
#include "precomp.hpp"
#include "matchers.hpp"
#include "util.hpp"
struct
CameraParams
{
CameraParams
();
CameraParams
(
const
CameraParams
&
other
);
const
CameraParams
&
operator
=
(
const
CameraParams
&
other
);
double
focal
;
// Focal length
cv
::
Mat
R
;
// Rotation
cv
::
Mat
t
;
// Translation
};
class
Estimator
{
public
:
void
operator
()(
const
std
::
vector
<
ImageFeatures
>
&
features
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
std
::
vector
<
CameraParams
>
&
cameras
)
{
estimate
(
features
,
pairwise_matches
,
cameras
);
}
protected
:
virtual
void
estimate
(
const
std
::
vector
<
ImageFeatures
>
&
features
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
std
::
vector
<
CameraParams
>
&
cameras
)
=
0
;
};
class
HomographyBasedEstimator
:
public
Estimator
{
public
:
HomographyBasedEstimator
()
:
is_focals_estimated_
(
false
)
{}
bool
isFocalsEstimated
()
const
{
return
is_focals_estimated_
;
}
private
:
void
estimate
(
const
std
::
vector
<
ImageFeatures
>
&
features
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
std
::
vector
<
CameraParams
>
&
cameras
);
bool
is_focals_estimated_
;
};
class
BundleAdjuster
:
public
Estimator
{
public
:
enum
{
RAY_SPACE
,
FOCAL_RAY_SPACE
};
BundleAdjuster
(
int
cost_space
=
FOCAL_RAY_SPACE
,
float
conf_thresh
=
1.
f
)
:
cost_space_
(
cost_space
),
conf_thresh_
(
conf_thresh
)
{}
private
:
void
estimate
(
const
std
::
vector
<
ImageFeatures
>
&
features
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
std
::
vector
<
CameraParams
>
&
cameras
);
void
calcError
(
cv
::
Mat
&
err
);
void
calcJacobian
();
int
num_images_
;
int
total_num_matches_
;
const
ImageFeatures
*
features_
;
const
MatchesInfo
*
pairwise_matches_
;
cv
::
Mat
cameras_
;
std
::
vector
<
std
::
pair
<
int
,
int
>
>
edges_
;
int
cost_space_
;
float
conf_thresh_
;
cv
::
Mat
err_
,
err1_
,
err2_
;
cv
::
Mat
J_
;
};
void
waveCorrect
(
std
::
vector
<
cv
::
Mat
>
&
rmats
);
//////////////////////////////////////////////////////////////////////////////
// Auxiliary functions
std
::
vector
<
int
>
leaveBiggestComponent
(
std
::
vector
<
ImageFeatures
>
&
features
,
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
float
conf_threshold
);
void
findMaxSpanningTree
(
int
num_images
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
Graph
&
span_tree
,
std
::
vector
<
int
>
&
centers
);
#endif // __OPENCV_MOTION_ESTIMATORS_HPP__
//M*/
#ifndef __OPENCV_MOTION_ESTIMATORS_HPP__
#define __OPENCV_MOTION_ESTIMATORS_HPP__
#include "precomp.hpp"
#include "matchers.hpp"
#include "util.hpp"
struct
CameraParams
{
CameraParams
();
CameraParams
(
const
CameraParams
&
other
);
const
CameraParams
&
operator
=
(
const
CameraParams
&
other
);
double
focal
;
// Focal length
cv
::
Mat
R
;
// Rotation
cv
::
Mat
t
;
// Translation
};
class
Estimator
{
public
:
void
operator
()(
const
std
::
vector
<
ImageFeatures
>
&
features
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
std
::
vector
<
CameraParams
>
&
cameras
)
{
estimate
(
features
,
pairwise_matches
,
cameras
);
}
protected
:
virtual
void
estimate
(
const
std
::
vector
<
ImageFeatures
>
&
features
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
std
::
vector
<
CameraParams
>
&
cameras
)
=
0
;
};
class
HomographyBasedEstimator
:
public
Estimator
{
public
:
HomographyBasedEstimator
()
:
is_focals_estimated_
(
false
)
{}
bool
isFocalsEstimated
()
const
{
return
is_focals_estimated_
;
}
private
:
void
estimate
(
const
std
::
vector
<
ImageFeatures
>
&
features
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
std
::
vector
<
CameraParams
>
&
cameras
);
bool
is_focals_estimated_
;
};
class
BundleAdjuster
:
public
Estimator
{
public
:
enum
{
RAY_SPACE
,
FOCAL_RAY_SPACE
};
BundleAdjuster
(
int
cost_space
=
FOCAL_RAY_SPACE
,
float
conf_thresh
=
1.
f
)
:
cost_space_
(
cost_space
),
conf_thresh_
(
conf_thresh
)
{}
private
:
void
estimate
(
const
std
::
vector
<
ImageFeatures
>
&
features
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
std
::
vector
<
CameraParams
>
&
cameras
);
void
calcError
(
cv
::
Mat
&
err
);
void
calcJacobian
();
int
num_images_
;
int
total_num_matches_
;
const
ImageFeatures
*
features_
;
const
MatchesInfo
*
pairwise_matches_
;
cv
::
Mat
cameras_
;
std
::
vector
<
std
::
pair
<
int
,
int
>
>
edges_
;
int
cost_space_
;
float
conf_thresh_
;
cv
::
Mat
err_
,
err1_
,
err2_
;
cv
::
Mat
J_
;
};
void
waveCorrect
(
std
::
vector
<
cv
::
Mat
>
&
rmats
);
//////////////////////////////////////////////////////////////////////////////
// Auxiliary functions
// Returns matches graph representation in DOT language
std
::
string
matchesGraphAsString
(
std
::
vector
<
std
::
string
>
&
pathes
,
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
float
conf_threshold
);
std
::
vector
<
int
>
leaveBiggestComponent
(
std
::
vector
<
ImageFeatures
>
&
features
,
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
float
conf_threshold
);
void
findMaxSpanningTree
(
int
num_images
,
const
std
::
vector
<
MatchesInfo
>
&
pairwise_matches
,
Graph
&
span_tree
,
std
::
vector
<
int
>
&
centers
);
#endif // __OPENCV_MOTION_ESTIMATORS_HPP__
modules/stitching/util.hpp
View file @
f95e71ea
...
...
@@ -108,8 +108,9 @@ bool overlapRoi(cv::Point tl1, cv::Point tl2, cv::Size sz1, cv::Size sz2, cv::Re
cv
::
Rect
resultRoi
(
const
std
::
vector
<
cv
::
Point
>
&
corners
,
const
std
::
vector
<
cv
::
Mat
>
&
images
);
cv
::
Rect
resultRoi
(
const
std
::
vector
<
cv
::
Point
>
&
corners
,
const
std
::
vector
<
cv
::
Size
>
&
sizes
);
cv
::
Point
resultTl
(
const
std
::
vector
<
cv
::
Point
>
&
corners
);
void
selectRandomSubset
(
int
count
,
int
size
,
std
::
vector
<
int
>
&
subset
);
// Returns random 'count' element subset of the {0,1,...,size-1} set
void
selectRandomSubset
(
int
count
,
int
size
,
std
::
vector
<
int
>
&
subset
);
#include "util_inl.hpp"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment