Blame tools/exp_combine.cpp

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