Blame tools/exp_combine.cpp

Packit bc1512
Packit bc1512
#include <gegl.h> 
Packit bc1512
Packit bc1512
#include <cstdlib>
Packit bc1512
#include <cstdio>
Packit bc1512
#include <cerrno>
Packit bc1512
#include <cmath>
Packit bc1512
Packit bc1512
#include <iostream>
Packit bc1512
Packit Service a56b9b
#include <gexiv2/gexiv2.h>
Packit bc1512
Packit bc1512
using namespace std;
Packit bc1512
Packit bc1512
enum
Packit bc1512
{
Packit bc1512
  ARG_COMMAND,
Packit bc1512
  ARG_OUTPUT,
Packit bc1512
  ARG_PATH_0,
Packit bc1512
Packit bc1512
  NUM_ARGS
Packit bc1512
};
Packit bc1512
Packit bc1512
Packit bc1512
static const
Packit bc1512
gchar *COMBINER_INPUT_PREFIX = "exposure-";
Packit bc1512
Packit bc1512
Packit bc1512
static void
Packit bc1512
check_usage (gint argc, gchar **argv)
Packit bc1512
{
Packit bc1512
  if (argc == 1)
Packit bc1512
    {
Packit bc1512
      g_print ("This tool combines multiple exposures of one scene into a "
Packit bc1512
               "single buffer.\n");
Packit bc1512
      goto die;
Packit bc1512
    }
Packit bc1512
Packit bc1512
  if (argc < NUM_ARGS)
Packit bc1512
    {
Packit bc1512
      g_print ("Error: Insufficient arguments\n");
Packit bc1512
      goto die;
Packit bc1512
    }
Packit bc1512
Packit bc1512
  return;
Packit bc1512
Packit bc1512
die:
Packit bc1512
  g_print ("Usage: %s <output> <input> [<input> ...]\n", argv[0]);
Packit bc1512
  exit (EXIT_FAILURE);
Packit bc1512
}
Packit bc1512
Packit bc1512
Packit bc1512
static gfloat
Packit bc1512
expcombine_get_file_ev (const gchar *path)
Packit bc1512
{
Packit Service a56b9b
  GError *error = NULL;
Packit Service a56b9b
  GExiv2Metadata *e2m = gexiv2_metadata_new ();
Packit Service a56b9b
  gfloat time, aperture, gain = 1.0f;
Packit bc1512
Packit Service a56b9b
  gexiv2_metadata_open_path (e2m, path, &error);
Packit Service a56b9b
  if (error)
Packit Service a56b9b
  {
Packit Service a56b9b
    g_warning ("%s", error->message);
Packit Service a56b9b
    exit (EXIT_FAILURE);
Packit Service a56b9b
  }
Packit bc1512
Packit bc1512
  /* Calculate the APEX brightness / EV */
Packit bc1512
Packit Service a56b9b
  {
Packit Service a56b9b
    gint nom, den;
Packit Service a56b9b
    gexiv2_metadata_get_exposure_time (e2m, &nom, &den;;
Packit Service a56b9b
    time = nom * 1.0f / den;
Packit Service a56b9b
  }
Packit Service a56b9b
  aperture = gexiv2_metadata_get_fnumber (e2m);
Packit bc1512
Packit bc1512
  /* iso */
Packit Service a56b9b
  if (gexiv2_metadata_has_tag (e2m, "Exif.Image.ISOSpeedRatings"))
Packit bc1512
    {
Packit Service a56b9b
      gain = gexiv2_metadata_get_iso_speed (e2m) / 100.0f;
Packit bc1512
    }
Packit Service a56b9b
  else
Packit bc1512
    {
Packit bc1512
      // Assume ISO is set at 100. It's reasonably likely that the ISO is the
Packit bc1512
      // same across all images anyway, and for our purposes the relative
Packit bc1512
      // values can be sufficient.
Packit bc1512
Packit bc1512
      gain = 1.0f;
Packit bc1512
    }
Packit bc1512
Packit bc1512
  return log2f (aperture * aperture) + log2f (1 / time) + log2f (gain);
Packit bc1512
}
Packit bc1512
Packit bc1512
Packit bc1512
int
Packit bc1512
main (int    argc,
Packit bc1512
      char **argv)
Packit bc1512
{
Packit bc1512
  guint     cursor;
Packit bc1512
  GeglNode *gegl, *combiner, *sink;
Packit bc1512
  gchar    *all_evs = g_strdup ("");
Packit bc1512
Packit bc1512
  g_thread_init (NULL);
Packit bc1512
  gegl_init (&argc, &argv);
Packit bc1512
  check_usage (argc, argv);
Packit bc1512
Packit bc1512
  gegl     = gegl_node_new ();
Packit bc1512
  combiner = gegl_node_new_child (gegl,
Packit bc1512
                                  "operation", "gegl:exp-combine",
Packit bc1512
                                  NULL);
Packit bc1512
Packit bc1512
  for (cursor = ARG_PATH_0; cursor < argc; ++cursor)
Packit bc1512
    {
Packit bc1512
      const gchar *input_path;
Packit bc1512
      gchar        ev_string[G_ASCII_DTOSTR_BUF_SIZE + 1];
Packit bc1512
      gfloat       ev_val;
Packit bc1512
Packit bc1512
      gchar        combiner_pad[strlen (COMBINER_INPUT_PREFIX) +
Packit bc1512
                                G_ASCII_DTOSTR_BUF_SIZE + 1];
Packit bc1512
      gint         err;
Packit bc1512
Packit bc1512
      GeglNode    *img;
Packit bc1512
      
Packit bc1512
      input_path = argv[cursor];
Packit bc1512
      ev_val     = expcombine_get_file_ev (input_path);
Packit bc1512
      if (isnan (ev_val))
Packit bc1512
        {
Packit bc1512
          g_print ("Failed to calculate exposure value for '%s'\n",
Packit bc1512
                   input_path);
Packit bc1512
          exit (EXIT_FAILURE);
Packit bc1512
        }
Packit bc1512
Packit bc1512
      g_ascii_dtostr (ev_string, G_N_ELEMENTS (ev_string), ev_val);
Packit bc1512
      all_evs = g_strconcat (all_evs, " ", ev_string, NULL);
Packit bc1512
Packit bc1512
      /* Construct and link the input image into the combiner */
Packit bc1512
      img = gegl_node_new_child (gegl,
Packit bc1512
                                 "operation", "gegl:load",
Packit bc1512
                                 "path",      input_path,
Packit bc1512
                                  NULL);
Packit bc1512
Packit bc1512
      /* Create the exposure pad name */
Packit bc1512
      err = snprintf (combiner_pad,
Packit bc1512
                      G_N_ELEMENTS (combiner_pad),
Packit bc1512
                      "%s%u",
Packit bc1512
                      COMBINER_INPUT_PREFIX,
Packit bc1512
                      cursor - ARG_PATH_0);
Packit bc1512
      if (err < 1 || err >= G_N_ELEMENTS (combiner_pad))
Packit bc1512
        {
Packit bc1512
          g_warning ("Unable to construct input pad name for exposure %u\n",
Packit bc1512
                     cursor);
Packit bc1512
          return (EXIT_FAILURE);
Packit bc1512
        }
Packit bc1512
Packit bc1512
      gegl_node_connect_to (img, "output", combiner, combiner_pad);
Packit bc1512
    }
Packit bc1512
Packit bc1512
  g_return_val_if_fail (all_evs[0] == ' ', EXIT_FAILURE);
Packit bc1512
  gegl_node_set (combiner, "exposures", all_evs + 1, NULL);
Packit bc1512
Packit bc1512
Packit bc1512
  /* We should not have skipped past the last element of the arguments */
Packit bc1512
  g_return_val_if_fail (cursor == argc, EXIT_FAILURE);
Packit bc1512
  sink     = gegl_node_new_child (gegl,
Packit bc1512
                                  "operation", "gegl:save",
Packit bc1512
                                  "path", argv[ARG_OUTPUT],
Packit bc1512
                                   NULL);
Packit bc1512
Packit bc1512
  gegl_node_link_many (combiner, sink, NULL);
Packit bc1512
  gegl_node_process (sink);
Packit bc1512
  return (EXIT_SUCCESS);
Packit bc1512
}