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
7881134c
Commit
7881134c
authored
May 28, 2011
by
Alexey Spizhevoy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added block-based gain compensator (opencv_stitching), added --preview flag.
parent
dc3fe6e9
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
199 additions
and
57 deletions
+199
-57
exposure_compensate.cpp
modules/stitching/exposure_compensate.cpp
+105
-10
exposure_compensate.hpp
modules/stitching/exposure_compensate.hpp
+21
-3
main.cpp
modules/stitching/main.cpp
+73
-44
No files found.
modules/stitching/exposure_compensate.cpp
View file @
7881134c
...
...
@@ -52,8 +52,10 @@ Ptr<ExposureCompensator> ExposureCompensator::createDefault(int type)
{
if
(
type
==
NO
)
return
new
NoExposureCompensator
();
if
(
type
==
OVERLAP
)
return
new
OverlapExposureCompensator
();
if
(
type
==
GAIN
)
return
new
GainCompensator
();
if
(
type
==
GAIN_BLOCKS
)
return
new
BlocksGainCompensator
();
CV_Error
(
CV_StsBadArg
,
"unsupported exposure compensation method"
);
return
NULL
;
}
...
...
@@ -69,8 +71,8 @@ void ExposureCompensator::feed(const vector<Point> &corners, const vector<Mat> &
}
void
OverlapExposure
Compensator
::
feed
(
const
vector
<
Point
>
&
corners
,
const
vector
<
Mat
>
&
images
,
const
vector
<
pair
<
Mat
,
uchar
>
>
&
masks
)
void
Gain
Compensator
::
feed
(
const
vector
<
Point
>
&
corners
,
const
vector
<
Mat
>
&
images
,
const
vector
<
pair
<
Mat
,
uchar
>
>
&
masks
)
{
CV_Assert
(
corners
.
size
()
==
images
.
size
()
&&
images
.
size
()
==
masks
.
size
());
...
...
@@ -96,7 +98,7 @@ void OverlapExposureCompensator::feed(const vector<Point> &corners, const vector
submask2
=
masks
[
j
].
first
(
Rect
(
roi
.
tl
()
-
corners
[
j
],
roi
.
br
()
-
corners
[
j
]));
intersect
=
(
submask1
==
masks
[
i
].
second
)
&
(
submask2
==
masks
[
j
].
second
);
N
(
i
,
j
)
=
N
(
j
,
i
)
=
countNonZero
(
intersect
);
N
(
i
,
j
)
=
N
(
j
,
i
)
=
max
(
1
,
countNonZero
(
intersect
)
);
double
Isum1
=
0
,
Isum2
=
0
;
for
(
int
y
=
0
;
y
<
roi
.
height
;
++
y
)
...
...
@@ -112,8 +114,8 @@ void OverlapExposureCompensator::feed(const vector<Point> &corners, const vector
}
}
}
I
(
i
,
j
)
=
Isum1
/
max
(
N
(
i
,
j
),
1
);
I
(
j
,
i
)
=
Isum2
/
max
(
N
(
i
,
j
),
1
);
I
(
i
,
j
)
=
Isum1
/
N
(
i
,
j
);
I
(
j
,
i
)
=
Isum2
/
N
(
i
,
j
);
}
}
}
...
...
@@ -135,11 +137,103 @@ void OverlapExposureCompensator::feed(const vector<Point> &corners, const vector
}
}
solve
(
A
,
b
,
gains
);
solve
(
A
,
b
,
gains
_
);
}
void
OverlapExposure
Compensator
::
apply
(
int
index
,
Point
/*corner*/
,
Mat
&
image
,
const
Mat
&
/*mask*/
)
void
Gain
Compensator
::
apply
(
int
index
,
Point
/*corner*/
,
Mat
&
image
,
const
Mat
&
/*mask*/
)
{
image
*=
gains
(
index
,
0
);
image
*=
gains
_
(
index
,
0
);
}
vector
<
double
>
GainCompensator
::
gains
()
const
{
vector
<
double
>
gains_vec
(
gains_
.
rows
);
for
(
int
i
=
0
;
i
<
gains_
.
rows
;
++
i
)
gains_vec
[
i
]
=
gains_
(
i
,
0
);
return
gains_vec
;
}
void
BlocksGainCompensator
::
feed
(
const
vector
<
Point
>
&
corners
,
const
vector
<
Mat
>
&
images
,
const
vector
<
pair
<
Mat
,
uchar
>
>
&
masks
)
{
CV_Assert
(
corners
.
size
()
==
images
.
size
()
&&
images
.
size
()
==
masks
.
size
());
const
int
num_images
=
static_cast
<
int
>
(
images
.
size
());
vector
<
Size
>
bl_per_imgs
(
num_images
);
vector
<
Point
>
block_corners
;
vector
<
Mat
>
block_images
;
vector
<
pair
<
Mat
,
uchar
>
>
block_masks
;
// Construct blocks for gain compensator
for
(
int
img_idx
=
0
;
img_idx
<
num_images
;
++
img_idx
)
{
Size
bl_per_img
((
images
[
img_idx
].
cols
+
bl_width_
-
1
)
/
bl_width_
,
(
images
[
img_idx
].
rows
+
bl_height_
-
1
)
/
bl_height_
);
int
bl_width
=
(
images
[
img_idx
].
cols
+
bl_per_img
.
width
-
1
)
/
bl_per_img
.
width
;
int
bl_height
=
(
images
[
img_idx
].
rows
+
bl_per_img
.
height
-
1
)
/
bl_per_img
.
height
;
bl_per_imgs
[
img_idx
]
=
bl_per_img
;
for
(
int
by
=
0
;
by
<
bl_per_img
.
height
;
++
by
)
{
for
(
int
bx
=
0
;
bx
<
bl_per_img
.
width
;
++
bx
)
{
Point
bl_tl
(
bx
*
bl_width
,
by
*
bl_height
);
Point
bl_br
(
min
(
bl_tl
.
x
+
bl_width
,
images
[
img_idx
].
cols
),
min
(
bl_tl
.
y
+
bl_height
,
images
[
img_idx
].
rows
));
block_corners
.
push_back
(
corners
[
img_idx
]
+
bl_tl
);
block_images
.
push_back
(
images
[
img_idx
](
Rect
(
bl_tl
,
bl_br
)));
block_masks
.
push_back
(
make_pair
(
masks
[
img_idx
].
first
(
Rect
(
bl_tl
,
bl_br
)),
masks
[
img_idx
].
second
));
}
}
}
GainCompensator
compensator
;
compensator
.
feed
(
block_corners
,
block_images
,
block_masks
);
vector
<
double
>
gains
=
compensator
.
gains
();
gain_maps_
.
resize
(
num_images
);
int
bl_idx
=
0
;
for
(
int
img_idx
=
0
;
img_idx
<
num_images
;
++
img_idx
)
{
Size
bl_per_img
=
bl_per_imgs
[
img_idx
];
gain_maps_
[
img_idx
].
create
(
bl_per_img
);
for
(
int
by
=
0
;
by
<
bl_per_img
.
height
;
++
by
)
for
(
int
bx
=
0
;
bx
<
bl_per_img
.
width
;
++
bx
,
++
bl_idx
)
gain_maps_
[
img_idx
](
by
,
bx
)
=
static_cast
<
float
>
(
gains
[
bl_idx
]);
Mat_
<
float
>
ker
(
1
,
3
);
ker
(
0
,
0
)
=
0.25
;
ker
(
0
,
1
)
=
0.5
;
ker
(
0
,
2
)
=
0.25
;
sepFilter2D
(
gain_maps_
[
img_idx
],
gain_maps_
[
img_idx
],
CV_32F
,
ker
,
ker
);
sepFilter2D
(
gain_maps_
[
img_idx
],
gain_maps_
[
img_idx
],
CV_32F
,
ker
,
ker
);
}
}
void
BlocksGainCompensator
::
apply
(
int
index
,
Point
/*corner*/
,
Mat
&
image
,
const
Mat
&
/*mask*/
)
{
CV_Assert
(
image
.
type
()
==
CV_8UC3
);
Mat_
<
float
>
gain_map
;
if
(
gain_maps_
[
index
].
size
()
==
image
.
size
())
gain_map
=
gain_maps_
[
index
];
else
resize
(
gain_maps_
[
index
],
gain_map
,
image
.
size
(),
0
,
0
,
INTER_LINEAR
);
for
(
int
y
=
0
;
y
<
image
.
rows
;
++
y
)
{
const
float
*
gain_row
=
gain_map
.
ptr
<
float
>
(
y
);
Point3_
<
uchar
>*
row
=
image
.
ptr
<
Point3_
<
uchar
>
>
(
y
);
for
(
int
x
=
0
;
x
<
image
.
cols
;
++
x
)
{
row
[
x
].
x
=
saturate_cast
<
uchar
>
(
row
[
x
].
x
*
gain_row
[
x
]);
row
[
x
].
y
=
saturate_cast
<
uchar
>
(
row
[
x
].
y
*
gain_row
[
x
]);
row
[
x
].
z
=
saturate_cast
<
uchar
>
(
row
[
x
].
z
*
gain_row
[
x
]);
}
}
}
\ No newline at end of file
modules/stitching/exposure_compensate.hpp
View file @
7881134c
...
...
@@ -48,7 +48,7 @@
class
ExposureCompensator
{
public
:
enum
{
NO
,
OVERLAP
,
SEGMENT
};
enum
{
NO
,
GAIN
,
GAIN_BLOCKS
};
static
cv
::
Ptr
<
ExposureCompensator
>
createDefault
(
int
type
);
void
feed
(
const
std
::
vector
<
cv
::
Point
>
&
corners
,
const
std
::
vector
<
cv
::
Mat
>
&
images
,
...
...
@@ -68,14 +68,31 @@ public:
};
class
OverlapExposure
Compensator
:
public
ExposureCompensator
class
Gain
Compensator
:
public
ExposureCompensator
{
public
:
void
feed
(
const
std
::
vector
<
cv
::
Point
>
&
corners
,
const
std
::
vector
<
cv
::
Mat
>
&
images
,
const
std
::
vector
<
std
::
pair
<
cv
::
Mat
,
uchar
>
>
&
masks
);
void
apply
(
int
index
,
cv
::
Point
corner
,
cv
::
Mat
&
image
,
const
cv
::
Mat
&
mask
);
std
::
vector
<
double
>
gains
()
const
;
cv
::
Mat_
<
double
>
gains
;
private
:
cv
::
Mat_
<
double
>
gains_
;
};
class
BlocksGainCompensator
:
public
ExposureCompensator
{
public
:
BlocksGainCompensator
(
int
bl_width
=
32
,
int
bl_height
=
32
)
:
bl_width_
(
bl_width
),
bl_height_
(
bl_height
)
{}
void
feed
(
const
std
::
vector
<
cv
::
Point
>
&
corners
,
const
std
::
vector
<
cv
::
Mat
>
&
images
,
const
std
::
vector
<
std
::
pair
<
cv
::
Mat
,
uchar
>
>
&
masks
);
void
apply
(
int
index
,
cv
::
Point
corner
,
cv
::
Mat
&
image
,
const
cv
::
Mat
&
mask
);
private
:
int
bl_width_
,
bl_height_
;
std
::
vector
<
cv
::
Mat_
<
float
>
>
gain_maps_
;
};
#endif // __OPENCV_EXPOSURE_COMPENSATE_HPP__
\ No newline at end of file
modules/stitching/main.cpp
View file @
7881134c
...
...
@@ -41,10 +41,12 @@
//M*/
// We follow to methods described in these two papers:
// - Heung-Yeung Shum and Richard Szeliski.
// Construction of panoramic mosaics with global and local alignment. 2000.
// - Matthew Brown and David G. Lowe.
// Automatic Panoramic Image Stitching using Invariant Features. 2007.
// 1) Construction of panoramic mosaics with global and local alignment.
// Heung-Yeung Shum and Richard Szeliski. 2000.
// 2) Eliminating Ghosting and Exposure Artifacts in Image Mosaics.
// Matthew Uyttendaele, Ashley Eden and Richard Szeliski. 2001.
// 3) Automatic Panoramic Image Stitching using Invariant Features.
// Matthew Brown and David G. Lowe. 2007.
#include "precomp.hpp"
#include "util.hpp"
...
...
@@ -59,45 +61,63 @@ using namespace cv;
void
printUsage
()
{
cout
<<
"Rotation model images stitcher.
\n\n
"
;
cout
<<
"Usage: opencv_stitching img1 img2 [...imgN]
\n
"
<<
"
\t
[--trygpu (yes|no)]
\n
"
<<
"
\t
[--work_megapix <float>]
\n
"
<<
"
\t
[--seam_megapix <float>]
\n
"
<<
"
\t
[--compose_megapix <float>]
\n
"
<<
"
\t
[--match_conf <float>]
\n
"
<<
"
\t
[--ba (ray|focal_ray)]
\n
"
<<
"
\t
[--conf_thresh <float>]
\n
"
<<
"
\t
[--wavecorrect (no|yes)]
\n
"
<<
"
\t
[--warp (plane|cylindrical|spherical)]
\n
"
<<
"
\t
[--exposcomp (no|overlap)]
\n
"
<<
"
\t
[--seam (no|voronoi|gc_color|gc_colorgrad)]
\n
"
<<
"
\t
[--blend (no|feather|multiband)]
\n
"
<<
"
\t
[--numbands <int>]
\n
"
<<
"
\t
[--output <result_img>]
\n\n
"
;
cout
<<
"--match_conf
\n
"
<<
"
\t
Good values are in [0.2, 0.8] range usually.
\n\n
"
;
cout
<<
"HINT:
\n
"
<<
"
\t
Try bigger values for --work_megapix if something is wrong.
\n\n
"
;
cout
<<
"Rotation model images stitcher.
\n\n
"
"opencv_stitching img1 img2 [...imgN] [flags]
\n\n
"
"Flags:
\n
"
" --preview
\n
"
" Run stitching in the preview mode. Works faster than usual mode,
\n
"
" but output image will have lower resolution.
\n
"
" --try_gpu (yes|no)
\n
"
" Try to use GPU. The default value is 'no'. All default values
\n
"
" are for CPU mode.
\n
"
" --work_megapix <float>
\n
"
" Resolution for image registration step. The default is 0.6.
\n
"
" --seam_megapix <float>
\n
"
" Resolution for seam estimation step. The default is 0.1.
\n
"
" --compose_megapix <float>
\n
"
" Resolution for compositing step. Use -1 for original resolution.
\n
"
" The default is -1.
\n
"
" --match_conf <float>
\n
"
" Confidence for feature matching step. The default is 0.6.
\n
"
" --ba (ray|focal_ray)
\n
"
" Bundle adjustment cost function. The default is 'focal_ray'.
\n
"
" --conf_thresh <float>
\n
"
" Threshold for two images are from the same panorama confidence.
\n
"
" The default is 'focal_ray'.
\n
"
" --wave_correct (no|yes)
\n
"
" Perform wave effect correction. The default is 'yes'.
\n
"
" --warp (plane|cylindrical|spherical)
\n
"
" Warp surface type. The default is 'spherical'.
\n
"
" --expos_comp (no|gain|gain_blocks)
\n
"
" Exposure compensation method. The default is 'gain'.
\n
"
" --seam (no|voronoi|gc_color|gc_colorgrad)
\n
"
" Seam estimation method. The default is 'gc_color'.
\n
"
" --blend (no|feather|multiband)
\n
"
" Blending method. The default is 'multiband'.
\n
"
" --num_bands <int>
\n
"
" Number of bands for multi-band blending method. The default is 5.
\n
"
" --output <result_img>
\n
"
;
}
// Default command line args
vector
<
string
>
img_names
;
bool
trygpu
=
false
;
bool
preview
=
false
;
bool
try_gpu
=
false
;
double
work_megapix
=
0.6
;
double
seam_megapix
=
0.1
;
double
compose_megapix
=
1
;
double
compose_megapix
=
-
1
;
int
ba_space
=
BundleAdjuster
::
FOCAL_RAY_SPACE
;
float
conf_thresh
=
1.
f
;
bool
wave_correct
=
true
;
int
warp_type
=
Warper
::
SPHERICAL
;
int
expos_comp_type
=
ExposureCompensator
::
OVERLAP
;
int
expos_comp_type
=
ExposureCompensator
::
GAIN
;
bool
user_match_conf
=
false
;
float
match_conf
=
0.6
f
;
int
seam_find_type
=
SeamFinder
::
GC_COLOR
;
int
blend_type
=
Blender
::
MULTI_BAND
;
int
numbands
=
5
;
int
num
_
bands
=
5
;
string
result_name
=
"result.png"
;
int
parseCmdArgs
(
int
argc
,
char
**
argv
)
...
...
@@ -107,18 +127,21 @@ int parseCmdArgs(int argc, char** argv)
printUsage
();
return
-
1
;
}
for
(
int
i
=
1
;
i
<
argc
;
++
i
)
{
if
(
string
(
argv
[
i
])
==
"--trygpu"
)
if
(
string
(
argv
[
i
])
==
"--preview"
)
{
preview
=
true
;
}
else
if
(
string
(
argv
[
i
])
==
"--try_gpu"
)
{
if
(
string
(
argv
[
i
+
1
])
==
"no"
)
trygpu
=
false
;
try
_
gpu
=
false
;
else
if
(
string
(
argv
[
i
+
1
])
==
"yes"
)
trygpu
=
true
;
try
_
gpu
=
true
;
else
{
cout
<<
"Bad --trygpu flag value
\n
"
;
cout
<<
"Bad --try
_
gpu flag value
\n
"
;
return
-
1
;
}
i
++
;
...
...
@@ -167,7 +190,7 @@ int parseCmdArgs(int argc, char** argv)
conf_thresh
=
static_cast
<
float
>
(
atof
(
argv
[
i
+
1
]));
i
++
;
}
else
if
(
string
(
argv
[
i
])
==
"--wavecorrect"
)
else
if
(
string
(
argv
[
i
])
==
"--wave
_
correct"
)
{
if
(
string
(
argv
[
i
+
1
])
==
"no"
)
wave_correct
=
false
;
...
...
@@ -175,7 +198,7 @@ int parseCmdArgs(int argc, char** argv)
wave_correct
=
true
;
else
{
cout
<<
"Bad --wavecorrect flag value
\n
"
;
cout
<<
"Bad --wave
_
correct flag value
\n
"
;
return
-
1
;
}
i
++
;
...
...
@@ -195,12 +218,14 @@ int parseCmdArgs(int argc, char** argv)
}
i
++
;
}
else
if
(
string
(
argv
[
i
])
==
"--exposcomp"
)
else
if
(
string
(
argv
[
i
])
==
"--expos
_
comp"
)
{
if
(
string
(
argv
[
i
+
1
])
==
"no"
)
expos_comp_type
=
ExposureCompensator
::
NO
;
else
if
(
string
(
argv
[
i
+
1
])
==
"overlap"
)
expos_comp_type
=
ExposureCompensator
::
OVERLAP
;
else
if
(
string
(
argv
[
i
+
1
])
==
"gain"
)
expos_comp_type
=
ExposureCompensator
::
GAIN
;
else
if
(
string
(
argv
[
i
+
1
])
==
"gain_blocks"
)
expos_comp_type
=
ExposureCompensator
::
GAIN_BLOCKS
;
else
{
cout
<<
"Bad exposure compensation method
\n
"
;
...
...
@@ -240,9 +265,9 @@ int parseCmdArgs(int argc, char** argv)
}
i
++
;
}
else
if
(
string
(
argv
[
i
])
==
"--numbands"
)
else
if
(
string
(
argv
[
i
])
==
"--num
_
bands"
)
{
numbands
=
atoi
(
argv
[
i
+
1
]);
num
_
bands
=
atoi
(
argv
[
i
+
1
]);
i
++
;
}
else
if
(
string
(
argv
[
i
])
==
"--output"
)
...
...
@@ -253,6 +278,10 @@ int parseCmdArgs(int argc, char** argv)
else
img_names
.
push_back
(
argv
[
i
]);
}
if
(
preview
)
{
compose_megapix
=
work_megapix
;
}
return
0
;
}
...
...
@@ -281,7 +310,7 @@ int main(int argc, char* argv[])
int64
t
=
getTickCount
();
vector
<
ImageFeatures
>
features
(
num_images
);
SurfFeaturesFinder
finder
(
trygpu
);
SurfFeaturesFinder
finder
(
try
_
gpu
);
Mat
full_img
,
img
;
vector
<
Mat
>
images
(
num_images
);
...
...
@@ -333,9 +362,9 @@ int main(int argc, char* argv[])
LOGLN
(
"Pairwise matching... "
);
t
=
getTickCount
();
vector
<
MatchesInfo
>
pairwise_matches
;
BestOf2NearestMatcher
matcher
(
trygpu
);
BestOf2NearestMatcher
matcher
(
try
_
gpu
);
if
(
user_match_conf
)
matcher
=
BestOf2NearestMatcher
(
trygpu
,
match_conf
);
matcher
=
BestOf2NearestMatcher
(
try
_
gpu
,
match_conf
);
matcher
(
features
,
pairwise_matches
);
LOGLN
(
"Pairwise matching, time: "
<<
((
getTickCount
()
-
t
)
/
getTickFrequency
())
<<
" sec"
);
...
...
@@ -533,7 +562,7 @@ int main(int argc, char* argv[])
if
(
blend_type
==
Blender
::
MULTI_BAND
)
{
MultiBandBlender
*
mb
=
dynamic_cast
<
MultiBandBlender
*>
(
static_cast
<
Blender
*>
(
blender
));
mb
->
setNumBands
(
numbands
);
mb
->
setNumBands
(
num
_
bands
);
}
blender
->
prepare
(
corners
,
sizes
);
}
...
...
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