From ed0ce68eebf9f36150d314bf9bc00c9497981d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Wed, 26 Jul 2023 09:46:50 +0200 Subject: [PATCH 1/8] [software] panoramaPostProcessing: export downscaled panorama levels --- .../pipeline/main_panoramaPostProcessing.cpp | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index dec90c4390..aae5b4b71c 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -200,7 +200,7 @@ int aliceVision_main(int argc, char** argv) int compressionLevel = 0; image::EImageColorSpace outputColorSpace = image::EImageColorSpace::LINEAR; size_t previewSize = 1000; - bool fillHoles = false; + bool fillHoles = false; // Description of mandatory parameters po::options_description requiredParams("Required parameters"); @@ -241,9 +241,6 @@ int aliceVision_main(int argc, char** argv) return EXIT_FAILURE; } - - fs::path previewPath = fs::path(outputPanoramaPath).parent_path() / "preview.jpg"; - //Get information about input panorama const oiio::ImageSpec &inputSpec = panoramaInput->spec(); const int tileWidth = inputSpec.tile_width; @@ -340,6 +337,30 @@ int aliceVision_main(int argc, char** argv) image::Image previewImage(previewSize, previewSize / 2); int previewCurrentRow = 0; + // Create image outputs for downscaled panorama levels + const int nbLevels = static_cast(std::floor(std::log2(tileSize))); + std::vector> levelOutputs; + + ALICEVISION_LOG_INFO("Number of downscaled panorama levels to generate: " << nbLevels); + + for (int levelIdx = 1; levelIdx <= nbLevels; ++levelIdx) + { + fs::path levelPath = fs::path(outputPanoramaPath).parent_path() / ("level_" + std::to_string(levelIdx) + ".exr"); + levelOutputs.push_back(std::move(oiio::ImageOutput::create(levelPath.string()))); + + oiio::ImageSpec levelSpec(outputSpec); + levelSpec.width /= (1 << levelIdx); + levelSpec.height /= (1 << levelIdx); + levelSpec.full_width /= (1 << levelIdx); + levelSpec.full_height /= (1 << levelIdx); + + if (!levelOutputs[levelIdx-1]->open(levelPath.string(), levelSpec)) + { + ALICEVISION_LOG_ERROR("Impossible to write downscaled panorama at level " << levelIdx); + return EXIT_FAILURE; + } + } + if (fillHoles) { ALICEVISION_LOG_INFO("Reduce image (" << width << "x" << height << ")"); @@ -566,9 +587,21 @@ int aliceVision_main(int argc, char** argv) previewCurrentRow++; } + // Write panorama output colorSpaceTransform(final, fromColorSpace, outputColorSpace, dcpProf, neutral); - panoramaOutput->write_scanlines(ty * tileSize, (ty + 1) * tileSize, 0, oiio::TypeDesc::FLOAT, final.data()); + + // Write downscaled panorama levels + for (int levelIdx = 1; levelIdx <= nbLevels; ++levelIdx) + { + image::Image & levelTile = pyramid[levelIdx]; + const int levelTileSize = tileSize / (1 << levelIdx); + const int levelWidth = width / (1 << levelIdx); + image::Image level(levelWidth, levelTileSize); + level.block(0, 0, levelTileSize, levelWidth) = levelTile.block(levelTileSize, levelTileSize, levelTileSize, levelWidth); + colorSpaceTransform(level, fromColorSpace, outputColorSpace, dcpProf, neutral); + levelOutputs[levelIdx-1]->write_scanlines(ty * levelTileSize, (ty + 1) * levelTileSize, 0, oiio::TypeDesc::FLOAT, level.data()); + } } } else @@ -628,6 +661,10 @@ int aliceVision_main(int argc, char** argv) panoramaInput->close(); panoramaOutput->close(); + for (int levelIdx = 1; levelIdx <= nbLevels; ++levelIdx) + { + levelOutputs[levelIdx-1]->close(); + } if (outputPanoramaPreviewPath != "") { From e0fc9d580ed0ded43656624a89bea0c6cb21f504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Wed, 26 Jul 2023 11:33:10 +0200 Subject: [PATCH 2/8] [software] panoramaPostProcessing: also export downscale levels when not filling holes --- .../pipeline/main_panoramaPostProcessing.cpp | 73 ++++++++++++++----- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index aae5b4b71c..9ef1d67127 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -443,7 +443,7 @@ int aliceVision_main(int argc, char** argv) int yend = (ty + 1) * tileSize - 1; //Build subimage - image::Image region(tileSize * rowSize, tileSize * 3); + image::Image region(tileSize * rowSize, tileSize * 3); image::Image subFiled(rowSize, 3, true, image::RGBAfColor(0.0f, 0.0f, 0.0f, 0.0f)); image::Image final(width, tileSize, true, image::RGBAfColor(0.0f, 0.0f, 0.0f, 0.0f)); @@ -565,7 +565,6 @@ int aliceVision_main(int argc, char** argv) } const image::Image & finalTile = pyramid[0]; - final.block(0, 0, tileSize, width) = finalTile.block(tileSize, tileSize, tileSize, width); //Fill preview image @@ -606,34 +605,58 @@ int aliceVision_main(int argc, char** argv) } else { - //Process one full row of tiles each iteration + //Process one full row of tiles each iteration for (int ty = 0; ty < countHeight; ty++) { int ybegin = ty * tileSize; int yend = (ty + 1) * tileSize - 1; + // Build subimage + image::Image region(tileSize * rowSize, tileSize * 3); image::Image final(width, tileSize, true, image::RGBAfColor(0.0f, 0.0f, 0.0f, 0.0f)); - - #pragma omp parallel for - for (int tx = 0; tx < countWidth; tx++) + + //Build a region + for (int ry = 0; ry < 3; ry++) { - image::Image tile(tileSize, tileSize); - if (!panoramaInput->read_tile(tx * tileSize, ybegin, 0, oiio::TypeDesc::FLOAT, tile.data())) + int dy = ry - 1; + int cy = ty + dy; + + #pragma omp parallel for + for (int rx = 0; rx < rowSize; rx++) { - ALICEVISION_LOG_ERROR("Error reading from image"); - } + int dx = rx - 1; + int cx = dx; - int available = width - tx*tileSize; - if (available < tileSize) - { - final.block(0, tx * tileSize, tileSize, available) = tile.block(0, 0, tileSize, available); - } - else - { - final.block(0, tx * tileSize, tileSize, tileSize) = tile; + image::Image tile(tileSize, tileSize); + if (!readFullTile(tile, panoramaInput, cx, cy)) + { + ALICEVISION_LOG_ERROR("Invalid tile"); + continue; + } + + region.block(ry * tileSize, rx * tileSize, tileSize, tileSize) = tile; } } + //First level is original image + std::vector> pyramid; + pyramid.push_back(region); + + //Build pyramid for tile + int cs = tileSize * rowSize; + while (cs != rowSize) + { + int ns = cs / 2; + image::Image smaller; + downscaleTriangle(smaller, region); + pyramid.push_back(smaller); + region = smaller; + cs = ns; + } + + const image::Image & finalTile = pyramid[0]; + final.block(0, 0, tileSize, width) = finalTile.block(tileSize, tileSize, tileSize, width); + //Fill preview image while (previewCurrentRow < previewImage.rows()) { @@ -653,9 +676,21 @@ int aliceVision_main(int argc, char** argv) previewCurrentRow++; } + // Write panorama output colorSpaceTransform(final, fromColorSpace, outputColorSpace, dcpProf, neutral); + panoramaOutput->write_scanlines(ty * tileSize, (ty + 1) * tileSize, 0, oiio::TypeDesc::FLOAT, final.data()); - panoramaOutput->write_scanlines(ybegin, yend, 0, oiio::TypeDesc::FLOAT, final.data()); + // Write downscaled panorama levels + for (int levelIdx = 1; levelIdx <= nbLevels; ++levelIdx) + { + image::Image & levelTile = pyramid[levelIdx]; + const int levelTileSize = tileSize / (1 << levelIdx); + const int levelWidth = width / (1 << levelIdx); + image::Image level(levelWidth, levelTileSize); + level.block(0, 0, levelTileSize, levelWidth) = levelTile.block(levelTileSize, levelTileSize, levelTileSize, levelWidth); + colorSpaceTransform(level, fromColorSpace, outputColorSpace, dcpProf, neutral); + levelOutputs[levelIdx-1]->write_scanlines(ty * levelTileSize, (ty + 1) * levelTileSize, 0, oiio::TypeDesc::FLOAT, level.data()); + } } } From 62e5e965cf773282d641ff38e714846cc814b93b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Wed, 26 Jul 2023 11:54:27 +0200 Subject: [PATCH 3/8] [software] panoramaPostProcessing: add --exportLevels option --- src/software/pipeline/main_panoramaPostProcessing.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index 9ef1d67127..2f189d254a 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -201,6 +201,7 @@ int aliceVision_main(int argc, char** argv) image::EImageColorSpace outputColorSpace = image::EImageColorSpace::LINEAR; size_t previewSize = 1000; bool fillHoles = false; + bool exportLevels = false; // Description of mandatory parameters po::options_description requiredParams("Required parameters"); @@ -221,6 +222,7 @@ int aliceVision_main(int argc, char** argv) "Only dwaa, dwab, zip and zips compression methods are concerned.") ("fillHoles", po::value(&fillHoles)->default_value(fillHoles), "Execute fill holes algorithm") + ("exportLevels", po::value(&exportLevels)->default_value(exportLevels), "Export downscaled panorama levels") ("previewSize", po::value(&previewSize)->default_value(previewSize), "Preview image width") ("outputColorSpace", po::value(&outputColorSpace)->default_value(outputColorSpace), "Color space for the output panorama.") ("outputPanoramaPreview,p", po::value(&outputPanoramaPreviewPath)->default_value(outputPanoramaPreviewPath), "Path of the output panorama preview."); @@ -338,7 +340,7 @@ int aliceVision_main(int argc, char** argv) int previewCurrentRow = 0; // Create image outputs for downscaled panorama levels - const int nbLevels = static_cast(std::floor(std::log2(tileSize))); + const int nbLevels = exportLevels ? static_cast(std::floor(std::log2(tileSize))) : 0; std::vector> levelOutputs; ALICEVISION_LOG_INFO("Number of downscaled panorama levels to generate: " << nbLevels); From bd5fe81bd22b1935033e7c152669019d17323d9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Thu, 27 Jul 2023 15:29:22 +0200 Subject: [PATCH 4/8] [software] panoramaPostProcessing: wrap around rows when reading tiles --- .../pipeline/main_panoramaPostProcessing.cpp | 106 +++++++++++++----- 1 file changed, 80 insertions(+), 26 deletions(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index 2f189d254a..23c44cea20 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -90,55 +90,109 @@ bool downscaleTriangle(image::Image & smaller, const image::I bool readFullTile(image::Image & output, std::unique_ptr & input, int tx, int ty) { const oiio::ImageSpec &inputSpec = input->spec(); - int tileSize = inputSpec.tile_width; - int width = inputSpec.width; - int height = inputSpec.height; + const int tileSize = inputSpec.tile_width; + const int width = inputSpec.width; + const int height = inputSpec.height; + + const int countWidth = std::ceil(double(width) / double(tileSize)); + const int countHeight = std::ceil(double(height) / double(tileSize)); - int countWidth = std::ceil(double(width) / double(tileSize)); - int countHeight = std::ceil(double(height) / double(tileSize)); + // Default filling + output.fill(image::RGBAfColor(0.0f, 0.0f, 0.0f, 0.0f)); - if (tx < 0 || tx >= countWidth || ty < 0 || ty >= countHeight) + // Make sure tile y-coordinate is in the right range + if (ty < 0 || ty >= countHeight) { - output.fill(image::RGBAfColor(0.0f, 0.0f, 0.0f, 0.0f)); return true; } - if (tx < 0) + if (tx == -1) { - tx = countWidth + tx; - } + // Wrap tile x-coordinate + const int offset = width - 1 - tileSize; + const int txLeft = offset / tileSize; - if (tx >= countWidth) - { - tx = tx - countWidth; - } + // Size of the left and right part of the tile + const int leftside = (txLeft + 1) * tileSize - offset; + const int rightside = tileSize - leftside; - /*int available = width - (tx * tileSize); + // Load left part tile + image::Image buf(tileSize, tileSize); + if (!input->read_tile(txLeft * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) + { + return false; + } + output.block(0, 0, tileSize, leftside) = buf.block(0, rightside, tileSize, leftside); - if (available < tileSize) + // Load right part tile to complete filling output + if (rightside > 0) + { + if (!input->read_tile((txLeft + 1) * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) + { + return false; + } + output.block(0, leftside, tileSize, rightside) = buf.block(0, 0, tileSize, rightside); + } + } + else if (tx == countWidth - 1) { + // Size of the left and right part of the tile + const int leftside = width - tx * tileSize; + const int rightside = tileSize - leftside; + + // Load last tile (the last column of this tile may be incomplete) image::Image buf(tileSize, tileSize); if (!input->read_tile(tx * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) { return false; } + output.block(0, 0, tileSize, leftside) = buf.block(0, 0, tileSize, leftside); - output.block(0, tileSize - available, tileSize, available) = buf.block(0, 0, tileSize, available); - - if (!input->read_tile((tx - 1) * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) + // Load first tile to complete filling output + if (rightside > 0) { - return false; + if (!input->read_tile(0, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) + { + return false; + } + output.block(0, leftside, tileSize, rightside) = buf.block(0, 0, tileSize, rightside); } + } + else if (tx == countWidth) + { + // Wrap tile x-coordinate + const int offset = countWidth * tileSize - width; + const int txLeft = offset / tileSize; - output.block(0, 0, tileSize, tileSize - available) = buf.block(0, available, tileSize, tileSize - available); + // Size of the left and right part of the tile + const int leftside = (txLeft + 1) * tileSize - offset; + const int rightside = tileSize - leftside; - return true; - }*/ + // Load left part tile + image::Image buf(tileSize, tileSize); + if (!input->read_tile(txLeft * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) + { + return false; + } + output.block(0, 0, tileSize, leftside) = buf.block(0, rightside, tileSize, leftside); - output.fill(image::RGBAfColor(0.0f, 0.0f, 0.0f, 0.0f)); - if (!input->read_tile(tx * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, output.data())) + // Load right part tile to complete filling output + if (rightside > 0) + { + if (!input->read_tile((txLeft + 1) * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) + { + return false; + } + output.block(0, leftside, tileSize, rightside) = buf.block(0, 0, tileSize, rightside); + } + } + else if (tx >= 0 && tx < countWidth - 1) { - return false; + // Load tile data directly into output + if (!input->read_tile(tx * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, output.data())) + { + return false; + } } return true; From 4668e03e75dd5a9e03d4ed72757856d214aa28ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Thu, 27 Jul 2023 16:25:46 +0200 Subject: [PATCH 5/8] [software] panoramaPostProcessing: refactorize readFullTile --- .../pipeline/main_panoramaPostProcessing.cpp | 61 +++++++++---------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index 23c44cea20..8986ff3f43 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -97,6 +97,22 @@ bool readFullTile(image::Image & output, std::unique_ptr & buf, + int txLeft, + int xOutput, int xBuf, int sliceWidth) -> bool + { + if (!input->read_tile(txLeft * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) + { + return false; + } + + output.block(0, xOutput, tileSize, sliceWidth) = buf.block(0, xBuf, tileSize, sliceWidth); + + return true; + }; + // Default filling output.fill(image::RGBAfColor(0.0f, 0.0f, 0.0f, 0.0f)); @@ -116,22 +132,15 @@ bool readFullTile(image::Image & output, std::unique_ptr buf(tileSize, tileSize); - if (!input->read_tile(txLeft * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) - { - return false; - } - output.block(0, 0, tileSize, leftside) = buf.block(0, rightside, tileSize, leftside); + + // Load left part tile + if (!readTilePartial(buf, txLeft, 0, rightside, leftside)) return false; // Load right part tile to complete filling output if (rightside > 0) { - if (!input->read_tile((txLeft + 1) * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) - { - return false; - } - output.block(0, leftside, tileSize, rightside) = buf.block(0, 0, tileSize, rightside); + if (!readTilePartial(buf, txLeft + 1, leftside, 0, rightside)) return false; } } else if (tx == countWidth - 1) @@ -140,22 +149,15 @@ bool readFullTile(image::Image & output, std::unique_ptr buf(tileSize, tileSize); - if (!input->read_tile(tx * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) - { - return false; - } - output.block(0, 0, tileSize, leftside) = buf.block(0, 0, tileSize, leftside); + + // Load last tile (which may be incomplete) + if (!readTilePartial(buf, tx, 0, 0, leftside)) return false; // Load first tile to complete filling output if (rightside > 0) { - if (!input->read_tile(0, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) - { - return false; - } - output.block(0, leftside, tileSize, rightside) = buf.block(0, 0, tileSize, rightside); + if (!readTilePartial(buf, 0, leftside, 0, rightside)) return false; } } else if (tx == countWidth) @@ -168,22 +170,15 @@ bool readFullTile(image::Image & output, std::unique_ptr buf(tileSize, tileSize); - if (!input->read_tile(txLeft * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) - { - return false; - } - output.block(0, 0, tileSize, leftside) = buf.block(0, rightside, tileSize, leftside); + + // Load left part tile + if (!readTilePartial(buf, txLeft, 0, rightside, leftside)) return false; // Load right part tile to complete filling output if (rightside > 0) { - if (!input->read_tile((txLeft + 1) * tileSize, ty * tileSize, 0, oiio::TypeDesc::FLOAT, buf.data())) - { - return false; - } - output.block(0, leftside, tileSize, rightside) = buf.block(0, 0, tileSize, rightside); + if (!readTilePartial(buf, txLeft + 1, leftside, 0, rightside)) return false; } } else if (tx >= 0 && tx < countWidth - 1) From fba25670df381b72cf645df68c6b44e1ac9bab74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Mon, 31 Jul 2023 09:39:45 +0200 Subject: [PATCH 6/8] [software] panoramaPostProcessing: update version --- src/software/pipeline/main_panoramaPostProcessing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index 8986ff3f43..bf3baebeb7 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -34,7 +34,7 @@ // These constants define the current software version. // They must be updated when the command line is changed. -#define ALICEVISION_SOFTWARE_VERSION_MAJOR 1 +#define ALICEVISION_SOFTWARE_VERSION_MAJOR 2 #define ALICEVISION_SOFTWARE_VERSION_MINOR 0 using namespace aliceVision; From 8b73584c4c9b4d9931c521a4e4962c149c6e9555 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Mon, 31 Jul 2023 12:13:52 +0200 Subject: [PATCH 7/8] [software] panoramaPostProcessing: add parameter for last level maximum width --- src/software/pipeline/main_panoramaPostProcessing.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index bf3baebeb7..7beaea8c21 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -251,6 +251,7 @@ int aliceVision_main(int argc, char** argv) size_t previewSize = 1000; bool fillHoles = false; bool exportLevels = false; + int lastLevelMaxSize = 3840; // Description of mandatory parameters po::options_description requiredParams("Required parameters"); @@ -272,6 +273,7 @@ int aliceVision_main(int argc, char** argv) ("fillHoles", po::value(&fillHoles)->default_value(fillHoles), "Execute fill holes algorithm") ("exportLevels", po::value(&exportLevels)->default_value(exportLevels), "Export downscaled panorama levels") + ("lastLevelMaxSize", po::value(&lastLevelMaxSize)->default_value(lastLevelMaxSize), "Maximum width of smallest downscaled panorama level.") ("previewSize", po::value(&previewSize)->default_value(previewSize), "Preview image width") ("outputColorSpace", po::value(&outputColorSpace)->default_value(outputColorSpace), "Color space for the output panorama.") ("outputPanoramaPreview,p", po::value(&outputPanoramaPreviewPath)->default_value(outputPanoramaPreviewPath), "Path of the output panorama preview."); @@ -389,7 +391,11 @@ int aliceVision_main(int argc, char** argv) int previewCurrentRow = 0; // Create image outputs for downscaled panorama levels - const int nbLevels = exportLevels ? static_cast(std::floor(std::log2(tileSize))) : 0; + const int nbLevels = exportLevels ? + static_cast(std::min( + std::floor(std::log2(tileSize)), + std::ceil(std::log2(width) - std::log2(lastLevelMaxSize)))) + : 0; std::vector> levelOutputs; ALICEVISION_LOG_INFO("Number of downscaled panorama levels to generate: " << nbLevels); From fc622bcd9f141c52ade625ce2446f2cf3ec2b923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vital?= Date: Mon, 31 Jul 2023 12:24:08 +0200 Subject: [PATCH 8/8] [software] panoramaPostProcessing: use level width in export name --- src/software/pipeline/main_panoramaPostProcessing.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/software/pipeline/main_panoramaPostProcessing.cpp b/src/software/pipeline/main_panoramaPostProcessing.cpp index 7beaea8c21..5b99cc2095 100644 --- a/src/software/pipeline/main_panoramaPostProcessing.cpp +++ b/src/software/pipeline/main_panoramaPostProcessing.cpp @@ -402,7 +402,8 @@ int aliceVision_main(int argc, char** argv) for (int levelIdx = 1; levelIdx <= nbLevels; ++levelIdx) { - fs::path levelPath = fs::path(outputPanoramaPath).parent_path() / ("level_" + std::to_string(levelIdx) + ".exr"); + const int levelWidth = width / (1 << levelIdx); + fs::path levelPath = fs::path(outputPanoramaPath).parent_path() / ("level_" + std::to_string(levelWidth) + ".exr"); levelOutputs.push_back(std::move(oiio::ImageOutput::create(levelPath.string()))); oiio::ImageSpec levelSpec(outputSpec);