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 2781ba
#include <exiv2/image.hpp>
Packit Service 2781ba
#include <exiv2/exif.hpp>
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 2781ba
  /* Open the file and read in the metadata */
Packit Service 2781ba
  Exiv2::Image::AutoPtr image;
Packit Service 2781ba
  try 
Packit Service 2781ba
    {
Packit Service 2781ba
      image = Exiv2::ImageFactory::open (path);
Packit Service 2781ba
      image->readMetadata ();
Packit Service 2781ba
    }
Packit Service 2781ba
  catch (Exiv2::Error ex)
Packit Service 2781ba
    {
Packit Service 2781ba
      g_print ("Error: unable to read metadata from path: '%s'\n", path);
Packit Service 2781ba
      exit (EXIT_FAILURE);
Packit Service 2781ba
    }
Packit Service 2781ba
Packit Service 2781ba
  Exiv2::ExifData &exifData = image->exifData ();
Packit Service 2781ba
  if (exifData.empty ())
Packit Service 2781ba
      return NAN;
Packit Service 2781ba
Packit Service 2781ba
  /* Calculate the APEX brightness / EV */
Packit Service 2781ba
  gfloat time, aperture, gain = 1.0f;
Packit Service 2781ba
Packit Service 2781ba
  time     = exifData["Exif.Photo.ExposureTime"].value().toFloat();
Packit Service 2781ba
  aperture = exifData["Exif.Photo.FNumber"     ].value().toFloat();
Packit Service 2781ba
Packit Service 2781ba
  /* iso */
Packit Service 2781ba
  try
Packit Service 2781ba
    {
Packit Service 2781ba
      gain = exifData["Exif.Photo.ISOSpeedRatings"].value().toLong() / 100.0f;
Packit Service 2781ba
    }
Packit Service 2781ba
  catch (Exiv2::Error ex)
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
}