merge.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. * Copyright 2011-2019 Blender Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "render/merge.h"
  17. #include "util/util_array.h"
  18. #include "util/util_map.h"
  19. #include "util/util_system.h"
  20. #include "util/util_time.h"
  21. #include "util/util_unique_ptr.h"
  22. #include <OpenImageIO/imageio.h>
  23. #include <OpenImageIO/filesystem.h>
  24. OIIO_NAMESPACE_USING
  25. CCL_NAMESPACE_BEGIN
  26. /* Merge Image Layer */
  27. enum MergeChannelOp {
  28. MERGE_CHANNEL_NOP,
  29. MERGE_CHANNEL_COPY,
  30. MERGE_CHANNEL_SUM,
  31. MERGE_CHANNEL_AVERAGE
  32. };
  33. struct MergeImagePass {
  34. /* Full channel name. */
  35. string channel_name;
  36. /* Channel format in the file. */
  37. TypeDesc format;
  38. /* Type of operation to perform when merging. */
  39. MergeChannelOp op;
  40. /* Offset of layer channels in input image. */
  41. int offset;
  42. /* Offset of layer channels in merged image. */
  43. int merge_offset;
  44. };
  45. struct MergeImageLayer {
  46. /* Layer name. */
  47. string name;
  48. /* Passes. */
  49. vector<MergeImagePass> passes;
  50. /* Sample amount that was used for rendering this layer. */
  51. int samples;
  52. };
  53. /* Merge Image */
  54. struct MergeImage {
  55. /* OIIO file handle. */
  56. unique_ptr<ImageInput> in;
  57. /* Image file path. */
  58. string filepath;
  59. /* Render layers. */
  60. vector<MergeImageLayer> layers;
  61. };
  62. /* Channel Parsing */
  63. static MergeChannelOp parse_channel_operation(const string &pass_name)
  64. {
  65. if (pass_name == "Depth" || pass_name == "IndexMA" || pass_name == "IndexOB" ||
  66. string_startswith(pass_name, "Crypto")) {
  67. return MERGE_CHANNEL_COPY;
  68. }
  69. else if (string_startswith(pass_name, "Debug BVH") ||
  70. string_startswith(pass_name, "Debug Ray") ||
  71. string_startswith(pass_name, "Debug Render Time")) {
  72. return MERGE_CHANNEL_SUM;
  73. }
  74. else {
  75. return MERGE_CHANNEL_AVERAGE;
  76. }
  77. }
  78. /* Splits in at its last dot, setting suffix to the part after the dot and
  79. * into the part before it. Returns whether a dot was found. */
  80. static bool split_last_dot(string &in, string &suffix)
  81. {
  82. size_t pos = in.rfind(".");
  83. if (pos == string::npos) {
  84. return false;
  85. }
  86. suffix = in.substr(pos + 1);
  87. in = in.substr(0, pos);
  88. return true;
  89. }
  90. /* Separate channel names as generated by Blender.
  91. * Multiview format: RenderLayer.Pass.View.Channel
  92. * Otherwise: RenderLayer.Pass.Channel */
  93. static bool parse_channel_name(
  94. string name, string &renderlayer, string &pass, string &channel, bool multiview_channels)
  95. {
  96. if (!split_last_dot(name, channel)) {
  97. return false;
  98. }
  99. string view;
  100. if (multiview_channels && !split_last_dot(name, view)) {
  101. return false;
  102. }
  103. if (!split_last_dot(name, pass)) {
  104. return false;
  105. }
  106. renderlayer = name;
  107. if (multiview_channels) {
  108. renderlayer += "." + view;
  109. }
  110. return true;
  111. }
  112. static bool parse_channels(const ImageSpec &in_spec,
  113. vector<MergeImageLayer> &layers,
  114. string &error)
  115. {
  116. const ParamValue *multiview = in_spec.find_attribute("multiView");
  117. const bool multiview_channels = (multiview && multiview->type().basetype == TypeDesc::STRING &&
  118. multiview->type().arraylen >= 2);
  119. layers.clear();
  120. /* Loop over all the channels in the file, parse their name and sort them
  121. * by RenderLayer.
  122. * Channels that can't be parsed are directly passed through to the output. */
  123. map<string, MergeImageLayer> file_layers;
  124. for (int i = 0; i < in_spec.nchannels; i++) {
  125. MergeImagePass pass;
  126. pass.channel_name = in_spec.channelnames[i];
  127. pass.format = (in_spec.channelformats.size() > 0) ? in_spec.channelformats[i] : in_spec.format;
  128. pass.offset = i;
  129. pass.merge_offset = i;
  130. string layername, passname, channelname;
  131. if (parse_channel_name(
  132. pass.channel_name, layername, passname, channelname, multiview_channels)) {
  133. /* Channer part of a render layer. */
  134. pass.op = parse_channel_operation(passname);
  135. }
  136. else {
  137. /* Other channels are added in unnamed layer. */
  138. layername = "";
  139. pass.op = parse_channel_operation(pass.channel_name);
  140. }
  141. file_layers[layername].passes.push_back(pass);
  142. }
  143. /* Loop over all detected RenderLayers, check whether they contain a full set of input channels.
  144. * Any channels that won't be processed internally are also passed through. */
  145. for (auto &i : file_layers) {
  146. const string &name = i.first;
  147. MergeImageLayer &layer = i.second;
  148. layer.name = name;
  149. layer.samples = 0;
  150. /* Determine number of samples from metadata. */
  151. if (layer.name == "") {
  152. layer.samples = 1;
  153. }
  154. else if (layer.samples < 1) {
  155. string sample_string = in_spec.get_string_attribute("cycles." + name + ".samples", "");
  156. if (sample_string != "") {
  157. if (!sscanf(sample_string.c_str(), "%d", &layer.samples)) {
  158. error = "Failed to parse samples metadata: " + sample_string;
  159. return false;
  160. }
  161. }
  162. }
  163. if (layer.samples < 1) {
  164. error = string_printf(
  165. "No sample number specified in the file for layer %s or on the command line",
  166. name.c_str());
  167. return false;
  168. }
  169. layers.push_back(layer);
  170. }
  171. return true;
  172. }
  173. static bool open_images(const vector<string> &filepaths, vector<MergeImage> &images, string &error)
  174. {
  175. for (const string &filepath : filepaths) {
  176. unique_ptr<ImageInput> in(ImageInput::open(filepath));
  177. if (!in) {
  178. error = "Couldn't open file: " + filepath;
  179. return false;
  180. }
  181. MergeImage image;
  182. image.in = std::move(in);
  183. image.filepath = filepath;
  184. if (!parse_channels(image.in->spec(), image.layers, error)) {
  185. return false;
  186. }
  187. if (image.layers.size() == 0) {
  188. error = "Could not find a render layer for merging";
  189. return false;
  190. }
  191. if (image.in->spec().deep) {
  192. error = "Merging deep images not supported.";
  193. return false;
  194. }
  195. if (images.size() > 0) {
  196. const ImageSpec &base_spec = images[0].in->spec();
  197. const ImageSpec &spec = image.in->spec();
  198. if (base_spec.width != spec.width || base_spec.height != spec.height ||
  199. base_spec.depth != spec.depth || base_spec.format != spec.format ||
  200. base_spec.deep != spec.deep) {
  201. error = "Images do not have matching size and data layout.";
  202. return false;
  203. }
  204. }
  205. images.push_back(std::move(image));
  206. }
  207. return true;
  208. }
  209. static void merge_render_time(ImageSpec &spec,
  210. const vector<MergeImage> &images,
  211. const string &name,
  212. const bool average)
  213. {
  214. double time = 0.0;
  215. for (const MergeImage &image : images) {
  216. string time_str = image.in->spec().get_string_attribute(name, "");
  217. time += time_human_readable_to_seconds(time_str);
  218. }
  219. if (average) {
  220. time /= images.size();
  221. }
  222. spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
  223. }
  224. static void merge_layer_render_time(ImageSpec &spec,
  225. const vector<MergeImage> &images,
  226. const string &layer_name,
  227. const string &time_name,
  228. const bool average)
  229. {
  230. string name = "cycles." + layer_name + "." + time_name;
  231. double time = 0.0;
  232. for (const MergeImage &image : images) {
  233. string time_str = image.in->spec().get_string_attribute(name, "");
  234. time += time_human_readable_to_seconds(time_str);
  235. }
  236. if (average) {
  237. time /= images.size();
  238. }
  239. spec.attribute(name, TypeDesc::STRING, time_human_readable_from_seconds(time));
  240. }
  241. static void merge_channels_metadata(vector<MergeImage> &images,
  242. ImageSpec &out_spec,
  243. vector<int> &channel_total_samples)
  244. {
  245. /* Based on first image. */
  246. out_spec = images[0].in->spec();
  247. /* Merge channels and compute offsets. */
  248. out_spec.nchannels = 0;
  249. out_spec.channelformats.clear();
  250. out_spec.channelnames.clear();
  251. for (MergeImage &image : images) {
  252. for (MergeImageLayer &layer : image.layers) {
  253. for (MergeImagePass &pass : layer.passes) {
  254. /* Test if matching channel already exists in merged image. */
  255. bool found = false;
  256. for (size_t i = 0; i < out_spec.nchannels; i++) {
  257. if (pass.channel_name == out_spec.channelnames[i]) {
  258. pass.merge_offset = i;
  259. channel_total_samples[i] += layer.samples;
  260. /* First image wins for channels that can't be averaged or summed. */
  261. if (pass.op == MERGE_CHANNEL_COPY) {
  262. pass.op = MERGE_CHANNEL_NOP;
  263. }
  264. found = true;
  265. break;
  266. }
  267. }
  268. if (!found) {
  269. /* Add new channel. */
  270. pass.merge_offset = out_spec.nchannels;
  271. channel_total_samples.push_back(layer.samples);
  272. out_spec.channelnames.push_back(pass.channel_name);
  273. out_spec.channelformats.push_back(pass.format);
  274. out_spec.nchannels++;
  275. }
  276. }
  277. }
  278. }
  279. /* Merge metadata. */
  280. merge_render_time(out_spec, images, "RenderTime", false);
  281. map<string, int> layer_num_samples;
  282. for (MergeImage &image : images) {
  283. for (MergeImageLayer &layer : image.layers) {
  284. if (layer.name != "") {
  285. layer_num_samples[layer.name] += layer.samples;
  286. }
  287. }
  288. }
  289. for (const auto &i : layer_num_samples) {
  290. string name = "cycles." + i.first + ".samples";
  291. out_spec.attribute(name, TypeDesc::STRING, string_printf("%d", i.second));
  292. merge_layer_render_time(out_spec, images, i.first, "total_time", false);
  293. merge_layer_render_time(out_spec, images, i.first, "render_time", false);
  294. merge_layer_render_time(out_spec, images, i.first, "synchronization_time", true);
  295. }
  296. }
  297. static void alloc_pixels(const ImageSpec &spec, array<float> &pixels)
  298. {
  299. const size_t width = spec.width;
  300. const size_t height = spec.height;
  301. const size_t num_channels = spec.nchannels;
  302. const size_t num_pixels = (size_t)width * (size_t)height;
  303. pixels.resize(num_pixels * num_channels);
  304. }
  305. static bool merge_pixels(const vector<MergeImage> &images,
  306. const ImageSpec &out_spec,
  307. const vector<int> &channel_total_samples,
  308. array<float> &out_pixels,
  309. string &error)
  310. {
  311. alloc_pixels(out_spec, out_pixels);
  312. memset(out_pixels.data(), 0, out_pixels.size() * sizeof(float));
  313. for (const MergeImage &image : images) {
  314. /* Read all channels into buffer. Reading all channels at once is
  315. * faster than individually due to interleaved EXR channel storage. */
  316. array<float> pixels;
  317. alloc_pixels(image.in->spec(), pixels);
  318. if (!image.in->read_image(TypeDesc::FLOAT, pixels.data())) {
  319. error = "Failed to read image: " + image.filepath;
  320. return false;
  321. }
  322. for (size_t li = 0; li < image.layers.size(); li++) {
  323. const MergeImageLayer &layer = image.layers[li];
  324. const size_t stride = image.in->spec().nchannels;
  325. const size_t out_stride = out_spec.nchannels;
  326. const size_t num_pixels = pixels.size();
  327. for (const MergeImagePass &pass : layer.passes) {
  328. size_t offset = pass.offset;
  329. size_t out_offset = pass.merge_offset;
  330. switch (pass.op) {
  331. case MERGE_CHANNEL_NOP:
  332. break;
  333. case MERGE_CHANNEL_COPY:
  334. for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
  335. out_pixels[out_offset] = pixels[offset];
  336. }
  337. break;
  338. case MERGE_CHANNEL_SUM:
  339. for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
  340. out_pixels[out_offset] += pixels[offset];
  341. }
  342. break;
  343. case MERGE_CHANNEL_AVERAGE:
  344. /* Weights based on sample metadata. Per channel since not
  345. * all files are guaranteed to have the same channels. */
  346. const int total_samples = channel_total_samples[out_offset];
  347. const float t = (float)layer.samples / (float)total_samples;
  348. for (; offset < num_pixels; offset += stride, out_offset += out_stride) {
  349. out_pixels[out_offset] += t * pixels[offset];
  350. }
  351. break;
  352. }
  353. }
  354. }
  355. }
  356. return true;
  357. }
  358. static bool save_output(const string &filepath,
  359. const ImageSpec &spec,
  360. const array<float> &pixels,
  361. string &error)
  362. {
  363. /* Write to temporary file path, so we merge images in place and don't
  364. * risk destroying files when something goes wrong in file saving. */
  365. string extension = OIIO::Filesystem::extension(filepath);
  366. string unique_name = ".merge-tmp-" + OIIO::Filesystem::unique_path();
  367. string tmp_filepath = filepath + unique_name + extension;
  368. unique_ptr<ImageOutput> out(ImageOutput::create(tmp_filepath));
  369. if (!out) {
  370. error = "Failed to open temporary file " + tmp_filepath + " for writing";
  371. return false;
  372. }
  373. /* Open temporary file and write image buffers. */
  374. if (!out->open(tmp_filepath, spec)) {
  375. error = "Failed to open file " + tmp_filepath + " for writing: " + out->geterror();
  376. return false;
  377. }
  378. bool ok = true;
  379. if (!out->write_image(TypeDesc::FLOAT, pixels.data())) {
  380. error = "Failed to write to file " + tmp_filepath + ": " + out->geterror();
  381. ok = false;
  382. }
  383. if (!out->close()) {
  384. error = "Failed to save to file " + tmp_filepath + ": " + out->geterror();
  385. ok = false;
  386. }
  387. out.reset();
  388. /* Copy temporary file to outputput filepath. */
  389. string rename_error;
  390. if (ok && !OIIO::Filesystem::rename(tmp_filepath, filepath, rename_error)) {
  391. error = "Failed to move merged image to " + filepath + ": " + rename_error;
  392. ok = false;
  393. }
  394. if (!ok) {
  395. OIIO::Filesystem::remove(tmp_filepath);
  396. }
  397. return ok;
  398. }
  399. /* Image Merger */
  400. ImageMerger::ImageMerger()
  401. {
  402. }
  403. bool ImageMerger::run()
  404. {
  405. if (input.empty()) {
  406. error = "No input file paths specified.";
  407. return false;
  408. }
  409. if (output.empty()) {
  410. error = "No output file path specified.";
  411. return false;
  412. }
  413. /* Open images and verify they have matching layout. */
  414. vector<MergeImage> images;
  415. if (!open_images(input, images, error)) {
  416. return false;
  417. }
  418. /* Merge metadata and setup channels and offsets. */
  419. ImageSpec out_spec;
  420. vector<int> channel_total_samples;
  421. merge_channels_metadata(images, out_spec, channel_total_samples);
  422. /* Merge pixels. */
  423. array<float> out_pixels;
  424. if (!merge_pixels(images, out_spec, channel_total_samples, out_pixels, error)) {
  425. return false;
  426. }
  427. /* We don't need input anymore at this point, and will possibly
  428. * overwrite the same file. */
  429. images.clear();
  430. /* Save output file. */
  431. return save_output(output, out_spec, out_pixels, error);
  432. }
  433. CCL_NAMESPACE_END