Skip to content

Commit 14b0b8f

Browse files
Merge pull request #2004 from alicevision/dev/randomApply
Node to set random pixel values on masked coordinates
2 parents 00adc51 + e5b9f23 commit 14b0b8f

File tree

3 files changed

+223
-0
lines changed

3 files changed

+223
-0
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
__version__ = "1.0"
2+
3+
from meshroom.core import desc
4+
from meshroom.core.utils import DESCRIBER_TYPES, VERBOSE_LEVEL
5+
6+
import os.path
7+
8+
9+
class MaskRandomApplying(desc.AVCommandLineNode):
10+
commandLine = "aliceVision_maskRandomApplying {allParams}"
11+
12+
size = desc.DynamicNodeSize("input")
13+
category = "Utils"
14+
documentation = """ Apply random values to images on the pixel whose mask value is 0 """
15+
16+
inputs = [
17+
desc.File(
18+
name="input",
19+
label="SfmData",
20+
description="Input SfmData with the list of views to process",
21+
value="",
22+
),
23+
desc.File(
24+
name="masks",
25+
label="Input Masks",
26+
description="Input Masks assumed to have same names than input images",
27+
value="",
28+
),
29+
desc.ChoiceParam(
30+
name="verboseLevel",
31+
label="Verbose Level",
32+
description="Verbosity level (fatal, error, warning, info, debug, trace).",
33+
values=VERBOSE_LEVEL,
34+
value="info",
35+
)
36+
]
37+
38+
outputs = [
39+
desc.File(
40+
name="outputSfmData",
41+
label="Output",
42+
description="Path to the output sfmData.",
43+
value="{nodeCacheFolder}/sfmData.abc",
44+
),
45+
desc.File(
46+
name="outputDirectory",
47+
label="Output Images Directory",
48+
description="Path to the directory with modified images.",
49+
value="{nodeCacheFolder}",
50+
)
51+
]

src/software/utils/CMakeLists.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ if (ALICEVISION_BUILD_SFM)
7171
${Boost_LIBRARIES}
7272
)
7373

74+
alicevision_add_software(aliceVision_maskRandomApplying
75+
SOURCE main_maskRandomApplying.cpp
76+
FOLDER ${FOLDER_SOFTWARE_UTILS}
77+
LINKS aliceVision_system
78+
aliceVision_cmdline
79+
aliceVision_image
80+
aliceVision_sfm
81+
aliceVision_sfmData
82+
aliceVision_sfmDataIO
83+
${Boost_LIBRARIES}
84+
)
85+
7486
# Track builder
7587
alicevision_add_software(aliceVision_tracksSimulating
7688
SOURCE main_tracksSimulating.cpp
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// This file is part of the AliceVision project.
2+
// Copyright (c) 2025 AliceVision contributors.
3+
// This Source Code Form is subject to the terms of the Mozilla Public License,
4+
// v. 2.0. If a copy of the MPL was not distributed with this file,
5+
// You can obtain one at https://mozilla.org/MPL/2.0/.
6+
7+
#include <aliceVision/cmdline/cmdline.hpp>
8+
#include <aliceVision/system/main.hpp>
9+
#include <aliceVision/image/io.hpp>
10+
#include <aliceVision/utils/filesIO.hpp>
11+
#include <aliceVision/sfmDataIO/sfmDataIO.hpp>
12+
13+
#include <boost/program_options.hpp>
14+
15+
#include <string>
16+
#include <sstream>
17+
#include <random>
18+
#include <filesystem>
19+
20+
// These constants define the current software version.
21+
// They must be updated when the command line is changed.
22+
#define ALICEVISION_SOFTWARE_VERSION_MAJOR 1
23+
#define ALICEVISION_SOFTWARE_VERSION_MINOR 0
24+
25+
using namespace aliceVision;
26+
27+
namespace po = boost::program_options;
28+
29+
30+
int aliceVision_main(int argc, char** argv)
31+
{
32+
// command-line parameters
33+
std::string inputSfmDataFilename;
34+
std::string outputSfmDataFilename;
35+
std::string outputDirectory;
36+
std::string masks;
37+
38+
// clang-format off
39+
po::options_description requiredParams("Required parameters");
40+
requiredParams.add_options()
41+
("input,i", po::value<std::string>(&inputSfmDataFilename)->required(),
42+
"Input SfmData.")
43+
("outputSfmData", po::value<std::string>(&outputSfmDataFilename)->required(),
44+
"Output SfmData.")
45+
("masks", po::value<std::string>(&masks)->required(),
46+
"Input Masks.")
47+
("outputDirectory", po::value<std::string>(&outputDirectory)->required(),
48+
"Output directory with modified images.");
49+
// clang-format on
50+
51+
CmdLine cmdline("AliceVision maskRandomApplying");
52+
cmdline.add(requiredParams);
53+
if (!cmdline.execute(argc, argv))
54+
{
55+
return EXIT_FAILURE;
56+
}
57+
58+
// set maxThreads
59+
HardwareContext hwc = cmdline.getHardwareContext();
60+
omp_set_num_threads(hwc.getMaxThreads());
61+
62+
if (!utils::exists(outputDirectory))
63+
{
64+
ALICEVISION_LOG_ERROR("Output Directory does not exists.");
65+
return EXIT_FAILURE;
66+
}
67+
68+
if (!utils::exists(masks))
69+
{
70+
ALICEVISION_LOG_ERROR("Masks Directory does not exists.");
71+
return EXIT_FAILURE;
72+
}
73+
74+
// Load input scene
75+
sfmData::SfMData sfmData;
76+
if (!sfmDataIO::load(sfmData, inputSfmDataFilename, sfmDataIO::ESfMData::ALL))
77+
{
78+
ALICEVISION_LOG_ERROR("The input SfMData file '" << inputSfmDataFilename << "' cannot be read");
79+
return EXIT_FAILURE;
80+
}
81+
82+
// List input images
83+
std::vector<IndexT> viewIds;
84+
std::vector<std::filesystem::path> imagePaths;
85+
for (const auto [idview, view]: sfmData.getViews().valueRange())
86+
{
87+
std::filesystem::path p(view.getImage().getImagePath());
88+
imagePaths.push_back(p);
89+
viewIds.push_back(idview);
90+
}
91+
92+
std::mt19937 gen;
93+
std::uniform_real_distribution<float> dis(0.0f, 1.0f);
94+
95+
#pragma omp parallel for schedule(dynamic)
96+
for (int chunkId = 0; chunkId < imagePaths.size(); chunkId++)
97+
{
98+
IndexT viewId = viewIds[chunkId];
99+
std::filesystem::path path = imagePaths[chunkId];
100+
101+
102+
std::string maskFileName = masks + "/" + path.filename().string();
103+
if (!utils::exists(maskFileName))
104+
{
105+
ALICEVISION_LOG_INFO(maskFileName << " not found.");
106+
continue;
107+
}
108+
109+
std::string outFileName = outputDirectory + "/" + path.filename().string();
110+
111+
112+
ALICEVISION_LOG_INFO("Processing " << path.string());
113+
114+
image::Image<image::RGBfColor> img;
115+
aliceVision::image::readImage(path.string(), img, image::EImageColorSpace::NO_CONVERSION);
116+
117+
image::Image<unsigned char> mask;
118+
aliceVision::image::readImage(maskFileName, mask, image::EImageColorSpace::NO_CONVERSION);
119+
120+
if (img.height() != mask.height())
121+
{
122+
ALICEVISION_LOG_INFO("Incompatible sizes.");
123+
continue;
124+
}
125+
126+
if (img.width() != mask.width())
127+
{
128+
ALICEVISION_LOG_INFO("Incompatible sizes.");
129+
continue;
130+
}
131+
132+
for (int i = 0; i < mask.height(); i++)
133+
{
134+
for (int j = 0; j < mask.width(); j++)
135+
{
136+
if (!mask(i, j))
137+
{
138+
auto & p = img(i, j);
139+
p.r() = dis(gen);
140+
p.g() = dis(gen);
141+
p.b() = dis(gen);
142+
}
143+
}
144+
}
145+
146+
aliceVision::image::ImageWriteOptions wopt;
147+
aliceVision::image::writeImage(outFileName, img, wopt);
148+
149+
sfmData.getView(viewId).getImage().setImagePath(outFileName);
150+
}
151+
152+
if (!sfmDataIO::save(sfmData, outputSfmDataFilename, sfmDataIO::ESfMData::ALL))
153+
{
154+
ALICEVISION_LOG_ERROR("An error occurred while trying to save '" << outputSfmDataFilename << "'");
155+
return EXIT_FAILURE;
156+
}
157+
158+
return EXIT_SUCCESS;
159+
}
160+

0 commit comments

Comments
 (0)