Skip to content

Instantly share code, notes, and snippets.

@ra-tolson
Last active September 6, 2019 16:47
Show Gist options
  • Save ra-tolson/8884c323f49d07eecbf243a299c0b88c to your computer and use it in GitHub Desktop.
Save ra-tolson/8884c323f49d07eecbf243a299c0b88c to your computer and use it in GitHub Desktop.
Gippy 1.0 Conversion Guide

Gippy 1.0 Conversion Guide for GIPS

API docs more or less here: https://gippy.readthedocs.io/en/latest/quickstart.html

The diffs here mostly represent actual changes to gips code for PR #401. The conversion wasn't perfect; see See Missing or Regressed Features below.

Many of the changes followed a regular pattern of naming changes. Classes are still in CamelCase. Methods and functions all changed to python_case. Examples:

- v = GeoWhatever(*args).GetSomeValue()
+ v = GeoWhatever(*args).some_value()   # getters lose their 'Get'
- GeoWhatever(*args).SetSomeValue(v)
+ GeoWhatever(*args).set_some_value(v)  # setters retain the 'set_'

Changes to Constants

The constants used to specify data types (gippy.GDT_SomeType) are gone; just use strings as you would with numpy:

-            imgout = gippy.GeoImage(fout, img, gippy.GDT_Float32, 2)
+            imgout = gippy.GeoImage.create_from(img, fout, 2, 'float32')

Get & Set Verbosity

Don't call gippy, call utils.verbosity; this way gips tracking its own verbosity is future-proofed:

- v = gippy.Options.verbose()
+ v = utils.verbosity()
- gippy.Options.SetVerbose(args.verbose)
+ utils.verbosity(args.verbose)

Other Gippy Utility Code

Get & set gippy options mostly as before:

-            os.putenv(
-                'GDAL_NUM_THREADS',
-                str(int(gippy.Options.NumCores()))
-            )
+            os.putenv('GDAL_NUM_THREADS', str(int(gippy.Options.cores())))
# in parser code:
     if 'format' in args:
-        gippy.Options.SetDefaultFormat(args.format)
+        gippy.Options.set_defaultformat(args.format)
     if 'chunksize' in args:
-        gippy.Options.SetChunkSize(args.chunksize)
+        gippy.Options.set_chunksize(args.chunksize)
     if 'numprocs' in args:
-        gippy.Options.SetNumCores(args.numprocs)
+        gippy.Options.set_cores(args.numprocs)

gippy.Recti is renamed to Chunks but isn't accessible, present workaround:

# setup
-        roi = gippy.Recti(pixx - 1, pixy - 1, 3, 3)
+        x0, y0, x1, y1 = pixx - 1, pixy - 1, pixx + 2, pixy + 2
# usage - note performance hit due to larger read:
-            vals = img[0].Read(roi).squeeze()
+            vals = img[0].read()[x0:x1,y0:y1].squeeze()
-            variances = img[1].Read(roi)
+            variances = img[1].read()[x0:x1,y0:y1]
# you can also:
 import gippy
+# temporary hack because gippy deletes gippy.gippy from its module scope
+gippy.gippy = sys.modules['gippy.gippy']
# then in working code, use it as a drop-in replacement for Recti:
-        ch = gippy.Recti(chunk[0], chunk[1], chunk[2], chunk[3])
+        ch = gippy.gippy.Chunk(chunk[0], chunk[1], chunk[2], chunk[3])

gippy.algorithms

Indices call changed radically. One call used to create multiple index product files. Now it assumes you want to put many indices layered into the same file, so we have to work around that. Full loop given for context:

# from landsatData._process_indices:
-        gippy_input = {} # map prod types to temp output filenames for feeding to gippy
-        tempfps_to_ptypes = {} # map temp output filenames to prod types, for AddFile
-        for prod_type, pt_split in indices.items():
-            temp_fp = self.temp_product_filename(sensor, prod_type)
-            gippy_input[pt_split[0]] = temp_fp
-            tempfps_to_ptypes[temp_fp] = prod_type
-
-        prodout = Indices(image, gippy_input, metadata) # used to call once
-
-        for temp_fp in prodout.values():
+        verbose_out("Starting on {} indices: {}".format(len(indices), indices.keys()), 2)
+        for prod_and_args, split_p_and_a in indices.items():
+            verbose_out("Starting on {}".format(prod_and_args), 3)
+            temp_fp = self.temp_product_filename(sensor, prod_and_args)
+            # indices() assumes many indices per file; we just want one
+            imgout = algorithms.indices(image, [split_p_and_a[0]], temp_fp)
+            imgout.add_meta(metadata)
             archived_fp = self.archive_temp_path(temp_fp)
-            self.AddFile(sensor, tempfps_to_ptypes[temp_fp], archived_fp)
+            self.AddFile(sensor, prod_and_args, archived_fp)

Fmask is a simple spelling change

# difference in import isn't significant here, just refactoring:
-                        imgout = Fmask(reflimg, fname, tolerance, dilation)
+                        imgout = algorithms.fmask(reflimg, fname, tolerance, dilation)

Linear transform is also a simple spelling change but segfaults for gippy 1.0:

-                        imgout = LinearTransform(tmpimg, fname, arr)
+                        imgout = algorithms.linear_transform(tmpimg, fname, arr)

The cookie cutter call cas reorganized arguments:

# note alltouch is removed because it's an AGS-gippy feature only:
-                        CookieCutter(
-                            images, self.spatial.site, fout, res[0], res[1],
-                            crop, interpolation, {}, alltouch,
-                        )
+                        # "" == default to the projection used by the GeoFeature self.spatial.site
+                        algorithms.cookie_cutter(images, fout, self.spatial.site, crop, "",
+                                                 res[0], res[1], interpolation)

GeoImage

For more cases & info see https://gippy.readthedocs.io/en/latest/quickstart.html#working-with-images

Constructors & Factories

The GeoImages factory is gone but replaced trivially:

-                    images = gippy.GeoImages(filenames)
+                    images = [gippy.GeoImage(f) for f in filenames]

The four-argument constructor is a factory now:

-        imgout = gippy.GeoImage(ofname, img, dtype, len(bands))
+        imgout = gippy.GeoImage.create_from(tmp, img, len(bands), dtype)

The more-than-four arugment constrctor is also a factory now; note MANY arguments defaulted here:

-            imgout = gippy.GeoImage(temp_fp, xsz, ysz, 1, dtype)
+            imgout = gippy.GeoImage.create(temp_fp, xsz, ysz, 1,
+                                           dtype=str(data.dtype))

methods

Several calls are just simple renames:

# metadata
-        imgout.SetMeta(pmeta)
+        imgout.add_meta(pmeta)
# band name
-            imgout.SetBandName(str(b), i + 1)
+            imgout.set_bandname(str(b), i + 1)
# image filename & basename
-        prodout[key] = imgout.Filename()
+        prodout[key] = imgout.filename()
-                            VerboseOut('  %s' % (img.Basename()), 2)
+                            verbose_out('  %s' % (img.basename()), 2)
# gain
-        imgout.SetGain(gain)
+        imgout.set_gain(gain)
# offset
-        imgout.SetOffset(offset)
+        imgout.set_offset(offset)
# nodata
-            imgout.SetNoData(-32768)
+            imgout.set_nodata(-32768)
-            vals[numpy.where(vals == img[0].NoDataValue())] = numpy.nan
+            vals[numpy.where(vals == img[0].nodata())] = numpy.nan
# affine
-            imgout.SetAffine(geo)
+            imgout.set_affine(geo)
# projection
-            imgout.SetProjection(PROJ)
+            imgout.set_srs(PROJ)
-    vecname = transform(vector.Filename(), img.Projection())
+    vecname = transform(vector.filename(), img.srs())
# Process renamed to save
-                        abimg.Process()
+                        abimg.save()
-                        gippy.GeoImage(fin).Process(fout)
+                        gippy.GeoImage(fin).save(fout)
# read & return data as a numpy array; but see below for important caveat:
-                        qadata = qaimg.Read()
+                        qadata = qaimg.read()
# compute mean
-            img.Mean(imgout[0])
+            img.mean(imgout[0])
# masking
-    img.AddMask(mask[0]).Process().ClearMasks()
+    img.add_mask(mask[0]).save(img.filename()).clear_masks()
# name seems unusually different but implementation is believed to be identical:
-                        tmpimg.PruneBands(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'])
+                        tmpimg.select(['BLUE', 'GREEN', 'RED', 'NIR', 'SWIR1', 'SWIR2'])
# iteration:  Use len(img) instead of img.NumBands():
-            for band in range(0, img.NumBands()):
+            for band in range(len(img)):
# But for some reason you can also (note images[0] is a GeoImage here): 
+    for b in range(0, images[0].nbands()):

Color table support is a special case. It seems incomplete in gippy 1.0:

+        # TODO gippy 1.0 supports add_colortable and clear_colortable but there's no way to
+        # get the colortable, and CopyColorTable is no longer supported; what's needed is:
+        # imgout[b].add_colortbale(images[0][b].colortable())
+    # original was:
+    # imgout.CopyColorTable(images[0])
+    verbose_out("Not copying color table to {};"
+                " not supported by gippy 1.0".format(os.path.basename(outfile)), 2)

GeoRaster

In gips our use case is entirely covered by simple renames:

# write
-            imgout[i].Write(arr.astype(npdtype))
+            imgout[i].write(arr.astype(npdtype))
# read
-                data = img[band].Read()
+                data = img[band].read()
# getters (presumably setters follow the pattern)
-                mask = img[band].DataMask()
+                mask = img[band].data_mask()
-    nd = images[0][0].NoDataValue()
-    srs = images[0].Projection()
+    nd = images[0][0].nodata()
+    srs = images[0].srs()
-                            [(reflimg[band].Resolution().x(),
+                            reflimg[b].resolution() for b in (a_obj.visbands + a_obj.lwbands)))
-            color = rad_image[i].Description()
+            color = rad_image[i].description()
# metadata, getting and setting; there's a missing method but it's trivially
# worked around:
-    for b in range(0, images[0].NumBands()):
-        imgout[b].CopyMeta(images[0][b])
+    for b in range(0, images[0].nbands()):
+        imgout[b].add_meta(images[0][b].meta())

GeoVector

Our use of GeoVector is simple enough that simple method re-spelling is sufficient:

# Several getters:
-            self.feature = (feature.Filename(), feature.LayerName(), feature.FID())
+            self.feature = (feature.filename(), feature.layer_name(), feature.fid())
-            self.sitename = feature.Basename()
+            self.sitename = feature.basename()
-        srs = osr.SpatialReference(vector.Projection())
+        srs = osr.SpatialReference(vector.srs())
-        e = utils.open_vector(cls.get_setting('tiles'), cls._tile_attribute)[tileid].Extent()
+        e = utils.open_vector(cls.get_setting('tiles'), cls._tile_attribute)[tileid].extent()
# setting the primary key:
-        vector.SetPrimaryKey(key)
+        vector.set_primary_key(key)

Missing or Regressed Features

These features are warned about or else raise NotImplementedErrors, and only affect certain products or options for gips commands:

  • GeoImage(...).read() always returns an nparray of 'float64' regardless of typing info saved to the GeoImage beforehand. read_raw() seems to do otherwise but isn't exposed to python.
  • GeoImage(...).SetUnits() is not available.
  • gippy.gippy is deleted by gippy at import time; see problem related to Recti above.
  • algorithms.linear_transform segfaults, breaking landsat's tcap product.
  • algorithms.acca has an array IndexError, breaking landsat's acca product.
  • algorithms.cookie_cutter segfaults when crop=True; error message just prior: Error creating /tmp/zs/zonalsummary/0/1970001_user_ukwn0.tifAttempt to create -2668x284 dataset is illegal,sizes must be larger than zero. Segmentation fault (core dumped)
  • color table support is incomplete, causing minor feature loss to gips_project, whose output files presumably won't have color tables.
  • AGS-gippy features aren't present in gippy 1.0, so there is loss of function:
    • alltouch, an option for algorithms.cookie_cutter, is absent, so that option doesn't function for gips_project.
    • gips.algorithms.AddShadowMask is a also absent, thus landsat's bqashadow product can't be generated.
@ircwaves
Copy link

gippy.Recti workaround is gippy.gippy.Chunk

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment