21
21
#include < opencv2/photo.hpp>
22
22
#include < opencv2/stitching.hpp>
23
23
#include < opencv2/stitching/detail/matchers.hpp>
24
+ #include < opencv2/stitching/detail/warpers.hpp>
25
+ #include < opencv2/stitching/warpers.hpp>
24
26
25
27
#include " xpano/algorithm/auto_crop.h"
26
28
#include " xpano/algorithm/blenders.h"
27
29
#include " xpano/algorithm/image.h"
28
30
#include " xpano/algorithm/stitcher.h"
31
+ #include " xpano/algorithm/warpers.h"
29
32
#include " xpano/utils/disjoint_set.h"
30
33
#include " xpano/utils/rect.h"
31
34
#include " xpano/utils/threadpool.h"
@@ -38,6 +41,7 @@ void InsertInOrder(int value, std::vector<int>* vec) {
38
41
auto iter = std::lower_bound (vec->begin (), vec->end (), value);
39
42
vec->insert (iter, value);
40
43
}
44
+
41
45
cv::Ptr <cv::WarperCreator> PickWarper (ProjectionOptions options) {
42
46
cv::Ptr <cv::WarperCreator> warper_creator;
43
47
switch (options.type ) {
@@ -74,25 +78,32 @@ cv::Ptr<cv::WarperCreator> PickWarper(ProjectionOptions options) {
74
78
return warper_creator;
75
79
}
76
80
77
- std::optional<cv::RotateFlags> GetRotationFlags (
78
- WaveCorrectionType wave_correction,
79
- cv::detail::WaveCorrectKind wave_correction_auto) {
80
- // have to rotate clockwise in case vertical wave correction was either
81
- // selected by user or autodetected
82
- switch (wave_correction) {
83
- case WaveCorrectionType::kOff :
84
- [[fallthrough]];
85
- case WaveCorrectionType::kHorizontal :
86
- return {};
87
- case WaveCorrectionType::kVertical :
88
- return cv::ROTATE_90_CLOCKWISE;
89
- case WaveCorrectionType::kAuto :
81
+ cv::Ptr <cv::WarperCreator> PickWarperPortrait (ProjectionOptions options) {
82
+ // When vertical wave correction is detected / selected, the portrait
83
+ // variants of projections are used (if implemented)
84
+ cv::Ptr <cv::WarperCreator> warper_creator;
85
+ switch (options.type ) {
86
+ case ProjectionType::kPerspective :
87
+ warper_creator = cv::makePtr<stitcher::PlanePortraitWarper>();
88
+ break ;
89
+ case ProjectionType::kCylindrical :
90
+ warper_creator = cv::makePtr<stitcher::CylindricalPortraitWarper>();
91
+ break ;
92
+ case ProjectionType::kSpherical :
93
+ warper_creator = cv::makePtr<stitcher::SphericalPortraitWarper>();
94
+ break ;
95
+ case ProjectionType::kCompressedRectilinear :
96
+ warper_creator = cv::makePtr<cv::CompressedRectilinearPortraitWarper>(
97
+ options.a_param , options.b_param );
98
+ break ;
99
+ case ProjectionType::kPanini :
100
+ warper_creator = cv::makePtr<cv::PaniniPortraitWarper>(options.a_param ,
101
+ options.b_param );
102
+ break ;
103
+ default :
90
104
break ;
91
105
}
92
- if (wave_correction_auto == cv::detail::WAVE_CORRECT_VERT) {
93
- return cv::ROTATE_90_CLOCKWISE;
94
- }
95
- return {};
106
+ return warper_creator;
96
107
}
97
108
98
109
cv::Ptr <cv::FeatureDetector> PickFeaturesFinder (FeatureType feature) {
@@ -242,9 +253,11 @@ std::vector<Pano> FindPanos(const std::vector<Match>& matches,
242
253
}
243
254
244
255
StitchResult Stitch (const std::vector<cv::Mat>& images,
256
+ const std::optional<Cameras>& cameras,
245
257
StitchUserOptions user_options, StitchOptions options) {
246
258
auto stitcher = stitcher::Stitcher::Create (cv::Stitcher::PANORAMA);
247
259
stitcher->SetWarper (PickWarper (user_options.projection ));
260
+ stitcher->SetPortraitWarper (PickWarperPortrait (user_options.projection ));
248
261
stitcher->SetFeaturesFinder (PickFeaturesFinder (user_options.feature ));
249
262
stitcher->SetFeaturesMatcher (cv::makePtr<cv::detail::BestOf2NearestMatcher>(
250
263
false , user_options.match_conf ));
@@ -259,7 +272,17 @@ StitchResult Stitch(const std::vector<cv::Mat>& images,
259
272
stitcher->SetProgressMonitor (options.progress_monitor );
260
273
261
274
cv::Mat pano;
262
- auto status = stitcher->Stitch (images, pano);
275
+ stitcher::Status status;
276
+
277
+ if (cameras &&
278
+ cameras->wave_correction_user == user_options.wave_correction &&
279
+ cameras->cameras .size () == images.size ()) {
280
+ stitcher->SetWaveCorrectKind (cameras->wave_correction_auto );
281
+ stitcher->SetTransform (images, cameras->cameras );
282
+ status = stitcher->ComposePanorama (pano);
283
+ } else {
284
+ status = stitcher->Stitch (images, pano);
285
+ }
263
286
264
287
if (status != stitcher::Status::kSuccess ) {
265
288
return {status, {}, {}};
@@ -270,16 +293,10 @@ StitchResult Stitch(const std::vector<cv::Mat>& images,
270
293
stitcher->ResultMask ().copyTo (mask);
271
294
}
272
295
273
- if (auto rotate = GetRotationFlags (user_options.wave_correction ,
274
- stitcher->WaveCorrectKind ());
275
- rotate) {
276
- cv::rotate (pano, pano, *rotate);
277
- if (options.return_pano_mask ) {
278
- cv::rotate (mask, mask, *rotate);
279
- }
280
- }
281
-
282
- return {status, pano, mask};
296
+ auto result_cameras =
297
+ Cameras{stitcher->Cameras (), user_options.wave_correction ,
298
+ stitcher->WaveCorrectKind (), stitcher->GetWarpHelper ()};
299
+ return {status, pano, mask, std::move (result_cameras)};
283
300
}
284
301
285
302
int StitchTasksCount (int num_images) {
@@ -338,4 +355,13 @@ Pano SinglePano(int size) {
338
355
return pano;
339
356
}
340
357
358
+ Cameras Rotate (const Cameras& cameras, const cv::Mat& rotation_matrix) {
359
+ Cameras rotated = cameras;
360
+ for (auto & camera : rotated.cameras ) {
361
+ camera.R = rotation_matrix * camera.R ;
362
+ }
363
+
364
+ return rotated;
365
+ }
366
+
341
367
} // namespace xpano::algorithm
0 commit comments