gnuastro-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gnuastro-commits] master ecc99534: MakeProfiles: new option to insert c


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master ecc99534: MakeProfiles: new option to insert custom image
Date: Sat, 9 Apr 2022 23:16:22 -0400 (EDT)

branch: master
commit ecc995343b4d1087ef042c85bf77c899fe8ca2ad
Author: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    MakeProfiles: new option to insert custom image
    
    Until now, MakeProfiles created the pixels of each profile internally and
    placed them in the image. However, the internal way it done this was to
    build an image for each profile separately (in parallel!) and put them into
    the image. Therefore a natural extension was to let the user provide a
    custom image to place in the desired coordinates.
    
    With this commit, it is now possible to do just that with a new type of
    profile ('custom-img') and two options: '--customimg' and
    '--customimghdu'. The user can give any number of custom images to these
    options and call them by their ID in the "radius" column.
---
 NEWS                      |  16 ++
 bin/mkprof/args.h         |  47 ++++-
 bin/mkprof/astmkprof.conf |   1 +
 bin/mkprof/main.h         |  10 +-
 bin/mkprof/mkprof.c       |  14 +-
 bin/mkprof/mkprof.h       |   1 +
 bin/mkprof/oneprofile.c   |  93 ++++++++--
 bin/mkprof/profiles.c     |  11 ++
 bin/mkprof/profiles.h     |   3 +
 bin/mkprof/ui.c           | 430 ++++++++++++++++++++++++++++------------------
 bin/mkprof/ui.h           |   3 +
 doc/gnuastro.texi         |  52 +++++-
 lib/options.c             |  45 ++---
 13 files changed, 514 insertions(+), 212 deletions(-)

diff --git a/NEWS b/NEWS
index a3549516..1e66dd33 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,16 @@ See the end of the file for license conditions.
 
 ** New features
 
+  MakeProfiles:
+   - It is now possible to insert a custom image as a new (10th)
+     'custom-img' profile. This is useful when you have no-noise FITS
+     images from numerical simulations for example, and you want to insert
+     those at a certain location within a larger image (while optionally
+     adding existing Sersic, point or other profiles in the same
+     command). The magnitude of the inserted image can be set in the
+     magnitude column of the input catalog. This can be disabled (to use
+     the original image pixel values) using the '--mcolnocustimg' option.
+
   astscript-radial-profile:
    --zeroisnotblank: new option to account for zero-valued pixels in the
      profile measurement. By default, during the internal cropping phase,
@@ -20,6 +30,12 @@ See the end of the file for license conditions.
 
 ** Changed features
 
+  MakeProfiles:
+   - The string identifier for custom radial profiles is now called
+     'custom-prof' (until now, it was called 'custom'). This was necessary
+     because of the new custom image feature that has been added. The code
+     for this custom radial profile function (8) hasn't changed.
+
 ** Bugs fixed
   bug #62216: MakeProfiles crash when a 3D cube is requested and input
               catalog is from a pipe. Found by Irene Pintos Castro.
diff --git a/bin/mkprof/args.h b/bin/mkprof/args.h
index 944406d5..743e0f20 100644
--- a/bin/mkprof/args.h
+++ b/bin/mkprof/args.h
@@ -88,9 +88,9 @@ struct argp_option program_options[] =
       UI_KEY_CUSTOMTABLE,
       "FITS/TXT",
       0,
-      "File for 'custom' profile.",
+      "File for 'custom-prof' profile.",
       GAL_OPTIONS_GROUP_INPUT,
-      &p->customname,
+      &p->customprofname,
       GAL_TYPE_STRING,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
@@ -103,12 +103,38 @@ struct argp_option program_options[] =
       0,
       "HDU of table given to '--customtable'.",
       GAL_OPTIONS_GROUP_INPUT,
-      &p->customhdu,
+      &p->customprofhdu,
       GAL_TYPE_STRING,
       GAL_OPTIONS_RANGE_ANY,
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "customimg",
+      UI_KEY_CUSTOMIMG,
+      "FITS",
+      0,
+      "Image file for 'custom-img' profile.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->customimgname,
+      GAL_TYPE_STRLL,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+    {
+      "customimghdu",
+      UI_KEY_CUSTOMIMGHDU,
+      "INT/STR",
+      0,
+      "HDU of image given to '--customimg'.",
+      GAL_OPTIONS_GROUP_INPUT,
+      &p->customimghdu,
+      GAL_TYPE_STRLL,
+      GAL_OPTIONS_RANGE_ANY,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
 
 
 
@@ -282,6 +308,19 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_MANDATORY,
       GAL_OPTIONS_NOT_SET
     },
+    {
+      "mcolnocustimg",
+      UI_KEY_MCOLNOCUSTIMG,
+      0,
+      0,
+      "Ignore the value of mcol in 'custom-img'.",
+      UI_GROUP_PROFILES,
+      &p->mcolnocustimg,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
     {
       "shift",
       UI_KEY_SHIFT,
@@ -391,7 +430,7 @@ struct argp_option program_options[] =
       0,
       "sersic (1), moffat (2), gaussian (3), point (4), "
       "flat (5), circumference (6), distance (7), "
-      "radial-table (8), azimuth (9).",
+      "custom-prof (8), azimuth (9), custom-img (10).",
       UI_GROUP_CATALOG,
       &p->fcol,
       GAL_TYPE_STRING,
diff --git a/bin/mkprof/astmkprof.conf b/bin/mkprof/astmkprof.conf
index 581ca2f7..0a94464d 100644
--- a/bin/mkprof/astmkprof.conf
+++ b/bin/mkprof/astmkprof.conf
@@ -21,6 +21,7 @@
 
 #input
  backhdu                   1
+ customimghdu              1
  customtablehdu            1
 
 # Output:
diff --git a/bin/mkprof/main.h b/bin/mkprof/main.h
index 03481ae3..46215336 100644
--- a/bin/mkprof/main.h
+++ b/bin/mkprof/main.h
@@ -68,8 +68,9 @@ enum profile_types
   PROFILE_FLAT,                 /* Flat profile.               */
   PROFILE_CIRCUMFERENCE,        /* Circumference profile.      */
   PROFILE_DISTANCE,             /* Elliptical radius of pixel. */
-  PROFILE_CUSTOM,               /* Radial prof. in file/table. */
+  PROFILE_CUSTOM_PROF,          /* Radial prof. in file/table. */
   PROFILE_AZIMUTH,              /* Azimuthal angle at distance.*/
+  PROFILE_CUSTOM_IMG,           /* Custom image to insert.     */
 
   PROFILE_MAXIMUM_CODE,         /* Just for a sanity check.    */
 };
@@ -118,8 +119,10 @@ struct mkprofparams
   char            *backname;  /* Name of background image file name.      */
   char             *catname;  /* Name of catalog of parameters.           */
   char             *backhdu;  /* HDU of background image.                 */
-  char          *customname;  /* Table to use for radial profile.         */
-  char           *customhdu;  /* HDU of table to use for radial profile.  */
+  char      *customprofname;  /* Table to use for radial profile.         */
+  char       *customprofhdu;  /* HDU of table to use for radial profile.  */
+  gal_list_str_t *customimgname;  /* Image to insert into the image.      */
+  gal_list_str_t  *customimghdu;  /* HDU of images for custom image.      */
   size_t             *dsize;  /* Size of the output image.                */
   uint8_t       clearcanvas;  /* Pixels in background image set to zero.  */
   gal_data_t        *kernel;  /* Parameters to define a kernel.           */
@@ -152,6 +155,7 @@ struct mkprofparams
   char                *tcol;  /* Truncation of the profiles.              */
   uint8_t       mforflatpix;  /* mcol is flat pixel value (f is 4 or 5).  */
   uint8_t  mcolisbrightness;  /* mcol is total brightness, not magnitude. */
+  uint8_t     mcolnocustimg;  /* mcol should be ignored in 'custom-img'.  */
   gal_data_t         *crpix;  /* CRPIX FITS header keywords.              */
   gal_data_t         *crval;  /* CRVAL FITS header keywords.              */
   gal_data_t         *cdelt;  /* For CDELTi FITS header keywords.         */
diff --git a/bin/mkprof/mkprof.c b/bin/mkprof/mkprof.c
index 4278f009..79022f5e 100644
--- a/bin/mkprof/mkprof.c
+++ b/bin/mkprof/mkprof.c
@@ -370,11 +370,12 @@ mkprof_build_single(struct mkonthread *mkp, long 
*fpixel_i, long *lpixel_i,
           /* If a crop is needed, set the starting pointer. */
           ind=gal_dimension_coord_to_index(ndim, ibq->image->dsize,
                                            start_indiv);
-          ptr=gal_pointer_increment(ibq->image->array, ind, ibq->image->type);
+          ptr=gal_pointer_increment(ibq->image->array, ind,
+                                    ibq->image->type);
         }
       else ptr=ibq->image->array;
-      ibq->overlap_i=gal_data_alloc(ptr, ibq->image->type, ndim, dsize, NULL,
-                                    0, -1, 1, NULL, NULL, NULL);
+      ibq->overlap_i=gal_data_alloc(ptr, ibq->image->type, ndim, dsize,
+                                    NULL, 0, -1, 1, NULL, NULL, NULL);
       ibq->overlap_i->block=ibq->image;
 
 
@@ -512,6 +513,11 @@ mkprof_build(void *inparam)
       /* Find the bounding box size (NOT oversampled). */
       if( p->f[id] == PROFILE_POINT )
         mkp->width[0]=mkp->width[1]=1;
+      else if( p->f[id] == PROFILE_CUSTOM_IMG )
+        {
+          mkp->width[0]=mkp->customimg->dsize[1]; /* 'width' is in */
+          mkp->width[1]=mkp->customimg->dsize[0]; /* FITS order not C. */
+        }
       else
         switch(ndim)
           {
@@ -765,7 +771,7 @@ mkprof(struct mkprofparams *p)
      thread. Note that we only want nt-1 threads to do the
      building. */
   errno=0;
-  mkp=malloc(nt*sizeof *mkp);
+  mkp=calloc(nt, sizeof *mkp);
   if(mkp==NULL)
     error(EXIT_FAILURE, errno, "%s: allocating %zu bytes for 'mkp'",
           __func__, (nt-1)*sizeof *mkp);
diff --git a/bin/mkprof/mkprof.h b/bin/mkprof/mkprof.h
index 8f86d8e7..a9b4214c 100644
--- a/bin/mkprof/mkprof.h
+++ b/bin/mkprof/mkprof.h
@@ -49,6 +49,7 @@ struct mkonthread
   long        fpixel_i[3];   /* fpixel_i before running overlap.      */
   int          correction;   /* ==1: correct the pixels afterwards.   */
   unsigned long  rng_seed;   /* Seed used to generate this profile.   */
+  gal_data_t   *customimg;   /* Custom image for this profile.        */
 
   /* Random number generator: */
   gsl_rng            *rng;   /* Copy of main random number generator. */
diff --git a/bin/mkprof/oneprofile.c b/bin/mkprof/oneprofile.c
index 62fee753..45a80271 100644
--- a/bin/mkprof/oneprofile.c
+++ b/bin/mkprof/oneprofile.c
@@ -536,6 +536,56 @@ oneprofile_ispsf(uint8_t fcode)
 
 
 
+static gal_data_t *
+oneprofile_custom_img(struct mkprofparams *p, size_t id)
+{
+  float *d, *df;
+  gal_data_t *out;
+  size_t i, imgcounter=0;
+  gal_list_str_t *timg, *thdu;
+
+  /* The identifier of the image (and its HDU) is in the radius column for
+     this type of profile (a custom image). Note that in 'ui.c', we checked
+     that for this profile type, the "radius" column only has integers. */
+  imgcounter=p->r[id];
+
+  /* Load the image. In 'ui.c', we have already checked that the number of
+     images given to '--customimg' is atleast equal to the largest
+     requested profile. Also, note that if only one HDU is given, we'll
+     assume that for all HDUs. */
+  thdu=p->customimghdu;
+  timg=p->customimgname; for(i=1;i<imgcounter;++i) timg=timg->next;
+  if(p->customimghdu->next)
+    for(i=1;i<imgcounter;++i) thdu=thdu->next;
+  out=gal_fits_img_read_to_type(timg->v, thdu->v, GAL_TYPE_FLOAT32,
+                                p->cp.minmapsize, p->cp.quietmmap);
+
+  /* Make sure the image has an odd number of pixels on each side. */
+  if( out->dsize[0]%2==0 || out->dsize[1]%2==0 )
+    error(EXIT_FAILURE, 0, "%s: doesn't have an odd number of pixels in "
+          "both axises, but is %zux%zu pixels. To have a clear centeral "
+          "pixel, it is necessary that the number of pixels in each side "
+          "of the image be an odd number",
+          gal_fits_name_save_as_string(timg->v, thdu->v), out->dsize[1],
+          out->dsize[0]);
+
+  /* If there are NaN pixels in the image, set them to '0' (which makes
+     them ineffective in MakeProfiles). */
+  if( gal_blank_present(out, 1) )
+    {
+      df=(d=out->array)+out->size;
+      out->flag &= !GAL_DATA_FLAG_BLANK_CH;
+      do if( isnan(*d) ) *d=0.0f; while(++d<df);
+    }
+
+  /* Return the image. */
+  return out;
+}
+
+
+
+
+
 /* Prepare all the parameters for any type of profile. */
 void
 oneprofile_set_prof_params(struct mkonthread *mkp)
@@ -704,7 +754,7 @@ oneprofile_set_prof_params(struct mkonthread *mkp)
 
 
 
-    case PROFILE_CUSTOM:
+    case PROFILE_CUSTOM_PROF:
       mkp->profile          = profiles_custom_table;
       mkp->truncr           = tp ? p->t[id] : p->t[id]*p->r[id];
       mkp->correction       = 0;
@@ -712,6 +762,14 @@ oneprofile_set_prof_params(struct mkonthread *mkp)
 
 
 
+    case PROFILE_CUSTOM_IMG:
+      mkp->profile          = profiles_custom_image; /* A place holder */
+      mkp->customimg        = oneprofile_custom_img(p, id);
+      mkp->correction       = p->mcolnocustimg ? 0 : 1;
+      break;
+
+
+
     default:
       error(EXIT_FAILURE, 0, "%s: a bug! Please contact us so we can "
             "correct this problem. The profile code %u is not recognized.",
@@ -756,24 +814,31 @@ oneprofile_make(struct mkonthread *mkp)
   oneprofile_center_oversampled(mkp);
 
 
-  /* From this point on, the widths will be in the actual pixel widths
-     (with oversampling). */
-  for(i=0;i<ndim;++i)
+  /* If a custom image is provided, there is no need to build a new
+     dataset. */
+  if(mkp->customimg)
+    mkp->ibq->image=mkp->customimg;
+  else
     {
-      mkp->width[i]  *= p->oversample;
-      dsize[ndim-i-1] = mkp->width[i];
-    }
-
+      /* From this point on, the widths will be in the actual pixel widths
+         (with oversampling). */
+      for(i=0;i<ndim;++i)
+        {
+          mkp->width[i]  *= p->oversample;
+          dsize[ndim-i-1] = mkp->width[i];
+        }
 
-  /* Allocate and clear the array for this one profile. */
-  mkp->ibq->image=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, ndim, dsize,
-                                 NULL, 1, p->cp.minmapsize, p->cp.quietmmap,
-                                 "MOCK", "Brightness", NULL);
 
+      /* Allocate and clear the array for this one profile. */
+      mkp->ibq->image=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, ndim, dsize,
+                                     NULL, 1, p->cp.minmapsize,
+                                     p->cp.quietmmap, "MOCK",
+                                     "Brightness", NULL);
 
-  /* Build the profile in the image. */
-  oneprofile_pix_by_pix(mkp);
 
+      /* Build the profile in the image. */
+      oneprofile_pix_by_pix(mkp);
+    }
 
   /* Correct the sum of pixels in the profile so it has the fixed total
      magnitude or pixel value, mkp->correction was set in
diff --git a/bin/mkprof/profiles.c b/bin/mkprof/profiles.c
index d1bde690..987127b9 100644
--- a/bin/mkprof/profiles.c
+++ b/bin/mkprof/profiles.c
@@ -136,6 +136,17 @@ profiles_custom_table(struct mkonthread *mkp)
 
 
 
+/* This is just a place-holder function, but will never be used. */
+double
+profiles_custom_image(struct mkonthread *mkp)
+{
+  return NAN;
+}
+
+
+
+
+
 /* The integral of the Gaussian from -inf to +inf equals the square root of
    PI. So from zero to +inf it equals half of that.*/
 double
diff --git a/bin/mkprof/profiles.h b/bin/mkprof/profiles.h
index 4cf8b09c..acdf58bc 100644
--- a/bin/mkprof/profiles.h
+++ b/bin/mkprof/profiles.h
@@ -32,6 +32,9 @@ profiles_azimuth(struct mkonthread *mkp);
 double
 profiles_custom_table(struct mkonthread *mkp);
 
+double
+profiles_custom_image(struct mkonthread *mkp);
+
 double
 profiles_gaussian_total(double q);
 
diff --git a/bin/mkprof/ui.c b/bin/mkprof/ui.c
index b6b63f7b..efa0f1a8 100644
--- a/bin/mkprof/ui.c
+++ b/bin/mkprof/ui.c
@@ -68,11 +68,12 @@ static char
 args_doc[] = "[Options] [Catalog]";
 
 const char
-doc[] = GAL_STRINGS_TOP_HELP_INFO PROGRAM_NAME" will create a FITS image "
-  "containing any number of mock astronomical profiles based on an input "
-  "catalog. All the profiles will be built from the center outwards. First "
-  "by Monte Carlo integration, then using the central pixel position. The "
-  "tolerance level specifies when the switch will occur.\n"
+doc[] = GAL_STRINGS_TOP_HELP_INFO PROGRAM_NAME" will create a FITS "
+  "image containing any number of mock astronomical profiles based on "
+  "an input catalog. All the profiles will be built from the center "
+  "outwards. First by Monte Carlo integration, then using the central "
+  "pixel position. The tolerance level specifies when the switch will "
+  "occur.\n"
   GAL_STRINGS_MORE_HELP_INFO
   /* After the list of options: */
   "\v"
@@ -127,8 +128,11 @@ ui_profile_name_read(char *string, size_t row)
   else if ( !strcmp("azimuth", string) )
     return PROFILE_DISTANCE;
 
-  else if ( !strcmp("custom", string) )
-    return PROFILE_CUSTOM;
+  else if ( !strcmp("custom-prof", string) )
+    return PROFILE_CUSTOM_PROF;
+
+  else if ( !strcmp("custom-img", string) )
+    return PROFILE_CUSTOM_IMG;
 
   else if ( !strcmp(GAL_BLANK_STRING, string) )
     error(EXIT_FAILURE, 0, "atleast one profile function is blank");
@@ -136,11 +140,11 @@ ui_profile_name_read(char *string, size_t row)
   else
     {
       if(row)
-        error(EXIT_FAILURE, 0, "'%s' not recognized as a profile function "
-              "name in row %zu", string, row);
+        error(EXIT_FAILURE, 0, "'%s' not recognized as a profile "
+              "function name in row %zu", string, row);
       else
-        error(EXIT_FAILURE, 0, "'%s' not recognized as a profile function "
-              "name in values to '--kernel' option", string);
+        error(EXIT_FAILURE, 0, "'%s' not recognized as a profile "
+              "function name in values to '--kernel' option", string);
     }
 
   return PROFILE_INVALID;
@@ -162,7 +166,9 @@ ui_profile_name_write(int profile_code)
     case PROFILE_FLAT:           return "flat";
     case PROFILE_CIRCUMFERENCE:  return "circum";
     case PROFILE_DISTANCE:       return "distance";
+    case PROFILE_CUSTOM_PROF:    return "custom-prof";
     case PROFILE_AZIMUTH:        return "azimuth";
+    case PROFILE_CUSTOM_IMG:     return "custom-img";
     default:
       error(EXIT_FAILURE, 0, "%s: %d not recognized as a profile code",
             __func__, profile_code);
@@ -312,20 +318,21 @@ ui_parse_kernel(struct argp_option *option, char *arg,
         case 2: nc += sprintf(sstr+nc, "%s,",    profile); break;
         case 3: nc += sprintf(sstr+nc, "%s-3d,", profile); break;
         default:
-          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to "
-                "fix the problem. %u is not a recognized kernel "
-                "dimensionality", __func__, PACKAGE_BUGREPORT, kernel->flag);
+          error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s "
+                "to fix the problem. %u is not a recognized kernel "
+                "dimensionality", __func__, PACKAGE_BUGREPORT,
+                kernel->flag);
         }
 
       /* Write the values into a string. */
       for(i=0;i<kernel->size;++i)
         {
           if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
-            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
-                  "can address the problem. The number of necessary "
-                  "characters in the statically allocated string has become "
-                  "too close to %d", __func__, PACKAGE_BUGREPORT,
-                  GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s "
+                  "so we can address the problem. The number of "
+                  "necessary characters in the statically allocated "
+                  "string has become too close to %d", __func__,
+                  PACKAGE_BUGREPORT, GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
           nc += sprintf(sstr+nc, "%g,", darray[i]);
         }
       sstr[nc-1]='\0';
@@ -386,15 +393,16 @@ ui_parse_kernel(struct argp_option *option, char *arg,
           dstr=c+1;
           if( (dstr[1]!='d' && dstr[1]!='D') || dstr[2]!='\0')
             error(EXIT_FAILURE, 0, "bad formatting in '--kernel' "
-                  "dimensionality. The dimensionality suffix must be either "
-                  "2d, 3d (not case sensitive). You have given '%s'", dstr);
+                  "dimensionality. The dimensionality suffix must be "
+                  "either 2d, 3d (not case sensitive). You have given "
+                  "'%s'", dstr);
           switch(dstr[0])
             {
             case '2': kernel->flag=2; break;
             case '3': kernel->flag=3; break;
             default:
-              error(EXIT_FAILURE, 0, "only 2 or 3 dimensional kernels can "
-                    "currently be built, you have asked for a %c "
+              error(EXIT_FAILURE, 0, "only 2 or 3 dimensional kernels "
+                    "can currently be built, you have asked for a %c "
                     "dimensional kernel", dstr[0]);
             }
         }
@@ -542,9 +550,9 @@ ui_read_check_only_options(struct mkprofparams *p)
      not called.  */
   if( p->mcolisbrightness==0 && isnan(p->zeropoint) )
     error(EXIT_FAILURE, 0, "no zeropoint magnitude given. A zeropoint "
-          "magnitude is necessary when '--mcolisbrightness' is not called "
-          "(i.e., when the contents of '--mcol' must be interpretted as "
-          "a magnitude, not brightness).");
+          "magnitude is necessary when '--mcolisbrightness' is not "
+          "called (i.e., when the contents of '--mcol' must be "
+          "interpretted as a magnitude, not brightness).");
 
   /* Make sure no zero value is given for the '--mergedsize' option (only
      when it is necessary). */
@@ -553,6 +561,28 @@ ui_read_check_only_options(struct mkprofparams *p)
       if(p->dsize[i]==0)
         error(EXIT_FAILURE, 0, "values to '--mergedsize' option must not "
               "be zero");
+
+  /* First, make sure all calls to '--customimg' and '--customimghdu' are
+     put into a single list, then make sure that if '--customimg' is given,
+     '--customimghdu' is also given. */
+  gal_options_merge_list_of_csv(&p->customimghdu);
+  gal_options_merge_list_of_csv(&p->customimgname);
+  if(p->customimgname && p->customimghdu==NULL)
+    error(EXIT_FAILURE, 0, "no '--customimghdu' given: when "
+          "'--customimg' is given, it is necessary to also specify "
+          "a HDU. If '--customimghdu' is given only once, it can be "
+          "used for any number of '--customimg's. Otherwise (if the "
+          "HDUs of different inputs differ), it is necessary to "
+          "have the same number of calls to both '--customimg' and "
+          "'--customimghdu'");
+  if(gal_list_str_number(p->customimghdu)!=1
+     && ( gal_list_str_number(p->customimghdu)
+          < gal_list_str_number(p->customimgname) ) )
+    error(EXIT_FAILURE, 0, "incorrect number of '--customimghdu' "
+          "options are given: you should either give it once "
+          "(same HDU in all images), or it should be called "
+          "at least the same number of times that you have calld "
+          "'--customimg'");
 }
 
 
@@ -689,6 +719,7 @@ ui_read_cols_2d(struct mkprofparams *p)
 {
   int checkblank;
   size_t i, counter=0;
+  size_t numcustomimg=0;
   char *colname=NULL, **strarr;
   gal_list_str_t *ccol, *colstrs=NULL;
   gal_data_t *cols, *tmp, *corrtype=NULL;
@@ -762,17 +793,19 @@ ui_read_cols_2d(struct mkprofparams *p)
 
               /* Check if they are in the correct range. */
               for(i=0;i<p->num;++i)
-                if(p->f[i]<=PROFILE_INVALID || p->f[i]>=PROFILE_MAXIMUM_CODE)
+                if(p->f[i]<=PROFILE_INVALID
+                   || p->f[i]>=PROFILE_MAXIMUM_CODE)
                   error(EXIT_FAILURE, 0, "%s: row %zu, the function "
-                        "code is %u. It should be >%d and <%d. Please run "
-                        "again with '--help' and check the acceptable "
+                        "code is %u. It should be >%d and <%d. Please "
+                        "run again with '--help' and check the acceptable "
                         "codes.\n\nAlternatively, you can use alphabetic "
-                        "strings to specify the profile functions, see the "
-                        "explanations under 'fcol' from the command "
-                        "below (press the 'SPACE' key to go down, and the "
-                        "'q' to return back to the command-line):\n\n"
+                        "strings to specify the profile functions, see "
+                        "the explanations under 'fcol' from the command "
+                        "below (press the 'SPACE' key to go down, and "
+                        "the 'q' to return back to the command-line):\n\n"
                         "    $ info %s\n", p->catname, i+1, p->f[i],
-                        PROFILE_INVALID, PROFILE_MAXIMUM_CODE, PROGRAM_EXEC);
+                        PROFILE_INVALID, PROFILE_MAXIMUM_CODE,
+                        PROGRAM_EXEC);
             }
           break;
 
@@ -813,10 +846,12 @@ ui_read_cols_2d(struct mkprofparams *p)
 
           /* Check if there is no negative or >1.0f axis ratio. */
           for(i=0;i<p->num;++i)
-            if( p->f[i]!=PROFILE_POINT && (p->q1[i]<=0.0f || p->q1[i]>1.0f) )
-              error(EXIT_FAILURE, 0, "%s: row %zu, the axis ratio value %g "
-                    "is not acceptable for a '%s' profile. It has to be >0 "
-                    "and <=1", p->catname, i+1, p->q1[i],
+            if( p->f[i]!=PROFILE_POINT
+                && p->f[i]!=PROFILE_CUSTOM_IMG
+                && (p->q1[i]<=0.0f || p->q1[i]>1.0f) )
+              error(EXIT_FAILURE, 0, "%s: row %zu, the axis ratio value "
+                    "%g is not acceptable for a '%s' profile. It has to "
+                    "be >0 and <=1", p->catname, i+1, p->q1[i],
                     ui_profile_name_write(p->f[i]));
           break;
 
@@ -825,7 +860,7 @@ ui_read_cols_2d(struct mkprofparams *p)
           colname="magnitude ('mcol')";
           corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT32);
           p->m=corrtype->array;
-          checkblank=0;          /* Magnitude can be NaN: to mask regions. */
+          checkblank=0;       /* Magnitude can be NaN: to mask regions. */
           break;
 
 
@@ -836,10 +871,12 @@ ui_read_cols_2d(struct mkprofparams *p)
 
           /* Check if there is no negative or zero truncation radius. */
           for(i=0;i<p->num;++i)
-            if(p->f[i]!=PROFILE_POINT && p->t[i]<=0.0f)
+            if(p->t[i]<=0.0f
+               && p->f[i]!=PROFILE_POINT
+               && p->f[i]!=PROFILE_CUSTOM_IMG )
               error(EXIT_FAILURE, 0, "%s: row %zu, the truncation radius "
-                    "value %g is not acceptable for a '%s' profile. It has "
-                    "to be larger than 0", p->catname, i+1, p->t[i],
+                    "value %g is not acceptable for a '%s' profile. It "
+                    "has to be larger than 0", p->catname, i+1, p->t[i],
                     ui_profile_name_write(p->f[i]));
           break;
 
@@ -873,7 +910,7 @@ ui_read_cols_2d(struct mkprofparams *p)
         }
     }
 
-  /* Multi-column sanity checks. */
+  /* Make sure flat profiles aren't given a value of zero. */
   counter=0;
   if( !p->cp.quiet && (p->mforflatpix || p->mcolisbrightness) )
     for(i=0;i<p->num;++i)
@@ -881,16 +918,43 @@ ui_read_cols_2d(struct mkprofparams *p)
                             || p->f[i]==PROFILE_FLAT
                             || p->f[i]==PROFILE_CIRCUMFERENCE ) )
         {
-          error(0, 0, "WARNING: atleast one single-valued profile (point, "
-                "flat, or circumference profiles) has a magnitude column "
-                "value of 0.0 while '--mforflatpix' or "
-                "'--mcolforbrightness' have also been given. In such cases "
-                "the profile's pixels will have a value of zero and thus "
-                "they will not be identifiable from the zero-valued "
-                "background. If this behavior is intended, this warning "
-                "can be suppressed with the '--quiet' (or '-q') option.\n");
+          error(0, 0, "WARNING: atleast one single-valued profile "
+                "(point, flat, or circumference profiles) has a "
+                "magnitude column value of 0.0 while '--mforflatpix' "
+                "or '--mcolforbrightness' have also been given. In "
+                "such cases the profile's pixels will have a value "
+                "of zero and thus they will not be identifiable from "
+                "the zero-valued background. If this behavior is "
+                "intended, this warning can be suppressed with the "
+                "'--quiet' (or '-q') option.\n");
           break;
         }
+
+  /* Make sure the custom image counters are properly given. */
+  for(i=0;i<p->num;++i)
+    if(p->f[i]==PROFILE_CUSTOM_IMG)
+      {
+        /* For a custom image, the radius column is the counter of the image
+           (given to '--customimg'), so it should be an integer. */
+        if( p->r[i]!=ceil(p->r[i]) )
+          error(EXIT_FAILURE, 0, "the value in the \"radius\" column "
+                "for a 'custom-img' should be an integer (counter of "
+                "the image given to '--customimg'), but in row number "
+                "%zu of the input table, it is '%g'", i, p->r[i]);
+
+        /* Find the largest custom image counter. */
+        if(p->r[i]>numcustomimg) numcustomimg=p->r[i];
+      }
+
+  /* Make sure that a sufficient number of custom images are given (as
+     defined by the largest number of custom image counter. */
+  if(numcustomimg>0
+     && numcustomimg>gal_list_str_number(p->customimgname))
+    error(EXIT_FAILURE, 0, "insufficient number of custom images: "
+          "only %zu image(s) given to '--customimg', but in the "
+          "catalog, at least one row requests custom image number "
+          "%zu (in the \"radius\" column)",
+          gal_list_str_number(p->customimgname), numcustomimg);
 }
 
 
@@ -910,9 +974,9 @@ ui_read_cols_3d(struct mkprofparams *p)
   /* The 3D-specific columns are not mandatory in 'args.h', so we need to
      check here if they are given or not before starting to read them. */
   if(p->p2col==NULL || p->p3col==NULL || p->q2col==NULL)
-    error(EXIT_FAILURE, 0, "at least one of '--p2col', '--p3col', or "
-          "'--q2col' have not been identified. When building a 3D profile, "
-          "these three columns are also mandatory");
+    error(EXIT_FAILURE, 0, "at least one of '--p2col', '--p3col', "
+          "or '--q2col' have not been identified. When building a "
+          "3D profile, these three columns are also mandatory");
 
   /* The coordinate columns are a linked list of strings. */
   ccol=p->ccol;
@@ -991,17 +1055,19 @@ ui_read_cols_3d(struct mkprofparams *p)
                  given as string, a non-matching string will result in an
                  error, so there is no need for this in that scenario. */
               for(i=0;i<p->num;++i)
-                if(p->f[i]<=PROFILE_INVALID || p->f[i]>=PROFILE_MAXIMUM_CODE)
+                if(p->f[i]<=PROFILE_INVALID
+                   || p->f[i]>=PROFILE_MAXIMUM_CODE)
                   error(EXIT_FAILURE, 0, "%s: row %zu, the function "
-                        "code is %u. It should be >%d and <%d. Please run "
-                        "again with '--help' and check the acceptable "
+                        "code is %u. It should be >%d and <%d. Please "
+                        "run again with '--help' and check the acceptable "
                         "codes.\n\nAlternatively, you can use alphabetic "
-                        "strings to specify the profile functions, see the "
-                        "explanations under 'fcol' from the command "
-                        "below (press the 'SPACE' key to go down, and the "
-                        "'q' to return back to the command-line):\n\n"
+                        "strings to specify the profile functions, see "
+                        "the explanations under 'fcol' from the command "
+                        "below (press the 'SPACE' key to go down, and "
+                        "the 'q' to return back to the command-line):\n\n"
                         "    $ info %s\n", p->catname, i+1, p->f[i],
-                        PROFILE_INVALID, PROFILE_MAXIMUM_CODE, PROGRAM_EXEC);
+                        PROFILE_INVALID, PROFILE_MAXIMUM_CODE,
+                        PROGRAM_EXEC);
             }
 
           /* General profile sanity checks. */
@@ -1023,9 +1089,9 @@ ui_read_cols_3d(struct mkprofparams *p)
           /* Check if there is no negative or zero-radius profile. */
           for(i=0;i<p->num;++i)
             if(p->f[i]!=PROFILE_POINT && p->r[i]<=0.0f)
-              error(EXIT_FAILURE, 0, "%s: row %zu, the radius value %g is "
-                    "not acceptable for a '%s' profile. It has to be larger "
-                    "than 0", p->catname, i+1, p->r[i],
+              error(EXIT_FAILURE, 0, "%s: row %zu, the radius value %g "
+                    "is not acceptable for a '%s' profile. It has to be "
+                    "larger than 0", p->catname, i+1, p->r[i],
                     ui_profile_name_write(p->f[i]));
           break;
 
@@ -1060,10 +1126,11 @@ ui_read_cols_3d(struct mkprofparams *p)
 
           /* Check if there is no negative or >1.0f axis ratio. */
           for(i=0;i<p->num;++i)
-            if( p->f[i]!=PROFILE_POINT && (p->q1[i]<=0.0f || p->q1[i]>1.0f) )
+            if( p->f[i]!=PROFILE_POINT
+                && (p->q1[i]<=0.0f || p->q1[i]>1.0f) )
               error(EXIT_FAILURE, 0, "%s: row %zu, the first axis ratio "
-                    "value %g is not acceptable for a '%s' profile. It has "
-                    "to be >0 and <=1", p->catname, i+1, p->q1[i],
+                    "value %g is not acceptable for a '%s' profile. It "
+                    "has to be >0 and <=1", p->catname, i+1, p->q1[i],
                     ui_profile_name_write(p->f[i]));
           break;
 
@@ -1074,10 +1141,11 @@ ui_read_cols_3d(struct mkprofparams *p)
 
           /* Check if there is no negative or >1.0f axis ratio. */
           for(i=0;i<p->num;++i)
-            if( p->f[i]!=PROFILE_POINT && (p->q2[i]<=0.0f || p->q2[i]>1.0f) )
+            if( p->f[i]!=PROFILE_POINT
+                && (p->q2[i]<=0.0f || p->q2[i]>1.0f) )
               error(EXIT_FAILURE, 0, "%s: row %zu, the second axis ratio "
-                    "value %g is not acceptable for a '%s' profile. It has "
-                    "to be >0 and <=1", p->catname, i+1, p->q2[i],
+                    "value %g is not acceptable for a '%s' profile. It "
+                    "has to be >0 and <=1", p->catname, i+1, p->q2[i],
                     ui_profile_name_write(p->f[i]));
           break;
 
@@ -1085,7 +1153,7 @@ ui_read_cols_3d(struct mkprofparams *p)
           colname="magnitude ('mcol')";
           corrtype=gal_data_copy_to_new_type_free(tmp, GAL_TYPE_FLOAT32);
           p->m=corrtype->array;
-          checkblank=0;          /* Magnitude can be NaN: to mask regions. */
+          checkblank=0;   /* Magnitude can be NaN: to mask regions. */
           break;
 
         case 13:
@@ -1153,21 +1221,34 @@ ui_prepare_columns(struct mkprofparams *p)
       p->num=1;
 
       /* Allocate the necessary columns. */
-      p->x  = gal_pointer_allocate(GAL_TYPE_FLOAT64, 1, 1, __func__, "p->x");
-      p->y  = gal_pointer_allocate(GAL_TYPE_FLOAT64, 1, 1, __func__, "p->y");
-      p->f  = gal_pointer_allocate(GAL_TYPE_UINT8,   1, 1, __func__, "p->f");
-      p->r  = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, "p->r");
-      p->n  = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, "p->n");
-      p->p1 = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, "p->p1");
-      p->q1 = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, "p->q1");
-      p->m  = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, "p->m");
-      p->t  = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, "p->t");
+      p->x  = gal_pointer_allocate(GAL_TYPE_FLOAT64, 1, 1, __func__,
+                                   "p->x");
+      p->y  = gal_pointer_allocate(GAL_TYPE_FLOAT64, 1, 1, __func__,
+                                   "p->y");
+      p->f  = gal_pointer_allocate(GAL_TYPE_UINT8,   1, 1, __func__,
+                                   "p->f");
+      p->r  = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                   "p->r");
+      p->n  = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                   "p->n");
+      p->p1 = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                   "p->p1");
+      p->q1 = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                   "p->q1");
+      p->m  = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                   "p->m");
+      p->t  = gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                   "p->t");
       if(p->ndim==3)
         {
-          p->z =gal_pointer_allocate(GAL_TYPE_FLOAT64, 1, 1, __func__, "p->z");
-          p->p2=gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, 
"p->p2");
-          p->p3=gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, 
"p->p3");
-          p->q2=gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__, 
"p->q2");
+          p->z =gal_pointer_allocate(GAL_TYPE_FLOAT64, 1, 1, __func__,
+                                     "p->z");
+          p->p2=gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                     "p->p2");
+          p->p3=gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                     "p->p3");
+          p->q2=gal_pointer_allocate(GAL_TYPE_FLOAT32, 1, 1, __func__,
+                                     "p->q2");
         }
 
       /* For profiles that need a different number of input values. Note
@@ -1241,20 +1322,31 @@ ui_prepare_columns(struct mkprofparams *p)
         }
     }
 
-  /* If a custom profile is requested, make sure that a custom file is
-     given. */
+  /* If a custom profile or image is requested, make sure that a custom
+     file is given. */
   for(i=0;i<p->num;++i)
-    if(p->f[i]==PROFILE_CUSTOM)
-      {
-        if(p->customname==NULL)
-          error(EXIT_FAILURE, 0, "at least one custom profile requested "
-                "(first occurrence in row %zu), but no file/table was given "
-                "to the '--customtable' option. See the description of "
-                "this '--customtable' for more information on the "
-                "desired format", i+1);
-        break;
-      }
-
+    {
+      if(p->f[i]==PROFILE_CUSTOM_PROF)
+        {
+          if(p->customprofname==NULL)
+            error(EXIT_FAILURE, 0, "at least one custom profile "
+                  "requested (first occurrence in row %zu), but no "
+                  "file/table was given to the '--customtable' "
+                  "option. See the description of '--customtable' "
+                  "for more information on the desired format", i+1);
+          break;
+        }
+      if(p->f[i]==PROFILE_CUSTOM_IMG)
+        {
+          if(p->customimgname==NULL)
+            error(EXIT_FAILURE, 0, "at least one custom image "
+                  "requested (first occurrence in row %zu), but no "
+                  "file/table was given to the '--customimg' "
+                  "option. See the description of '--customimg' "
+                  "for more information on the desired format", i+1);
+          break;
+        }
+    }
 }
 
 
@@ -1273,8 +1365,9 @@ ui_wcs_sanity_check(struct mkprofparams *p)
   if(p->crpix)
     {
       if(p->crpix->size!=ndim)
-        error(EXIT_FAILURE, 0, "%zu values given to '--crpix'. This must be "
-              "the same as the output dimension (%zu)", p->crpix->size, ndim);
+        error(EXIT_FAILURE, 0, "%zu values given to '--crpix'. This "
+              "must be the same as the output dimension (%zu)",
+              p->crpix->size, ndim);
       return 0;
     }
   else return 1;
@@ -1282,8 +1375,9 @@ ui_wcs_sanity_check(struct mkprofparams *p)
   if(p->crval)
     {
       if(p->crval->size!=ndim)
-        error(EXIT_FAILURE, 0, "%zu values given to '--crval'. This must be "
-              "the same as the output dimension (%zu)", p->crval->size, ndim);
+        error(EXIT_FAILURE, 0, "%zu values given to '--crval'. This "
+              "must be the same as the output dimension (%zu)",
+              p->crval->size, ndim);
       return 0;
     }
   else return 1;
@@ -1291,8 +1385,9 @@ ui_wcs_sanity_check(struct mkprofparams *p)
   if(p->cdelt)
     {
       if(p->cdelt->size!=ndim)
-        error(EXIT_FAILURE, 0, "%zu values given to '--cdelt'. This must be "
-              "the same as the output dimension (%zu)", p->cdelt->size, ndim);
+        error(EXIT_FAILURE, 0, "%zu values given to '--cdelt'. This "
+              "must be the same as the output dimension (%zu)",
+              p->cdelt->size, ndim);
       return 0;
     }
   else return 1;
@@ -1300,8 +1395,8 @@ ui_wcs_sanity_check(struct mkprofparams *p)
   if(p->pc)
     {
       if(p->pc->size!=ndim*ndim)
-        error(EXIT_FAILURE, 0, "%zu values given to '--pc'. This must be "
-              "the square as the output dimension (%zu)", p->pc->size,
+        error(EXIT_FAILURE, 0, "%zu values given to '--pc'. This must "
+              "be the square as the output dimension (%zu)", p->pc->size,
               ndim*ndim);
       return 0;
     }
@@ -1310,8 +1405,9 @@ ui_wcs_sanity_check(struct mkprofparams *p)
   if(p->cunit)
     {
       if(p->cunit->size!=ndim)
-        error(EXIT_FAILURE, 0, "%zu values given to '--cunit'. This must be "
-              "the same as the output dimension (%zu)", p->cunit->size, ndim);
+        error(EXIT_FAILURE, 0, "%zu values given to '--cunit'. This "
+              "must be the same as the output dimension (%zu)",
+              p->cunit->size, ndim);
       return 0;
     }
   else return 1;
@@ -1319,8 +1415,9 @@ ui_wcs_sanity_check(struct mkprofparams *p)
   if(p->ctype)
     {
       if(p->ctype->size!=ndim)
-        error(EXIT_FAILURE, 0, "%zu values given to '--ctype'. This must be "
-              "the same as the output dimension (%zu)", p->ctype->size, ndim);
+        error(EXIT_FAILURE, 0, "%zu values given to '--ctype'. This "
+              "must be the same as the output dimension (%zu)",
+              p->ctype->size, ndim);
       return 0;
     }
   else return 1;
@@ -1457,9 +1554,9 @@ ui_prepare_canvas(struct mkprofparams *p)
 
           /* Make sure it has the same number of elements as naxis. */
           if(p->ndim!=nshift)
-            error(EXIT_FAILURE, 0, "%zu and %zu elements given to '--ndim' "
-                  "and '--shift' respectively. These two numbers must be the "
-                  "same", p->ndim, nshift);
+            error(EXIT_FAILURE, 0, "%zu and %zu elements given to "
+                  "'--ndim' and '--shift' respectively. These two "
+                  "numbers must be the same", p->ndim, nshift);
         }
       else
         {
@@ -1467,19 +1564,20 @@ ui_prepare_canvas(struct mkprofparams *p)
              zero. Also, a PSF profile should exist in the image. */
           if(p->prepforconv)
             {
-              /* Check if there is at least one Moffat or Gaussian profile. */
+              /* Check if there is at least one Moffat or Gaussian
+                 profile. */
               for(i=0;i<p->num;++i)
                 if( oneprofile_ispsf(p->f[i]) )
                   {
                     /* Calculate the size of the box holding the PSF. Note:
 
                        - For the Moffat and Gaussian profiles, the radius
-                       column is actually the FWHM which is actually the
-                       diameter, not radius. So we have to divide it by
-                       half.
+                         column is actually the FWHM which is actually the
+                         diameter, not radius. So we have to divide it by
+                         half.
 
-                       - encloseellipse outputs the total width, we only want
-                       half of it for the shift. */
+                       - encloseellipse outputs the total width, we only
+                         want half of it for the shift. */
                     setshift=1;
                     truncr = p->tunitinp ? p->t[i] : p->t[i] * p->r[i]/2;
                     if(p->ndim==2)
@@ -1493,7 +1591,7 @@ ui_prepare_canvas(struct mkprofparams *p)
                         semiaxes[0]  = truncr;
                         semiaxes[1]  = truncr * p->q1[i];
                         semiaxes[2]  = truncr * p->q2[i];
-                        gal_box_bound_ellipsoid( semiaxes, euler_deg, width);
+                        gal_box_bound_ellipsoid(semiaxes, euler_deg, width);
                       }
                   }
 
@@ -1597,21 +1695,22 @@ ui_finalize_coordinates(struct mkprofparams *p)
             }
 
           /* Allocate the list of coordinates. */
-          gal_list_data_add_alloc(&coords, arr, GAL_TYPE_FLOAT64, 1, &p->num,
-                                  NULL, 0, -1, 1, NULL, NULL, NULL);
+          gal_list_data_add_alloc(&coords, arr, GAL_TYPE_FLOAT64, 1,
+                                  &p->num, NULL, 0, -1, 1, NULL, NULL,
+                                  NULL);
         }
 
       /* Convert the world coordinates to image coordinates (inplace). */
       gal_wcs_world_to_img(coords, p->wcs, 1);
 
 
-      /* If any conversions created a WCSLIB error, both the outputs will be
-         set to NaN. */
+      /* If any conversions created a WCSLIB error, both the outputs will
+         be set to NaN. */
       for(i=0;i<p->num;++i)
         if( isnan(p->x[i]) )
-          error(EXIT_FAILURE, 0, "catalog row %zu: WCSLIB could not convert "
-                "(%f, %f) coordinates into image coordinates", i, p->x[i],
-                p->y[i]);
+          error(EXIT_FAILURE, 0, "catalog row %zu: WCSLIB could not "
+                "convert (%f, %f) coordinates into image coordinates",
+                i, p->x[i], p->y[i]);
 
       /* We want the actual arrays of each 'coords' column. So, first we'll
          set all the array elements to NULL, then free it. */
@@ -1654,37 +1753,39 @@ ui_make_log(struct mkprofparams *p)
   if(p->cp.log==0) return;
 
   /* Individual created. */
-  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_UINT8, 1, &p->num, NULL,
-                          1, p->cp.minmapsize, p->cp.quietmmap,
+  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_UINT8, 1, &p->num,
+                          NULL, 1, p->cp.minmapsize, p->cp.quietmmap,
                           "INDIV_CREATED", "bool",
-                          "If an individual image was made (1) or not (0).");
+                          "If an individual image was made (1) or "
+                          "not (0).");
 
   /* Fraction of monte-carlo. */
-  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_FLOAT32, 1, &p->num, NULL,
-                          1, p->cp.minmapsize, p->cp.quietmmap,
+  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_FLOAT32, 1, &p->num,
+                          NULL, 1, p->cp.minmapsize, p->cp.quietmmap,
                           "FRAC_MONTECARLO", "frac",
-                          "Fraction of brightness in Monte-carlo integrated "
-                          "pixels.");
+                          "Fraction of brightness in Monte-carlo "
+                          "integrated pixels.");
 
   /* Number of monte-carlo. */
-  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_UINT64, 1, &p->num, NULL,
-                          1, p->cp.minmapsize, p->cp.quietmmap,
+  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_UINT64, 1, &p->num,
+                          NULL, 1, p->cp.minmapsize, p->cp.quietmmap,
                           "NUM_MONTECARLO", "count",
                           "Number of Monte Carlo integrated pixels.");
 
   /* Magnitude of profile overlap. */
-  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_FLOAT32, 1, &p->num, NULL,
-                          1, p->cp.minmapsize, p->cp.quietmmap, "MAG_OVERLAP",
-                          "mag", "Magnitude of profile's overlap with merged "
+  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_FLOAT32, 1, &p->num,
+                          NULL, 1, p->cp.minmapsize, p->cp.quietmmap,
+                          "MAG_OVERLAP", "mag",
+                          "Magnitude of profile's overlap with merged "
                           "image.");
 
   /* Row number in input catalog. */
   name=gal_fits_name_save_as_string(p->catname, p->cp.hdu);
   if( asprintf(&comment, "Row number of profile in %s.", name)<0 )
     error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
-  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_UINT64, 1, &p->num, NULL,
-                          1, p->cp.minmapsize, p->cp.quietmmap, "INPUT_ROW_NO",
-                          "count", comment);
+  gal_list_data_add_alloc(&p->log, NULL, GAL_TYPE_UINT64, 1, &p->num,
+                          NULL, 1, p->cp.minmapsize, p->cp.quietmmap,
+                          "INPUT_ROW_NO", "count", comment);
   free(comment);
   free(name);
 }
@@ -1704,7 +1805,7 @@ ui_read_custom_table(struct mkprofparams *p)
   double *min, *max;
 
   /* Read the input radial table. */
-  cols=gal_table_read(p->customname, p->customhdu,
+  cols=gal_table_read(p->customprofname, p->customprofhdu,
                       NULL, NULL, p->cp.searchin, p->cp.ignorecase,
                       p->cp.numthreads, p->cp.minmapsize,
                       p->cp.quietmmap, NULL);
@@ -1716,7 +1817,8 @@ ui_read_custom_table(struct mkprofparams *p)
           "value. Column 2: the radial interval's higher value. "
           "Column 3: the value to use for pixels within that radius "
           "interval",
-          gal_fits_name_save_as_string(p->customname, p->customhdu),
+          gal_fits_name_save_as_string(p->customprofname,
+                                       p->customprofhdu),
           gal_list_data_number(cols));
 
   /* Make sure none of the three columns are string type. */
@@ -1724,8 +1826,8 @@ ui_read_custom_table(struct mkprofparams *p)
       || cols->next->type==GAL_TYPE_STRING
       || cols->next->next->type==GAL_TYPE_STRING )
     error(EXIT_FAILURE, 0, "%s: the columns should only have numeric "
-          "data types", gal_fits_name_save_as_string(p->customname,
-                                                     p->customhdu));
+          "data types", gal_fits_name_save_as_string(p->customprofname,
+                                                     p->customprofhdu));
 
   /* Fill the final table as a double type. */
   p->custom=gal_data_copy_to_new_type(cols, GAL_TYPE_FLOAT64);
@@ -1740,13 +1842,13 @@ ui_read_custom_table(struct mkprofparams *p)
   max=p->custom->next->array;
   for(i=0;i<p->custom->size;++i)
     if(min[i]>=max[i])
-      error(EXIT_FAILURE, 0, "%s: the first column of row %zu (with value "
-            "%g) is larger or equal to the second column (with value %g). "
-            "However, the first column is the lower-limit of the radial "
-            "interval and the second column is the upper-limit. So the "
-            "first column must have a lower value",
-            gal_fits_name_save_as_string(p->customname,
-                                         p->customhdu), i+1,
+      error(EXIT_FAILURE, 0, "%s: the first column of row %zu (with "
+            "value %g) is larger or equal to the second column (with "
+            "value %g). However, the first column is the lower-limit "
+            "of the radial interval and the second column is the "
+            "upper-limit. So the first column must have a lower value",
+            gal_fits_name_save_as_string(p->customprofname,
+                                         p->customprofhdu), i+1,
             min[i], max[i]);
 
   /* Check if the input table is regular and sorted (which can greatly
@@ -1784,8 +1886,8 @@ ui_read_ndim(struct mkprofparams *p)
 
       /* Make sure the kernel and background are not given together. */
       if(p->backname)
-        error(EXIT_FAILURE, 0, "the '--kernel' and '--background' options "
-              "cannot be called together");
+        error(EXIT_FAILURE, 0, "the '--kernel' and '--background' "
+              "options cannot be called together");
     }
   else
     {
@@ -1803,7 +1905,8 @@ ui_read_ndim(struct mkprofparams *p)
           if(p->nomerged)
             {
               /* Get the number of the background image's dimensions. */
-              dsize=gal_fits_img_info_dim(p->backname, p->backhdu, &p->ndim);
+              dsize=gal_fits_img_info_dim(p->backname, p->backhdu,
+                                          &p->ndim);
               p->ndim=gal_dimension_remove_extra(p->ndim, dsize, NULL);
               free(dsize);
             }
@@ -1821,9 +1924,9 @@ ui_read_ndim(struct mkprofparams *p)
 
           /* Make sure the dimensionality is supported. */
           if(p->ndim!=2 && p->ndim!=3)
-            error(EXIT_FAILURE, 0, "%s (hdu %s) has %zu dimensions. Currently "
-                  "only 2 or 3 dimensional outputs can be produced",
-                  p->backname, p->backhdu, p->ndim);
+            error(EXIT_FAILURE, 0, "%s (hdu %s) has %zu dimensions. "
+                  "Currently only 2 or 3 dimensional outputs can be "
+                  "produced", p->backname, p->backhdu, p->ndim);
         }
       else
         {
@@ -1835,8 +1938,8 @@ ui_read_ndim(struct mkprofparams *p)
           /* Make sure the dimensionality is supported. */
           if(p->ndim!=2 && p->ndim!=3)
             error(EXIT_FAILURE, 0, "%zu values given to '--mergedsize'. "
-                  "Currently only 2 or 3 dimensional outputs can be produced",
-                  p->ndim);
+                  "Currently only 2 or 3 dimensional outputs can be "
+                  "produced", p->ndim);
         }
     }
 }
@@ -1857,7 +1960,7 @@ ui_preparations(struct mkprofparams *p)
   ui_prepare_columns(p);
 
   /* Read the radial table. */
-  if(p->customname) ui_read_custom_table(p);
+  if(p->customprofname) ui_read_custom_table(p);
 
   /* If the kernel option was given, some parameters need to be
      over-written: */
@@ -1929,7 +2032,8 @@ ui_print_intro(struct mkprofparams *p)
 
   if(p->cp.quiet) return;
 
-  printf(PROGRAM_NAME" "PACKAGE_VERSION" started on %s", ctime(&p->rawtime));
+  printf(PROGRAM_NAME" "PACKAGE_VERSION" started on %s",
+         ctime(&p->rawtime));
 
   if(p->kernel)
     {
diff --git a/bin/mkprof/ui.h b/bin/mkprof/ui.h
index 3e99ec4c..2f91b0d2 100644
--- a/bin/mkprof/ui.h
+++ b/bin/mkprof/ui.h
@@ -75,6 +75,7 @@ enum option_keys_enum
   UI_KEY_PSFINIMG        = 1000,
   UI_KEY_MAGATPEAK,
   UI_KEY_MCOLISBRIGHTNESS,
+  UI_KEY_MCOLNOCUSTIMG,
   UI_KEY_MODE,
   UI_KEY_CCOL,
   UI_KEY_FCOL,
@@ -93,7 +94,9 @@ enum option_keys_enum
   UI_KEY_PC,
   UI_KEY_CUNIT,
   UI_KEY_CTYPE,
+  UI_KEY_CUSTOMIMG,
   UI_KEY_CUSTOMTABLE,
+  UI_KEY_CUSTOMIMGHDU,
   UI_KEY_CUSTOMTABLEHDU,
 };
 
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 789adb23..df2f9904 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -22674,19 +22674,27 @@ You can use this for checks or as a first 
approximation to define your own highe
 In the latter case, just note that the central values are going to be 
incorrect (see @ref{Sampling from a function}).
 
 @item
-Custom profile with `@code{custom}' or `@code{8}'.
+Custom radial profile with `@code{custom-prof}' or `@code{8}'.
 The values to use for each radial interval should be in the table given to 
@option{--customtable}. For more, see @ref{MakeProfiles profile settings}.
 
 @item
 Azimuthal angle profile with `@code{azimuth}' or `@code{9}'.
 Every pixel within the truncation radius will be given its azimuthal angle (in 
degrees, from 0 to 360) from the major axis.
 In combination with the radial distance profile, you can now create complex 
features in polar coordinates, such as tidal tails or tidal shocks (using the 
Arithmetic program to mix the radius and azimuthal angle through a function to 
create your desired features).
+
+@item
+Custom image with `@code{custom-img}' or `@code{10}'.
+The image(s) to use should be given to the @option{--customimg} option (which 
can be called multiple times for multiple images).
+To identify which one of the images (given to @option{--customimg}) should be 
used, you should specify their counter in the ``radius'' column below.
+For more, see the description of @code{custom-img} in @ref{MakeProfiles 
profile settings}.
 @end itemize
 
 @item --rcol=STR/INT
 The radius parameter of the profiles.
 Effective radius (@mymath{r_e}) if S@'ersic, FWHM if Moffat or Gaussian.
 
+For a custom image profile, this option is not interpreted as a radius, but as 
a counter (identifying which one of the images given to @option{--customimg} 
should be used for each row).
+
 @item --ncol=STR/INT
 The S@'ersic index (@mymath{n}) or Moffat @mymath{\beta}.
 
@@ -22789,6 +22797,10 @@ The zero point magnitude (value to the 
@option{--zeropoint} option) is ignored a
 Recall that the total profile magnitude or brightness that is specified with 
in the @option{--mcol} column of the input catalog is not an integration to 
infinity, but the actual sum of pixels in the profile (until the desired 
truncation radius).
 See @ref{Profile magnitude} for more on this point.
 
+@item --mcolnocustimg
+Don't touch (re-scale) the custom image that should be inserted in 
@code{custom-img} profile (see the description of @option{--fcol} in 
@ref{MakeProfiles catalog}).
+By default, MakeProfiles will scale (multiply) the custom image's pixels to 
have the desired magnitude (or brightness if @option{--mcolisbrightness} is 
called) in that row.
+
 @item --magatpeak
 The magnitude column in the catalog (see @ref{MakeProfiles catalog}) will be 
used to find the brightness only for the peak profile pixel, not the full 
profile.
 Note that this is the flux of the profile's peak pixel in the final output of 
MakeProfiles.
@@ -22809,10 +22821,10 @@ Also note that in such cases, besides de-convolution, 
you will have to set @opti
 @end cartouche
 
 @item --customtable FITS/TXT
-The filename of the table to use in the custom profiles (see description of 
@option{--fcol} in @ref{MakeProfiles catalog}.
+The filename of the table to use in the custom radial profiles (see 
description of @option{--fcol} in @ref{MakeProfiles catalog}.
 This can be a plain-text table, or FITS table, see @ref{Tables}, if it is a 
FITS table, you can use @option{--customtablehdu} to specify which HDU should 
be used (described below).
 
-A custom profile can have any value you want for a given radial profile 
(including NaN/blank values).
+A custom radial profile can have any value you want for a given radial profile 
(including NaN/blank values).
 Each interval is defined by its minimum (inclusive) and maximum (exclusive) 
radius, when a pixel center falls within a radius interval, the value specified 
for that interval will be used.
 If a pixel is not in the given intervals, a value of 0.0 will be used for that 
pixel.
 
@@ -22853,10 +22865,42 @@ asttable radial.fits -c'arith $1 1 -' -c1,2 
-ocustom.fits
 In case the intervals are different from 1 (for example 0.5), change the 
@code{$1 1 -} to @code{$1 0.5 -}.
 On a side-note, Gnuastro has features to extract the radial profile of an 
object from the image, see @ref{Generate radial profile}.
 
-
 @item --customtablehdu INT/STR
 The HDU/extension in the FITS file given to @option{--customtable}.
 
+@item --customimg=STR[,STR]
+A custom FITS image that should be used for the @code{custom-img} profiles 
(see the description of @option{--fcol} in @ref{MakeProfiles catalog}).
+Multiple files can be given to this option (separated by a comma), and this 
option can be called multiple times itself (useful when many custom image 
profiles should be added).
+If the HDU of the images are different, you can use @option{--customimghdu} 
(described below).
+
+Through the ``radius'' column, MakeProfiles will know which one of the images 
given to this this option should be used in each row.
+For example let's assume your input catalog (@file{cat.fits}) has the 
following contents (output of first command below), and you call MakeProfiles 
like like the second command below to insert four profiles into the background 
@file{back.fits} image.
+
+The first profile below is Sersic (with an @option{--fcol}, or 4-th column, 
code of @code{1}).
+So MakeProfiles builds the pixels of the first profile, and all column values 
are meaningful.
+However, the second, third and fourth inserted objects are custom images (with 
an @option{--fcol} code of @code{10}).
+For the custom image profiles, you see that the radius column has values of 
@code{1} or @code{2}.
+This tells MakeProfiles to use the first image given to @option{--customimg} 
(or @file{gal-1.fits}) for the second and fourth inserted objects.
+The second image given to @option{--customimage} (or @file{gal-2.fits}) will 
be used for the third inserted object.
+Finally, all three custom image profiles have different magnitudes, and the 
values in @option{--ncol}, @option{--pcol}, @option{--qcol} and @option{--tcol} 
are ignored.
+
+@example
+$ cat cat.fits
+1 53.15506 -27.785165 1  20 1 20 0.6 25 5
+2 53.15602 -27.777887 10 1  0 0  0   22 0
+3 53.16440 -27.775876 10 2  0 0  0   24 0
+4 53.16849 -27.787406 10 1  0 0  0   23 0
+
+$ astmkprof cat.fits --mode=wcs --zeropoint=25.68 \
+            --background=back.fits --output=out.fits \
+            --customimg=gal-1.fits --customimg=gal-2.fits
+@end example
+
+@item --customimghdu=INT/STR
+The HDU(s) of the images given to @option{--customimghdu}.
+If this option is only called once, but @option{--customimg} is called many 
times, MakeProfiles will assume that all images given to @option{--customimg} 
have the same HDU.
+Otherwise (if the number of HDUs is equal to the number of images), then each 
image will use its corresponding HDU.
+
 @item -X INT,INT
 @itemx --shift=INT,INT
 Shift all the profiles and enlarge the image along each dimension.
diff --git a/lib/options.c b/lib/options.c
index 2e2e3ef6..1dbf0579 100644
--- a/lib/options.c
+++ b/lib/options.c
@@ -1171,6 +1171,9 @@ gal_options_merge_list_of_csv(gal_list_str_t **list)
   char *c, **strarr;
   gal_list_str_t *tmp, *in=*list, *out=NULL;
 
+  /* Incase the input is NULL, this option doesn't need to do anything. */
+  if(in==NULL) return;
+
   /* Go over each input and add it to the list. */
   for(tmp=in; tmp!=NULL; tmp=tmp->next)
     {
@@ -1179,7 +1182,7 @@ gal_options_merge_list_of_csv(gal_list_str_t **list)
          two single space characters). This can happen with options have
          have longer scripts and the user is forced to break the line with
          a '\' followed by newline. */
-      for(c=tmp->v;*c!='\0';++c)
+      for(c=tmp->v; *c!='\0'; ++c)
         if(*c=='\\' && *(c+1)=='\n') { *c=' '; *(++c)=' '; }
 
       /* Read the different comma-separated strings into an array (within a
@@ -1241,10 +1244,10 @@ gal_options_parse_sizes_reverse(struct argp_option 
*option, char *arg,
       for(i=num-1;i>=0;--i)
         {
           if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
-            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
-                  "can address the problem. The number of necessary "
-                  "characters in the statically allocated string has become "
-                  "too close to %d", __func__, PACKAGE_BUGREPORT,
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s "
+                  "so we can address the problem. The number of necessary "
+                  "characters in the statically allocated string has "
+                  "become too close to %d", __func__, PACKAGE_BUGREPORT,
                   GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
           nc += sprintf(sstr+nc, "%zu,", array[i]);
         }
@@ -1328,10 +1331,10 @@ gal_options_parse_csv_float64(struct argp_option 
*option, char *arg,
       for(i=0;i<values->size;++i)
         {
           if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
-            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
-                  "can address the problem. The number of necessary "
-                  "characters in the statically allocated string has become "
-                  "too close to %d", __func__, PACKAGE_BUGREPORT,
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s "
+                  "so we can address the problem. The number of necessary "
+                  "characters in the statically allocated string has "
+                  "become too close to %d", __func__, PACKAGE_BUGREPORT,
                   GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
           nc += sprintf(sstr+nc, "%g,", darray[i]);
         }
@@ -1476,11 +1479,11 @@ gal_options_parse_name_and_values(struct argp_option 
*option, char *arg,
       for(i=0;i<existing->size;++i)
         {
           if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
-            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
-                  "can address the problem. The number of necessary "
-                  "characters in the statically allocated string has become "
-                  "too close to %d", __func__, PACKAGE_BUGREPORT,
-                  GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s "
+                  "so we can address the problem. The number of "
+                  "necessary characters in the statically allocated "
+                  "string has become too close to %d", __func__,
+                  PACKAGE_BUGREPORT, GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
           if(str0_f641) nc += sprintf(sstr+nc, "%g,", darray[i]);
           else          nc += sprintf(sstr+nc, "%s,", strarr[i]);
         }
@@ -1512,8 +1515,10 @@ gal_options_parse_name_and_values(struct argp_option 
*option, char *arg,
 
       /* Read the values. */
       dataset=( str0_f641
-                ? gal_options_parse_list_of_numbers(values, filename, lineno)
-                : gal_options_parse_list_of_strings(values, filename, lineno));
+                ? gal_options_parse_list_of_numbers(values, filename,
+                                                    lineno)
+                : gal_options_parse_list_of_strings(values, filename,
+                                                    lineno));
 
       /* If there actually was a string of numbers, add the dataset to the
          rest. */
@@ -1705,10 +1710,10 @@ gal_options_parse_colon_sep_csv(struct argp_option 
*option, char *arg,
         {
           /* Make sure we aren't passing the allocated space. */
           if( nc > GAL_OPTIONS_STATIC_MEM_FOR_VALUES-100 )
-            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s so we "
-                  "can address the problem. The number of necessary "
-                  "characters in the statically allocated string has become "
-                  "too close to %d", __func__, PACKAGE_BUGREPORT,
+            error(EXIT_FAILURE, 0, "%s: a bug! please contact us at %s "
+                  "so we can address the problem. The number of necessary "
+                  "characters in the statically allocated string has "
+                  "become too close to %d", __func__, PACKAGE_BUGREPORT,
                   GAL_OPTIONS_STATIC_MEM_FOR_VALUES);
 
           /* Print the two values in the expected format. */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]