gnuastro-commits
[Top][All Lists]
Advanced

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

[gnuastro-commits] master a4dbaba 055/113: Recent work in master importe


From: Mohammad Akhlaghi
Subject: [gnuastro-commits] master a4dbaba 055/113: Recent work in master imported, minor conflict fixed
Date: Fri, 16 Apr 2021 10:33:45 -0400 (EDT)

branch: master
commit a4dbaba41ec28d83189ffd079b53d28f44e48df0
Merge: b1ea932 ea1dfa0
Author: Mohammad Akhlaghi <mohammad@akhlaghi.org>
Commit: Mohammad Akhlaghi <mohammad@akhlaghi.org>

    Recent work in master imported, minor conflict fixed
    
    A minor conflict just came up in `bin/segment/clumps.c' about the 3rd value
    to `coord' and the fact that a single-valued STD is now stored as a
    dataset. So it was essentially just removing the conflict signs (and the
    old STD check statement).
---
 NEWS                        |  15 ++-
 bin/mkcatalog/ui.c          |   2 +-
 bin/mkcatalog/upperlimit.c  |   6 +-
 bin/mknoise/Makefile.am     |   2 +-
 bin/noisechisel/detection.c |   4 +-
 bin/segment/args.h          |  26 ++++
 bin/segment/clumps.c        |  40 +++---
 bin/segment/main.h          |   4 +-
 bin/segment/segment.c       | 289 +++++++++++++++++++++++++-------------------
 bin/segment/ui.c            | 143 +++++++++++-----------
 bin/segment/ui.h            |   2 +
 doc/gnuastro.texi           |  98 ++++++++++-----
 doc/release-checklist.txt   |  16 ++-
 lib/binary.c                |  78 +++++++++++-
 lib/blank.c                 |   2 +-
 lib/data.c                  |   6 +-
 lib/gnuastro/binary.h       |   6 +-
 lib/gnuastro/data.h         |   2 +-
 lib/gnuastro/label.h        |   3 +-
 lib/gnuastro/qsort.h        |   3 +-
 lib/label.c                 |   7 +-
 lib/qsort.c                 |   8 ++
 lib/statistics.c            |   2 +-
 lib/tiff.c                  |   2 +-
 lib/tile.c                  |  14 ++-
 lib/wcs.c                   |   2 +-
 26 files changed, 501 insertions(+), 281 deletions(-)

diff --git a/NEWS b/NEWS
index 96ac855..f0014f8 100644
--- a/NEWS
+++ b/NEWS
@@ -36,7 +36,7 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
     --instd: Sky standard deviation as a single value or file (dataset).
     --valuesfile: filename containing the values dataset.
     --valueshdu: HDU/extension containing the values dataset.
-    --clumpscat: Make a clumps catalog also (`WCLUMPS' keyword not used 
anymore).
+    --clumpscat: Make a clumps catalog also.
     --noclumpsort: Don't sort the clumps catalog by host object ID.
     --subtractsky: Subtract the given Sky from the values dataset.
     --variance: input standard deviation image is actually variance.
@@ -66,8 +66,9 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
   Libraries:
     gal_array_read: read array from any of known formats (FITS,TIFF,JPEG,...).
     gal_array_read_to_type: similar to `gal_array_read', but to given type.
-    gal_array_read_one_ch: Read in the data and make sure it is in one channel.
+    gal_array_read_one_ch: Read a dataset, abort if it has multiple channels.
     gal_array_read_one_ch_to_type: Make sure input is in one channel and type.
+    gal_binary_label_holes: label the holes within the foreground.
     gal_blank_is: check to see if argument is blank in its type or not.
     gal_eps_name_is_eps: Returns 1 if given filename is EPS.
     gal_eps_suffix_is_eps: Returns 1 if given suffix is EPS.
@@ -82,6 +83,7 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
     gal_pdf_name_is_pdf: Returns 1 if given filename is PDF.
     gal_pdf_suffix_is_pdf: Returns 1 if given suffix is PDF.
     gal_pdf_write: Writes a dataset into an PDF file.
+    gal_qsort_index_float_increasing: Sort indexs in increasing value order.
     gal_tiff_name_is_tiff: check if name contains a TIFF suffix.
     gal_tiff_suffix_is_tiff: check if suffix is a TIFF suffix.
     gal_tiff_dir_string_read: convert a string to a TIFF directory number.
@@ -123,6 +125,10 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
     - With no output name, the output has a `_detected.fits' suffix.
 
   MakeCatalog:
+
+    - The `WCLUMPS' keyword in the objects labeled image is no longer used
+         to see if a clumps catalog should also be made. To build a clumps
+         catalog, you can now use the `--clumpscat' option.
     - Estimation of noise-level is now done per-pixel over the whole
          label. Until now the average noise level was used.
     --objectsfile has been removed. The main input argument is now assumed
@@ -146,6 +152,10 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
     gal_statistics_number: the output dataset now has a `size_t' type. Until
         now it was `uint64_t'.
 
+  Library:
+    - gal_binary_holes_fill: new name for `gal_binary_fill_holes'.
+    - gal_data_num_between: new name for `gal_data_ptr_dist'.
+
 ** Bug fixes
 
   bug #52979: Many unused result warnings for asprintf in some compilers.
@@ -166,6 +176,7 @@ GNU Astronomy Utilities NEWS                          -*- 
outline -*-
 
 
 
+
 * Noteworthy changes in release 0.5 (library 3.0.0) (2017-12-22) [stable]
 
 ** New features
diff --git a/bin/mkcatalog/ui.c b/bin/mkcatalog/ui.c
index 46b9eeb..65c1142 100644
--- a/bin/mkcatalog/ui.c
+++ b/bin/mkcatalog/ui.c
@@ -999,7 +999,7 @@ ui_preparations_read_inputs(struct mkcatalogparams *p)
          is not larger than the maximum number of labels. */
       if(p->checkupperlimit[0] != GAL_BLANK_INT32
          && p->checkupperlimit[0] > p->numobjects)
-        error(EXIT_FAILURE, 0, "%d (object identifer for the "
+        error(EXIT_FAILURE, 0, "%d (object identifier for the "
               "`--checkupperlimit' option) is larger than the number of "
               "objects in the input labels (%zu)", p->checkupperlimit[0],
               p->numobjects);
diff --git a/bin/mkcatalog/upperlimit.c b/bin/mkcatalog/upperlimit.c
index 00cc09c..e571641 100644
--- a/bin/mkcatalog/upperlimit.c
+++ b/bin/mkcatalog/upperlimit.c
@@ -160,8 +160,8 @@ upperlimit_random_range(struct mkcatalog_passparams *pp, 
gal_data_t *tile,
   /* Set the minimum and maximum acceptable value for the range.  */
   if(p->uprange)
     {
-      tstart=gal_data_ptr_dist(tile->block->array, tile->array,
-                               p->objects->type);
+      tstart=gal_data_num_between(tile->block->array, tile->array,
+                                  p->objects->type);
       gal_dimension_index_to_coord(tstart, ndim, dsize, coord);
     }
 
@@ -746,7 +746,7 @@ upperlimit_one_tile(struct mkcatalog_passparams *pp, 
gal_data_t *tile,
 
 
 /*********************************************************************/
-/*******************     High level funciton      ********************/
+/*******************     High level function      ********************/
 /*********************************************************************/
 void
 upperlimit_calculate(struct mkcatalog_passparams *pp)
diff --git a/bin/mknoise/Makefile.am b/bin/mknoise/Makefile.am
index e70573c..c87dd7c 100644
--- a/bin/mknoise/Makefile.am
+++ b/bin/mknoise/Makefile.am
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.inx
 ##
 ## Original author:
-##     Mohammad Akhlaghi <akhlaghi@gnu.org>
+##     Mohammad Akhlaghi <mohammad@akhlaghi.org>
 ## Contributing author(s):
 ## Copyright (C) 2015-2018, Free Software Foundation, Inc.
 ##
diff --git a/bin/noisechisel/detection.c b/bin/noisechisel/detection.c
index 3894141..24b08d8 100644
--- a/bin/noisechisel/detection.c
+++ b/bin/noisechisel/detection.c
@@ -280,7 +280,7 @@ detection_fill_holes_open(void *in_prm)
 
       /* Fill the holes in this tile: holes with maximal connectivity means
          that they are most strongly bounded. */
-      gal_binary_fill_holes(copy, copy->ndim, -1);
+      gal_binary_holes_fill(copy, copy->ndim, -1);
       if(fho_prm->step==1)
         {
           detection_write_in_large(tile, copy);
@@ -1051,7 +1051,7 @@ detection_quantile_expand(struct noisechiselparams *p, 
gal_data_t *workbin)
       bf=(b=workbin->array)+workbin->size;
       do *b = (*o++ == 1); while(++b<bf);
       workbin=gal_binary_dilate(workbin, 1, 1, 1);
-      gal_binary_fill_holes(workbin, 1, p->detgrowmaxholesize);
+      gal_binary_holes_fill(workbin, 1, p->detgrowmaxholesize);
 
       /* Get the labeled image. */
       numexpanded=gal_binary_connected_components(workbin, &p->olabel,
diff --git a/bin/segment/args.h b/bin/segment/args.h
index 280a0cc..78a56c8 100644
--- a/bin/segment/args.h
+++ b/bin/segment/args.h
@@ -195,6 +195,19 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_SET
     },
     {
+      "onlyclumps",
+      UI_KEY_ONLYCLUMPS,
+      0,
+      0,
+      "Finish after finding true clumps.",
+      GAL_OPTIONS_GROUP_OUTPUT,
+      &p->onlyclumps,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+    {
       "grownclumps",
       UI_KEY_GROWNCLUMPS,
       0,
@@ -264,6 +277,19 @@ struct argp_option program_options[] =
       GAL_OPTIONS_NOT_SET
     },
     {
+      "minima",
+      UI_KEY_MINIMA,
+      0,
+      0,
+      "Built internal clumps from minima.",
+      UI_GROUP_SEGMENTATION,
+      &p->minima,
+      GAL_OPTIONS_NO_ARG_TYPE,
+      GAL_OPTIONS_RANGE_0_OR_1,
+      GAL_OPTIONS_NOT_MANDATORY,
+      GAL_OPTIONS_NOT_SET
+    },
+    {
       "snminarea",
       UI_KEY_SNMINAREA,
       "INT",
diff --git a/bin/segment/clumps.c b/bin/segment/clumps.c
index bd6b232..b27fce1 100644
--- a/bin/segment/clumps.c
+++ b/bin/segment/clumps.c
@@ -29,7 +29,6 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 #include <string.h>
 
 #include <gnuastro/fits.h>
-#include <gnuastro/qsort.h>
 #include <gnuastro/blank.h>
 #include <gnuastro/label.h>
 #include <gnuastro/threads.h>
@@ -70,8 +69,8 @@ clumps_grow_prepare_initial(struct clumps_thread_params 
*cltprm)
   double wcoord[3]={0.0f,0.0f,0.0f}, sum=0.0f;
   size_t ndiffuse=0, coord[3], tcoord[3], *dindexs;
   size_t *s, *sf, *dsize=input->dsize, ndim=input->ndim;
+  float glimit, *imgss=input->array, *std=p->std->array;
   int32_t *olabel=p->olabel->array, *clabel=p->clabel->array;
-  float glimit, *imgss=input->array, *std=p->std?p->std->array:NULL;
 
 
   /* Find the flux weighted center (meaningful only for positive valued
@@ -116,14 +115,14 @@ clumps_grow_prepare_initial(struct clumps_thread_params 
*cltprm)
 
 
   /* Find the growth limit. Note that the STD may be a value, or a dataset
-     (which may be a full sized image or a tessellation). If its a dataset,
-     `stdval==NAN', and we'll check through the number of elements to see
-     what kind of dataset it is.. */
-  cltprm->std = ( p->std
+     (which may be a full sized image or a tessellation). If its not a
+     single value, we'll check through the number of elements to see what
+     kind of dataset it is (if its a tile or full image). */
+  cltprm->std = ( p->std->size>1
                   ? ( p->std->size==p->input->size
                       ? std[gal_dimension_coord_to_index(ndim, dsize, coord)]
                       : std[gal_tile_full_id_from_coord(&p->cp.tl, coord)] )
-                  : p->stdval );
+                  : std[0] );
   if(p->variance) cltprm->std = sqrt(cltprm->std);
 
 
@@ -248,9 +247,9 @@ clumps_get_raw_info(struct clumps_thread_params *cltprm)
   double *row, *info=cltprm->info->array;
   size_t nngb=gal_dimension_num_neighbors(ndim);
   struct gal_tile_two_layer_params *tl=&p->cp.tl;
+  float *arr=p->input->array, *std=p->std->array;
   size_t *dinc=gal_dimension_increment(ndim, dsize);
   int32_t lab, nlab, *ngblabs, *clabel=p->clabel->array;
-  float *arr=p->input->array, *std=p->std?p->std->array:NULL;
 
   /* Allocate the array to keep the neighbor labels of river pixels. */
   ngblabs=gal_data_malloc_array(GAL_TYPE_INT32, nngb, __func__, "ngblabs");
@@ -341,13 +340,13 @@ clumps_get_raw_info(struct clumps_thread_params *cltprm)
                 coord[2]=GAL_DIMENSION_FLT_TO_INT(row[INFO_Z]/row[INFO_SFF]);
 
               /* Find the corresponding standard deviation. */
-              row[INFO_INSTD]=( p->std
+              row[INFO_INSTD]=( p->std->size>1
                                 ? ( p->std->size==p->input->size
                                     ? std[gal_dimension_coord_to_index(ndim,
                                                                dsize, coord)]
                                     : std[gal_tile_full_id_from_coord(tl,
                                                                     coord)] )
-                                : p->stdval );
+                                : std[0] );
               if(p->variance) row[INFO_INSTD] = sqrt(row[INFO_INSTD]);
 
               /* For a check
@@ -440,7 +439,7 @@ clumps_make_sn_table(struct clumps_thread_params *cltprm)
          noise cases) or the area is smaller than the minimum area to
          calculate signal-to-noise, then set the S/N of this segment to
          zero. */
-      if( I>O && Ni>p->snminarea )
+      if( (p->minima ? O>I : I>O) && Ni>p->snminarea )
         {
           /* For easy reading, define `var' for variance.  */
           var = row[INFO_INSTD] * row[INFO_INSTD];
@@ -452,7 +451,7 @@ clumps_make_sn_table(struct clumps_thread_params *cltprm)
              equal to i. */
           ind = sky0_det1 ? i : counter++;
           if(cltprm->snind) indarr[ind]=i;
-          snarr[ind]=( sqrt(Ni/p->cpscorr) * (I-O)
+          snarr[ind]=( sqrt(Ni/p->cpscorr) * ( p->minima ? O-I : I-O)
                        / sqrt( (I>0?I:-1*I) + (O>0?O:-1*O) + var ) );
         }
       else
@@ -639,9 +638,9 @@ clumps_find_make_sn_table(void *in_prm)
              rivers and not include them in the list of indexs to set
              clumps. To do that, we need this tile's starting
              coordinates. */
-          gal_dimension_index_to_coord(gal_data_ptr_dist(p->clabel->array,
-                                                         tile->array,
-                                                         p->clabel->type),
+          gal_dimension_index_to_coord(gal_data_num_between(p->clabel->array,
+                                                            tile->array,
+                                                            p->clabel->type),
                                        ndim, dsize, scoord);
 
 
@@ -686,16 +685,16 @@ clumps_find_make_sn_table(void *in_prm)
                     {
                       if(cltprm.id==282) *i+=2;
                   */
-                      indarr[c++]=gal_data_ptr_dist(p->clabel->array, i,
-                                                    p->clabel->type);
+                      indarr[c++]=gal_data_num_between(p->clabel->array, i,
+                                                       p->clabel->type);
                   /*
                     }
                   else
                     if(cltprm.id==282)
                       {
                         int32_t *clabel=p->clabel->array;
-                        size_t kjd=gal_data_ptr_dist(p->clabel->array, i,
-                                                     p->clabel->type);
+                        size_t kjd=gal_data_num_between(p->clabel->array, i,
+                                                        p->clabel->type);
                         printf("%zu, %zu: %u\n", kjd%dsize[1]+1,
                                kjd/dsize[1]+1, clabel[kjd]);
                       }
@@ -711,7 +710,8 @@ clumps_find_make_sn_table(void *in_prm)
           /* Generate the clumps over this region. */
           cltprm.numinitclumps=gal_label_oversegment(p->conv, cltprm.indexs,
                                                      p->clabel,
-                                                     cltprm.topinds);
+                                                     cltprm.topinds,
+                                                     !p->minima);
 
 
           /* Set all river pixels to GAL_LABEL_INIT (to be distinguishable
diff --git a/bin/segment/main.h b/bin/segment/main.h
index 62f3102..e632ae5 100644
--- a/bin/segment/main.h
+++ b/bin/segment/main.h
@@ -60,6 +60,7 @@ struct segmentparams
   char               *stdname;  /* File name of Standard deviation image. */
   char                *stdhdu;  /* HDU of Stanard deviation image.        */
   uint8_t            variance;  /* The input STD is actually variance.    */
+  uint8_t              minima;  /* Build clumps from their minima, maxima.*/
   uint8_t           rawoutput;  /* Output only object and clump labels.   */
 
   float            minskyfrac;  /* Undetected area min. frac. in tile.    */
@@ -69,6 +70,7 @@ struct segmentparams
   float               snquant;  /* Quantile of clumps in sky for true S/N.*/
   uint8_t    keepmaxnearriver;  /* Keep clumps with a peak near a river.  */
   float         clumpsnthresh;  /* Clump S/N threshold.                   */
+  uint8_t          onlyclumps;  /* Finish after finding true clumps.      */
   float               gthresh;  /* Multiple of STD to stop growing clumps.*/
   size_t       minriverlength;  /* Min, len of good grown clump rivers.   */
   float           objbordersn;  /* Minimum S/N for grown clumps to be one.*/
@@ -88,8 +90,6 @@ struct segmentparams
   gal_data_t          *olabel;  /* Object labels.                         */
   gal_data_t          *clabel;  /* Clumps labels.                         */
   gal_data_t             *std;  /* STD of undetected pixels, per tile.    */
-  float                stdval;  /* Single value to use for std deviation. */
-  float                skyval;  /* Single value to use for Sky.           */
 
   float               cpscorr;  /* Counts/second correction.              */
   size_t        numdetections;  /* Number of final detections.            */
diff --git a/bin/segment/segment.c b/bin/segment/segment.c
index 9fc1f5c..da38458 100644
--- a/bin/segment/segment.c
+++ b/bin/segment/segment.c
@@ -148,13 +148,13 @@ segment_initialize(struct segmentparams *p)
   /* If the (minimum) standard deviation is less than 1, then the units of
      the input are in units of counts/time. As described in the NoiseChisel
      paper, we need to correct the S/N equation later. */
-  if(p->std)
+  if(p->std->size>1)
     {
       min=gal_statistics_minimum(p->std);
       minv=*(float *)(min->array);
       gal_data_free(min);
     }
-  else minv=p->stdval;
+  else minv=*(float *)(p->std->array);
   if(p->variance) minv=sqrt(minv);
   p->cpscorr = minv>1 ? 1.0 : minv;
 }
@@ -199,7 +199,7 @@ segment_relab_noseg(struct clumps_thread_params *cltprm)
 
 /* Find the adjacency matrixs (number, sum and signal to noise) for the
    rivers between potentially separate objects in a detection region. They
-   have to be allocated prior to entering this funciton.
+   have to be allocated prior to entering this function.
 
    The way to find connected objects is through an adjacency matrix. It is
    a square matrix with a side equal to numobjs. So to see if regions `a`
@@ -453,8 +453,11 @@ static void
 segment_relab_overall(struct clumps_thread_params *cltprm)
 {
   struct clumps_params *clprm=cltprm->clprm;
-  int32_t startinglab, *olabel=clprm->p->olabel->array;
+
+  int32_t startinglab;
+  uint8_t onlyclumps=clprm->p->onlyclumps;
   size_t *s=cltprm->indexs->array, *sf=s+cltprm->indexs->size;
+  int32_t *clabel=clprm->p->clabel->array, *olabel=clprm->p->olabel->array;
 
   /* Lock the mutex if we are working on more than one thread. NOTE: it is
      very important to keep the number of operations within the mutex to a
@@ -462,18 +465,31 @@ segment_relab_overall(struct clumps_thread_params *cltprm)
   if(clprm->p->cp.numthreads>1)
     pthread_mutex_lock(&clprm->labmutex);
 
-  /* Save the total number of objects found so far into `startinglab', then
-     increment the total number of objects and clumps. */
-  startinglab        = clprm->totobjects;
-  clprm->totobjects += cltprm->numobjects;
+  /* Set the starting label for re-labeling (THIS HAS TO BE BEFORE
+     CORRECTING THE TOTAL NUMBER OF CLUMPS/OBJECTS). */
+  startinglab = onlyclumps ? clprm->totclumps : clprm->totobjects;
+
+  /* Save the total number of clumps and objects. */
   clprm->totclumps  += cltprm->numtrueclumps;
+  if( !onlyclumps ) clprm->totobjects += cltprm->numobjects;
 
   /* Unlock the mutex (if it was locked). */
   if(clprm->p->cp.numthreads>1)
     pthread_mutex_unlock(&clprm->labmutex);
 
   /* Increase all the object labels by `startinglab'. */
-  do olabel[*s] += startinglab; while(++s<sf);
+  if( onlyclumps )
+    {
+      if(cltprm->numtrueclumps>0)
+        {
+          do
+            if(clabel[*s]>0)
+              clabel[*s] += startinglab;
+          while(++s<sf);
+        }
+    }
+  else
+    do olabel[*s] += startinglab; while(++s<sf);
 }
 
 
@@ -512,7 +528,7 @@ segment_on_threads(void *in_prm)
   int32_t *clabel=p->clabel->array, *olabel=p->olabel->array;
 
   /* Initialize the general parameters for this thread. */
-  cltprm.clprm   = clprm;
+  cltprm.clprm = clprm;
 
   /* Go over all the detections given to this thread (counting from zero.) */
   for(i=0; tprm->indexs[i] != GAL_BLANK_SIZE_T; ++i)
@@ -522,6 +538,7 @@ segment_on_threads(void *in_prm)
          the ID given to this thread. */
       cltprm.id     = tprm->indexs[i]+1;
       cltprm.indexs = &clprm->labindexs[ cltprm.id ];
+      cltprm.numinitclumps = cltprm.numtrueclumps = cltprm.numobjects = 0;
 
 
       /* The `topinds' array is only necessary when the user wants to
@@ -542,7 +559,8 @@ segment_on_threads(void *in_prm)
 
       /* Find the clumps over this region. */
       cltprm.numinitclumps=gal_label_oversegment(p->conv, cltprm.indexs,
-                                                 p->clabel, cltprm.topinds);
+                                                 p->clabel, cltprm.topinds,
+                                                 !p->minima);
 
 
       /* Set all the river pixels to zero (we don't need them any more in
@@ -573,102 +591,107 @@ segment_on_threads(void *in_prm)
       if(clprm->step==1 || p->checksn)
         { gal_data_free(topinds); continue; }
 
-      /* Only keep true clumps. */
+      /* Only keep true clumps and abort if the user only wants clumps. */
       clumps_det_keep_true_relabel(&cltprm);
       gal_data_free(topinds);
       if(clprm->step==2) continue;
 
-
-      /* Set the internal (with the detection) clump and object
-         labels. Segmenting a detection into multiple objects is only
-         defined when there is more than one true clump over the
-         detection. When there is only one true clump
-         (cltprm->numtrueclumps==1) or none (p->numtrueclumps==0), then
-         just set the required preliminaries to make the next steps be
-         generic for all cases. */
-      if(cltprm.numtrueclumps<=1)
+      /* When only clumps are desired ignore the rest of the process. */
+      if(!p->onlyclumps)
         {
-          /* Set the basics. */
-          cltprm.numobjects=1;
-          segment_relab_noseg(&cltprm);
-
-          /* If the user wanted a check image, this object doesn't
-             change. */
-          if( clprm->step >= 3 && clprm->step <= 6) continue;
-
-          /* If the user has asked for grown clumps in the clumps image
-             instead of the raw clumps, then replace the indexs in the
-             `clabel' array is well. In this case, there will always be one
-             "clump". */
-          if(p->grownclumps)
-            {
-              sf=(s=cltprm.indexs->array)+cltprm.indexs->size;
-              do clabel[ *s++ ] = 1; while(s<sf);
-              cltprm.numtrueclumps=1;
-            }
-        }
-      else
-        {
-          /* Grow the true clumps over the detection. */
-          clumps_grow_prepare_initial(&cltprm);
-          if(cltprm.diffuseindexs->size)
-            gal_label_grow_indexs(p->olabel, cltprm.diffuseindexs, 1, 1);
-          if(clprm->step==3)
-            { gal_data_free(cltprm.diffuseindexs); continue; }
-
-          /* If grown clumps are desired instead of the raw clumps, then
-             replace all the grown clumps with those in clabel. */
-          if(p->grownclumps)
-            {
-              sf=(s=cltprm.indexs->array)+cltprm.indexs->size;
-              do
-                if(olabel[*s]>0) clabel[*s]=olabel[*s];
-              while(++s<sf);
-            }
-
-          /* Identify the objects in this detection using the grown clumps
-             and correct the grown clump labels into new object labels. */
-          segment_relab_to_objects(&cltprm);
-          if(clprm->step==4)
+          /* Set the internal (with the detection) clump and object
+             labels. Segmenting a detection into multiple objects is only
+             defined when there is more than one true clump over the
+             detection. When there is only one true clump
+             (cltprm->numtrueclumps==1) or none (p->numtrueclumps==0), then
+             just set the required preliminaries to make the next steps be
+             generic for all cases. */
+          if(cltprm.numtrueclumps<=1)
             {
-              gal_data_free(cltprm.clumptoobj);
-              gal_data_free(cltprm.diffuseindexs);
-              continue;
+              /* Set the basics. */
+              cltprm.numobjects=1;
+              segment_relab_noseg(&cltprm);
+
+              /* If the user wanted a check image, this object doesn't
+                 change. */
+              if( clprm->step >= 3 && clprm->step <= 6) continue;
+
+              /* If the user has asked for grown clumps in the clumps image
+                 instead of the raw clumps, then replace the indexs in the
+                 `clabel' array is well. In this case, there will always be
+                 one "clump". */
+              if(p->grownclumps)
+                {
+                  sf=(s=cltprm.indexs->array)+cltprm.indexs->size;
+                  do clabel[ *s++ ] = 1; while(s<sf);
+                  cltprm.numtrueclumps=1;
+                }
             }
-
-          /* Continue the growth and cover the whole area, we don't need
-             the diffuse indexs any more, so after filling the detected
-             region, free the indexs. */
-          if( cltprm.numobjects == 1 )
-            segment_relab_noseg(&cltprm);
           else
             {
-              /* Correct the labels so every non-labeled pixel can be
-                 grown. */
-              clumps_grow_prepare_final(&cltprm);
+              /* Grow the true clumps over the detection. */
+              clumps_grow_prepare_initial(&cltprm);
+              if(cltprm.diffuseindexs->size)
+                gal_label_grow_indexs(p->olabel, cltprm.diffuseindexs, 1, 1);
+              if(clprm->step==3)
+                { gal_data_free(cltprm.diffuseindexs); continue; }
 
-              /* Cover the whole area (using maximum connectivity to not
-                 miss any pixels). */
-              gal_label_grow_indexs(p->olabel, cltprm.diffuseindexs, 0,
-                                    p->olabel->ndim);
+              /* If grown clumps are desired instead of the raw clumps,
+                 then replace all the grown clumps with those in clabel. */
+              if(p->grownclumps)
+                {
+                  sf=(s=cltprm.indexs->array)+cltprm.indexs->size;
+                  do
+                    if(olabel[*s]>0) clabel[*s]=olabel[*s];
+                  while(++s<sf);
+                }
 
-              /* Make sure all diffuse pixels are labeled. */
-              if(cltprm.diffuseindexs->size)
-                error(EXIT_FAILURE, 0, "a bug! Please contact us at %s to "
-                      "fix it. %zu pixels of detection %zu have not been "
-                      "labeled (as an object)", PACKAGE_BUGREPORT,
-                      cltprm.diffuseindexs->size, cltprm.id);
+              /* Identify the objects in this detection using the grown
+                 clumps and correct the grown clump labels into new object
+                 labels. */
+              segment_relab_to_objects(&cltprm);
+              if(clprm->step==4)
+                {
+                  gal_data_free(cltprm.clumptoobj);
+                  gal_data_free(cltprm.diffuseindexs);
+                  continue;
+                }
+
+              /* Continue the growth and cover the whole area, we don't
+                 need the diffuse indexs any more, so after filling the
+                 detected region, free the indexs. */
+              if( cltprm.numobjects == 1 )
+                segment_relab_noseg(&cltprm);
+              else
+                {
+                  /* Correct the labels so every non-labeled pixel can be
+                     grown. */
+                  clumps_grow_prepare_final(&cltprm);
+
+                  /* Cover the whole area (using maximum connectivity to
+                     not miss any pixels). */
+                  gal_label_grow_indexs(p->olabel, cltprm.diffuseindexs, 0,
+                                        p->olabel->ndim);
+
+                  /* Make sure all diffuse pixels are labeled. */
+                  if(cltprm.diffuseindexs->size)
+                    error(EXIT_FAILURE, 0, "a bug! Please contact us at %s "
+                          "to fix it. %zu pixels of detection %zu have not "
+                          "been labeled (as an object)", PACKAGE_BUGREPORT,
+                          cltprm.diffuseindexs->size, cltprm.id);
+                }
+              gal_data_free(cltprm.diffuseindexs);
+              if(clprm->step==5)
+                { gal_data_free(cltprm.clumptoobj); continue; }
+
+              /* Correct the clump labels. Note that this is only necessary
+                 when there is more than object over the detection or when
+                 there were multiple clumps over the detection. */
+              if(cltprm.numobjects>1)
+                segment_relab_clumps_in_objects(&cltprm);
+              gal_data_free(cltprm.clumptoobj);
+              if(clprm->step==6) {continue;}
             }
-          gal_data_free(cltprm.diffuseindexs);
-          if(clprm->step==5) { gal_data_free(cltprm.clumptoobj); continue; }
-
-          /* Correct the clump labels. Note that this is only necessary
-             when there is more than object over the detection or when
-             there were multiple clumps over the detection. */
-          if(cltprm.numobjects>1)
-            segment_relab_clumps_in_objects(&cltprm);
-          gal_data_free(cltprm.clumptoobj);
-          if(clprm->step==6) {continue;}
         }
 
       /* Convert the object labels to their final value */
@@ -771,6 +794,7 @@ static void
 segment_detections(struct segmentparams *p)
 {
   char *msg;
+  int continuecheck=1;
   struct clumps_params clprm;
   gal_data_t *labindexs, *claborig, *demo=NULL;
 
@@ -809,7 +833,7 @@ segment_detections(struct segmentparams *p)
 
 
       /* Do each step. */
-      while(clprm.step<8)
+      while(clprm.step<8 && continuecheck)
         {
           /* Reset the temporary copy of clabel back to its original. */
           if(clprm.step>1)
@@ -852,18 +876,28 @@ segment_detections(struct segmentparams *p)
               break;
 
             case 3:
-              demo=p->olabel;
-              demo->name = "DET_CLUMPS_GROWN";
-              if(!p->cp.quiet)
+              /* If the user only wanted clumps, there is no point in
+                 continuing after this point. We DON'T WANT this at the end
+                 of `2', otherwise, the `DET_CLUMPS_TRUE' extension will be
+                 different when `--onlyclumps' is called and when it
+                 isn't.*/
+              if(p->onlyclumps)
+                continuecheck=0;
+              else
                 {
-                  gal_timing_report(NULL, "Identify objects...",
-                                    1);
-                  if( asprintf(&msg, "True clumps grown                  "
-                               "(HDU: `%s').", demo->name)<0 )
-                    error(EXIT_FAILURE, 0, "%s: asprintf allocation",
-                          __func__);
-                  gal_timing_report(NULL, msg, 2);
-                  free(msg);
+                  demo=p->olabel;
+                  demo->name = "DET_CLUMPS_GROWN";
+                  if(!p->cp.quiet)
+                    {
+                      gal_timing_report(NULL, "Identify objects...",
+                                        1);
+                      if( asprintf(&msg, "True clumps grown                  "
+                                   "(HDU: `%s').", demo->name)<0 )
+                        error(EXIT_FAILURE, 0, "%s: asprintf allocation",
+                              __func__);
+                      gal_timing_report(NULL, msg, 2);
+                      free(msg);
+                    }
                 }
               break;
 
@@ -934,7 +968,8 @@ segment_detections(struct segmentparams *p)
              default values are hard to view, so we'll make a copy of the
              demo, set all Sky regions to blank and all clump macro values
              to zero. */
-          gal_fits_img_write(demo, p->segmentationname, NULL, PROGRAM_NAME);
+          if(continuecheck)
+            gal_fits_img_write(demo, p->segmentationname, NULL, PROGRAM_NAME);
 
           /* If the user wanted to check the clump S/N values, then break
              out of the loop, we don't need the rest of the process any
@@ -962,6 +997,7 @@ segment_detections(struct segmentparams *p)
   p->numclumps=clprm.totclumps;
   p->numobjects=clprm.totobjects;
 
+
   /* If the user wanted to see the S/N table, then make the S/N table. */
   if(p->checksn) segment_save_sn_table(&clprm);
 
@@ -1019,17 +1055,19 @@ segment_output(struct segmentparams *p)
 
 
   /* The object labels. */
-  gal_fits_key_list_add(&keys, GAL_TYPE_SIZE_T, "NUMLABS", 0,
-                        &p->numobjects, 0, "Total number of objects", 0,
-                        "counter");
-  p->olabel->name="OBJECTS";
-  gal_fits_img_write(p->olabel, p->cp.output, keys, PROGRAM_NAME);
-  p->olabel->name=NULL;
-  keys=NULL;
-
+  if(!p->onlyclumps)
+    {
+      gal_fits_key_list_add(&keys, GAL_TYPE_SIZE_T, "NUMLABS", 0,
+                            &p->numobjects, 0, "Total number of objects", 0,
+                            "counter");
+      p->olabel->name="OBJECTS";
+      gal_fits_img_write(p->olabel, p->cp.output, keys, PROGRAM_NAME);
+      p->olabel->name=NULL;
+      keys=NULL;
+    }
 
   /* The Standard deviation image (if one was actually given). */
-  if( !p->rawoutput && p->std)
+  if( !p->rawoutput && p->std->size>1 )
     {
       /* See if any keywords should be written (possibly inherited from the
          detection program). */
@@ -1153,10 +1191,19 @@ segment(struct segmentparams *p)
   /* Report the results and timing to the user. */
   if(!p->cp.quiet)
     {
-      if( asprintf(&msg, "%zu object%s""containing %zu clump%sfound.",
-                   p->numobjects, p->numobjects==1 ? " " : "s ",
-                   p->numclumps,  p->numclumps ==1 ? " " : "s ")<0 )
-        error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
+      if(p->onlyclumps)
+        {
+          if( asprintf(&msg, "%zu clump%sfound.",
+                       p->numclumps,  p->numclumps ==1 ? " " : "s ")<0 )
+            error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
+        }
+      else
+        {
+          if( asprintf(&msg, "%zu object%s""containing %zu clump%sfound.",
+                       p->numobjects, p->numobjects==1 ? " " : "s ",
+                       p->numclumps,  p->numclumps ==1 ? " " : "s ")<0 )
+            error(EXIT_FAILURE, 0, "%s: asprintf allocation", __func__);
+        }
       gal_timing_report(&t1, msg, 1);
       free(msg);
     }
diff --git a/bin/segment/ui.c b/bin/segment/ui.c
index 5982fc9..648aaf4 100644
--- a/bin/segment/ui.c
+++ b/bin/segment/ui.c
@@ -115,8 +115,6 @@ ui_initialize_options(struct segmentparams *p,
   cp->numthreads         = gal_threads_number();
   cp->coptions           = gal_commonopts_options;
 
-  p->skyval              = NAN;
-  p->stdval              = NAN;
   p->medstd              = NAN;
   p->minstd              = NAN;
   p->maxstd              = NAN;
@@ -224,8 +222,6 @@ parse_opt(int key, char *arg, struct argp_state *state)
 static void
 ui_read_check_only_options(struct segmentparams *p)
 {
-  char *tailptr;
-
   /* If the full area is to be used as a single detection, we can't find
      the S/N value from the un-detected regions, so the user must have
      given the `clumpsnthresh' option. */
@@ -239,28 +235,6 @@ ui_read_check_only_options(struct segmentparams *p)
           "mandatory to provide a signal-to-noise ratio manually",
           UI_KEY_CLUMPSNTHRESH);
 
-  /* See if `--sky' is a filename or a value. When the string is only a
-     number (and nothing else), `tailptr' will point to the end of the
-     string (`\0'). When the string doesn't start with a number, it will
-     point to the start of the string. However, file names might also be
-     things like `1_sky.fits'. In such cases, `strtod' will return `1.0'
-     and `tailptr' will be `_std.fits', so we need to reset `p->stdval' to
-     NaN. */
-  if(p->skyname)
-    {
-      p->skyval=strtod(p->skyname, &tailptr);
-      if(tailptr==p->skyname || *tailptr!='\0')
-        p->skyval=NAN;
-    }
-
-  /* Similar to `--sky' above. */
-  if(p->stdname)
-    {
-      p->stdval=strtod(p->stdname, &tailptr);
-      if(tailptr==p->stdname || *tailptr!='\0')
-        p->stdval=NAN;
-    }
-
   /* If the convolved HDU is given. */
   if(p->convolvedname && p->chdu==NULL)
     error(EXIT_FAILURE, 0, "no value given to `--convolvedhdu'. When the "
@@ -706,15 +680,32 @@ ui_subtract_sky(gal_data_t *in, gal_data_t *sky,
 /* The Sky and Sky standard deviation images can be a `oneelempertile'
    image (only one element/pixel for a tile). So we need to do some extra
    checks on them (after reading the tessellation). */
-static void
+static float
 ui_read_std_and_sky(struct segmentparams *p)
 {
   size_t one=1;
+  char *tailptr;
+  float tmpval, skyval=NAN;
   struct gal_tile_two_layer_params *tl=&p->cp.tl;
   gal_data_t *sky, *keys=gal_data_array_calloc(3);
 
-  /* Read the standard devitaion image (if it isn't a single number). */
-  if(isnan(p->stdval))
+  /* See if the name used for the standard deviation is a filename or a
+     value. When the string is only a number (and nothing else), `tailptr'
+     will point to the end of the string (`\0'). When the string doesn't
+     start with a number, it will point to the start of the
+     string. However, file names might also be things like `1_std.fits'. In
+     such cases, `strtod' will return `1.0' and `tailptr' will be
+     `_std.fits'. Thus the most robust test is to see if `tailptr' is the
+     NULL string character. */
+  tmpval=strtod(p->usedstdname, &tailptr);
+  if(*tailptr=='\0')
+    {
+      /* Allocate the dataset to keep the value and write it in. */
+      p->std=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL, 0,
+                            -1, NULL, NULL, NULL);
+      *(float *)(p->std->array) = tmpval;
+    }
+  else
     {
       /* Make sure a HDU is also given. */
       if(p->stdhdu==NULL)
@@ -736,13 +727,44 @@ ui_read_std_and_sky(struct segmentparams *p)
                     p->usedstdname, p->stdhdu);
     }
 
+  /* When the Standard deviation dataset (not single value) is made by
+     NoiseChisel, it puts three basic statistics of the pre-interpolation
+     distribution of standard deviations in `MEDSTD', `MINSTD' and
+     `MAXSTD'. The `MEDSTD' in particular is most important because it
+     can't be inferred after the interpolations and it can be useful in
+     MakeCatalog later to give a more accurate estimate of the noise
+     level. So if they are present, we will read them here and write them
+     to the STD output (which is created when `--rawoutput' is not
+     given). */
+  if(!p->rawoutput && p->std->size>1)
+    {
+      keys[0].next=&keys[1];
+      keys[1].next=&keys[2];
+      keys[2].next=NULL;
+      keys[0].array=&p->medstd;     keys[0].name="MEDSTD";
+      keys[1].array=&p->minstd;     keys[1].name="MINSTD";
+      keys[2].array=&p->maxstd;     keys[2].name="MAXSTD";
+      keys[0].type=keys[1].type=keys[2].type=GAL_TYPE_FLOAT32;
+      gal_fits_key_read(p->usedstdname, p->stdhdu, keys, 0, 0);
+      if(keys[0].status) p->medstd=NAN;
+      if(keys[1].status) p->minstd=NAN;
+      if(keys[2].status) p->maxstd=NAN;
+      keys[0].name=keys[1].name=keys[2].name=NULL;
+      keys[0].array=keys[1].array=keys[2].array=NULL;
+      gal_data_array_free(keys, 3, 1);
+    }
 
-  /* If a Sky image is given, subtract it from the values and convolved
-     images immediately and free it. */
+  /* Similar to `--std' above. */
   if(p->skyname)
     {
-      /* If its a file, read it into memory. */
-      if( isnan(p->skyval) )
+      tmpval=strtod(p->skyname, &tailptr);
+      if(*tailptr=='\0')
+        {
+          sky=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL, 0, -1,
+                             NULL, NULL, NULL);
+          *(float *)(sky->array) = skyval = tmpval;
+        }
+      else
         {
           /* Make sure a HDU is also given. */
           if(p->skyhdu==NULL)
@@ -762,14 +784,8 @@ ui_read_std_and_sky(struct segmentparams *p)
           ui_check_size(p->input, sky, tl->tottiles, p->inputname, p->cp.hdu,
                         p->skyname, p->skyhdu);
         }
-      else
-        {
-          sky=gal_data_alloc(NULL, GAL_TYPE_FLOAT32, 1, &one, NULL, 0, -1,
-                             NULL, NULL, NULL);
-          *((float *)(sky->array)) = p->skyval;
-        }
 
-      /* Subtract it from the input. */
+      /* Subtract the sky from the input. */
       ui_subtract_sky(p->input, sky, tl);
 
       /* If a convolved image is given, subtract the Sky from that too. */
@@ -778,42 +794,17 @@ ui_read_std_and_sky(struct segmentparams *p)
 
       /* Clean up. */
       gal_data_free(sky);
-      p->skyval=NAN;
     }
 
-
-  /* When the Standard deviation image is made by NoiseChisel, it puts
-     three basic statistics of the pre-interpolation distribution of
-     standard deviations in `MEDSTD', `MINSTD' and `MAXSTD'. The `MEDSTD'
-     in particular is most important because it can't be inferred after the
-     interpolations and it can be useful in MakeCatalog later to give a
-     more accurate estimate of the noise level. So if they are present, we
-     will read them here and write them to the STD output (which is created
-     when `--rawoutput' is not given). */
-  if(!p->rawoutput && p->std)
-    {
-      keys[0].next=&keys[1];
-      keys[1].next=&keys[2];
-      keys[2].next=NULL;
-      keys[0].array=&p->medstd;     keys[0].name="MEDSTD";
-      keys[1].array=&p->minstd;     keys[1].name="MINSTD";
-      keys[2].array=&p->maxstd;     keys[2].name="MAXSTD";
-      keys[0].type=keys[1].type=keys[2].type=GAL_TYPE_FLOAT32;
-      gal_fits_key_read(p->usedstdname, p->stdhdu, keys, 0, 0);
-      if(keys[0].status) p->medstd=NAN;
-      if(keys[1].status) p->minstd=NAN;
-      if(keys[2].status) p->maxstd=NAN;
-      keys[0].name=keys[1].name=keys[2].name=NULL;
-      keys[0].array=keys[1].array=keys[2].array=NULL;
-      gal_data_array_free(keys, 3, 1);
-    }
+  /* Return the sky value (possibly necessary in verbose mode). */
+  return skyval;
 }
 
 
 
 
 
-static void
+static float
 ui_preparations(struct segmentparams *p)
 {
   /* Set the input names. */
@@ -834,7 +825,7 @@ ui_preparations(struct segmentparams *p)
   ui_prepare_tiles(p);
 
   /* Prepare the (optional Sky, and) Sky Standard deviation image. */
-  ui_read_std_and_sky(p);
+  return ui_read_std_and_sky(p);
 }
 
 
@@ -861,6 +852,7 @@ ui_preparations(struct segmentparams *p)
 void
 ui_read_check_inputs_setup(int argc, char *argv[], struct segmentparams *p)
 {
+  float sky;
   char *stdunit;
   struct gal_options_common_params *cp=&p->cp;
 
@@ -908,7 +900,7 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
segmentparams *p)
 
 
   /* Read/allocate all the necessary starting arrays. */
-  ui_preparations(p);
+  sky=ui_preparations(p);
 
 
   /* Let the user know that processing has started. */
@@ -923,19 +915,19 @@ ui_read_check_inputs_setup(int argc, char *argv[], struct 
segmentparams *p)
       /* Sky value information. */
       if(p->skyname)
         {
-          if( isnan(p->skyval) )
+          if( isnan(sky) )
             printf("  - Sky: %s (hdu: %s)\n", p->skyname, p->skyhdu);
           else
-            printf("  - Sky: %g\n", p->skyval);
+            printf("  - Sky: %g\n", sky);
         }
 
       /* Sky Standard deviation information. */
-      stdunit = p->variance ? "variance" : "STD";
-      if(p->std)
+      stdunit = p->variance ? "VAR" : "STD";
+      if(p->std->size>1)
         printf("  - Sky %s: %s (hdu: %s)\n", stdunit, p->usedstdname,
                p->stdhdu);
       else
-        printf("  - Sky %s: %g\n", stdunit, p->stdval);
+        printf("  - Sky %s: %g\n", stdunit, *(float *)(p->std->array) );
 
       /* Convolution information. */
       if(p->convolvedname)
@@ -1026,6 +1018,7 @@ ui_free_report(struct segmentparams *p, struct timeval 
*t1)
   /* Free the allocated arrays: */
   free(p->cp.hdu);
   free(p->cp.output);
+  gal_data_free(p->std);
   gal_data_free(p->input);
   gal_data_free(p->kernel);
   gal_data_free(p->binary);
diff --git a/bin/segment/ui.h b/bin/segment/ui.h
index 79a2cc5..a2e9c8f 100644
--- a/bin/segment/ui.h
+++ b/bin/segment/ui.h
@@ -79,8 +79,10 @@ enum option_keys_enum
   UI_KEY_STD,
   UI_KEY_STDHDU,
   UI_KEY_VARIANCE,
+  UI_KEY_MINIMA,
   UI_KEY_RAWOUTPUT,
   UI_KEY_MINNUMFALSE,
+  UI_KEY_ONLYCLUMPS,
   UI_KEY_GROWNCLUMPS,
   UI_KEY_CHECKSN,
   UI_KEY_CHECKSEGMENTATION,
diff --git a/doc/gnuastro.texi b/doc/gnuastro.texi
index 1f11cb8..5487963 100644
--- a/doc/gnuastro.texi
+++ b/doc/gnuastro.texi
@@ -14809,12 +14809,14 @@ many illustrative figures) is Section 3.2 of
 @url{https://arxiv.org/abs/1505.01664, Akhlaghi and Ichikawa [2015]}.
 
 As a summary, Segment first finds true @emph{clump}s over the
-detections. Clumps are associated with local maxima and extend over the
-neighboring pixels until they reach a local minimum (@emph{river}). Segment
-will use the distribution of clump signal-to-noise ratios over the
-undetected regions as reference to find ``true'' clumps over the
-detections. Using the undetected regions can be disabled by directly giving
-a signal-to-noise ratio to @option{--clumpsnthresh}.
+detections. Clumps are associated with local maxima/minima@footnote{By
+default the maximum is used as the first clump pixel, to define clumps
+based on local minima, use the @option{--minima} option.})  and extend over
+the neighboring pixels until they reach a local minimum/maximum
+(@emph{river}). Segment will use the distribution of clump signal-to-noise
+ratios over the undetected regions as reference to find ``true'' clumps
+over the detections. Using the undetected regions can be disabled by
+directly giving a signal-to-noise ratio to @option{--clumpsnthresh}.
 
 The true clumps are then grown to a certain threshold over the
 detections. Based on the strength of the connections between the grown
@@ -15132,6 +15134,13 @@ fields. Operationally, this is almost identical to 
NoiseChisel's
 @option{--minskyfrac} option (@ref{Detection options}). Please see the
 descriptions there for more.
 
+@item --minima
+Build the clumps based on the local minima, not maxima. By default, clumps
+are built starting from local maxima (see Figure 8 of
+@url{https://arxiv.org/abs/1505.01664, Akhlaghi and Ichikawa
+[2015]}). Therefore, this option can be useful when you are searching for
+true local minima (for example absorption features).
+
 @item -m INT
 @itemx --snminarea=INT
 The minimum area which a clump in the undetected regions should have in
@@ -15181,14 +15190,14 @@ option and visually inspected with 
@option{--checksegmentation}.
 
 @item -v
 @itemx --keepmaxnearriver
-Keep a clump whose maximum flux is 8-connected to a river pixel. By default
-such clumps over detections are considered to be noise and are removed
-irrespective of their brightness (see @ref{Flux Brightness and
-magnitude}). Over large profiles, that sink into the noise very slowly,
-noise can cause part of the profile (which was flat without noise) to
-become a very large and with a very high Signal to noise ratio. In such
-cases, the pixel with the maximum flux in the clump will be immediately
-touching a river pixel.
+Keep a clump whose maximum (minimum if @option{--minima} is called) flux is
+8-connected to a river pixel. By default such clumps over detections are
+considered to be noise and are removed irrespective of their brightness
+(see @ref{Flux Brightness and magnitude}). Over large profiles, that sink
+into the noise very slowly, noise can cause part of the profile (which was
+flat without noise) to become a very large and with a very high Signal to
+noise ratio. In such cases, the pixel with the maximum flux in the clump
+will be immediately touching a river pixel.
 
 @item -s FLT
 @itemx --clumpsnthresh=FLT
@@ -15266,14 +15275,15 @@ definition of clumps and objects, please see Section 
3.2 of
 @url{https://arxiv.org/abs/1505.01664, Akhlaghi and Ichikawa [2015]} and
 @ref{Segmentation options}.
 
-The clumps are ``true'' local maxima and their surrounding pixels until a
-local minimum (caused by noise fluctuations, or another ``true''
-clump). Therefore it may happen that some of the input detections aren't
-covered by clumps at all (very diffuse objects without any strong peak),
-while some objects may contain many clumps. Even in those that have clumps,
-there will be regions that are too diffuse. The diffuse regions (within the
-input detected regions) are given a negative label (-1) to help you
-separate them from the undetected regions (with a value of zero).
+The clumps are ``true'' local maxima (minima if @option{--minima} is
+called) and their surrounding pixels until a local minimum/maximum (caused
+by noise fluctuations, or another ``true'' clump). Therefore it may happen
+that some of the input detections aren't covered by clumps at all (very
+diffuse objects without any strong peak), while some objects may contain
+many clumps. Even in those that have clumps, there will be regions that are
+too diffuse. The diffuse regions (within the input detected regions) are
+given a negative label (-1) to help you separate them from the undetected
+regions (with a value of zero).
 
 Each clump is labeled with respect to its host object. Therefore, if an
 object has three clumps for example, the clumps within it have labels 1, 2
@@ -15320,6 +15330,18 @@ Don't abort Segment after producing the check 
image(s). The usage of this
 option is identical to NoiseChisel's @option{--continueaftercheck} option
 (@ref{NoiseChisel input}). Please see the descriptions there for more.
 
+@item --onlyclumps
+Abort Segment after finding true clumps and don't continue with finding
+options. Therefore, no @code{OBJECTS} extension will be present in the
+output. Each true clump in @code{CLUMPS} will get a unique label, but
+diffuse regions will still have a negative value.
+
+To make a catalog of the clumps, the input detection map (where all the
+labels are one) can be fed into @ref{MakeCatalog} along with the input
+detection map to Segment (that only had a value of @code{1} for all
+detected pixels) with @option{--clumpscat}. In this way, MakeCatalog will
+assume all the clumps belong to a single ``object''.
+
 @item --grownclumps
 In the output @code{CLUMPS} extension, store the grown clumps. If a
 detected region contains no clumps or only one clump, then it will be fully
@@ -21466,10 +21488,10 @@ function will use the given @code{type} to calculate 
where the incremented
 element is located in memory.
 @end deftypefun
 
-@deftypefun size_t gal_data_ptr_dist (void @code{*earlier}, void 
@code{*later}, uint8_t @code{type})
-Return the number of elements between @code{earlier} and @code{later}
-assuming each element has a type defined by @code{type} (for the type
-codes, see @ref{Library data types}).
+@deftypefun size_t gal_data_num_between (void @code{*earlier}, void 
@code{*later}, uint8_t @code{type})
+Return the number of elements (in the given @code{type}) between
+@code{earlier} and @code{later}. For the type codes, see @ref{Library data
+types}).
 @end deftypefun
 
 @deftypefun {void *} gal_data_malloc_array (uint8_t @code{type}, size_t 
@code{size}, const char @code{*funcname}, const char @code{*varname})
@@ -22590,7 +22612,7 @@ Getting arrays (commonly images or cubes) from a file 
into your program or
 writing them after the processing into an output file are some of the most
 common operations. The functions in this section are designed for such
 operations with the known file types. The functions here are thus just
-wrappers around funcitons of lower-level file type functions of this
+wrappers around functions of lower-level file type functions of this
 library, for example @ref{FITS files} or @ref{TIFF files}. If the file type
 of the input/output file is already known, you can use the functions in
 those sections respectively.
@@ -24381,7 +24403,7 @@ must have the same size. When @code{OTHER} is a tile it 
must have the same
 size as @code{IN} and parsing will start from its starting element/pixel.
 Also, the respective allocated blocks of @code{OTHER} and @code{IN} (if
 different) may have different sizes. Using @code{OTHER} (along with
-@code{PARSE_OTHER}), this funciton-like macro will thus enable you to parse
+@code{PARSE_OTHER}), this function-like macro will thus enable you to parse
 and define your own operation on two fixed size regions in one or two
 blocks of memory. In the latter case, they may have different numeric
 datatypes, see @ref{Numeric data types}).
@@ -24997,6 +25019,12 @@ main (void)
 The output will be: @code{2, 0, 1, 3}.
 @end deftypefun
 
+@deftypefun int gal_qsort_index_float_increasing (const void @code{*a}, const 
void @code{*b})
+Similar to @code{gal_qsort_index_float_decreasing}, but will sort the
+indexes such that the values of @code{gal_qsort_index_arr} are in
+increasing order.
+@end deftypefun
+
 
 @deftypefun int gal_qsort_TYPE_increasing (const void @code{*a}, const void 
@code{*b})
 When passed to @code{qsort}, this function will sort an @code{TYPE} array
@@ -25628,7 +25656,19 @@ Although the adjacency matrix as used here is 
symmetric, currently this
 function assumes that it is filled on both sides of the diagonal.
 @end deftypefun
 
-@deftypefun void gal_binary_fill_holes (gal_data_t @code{*input}, int 
@code{connectivity})
+@deftypefun {gal_data_t *} gal_binary_holes_label (gal_data_t @code{*input}, 
int @code{connectivity}, size_t @code{*numholes})
+Label all the holes in the foreground (non-zero elements in input) as
+independent regions. Holes are background regions (zero-valued in input)
+that are fully surrounded by the foreground, as defined by
+@code{connectivity}. The returned dataset has a 32-bit signed integer type
+with the size of the input. All holes in the input will have
+labels/counters greater or equal to @code{1}. The rest of the background
+regions will still have a value of @code{0} and the initial foreground
+pixels will have a value of @code{-1}. The total number of holes will be
+written where @code{numholes} points to.
+@end deftypefun
+
+@deftypefun void gal_binary_holes_fill (gal_data_t @code{*input}, int 
@code{connectivity})
 Fill all the holes (0 valued pixels surrounded by 1 valued pixels) within a
 region of the binary @code{input} dataset. The connectivity of the holes
 can be set with @code{connectivity}. This function currently only works on
diff --git a/doc/release-checklist.txt b/doc/release-checklist.txt
index e6cb40a..dd926a8 100644
--- a/doc/release-checklist.txt
+++ b/doc/release-checklist.txt
@@ -184,9 +184,14 @@ Steps necessary to Package Gnuastro for Debian.
      $ sudo apt-get upgrade
 
  - If this is the first time you are packaging on this system, you will
-   need to install the following programs:
-
-     $ sudo apt-get install devscripts pbuilder pristine-tar git quilt lintian
+   need to install the following programs. The first group of packages are
+   general for package building, and the second are only for Gnuastro.
+
+     $ sudo apt-get install ssh devscripts pbuilder pristine-tar git quilt \
+                            lintian lzip emacs
+     $ sudo apt-get install debhelpler ghostscript libcfitsio-dev \
+                            libtool-bin libgsl0-dev libjpeg-dev   \
+                            libtiff-dev libgit2-dev wcslib-dev
      $ sudo pbuilder create
      $ emacs ~/.devscripts
 
@@ -245,7 +250,8 @@ Steps necessary to Package Gnuastro for Debian.
    changed to an `underscore' and an `orig' is added), then go into the
    cloned directory.
 
-     $ ln -s gnuastro-$ver-XXXX.tar.gz gnuastro_$ver.orig.tar.gz
+     $ mv gnuastro-$ver-XXXX.tar.gz      gnuastro_$ver.orig.tar.gz
+     $ mv gnuastro-$ver-XXXX..tar.gz.sig gnuastro_$ver.orig.tar.gz.asc
      $ cd gnuastro
 
 
@@ -267,7 +273,7 @@ Steps necessary to Package Gnuastro for Debian.
      $ git commit -m "Upstream Gnuastro $ver"
      $ git tag upstream/$ver
      $ pristine-tar commit ../gnuastro_$ver.orig.tar.gz          \
-                    -s ../gnuastro-$ver.tar.gz.sig
+                    -s ../gnuastro_$ver.orig.tar.gz.asc
 
 
  - We are done with the `upstream' and `pristine-tar' branches and can
diff --git a/lib/binary.c b/lib/binary.c
index 6df7026..39369c9 100644
--- a/lib/binary.c
+++ b/lib/binary.c
@@ -661,6 +661,82 @@ binary_make_padded_inverse(gal_data_t *input, gal_data_t 
**outtile)
 
 
 
+gal_data_t *
+gal_binary_holes_label(gal_data_t *input, int connectivity,
+                       size_t *numholes)
+{
+  size_t d;
+  int32_t *lab;
+  gal_data_t *inv, *tile, *holelabs=NULL;
+
+  /* A small sanity check. */
+  if( input->type != GAL_TYPE_UINT8 )
+    error(EXIT_FAILURE, 0, "%s: input must have `uint8' type, but its "
+          "input dataset has `%s' type", __func__,
+          gal_type_name(input->type, 1));
+
+
+  /* Make the inverse image. */
+  inv=binary_make_padded_inverse(input, &tile);
+
+
+  /* Label the holes. Recall that the first label is just the undetected
+     regions, so we should subtract that from the total number.*/
+  *numholes=gal_binary_connected_components(inv, &holelabs, connectivity);
+  *numholes -= 1;
+
+
+  /* Any pixel with a label larger than 1 is a hole in the input image and
+     we should invert the respective pixel. To do it, we'll use the tile
+     that was defined before, just change its block and array.*/
+  tile->array=gal_tile_block_relative_to_other(tile, holelabs);
+  tile->block=holelabs; /* has to be after correcting `tile->array'. */
+
+
+  /* The type of the tile is already known (it is `int32_t') and we have no
+     output/other, so we'll just put `int' as a place-holder. In this way
+     we can avoid the switch statement of GAL_TILE_PARSE_OPERATE, and
+     directly use the workhorse macro `GAL_TILE_PO_OISET'. */
+  lab=(holelabs)->array;
+  GAL_TILE_PO_OISET(int32_t, int, tile, NULL, 0, 0, {
+      *lab++ = ( *i
+                 ? ( *i==1
+                     ? 0        /* Originally, was background. */
+                     : *i-1 )   /* Real label: -1 (background has 1). */
+                 : -1 );        /* Originally, was foreground. */
+    });
+
+
+  /* Clean up */
+  tile->array=NULL;
+  gal_data_free(inv);
+  gal_data_free(tile);
+
+
+  /* Correct the sizes of the hole labels array. We have already filled the
+     from the start, effectively removing the paddings. Therefore, ee will
+     just correct the sizes and we won't bother actually re-allocating the
+     array size in memory. According to the GNU C library's description
+     after `realloc': "In several allocation implementations, making a
+     block smaller sometimes necessitates copying it, so it can fail if no
+     other space is available.". The extra padding is only 2 pixels wide,
+     thus, the extra space is negligible compared to the actual array. So
+     it isn't worth possibly having to copy the whole array to another
+     location. Later, when we free the space, the kernel knows how much the
+     allocated size is. */
+  for(d=0;d<input->ndim;++d)
+    holelabs->dsize[d] = input->dsize[d];
+  holelabs->size=input->size;
+
+
+  /* Return the number of holes.  */
+  return holelabs;
+}
+
+
+
+
+
 /* Fill all the holes in an input unsigned char array.
 
    The basic method is this:
@@ -684,7 +760,7 @@ binary_make_padded_inverse(gal_data_t *input, gal_data_t 
**outtile)
       Any pixel with a label larger than 1, is therefore a bounded
       hole that is not 8-connected to the rest of the holes.  */
 void
-gal_binary_fill_holes(gal_data_t *input, int connectivity, size_t maxsize)
+gal_binary_holes_fill(gal_data_t *input, int connectivity, size_t maxsize)
 {
   uint8_t *in;
   uint32_t *i, *fi;
diff --git a/lib/blank.c b/lib/blank.c
index 11cbd6b..a3ebc19 100644
--- a/lib/blank.c
+++ b/lib/blank.c
@@ -154,7 +154,7 @@ gal_blank_is(void *pointer, uint8_t type)
   /* Control should not reach here, so print an error if it does, then
      return a 0 (just to avoid compiler warnings). */
   error(EXIT_FAILURE, 0, "%s: a bug! Please contact us at %s to address the "
-        "problem. Control should not reach the end of this funciton",
+        "problem. Control should not reach the end of this function",
         __func__, PACKAGE_BUGREPORT);
   return 0;
 }
diff --git a/lib/data.c b/lib/data.c
index 9317b62..58f03d8 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -109,10 +109,10 @@ gal_data_ptr_increment(void *pointer, size_t increment, 
uint8_t type)
 
 
 
-/* Find the distance between two void pointers with a given type. See the
-   explanations before `gal_data_ptr_increment'. */
+/* Find the number of values between two void pointers with a given
+   type. See the explanations before `gal_data_ptr_increment'. */
 size_t
-gal_data_ptr_dist(void *earlier, void *later, uint8_t type)
+gal_data_num_between(void *earlier, void *later, uint8_t type)
 {
   char *e=(char *)earlier, *l=(char *)later;
   return (l-e)/gal_type_sizeof(type);
diff --git a/lib/gnuastro/binary.h b/lib/gnuastro/binary.h
index 4ae9357..5766123 100644
--- a/lib/gnuastro/binary.h
+++ b/lib/gnuastro/binary.h
@@ -97,8 +97,12 @@ gal_binary_connected_adjacency_matrix(gal_data_t *adjacency,
 /*********************************************************************/
 /*****************            Fill holes          ********************/
 /*********************************************************************/
+gal_data_t *
+gal_binary_holes_label(gal_data_t *input, int connectivity,
+                       size_t *numholes);
+
 void
-gal_binary_fill_holes(gal_data_t *input, int connectivity, size_t maxsize);
+gal_binary_holes_fill(gal_data_t *input, int connectivity, size_t maxsize);
 
 
 
diff --git a/lib/gnuastro/data.h b/lib/gnuastro/data.h
index c6332de..2e0aeee 100644
--- a/lib/gnuastro/data.h
+++ b/lib/gnuastro/data.h
@@ -239,7 +239,7 @@ void *
 gal_data_ptr_increment(void *pointer, size_t increment, uint8_t type);
 
 size_t
-gal_data_ptr_dist(void *earlier, void *later, uint8_t type);
+gal_data_num_between(void *earlier, void *later, uint8_t type);
 
 void *
 gal_data_malloc_array(uint8_t type, size_t size, const char *funcname,
diff --git a/lib/gnuastro/label.h b/lib/gnuastro/label.h
index e73b7d8..d494588 100644
--- a/lib/gnuastro/label.h
+++ b/lib/gnuastro/label.h
@@ -60,7 +60,8 @@ __BEGIN_C_DECLS  /* From C++ preparations */
 /* Functions. */
 size_t
 gal_label_oversegment(gal_data_t *input, gal_data_t *indexs,
-                      gal_data_t *label, size_t *topinds);
+                      gal_data_t *label, size_t *topinds,
+                      int min0_max1);
 
 void
 gal_label_grow_indexs(gal_data_t *labels, gal_data_t *indexs, int withrivers,
diff --git a/lib/gnuastro/qsort.h b/lib/gnuastro/qsort.h
index 5daa693..2b20876 100644
--- a/lib/gnuastro/qsort.h
+++ b/lib/gnuastro/qsort.h
@@ -55,7 +55,8 @@ extern float *gal_qsort_index_arr;
 int
 gal_qsort_index_float_decreasing(const void * a, const void * b);
 
-
+int
+gal_qsort_index_float_increasing(const void * a, const void * b);
 
 
 
diff --git a/lib/label.c b/lib/label.c
index 538f704..16178a7 100644
--- a/lib/label.c
+++ b/lib/label.c
@@ -54,7 +54,8 @@ along with Gnuastro. If not, see 
<http://www.gnu.org/licenses/>.
 */
 size_t
 gal_label_oversegment(gal_data_t *input, gal_data_t *indexs,
-                      gal_data_t *label, size_t *topinds)
+                      gal_data_t *label, size_t *topinds,
+                      int min0_max1)
 {
   size_t ndim=input->ndim;
 
@@ -101,7 +102,9 @@ gal_label_oversegment(gal_data_t *input, gal_data_t *indexs,
      defined as static in `gnuastro/qsort.h') */
   gal_qsort_index_arr=input->array;
   qsort(indexs->array, indexs->size, sizeof(size_t),
-        gal_qsort_index_float_decreasing);
+        min0_max1
+        ? gal_qsort_index_float_decreasing
+        : gal_qsort_index_float_increasing );
 
 
   /* Initialize the region we want to over-segment. */
diff --git a/lib/qsort.c b/lib/qsort.c
index 6e6cd70..9800b5c 100644
--- a/lib/qsort.c
+++ b/lib/qsort.c
@@ -40,6 +40,14 @@ gal_qsort_index_float_decreasing(const void * a, const void 
* b)
   return (tb > ta) - (tb < ta);
 }
 
+int
+gal_qsort_index_float_increasing(const void * a, const void * b)
+{
+  float ta=gal_qsort_index_arr[ *(size_t *)a ];
+  float tb=gal_qsort_index_arr[ *(size_t *)b ];
+  return (ta > tb) - (ta < tb);
+}
+
 
 
 
diff --git a/lib/statistics.c b/lib/statistics.c
index 8d2673c..2d0c0d7 100644
--- a/lib/statistics.c
+++ b/lib/statistics.c
@@ -2015,7 +2015,7 @@ gal_statistics_sigma_clip(gal_data_t *input, float 
multip, float param,
 
 
 #if 0
-/* Using the cumulative distribution function this funciton will
+/* Using the cumulative distribution function this function will
    remove outliers from a dataset. */
 void
 gal_statistics_remove_outliers_flat_cdf(float *sorted, size_t *outsize)
diff --git a/lib/tiff.c b/lib/tiff.c
index 450e55f..05526d3 100644
--- a/lib/tiff.c
+++ b/lib/tiff.c
@@ -267,7 +267,7 @@ tiff_read_contig_strip_data(TIFF *tif, char *filename, 
size_t dir,
   size_t ostart=0;
   unsigned char *buf;
   uint32_t row, rowsperstrip = (uint32_t)-1;
-  size_t nrow, scanline=TIFFScanlineSize(tif);
+  size_t nrow=0, scanline=TIFFScanlineSize(tif);
   uint32 h=out->ndim==2?out->dsize[0]:out->dsize[1];
 
   /* Allocate the buffer. */
diff --git a/lib/tile.c b/lib/tile.c
index b46c002..71c036b 100644
--- a/lib/tile.c
+++ b/lib/tile.c
@@ -65,7 +65,7 @@ gal_tile_start_coord(gal_data_t *tile, size_t *start_coord)
   else
     {
       /* Calculate the coordinates of the first pixel of the tile. */
-      ind = gal_data_ptr_dist(block->array, tile->array, block->type);
+      ind = gal_data_num_between(block->array, tile->array, block->type);
       gal_dimension_index_to_coord(ind, ndim, block->dsize, start_coord);
     }
 }
@@ -97,7 +97,7 @@ gal_tile_start_end_coord(gal_data_t *tile, size_t *start_end, 
int rel_block)
 
   /* Get the starting index. Note that for the type we need the allocated
      block dataset and can't rely on the tiles. */
-  start_ind=gal_data_ptr_dist(block->array, tile->array, block->type);
+  start_ind=gal_data_num_between(block->array, tile->array, block->type);
 
   /* Get the coordinates of the starting point relative to the allocated
      block. */
@@ -108,7 +108,7 @@ gal_tile_start_end_coord(gal_data_t *tile, size_t 
*start_end, int rel_block)
   if(host!=block)
     {
       /* Get the host's starting coordinates. */
-      start_ind=gal_data_ptr_dist(block->array, host->array, block->type);
+      start_ind=gal_data_num_between(block->array, host->array, block->type);
 
       /* Temporarily put the host's coordinates in the place held for the
          ending coordinates. */
@@ -145,7 +145,8 @@ gal_tile_start_end_ind_inclusive(gal_data_t *tile, 
gal_data_t *work,
   /* The starting index can be found from the distance of the `tile->array'
      pointer and `block->array' pointer. IMPORTANT: with the type of the
      block array.  */
-  start_end_inc[0]=gal_data_ptr_dist(block->array, tile->array, block->type);
+  start_end_inc[0]=gal_data_num_between(block->array, tile->array,
+                                        block->type);
 
 
   /* To find the end index, we need to know the coordinates of the starting
@@ -515,8 +516,9 @@ gal_tile_block_relative_to_other(gal_data_t *tile, 
gal_data_t *other)
 {
   gal_data_t *block=gal_tile_block(tile);
   return gal_data_ptr_increment(other->array,
-                                gal_data_ptr_dist(block->array,
-                                                  tile->array, block->type),
+                                gal_data_num_between(block->array,
+                                                     tile->array,
+                                                     block->type),
                                 other->type);
 }
 
diff --git a/lib/wcs.c b/lib/wcs.c
index 070fb9a..3d12fea 100644
--- a/lib/wcs.c
+++ b/lib/wcs.c
@@ -280,7 +280,7 @@ gal_wcs_on_tile(gal_data_t *tile)
       tile->wcs=gal_wcs_copy(block->wcs);
 
       /* Find the coordinates of the tile's starting index. */
-      start_ind=gal_data_ptr_dist(block->array, tile->array, block->type);
+      start_ind=gal_data_num_between(block->array, tile->array, block->type);
       gal_dimension_index_to_coord(start_ind, ndim, block->dsize, coord);
 
       /* Correct the copied WCS structure. Note that crpix is indexed in



reply via email to

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