Skip to content

Commit 2178134

Browse files
authored
Bugfix check pano size (#121)
* check pano size and exit early * add test for pano too large error
1 parent 0048d1d commit 2178134

File tree

7 files changed

+97
-20
lines changed

7 files changed

+97
-20
lines changed

tests/stitcher_pipeline_test.cc

+56
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <catch2/matchers/catch_matchers_floating_point.hpp>
1515
#include <catch2/matchers/catch_matchers_string.hpp>
1616
#include <catch2/matchers/catch_matchers_vector.hpp>
17+
1718
#ifdef XPANO_WITH_EXIV2
1819
#include <exiv2/exiv2.hpp>
1920
#endif
@@ -23,6 +24,7 @@
2324

2425
#include "tests/utils.h"
2526
#include "xpano/algorithm/options.h"
27+
#include "xpano/algorithm/stitcher.h"
2628
#include "xpano/constants.h"
2729

2830
using Catch::Matchers::Equals;
@@ -143,6 +145,60 @@ TEST_CASE("Stitcher pipeline defaults [extra results]") {
143145
CHECK(stitch_result1.cameras->cameras.size() == 3);
144146
}
145147

148+
const std::vector<std::filesystem::path> kInputsFirstPano = {
149+
"data/image01.jpg", "data/image02.jpg", "data/image03.jpg",
150+
"data/image04.jpg", "data/image05.jpg"};
151+
152+
TEST_CASE("Pano too large") {
153+
xpano::pipeline::StitcherPipeline<kReturnFuture> stitcher;
154+
155+
auto loading_task = stitcher.RunLoading(kInputsFirstPano, {}, {});
156+
auto stitch_data = loading_task.future.get();
157+
auto progress = loading_task.progress->Report();
158+
CHECK(progress.tasks_done == progress.num_tasks);
159+
160+
CHECK(stitch_data.images.size() == 5);
161+
REQUIRE(stitch_data.panos.size() == 1);
162+
REQUIRE_THAT(stitch_data.panos[0].ids, Equals<int>({0, 1, 2, 3, 4}));
163+
164+
const float eps = 0.02;
165+
166+
// stitch for the 1st time
167+
auto proj_options = xpano::algorithm::StitchUserOptions{
168+
.projection = {.type = xpano::algorithm::ProjectionType::kPerspective}};
169+
auto stitching_task0 = stitcher.RunStitching(
170+
stitch_data, {.pano_id = 0, .stitch_algorithm = proj_options});
171+
172+
auto stitch_result0 = stitching_task0.future.get();
173+
progress = stitching_task0.progress->Report();
174+
CHECK(progress.tasks_done == progress.num_tasks);
175+
176+
REQUIRE(stitch_result0.pano.has_value());
177+
CHECK_THAT(stitch_result0.pano->rows, WithinRel(1737, eps));
178+
CHECK_THAT(stitch_result0.pano->cols, WithinRel(4303, eps));
179+
180+
REQUIRE(stitch_result0.cameras.has_value());
181+
CHECK(stitch_result0.cameras->cameras.size() == 5);
182+
183+
// rotate and stitch again
184+
auto rot_data = std::array{0.86f, -0.31f, -0.42f, 0.02f, 0.82f,
185+
-0.57f, 0.52f, 0.48f, 0.71f};
186+
auto rotation_matrix = cv::Mat(3, 3, CV_32F, rot_data.data());
187+
188+
stitch_data.panos[0].cameras =
189+
xpano::algorithm::Rotate(*stitch_result0.cameras, rotation_matrix);
190+
auto stitching_task1 = stitcher.RunStitching(
191+
stitch_data, {.pano_id = 0, .stitch_algorithm = proj_options});
192+
193+
auto stitch_result1 = stitching_task1.future.get();
194+
progress = stitching_task1.progress->Report();
195+
196+
REQUIRE(progress.tasks_done != progress.num_tasks);
197+
REQUIRE_FALSE(stitch_result1.pano.has_value());
198+
REQUIRE(stitch_result1.status ==
199+
xpano::algorithm::stitcher::Status::kErrPanoTooLarge);
200+
}
201+
146202
TEST_CASE("Stitcher pipeline single pano matching") {
147203
xpano::pipeline::StitcherPipeline<kReturnFuture> stitcher;
148204
auto loading_task = stitcher.RunLoading(

xpano/algorithm/algorithm.cc

+3
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ int StitchTasksCount(int num_images) {
301301
1 + // match features
302302
1 + // estimate homography
303303
1 + // bundle adjustment
304+
1 + // compute pano size
304305
1 + // prepare seams
305306
1 + // find seams
306307
num_images + // compose
@@ -320,6 +321,8 @@ std::string ToString(stitcher::Status& status) {
320321
return "ERR_HOMOGRAPHY_EST_FAIL";
321322
case stitcher::Status::kErrCameraParamsAdjustFail:
322323
return "ERR_CAMERA_PARAMS_ADJUST_FAIL";
324+
case stitcher::Status::kErrPanoTooLarge:
325+
return "ERR_PANO_TOO_LARGE\nReset the project through the edit menu.";
323326
default:
324327
return "ERR_UNKNOWN";
325328
}

xpano/algorithm/progress.h

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ enum class ProgressType {
2020
kStitchMatchFeatures,
2121
kStitchEstimateHomography,
2222
kStitchBundleAdjustment,
23+
kStitchComputeRoi,
2324
kStitchSeamsPrepare,
2425
kStitchSeamsFind,
2526
kStitchCompose,

xpano/algorithm/stitcher.cc

+31-19
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757

5858
#include <spdlog/spdlog.h>
5959

60+
#include "xpano/constants.h"
6061
#include "xpano/utils/opencv.h"
6162

6263
namespace xpano::algorithm::stitcher {
@@ -255,22 +256,6 @@ Status Stitcher::EstimateSeams(std::vector<cv::UMat> *seams) {
255256

256257
// NOLINTNEXTLINE(readability-function-cognitive-complexity):
257258
Status Stitcher::ComposePanorama(cv::OutputArray pano) {
258-
spdlog::info("Estimating seams... ");
259-
NextTask(ProgressType::kStitchSeamsPrepare);
260-
261-
std::vector<cv::UMat> masks_warped;
262-
if (auto status = EstimateSeams(&masks_warped); status != Status::kSuccess) {
263-
return status;
264-
}
265-
266-
seam_est_imgs_.clear();
267-
268-
if (Cancelled()) {
269-
return Status::kCancelled;
270-
}
271-
spdlog::info("Compositing...");
272-
auto compositing_total_timer = Timer();
273-
274259
cv::UMat img_warped;
275260
cv::UMat dilated_mask;
276261
cv::UMat seam_mask;
@@ -285,6 +270,8 @@ Status Stitcher::ComposePanorama(cv::OutputArray pano) {
285270

286271
cv::Ptr<cv::detail::RotationWarper> warper;
287272
{
273+
spdlog::info("Calculating pano size... ");
274+
NextTask(ProgressType::kStitchComputeRoi);
288275
auto compute_roi_timer = Timer();
289276

290277
// Update warped image scale
@@ -300,12 +287,37 @@ Status Stitcher::ComposePanorama(cv::OutputArray pano) {
300287
corners[i] = roi.tl();
301288
sizes[i] = roi.size();
302289
}
303-
compute_roi_timer.Report(" compute roi time");
290+
compute_roi_timer.Report(" compute pano size time");
304291
}
305-
306292
auto dst_roi = cv::detail::resultRoi(corners, sizes);
307-
blender_->prepare(dst_roi);
308293

294+
if (dst_roi.width >= kMaxPanoSize || dst_roi.height >= kMaxPanoSize) {
295+
spdlog::error("Panorama is too large to compute: {}x{}, max size is {}",
296+
dst_roi.width, dst_roi.height, kMaxPanoSize);
297+
return Status::kErrPanoTooLarge;
298+
}
299+
300+
std::vector<cv::UMat> masks_warped;
301+
{
302+
spdlog::info("Estimating seams... ");
303+
NextTask(ProgressType::kStitchSeamsPrepare);
304+
305+
if (auto status = EstimateSeams(&masks_warped);
306+
status != Status::kSuccess) {
307+
return status;
308+
}
309+
310+
seam_est_imgs_.clear();
311+
312+
if (Cancelled()) {
313+
return Status::kCancelled;
314+
}
315+
}
316+
317+
spdlog::info("Compositing...");
318+
auto compositing_total_timer = Timer();
319+
320+
blender_->prepare(dst_roi);
309321
for (size_t img_idx = 0; img_idx < imgs_.size(); ++img_idx) {
310322
NextTask(ProgressType::kStitchCompose);
311323
if (auto non_zero = cv::countNonZero(masks_warped[img_idx]);

xpano/algorithm/stitcher.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ enum class Status {
6464
kCancelled,
6565
kErrNeedMoreImgs,
6666
kErrHomographyEstFail,
67-
kErrCameraParamsAdjustFail
67+
kErrCameraParamsAdjustFail,
68+
kErrPanoTooLarge
6869
};
6970

7071
struct WarpHelper {

xpano/constants.h

+2
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,6 @@ constexpr int kCancelAnimationFrameDuration = 128;
103103
const std::string kGithubIssuesLink = "https://github.com/krupkat/xpano/issues";
104104
const std::string kAuthorEmail = "[email protected]";
105105

106+
const int kMaxPanoSize = 16384;
107+
106108
} // namespace xpano

xpano/gui/panels/sidebar.cc

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ std::string ProgressLabel(pipeline::ProgressType type) {
5757
return "Estimating homography";
5858
case pipeline::ProgressType::kStitchBundleAdjustment:
5959
return "Bundle adjustment";
60+
case pipeline::ProgressType::kStitchComputeRoi:
61+
return "Computing pano size";
6062
case pipeline::ProgressType::kStitchSeamsPrepare:
6163
return "Preparing seams";
6264
case pipeline::ProgressType::kStitchSeamsFind:

0 commit comments

Comments
 (0)