hycore

A functional data structure for creating, managing and analysing hyperspectral drillcore datasets using python and hylite.

  1"""
  2A functional data structure for creating, managing and analysing hyperspectral drillcore datasets using python and hylite.
  3"""
  4
  5from .coreshed import *
  6
  7import os
  8from pathlib import Path
  9import shutil
 10
 11sandbox = None
 12
 13def loadShed( path ):
 14    """
 15    Load a shed Object
 16    :param path: Open the specified Shed.
 17    :return: A hycore.Shed instance.
 18    """
 19
 20    # check shed exists and is a directory
 21    pth = os.path.splitext(path)[0] + ".shed"
 22    if not os.path.exists(pth) and os.path.isdir(pth):
 23        raise FileNotFoundError("%s is not a valid hycore.Shed" % path)
 24    name = os.path.basename( os.path.splitext( path )[0] )
 25
 26    # load header (if one exists)
 27    from hylite import io
 28    header = None
 29    hdr = os.path.splitext(path)[0] + ".hdr"
 30    if os.path.exists(hdr):
 31        header = io.loadHeader( hdr )
 32
 33    # create and return Shed instance
 34    from hycore.coreshed import Shed
 35    S = Shed(name, os.path.dirname( pth ) , header )
 36
 37    # load holes and boxes to ensure correct dtype (Hole or Box, not HyCollection)
 38    _ = S.getBoxes()
 39
 40    return Shed(name, os.path.dirname( pth ) , header )
 41
 42def get_sandbox( fill=False, vis=False, mosaic=False ):
 43    """
 44    Return a sandbox directory on the local file system for reading / writing temporary files.
 45    :param fill: True if a dummy hyperspectral core database should be added to the sandbox directory. If this is
 46                  set, a shed will be returned rather than the directory path.
 47    :param vis: True if .png previews should be generated in the shed.
 48    :param mosaic: True if .png mosiacs should be generated for each drillcore.
 49    :return: A Path defining the sandbox directory or a Shed instance (if fill = True).
 50    """
 51    global sandbox
 52    if sandbox is None:
 53        sandbox = Path( os.path.join(os.getcwd(), 'sandbox') )
 54    os.makedirs( sandbox, exist_ok = True ) # if we are getting it, the sandbox dir should exist!
 55
 56    from hycore.generator import genTray
 57    from hycore.coreshed import Shed
 58
 59    if fill:
 60        # create a dummy coreshed!
 61        S = Shed('eldorado', sandbox)
 62
 63        # add fake holes and data
 64        h1 = [False, False, True]  # True / False are lithology codes
 65        h2 = [True, False, True]
 66        h3 = [False]  # include a hole with only one tray for testing purposes
 67        for h, n, c, b in zip([h1, h2, h3], [4, 5, 4], ['H01', 'H03', 'H02'], [1.0, 0.4, 1.0]):
 68            trays = [genTray(n, l) for l in h]
 69            ids = [i + 1 for i in range(len(h))]
 70            for (timg, A, mask), i in zip(trays, ids):
 71                # add Fenix image
 72                timg.data[..., timg.get_band_index(2180.):timg.get_band_index(
 73                    2210.)] *= b  # adjust brightness of 2200 nm band to provide visual difference between different holes
 74                t = S.addHSI('FENIX', c, '%03d' % i, timg)
 75
 76                # add mask
 77                t.mask = hylite.HyImage(mask.astype(np.uint8))
 78
 79                # add a result
 80                from hylite.analyse import band_ratio
 81                R = band_ratio(t.FENIX, 2230., 2200.)
 82                G = band_ratio(t.FENIX, 2190., 2200.)
 83                B = band_ratio(t.FENIX, 2140., 2160.)
 84                stack = hylite.HyImage(np.clip(np.dstack([(R.data - 1.0) / 0.2,
 85                                                          (G.data - 1.) / 0.2,
 86                                                          (B.data - 1.0) / 0.2]), 0, 1))
 87                stack.data = (stack.data * 255).astype(np.uint8)  # convert to RGB
 88                t.results.BR_Clays = stack
 89
 90                def saveLegend(red, green, blue, path):
 91                    import matplotlib.pyplot as plt
 92                    tr = [np.nan, np.nan, np.nan]
 93                    plt.figure(figsize=(4, 0.5))
 94                    plt.fill(tr, tr, label=red, color='r')
 95                    plt.fill(tr, tr, label=green, color='g')
 96                    plt.fill(tr, tr, label=blue, color='b')
 97                    plt.legend(ncol=3, loc='center')
 98                    plt.axis('off')
 99                    os.makedirs(os.path.dirname(path), exist_ok=True)
100                    plt.tight_layout()
101                    plt.savefig(path, dpi=300)
102                    plt.close()
103
104                saveLegend(r"R= ($\frac{2230}{2200}$)",
105                           r"G= ($\frac{2190}{2200}$)",
106                           r"B= ($\frac{2140}{2160}$)",
107                           os.path.join(t.results.getDirectory(), 'LEG_Clays.png'))
108
109                # add fake image as though from another sensor
110                lwir = timg.copy()
111                lwir.data = 1. - lwir.data
112                lwir.set_wavelengths(timg.get_wavelengths() * 10 - 13000)
113                t = S.addHSI('LWIR', c, '%03d' % i, lwir)
114                t.start = (i - 1) * n
115                t.end = i * n
116                t.save()
117                t.free()
118
119        # add a box that is non-contiguous (has a gap)
120        t = S.addHSI('FENIX', 'H01', '004', timg)
121        t = S.addHSI('LWIR', 'H01', '004', lwir)
122        t.start = 15
123        t.end = 20
124        t.mask = hylite.HyImage(mask.astype(np.uint8))
125        t.results.BR_Clays = stack
126        t.save()
127        t.free()
128        saveLegend(r"R= ($\frac{2230}{2200}$)",
129                   r"G= ($\frac{2190}{2200}$)",
130                   r"B= ($\frac{2140}{2160}$)",
131                   os.path.join(t.results.getDirectory(), 'LEG_Clays.png'))
132
133        if vis:
134            for b in S.getBoxes():
135                b.updateVis(qaqc=False, thumb='FENIX')
136
137        if mosaic:
138            from hycore.templates import unwrap_tray, Template, Canvas, compositeStack
139            for i, h in enumerate(S.getHoles()):
140                # get pole mosaic of core
141                T = h.getTemplate(method='pole', res=2e-3)
142
143                # apply template to generate strips for various products
144                for f in ['FENIX.png', 'LWIR.png', 'BR_Clays.png']:
145                    m = T.apply(f, (0,1,2))
146                    h.results.set(f, m)
147                h.results.save()
148                h.save()
149                h.free()
150
151            # add some example annotations to the final hole
152            h.annotate("Vein 1", "I think there's gold here!", depth_from=0.5, group='Gold')
153            h.annotate("Vein 2", "No gold here.", depth_from=1, depth_to=2, group='Gold')
154            h.annotate("Fault 1", "What a bloody mess!", depth_from=0.5, depth_to=2, group='Faults')
155            h.annotate("Fault 2", "https://en.wikipedia.org/wiki/San_Andreas_Fault",
156                       depth_from=2.1, depth_to=2.1, group='Faults', type='link')
157            h.save()
158
159        S.save()
160        S.free()
161        return S
162    else:
163        return sandbox
164
165
166def set_sandbox( path ):
167    """
168    Set the sandbox directory for hycore to use.
169    :param path: A path to the new sandbox directory
170    :return: None
171    """
172    global sandbox
173    sandbox = sandbox
174
175def empty_sandbox():
176    """
177    Remove the sandbox directory (if it exists).
178    :return: None
179    """
180    shutil.rmtree( get_sandbox() )
def loadShed(path):
14def loadShed( path ):
15    """
16    Load a shed Object
17    :param path: Open the specified Shed.
18    :return: A hycore.Shed instance.
19    """
20
21    # check shed exists and is a directory
22    pth = os.path.splitext(path)[0] + ".shed"
23    if not os.path.exists(pth) and os.path.isdir(pth):
24        raise FileNotFoundError("%s is not a valid hycore.Shed" % path)
25    name = os.path.basename( os.path.splitext( path )[0] )
26
27    # load header (if one exists)
28    from hylite import io
29    header = None
30    hdr = os.path.splitext(path)[0] + ".hdr"
31    if os.path.exists(hdr):
32        header = io.loadHeader( hdr )
33
34    # create and return Shed instance
35    from hycore.coreshed import Shed
36    S = Shed(name, os.path.dirname( pth ) , header )
37
38    # load holes and boxes to ensure correct dtype (Hole or Box, not HyCollection)
39    _ = S.getBoxes()
40
41    return Shed(name, os.path.dirname( pth ) , header )

Load a shed Object

Parameters
  • path: Open the specified Shed.
Returns

A hycore.Shed instance.

def get_sandbox(fill=False, vis=False, mosaic=False):
 43def get_sandbox( fill=False, vis=False, mosaic=False ):
 44    """
 45    Return a sandbox directory on the local file system for reading / writing temporary files.
 46    :param fill: True if a dummy hyperspectral core database should be added to the sandbox directory. If this is
 47                  set, a shed will be returned rather than the directory path.
 48    :param vis: True if .png previews should be generated in the shed.
 49    :param mosaic: True if .png mosiacs should be generated for each drillcore.
 50    :return: A Path defining the sandbox directory or a Shed instance (if fill = True).
 51    """
 52    global sandbox
 53    if sandbox is None:
 54        sandbox = Path( os.path.join(os.getcwd(), 'sandbox') )
 55    os.makedirs( sandbox, exist_ok = True ) # if we are getting it, the sandbox dir should exist!
 56
 57    from hycore.generator import genTray
 58    from hycore.coreshed import Shed
 59
 60    if fill:
 61        # create a dummy coreshed!
 62        S = Shed('eldorado', sandbox)
 63
 64        # add fake holes and data
 65        h1 = [False, False, True]  # True / False are lithology codes
 66        h2 = [True, False, True]
 67        h3 = [False]  # include a hole with only one tray for testing purposes
 68        for h, n, c, b in zip([h1, h2, h3], [4, 5, 4], ['H01', 'H03', 'H02'], [1.0, 0.4, 1.0]):
 69            trays = [genTray(n, l) for l in h]
 70            ids = [i + 1 for i in range(len(h))]
 71            for (timg, A, mask), i in zip(trays, ids):
 72                # add Fenix image
 73                timg.data[..., timg.get_band_index(2180.):timg.get_band_index(
 74                    2210.)] *= b  # adjust brightness of 2200 nm band to provide visual difference between different holes
 75                t = S.addHSI('FENIX', c, '%03d' % i, timg)
 76
 77                # add mask
 78                t.mask = hylite.HyImage(mask.astype(np.uint8))
 79
 80                # add a result
 81                from hylite.analyse import band_ratio
 82                R = band_ratio(t.FENIX, 2230., 2200.)
 83                G = band_ratio(t.FENIX, 2190., 2200.)
 84                B = band_ratio(t.FENIX, 2140., 2160.)
 85                stack = hylite.HyImage(np.clip(np.dstack([(R.data - 1.0) / 0.2,
 86                                                          (G.data - 1.) / 0.2,
 87                                                          (B.data - 1.0) / 0.2]), 0, 1))
 88                stack.data = (stack.data * 255).astype(np.uint8)  # convert to RGB
 89                t.results.BR_Clays = stack
 90
 91                def saveLegend(red, green, blue, path):
 92                    import matplotlib.pyplot as plt
 93                    tr = [np.nan, np.nan, np.nan]
 94                    plt.figure(figsize=(4, 0.5))
 95                    plt.fill(tr, tr, label=red, color='r')
 96                    plt.fill(tr, tr, label=green, color='g')
 97                    plt.fill(tr, tr, label=blue, color='b')
 98                    plt.legend(ncol=3, loc='center')
 99                    plt.axis('off')
100                    os.makedirs(os.path.dirname(path), exist_ok=True)
101                    plt.tight_layout()
102                    plt.savefig(path, dpi=300)
103                    plt.close()
104
105                saveLegend(r"R= ($\frac{2230}{2200}$)",
106                           r"G= ($\frac{2190}{2200}$)",
107                           r"B= ($\frac{2140}{2160}$)",
108                           os.path.join(t.results.getDirectory(), 'LEG_Clays.png'))
109
110                # add fake image as though from another sensor
111                lwir = timg.copy()
112                lwir.data = 1. - lwir.data
113                lwir.set_wavelengths(timg.get_wavelengths() * 10 - 13000)
114                t = S.addHSI('LWIR', c, '%03d' % i, lwir)
115                t.start = (i - 1) * n
116                t.end = i * n
117                t.save()
118                t.free()
119
120        # add a box that is non-contiguous (has a gap)
121        t = S.addHSI('FENIX', 'H01', '004', timg)
122        t = S.addHSI('LWIR', 'H01', '004', lwir)
123        t.start = 15
124        t.end = 20
125        t.mask = hylite.HyImage(mask.astype(np.uint8))
126        t.results.BR_Clays = stack
127        t.save()
128        t.free()
129        saveLegend(r"R= ($\frac{2230}{2200}$)",
130                   r"G= ($\frac{2190}{2200}$)",
131                   r"B= ($\frac{2140}{2160}$)",
132                   os.path.join(t.results.getDirectory(), 'LEG_Clays.png'))
133
134        if vis:
135            for b in S.getBoxes():
136                b.updateVis(qaqc=False, thumb='FENIX')
137
138        if mosaic:
139            from hycore.templates import unwrap_tray, Template, Canvas, compositeStack
140            for i, h in enumerate(S.getHoles()):
141                # get pole mosaic of core
142                T = h.getTemplate(method='pole', res=2e-3)
143
144                # apply template to generate strips for various products
145                for f in ['FENIX.png', 'LWIR.png', 'BR_Clays.png']:
146                    m = T.apply(f, (0,1,2))
147                    h.results.set(f, m)
148                h.results.save()
149                h.save()
150                h.free()
151
152            # add some example annotations to the final hole
153            h.annotate("Vein 1", "I think there's gold here!", depth_from=0.5, group='Gold')
154            h.annotate("Vein 2", "No gold here.", depth_from=1, depth_to=2, group='Gold')
155            h.annotate("Fault 1", "What a bloody mess!", depth_from=0.5, depth_to=2, group='Faults')
156            h.annotate("Fault 2", "https://en.wikipedia.org/wiki/San_Andreas_Fault",
157                       depth_from=2.1, depth_to=2.1, group='Faults', type='link')
158            h.save()
159
160        S.save()
161        S.free()
162        return S
163    else:
164        return sandbox

Return a sandbox directory on the local file system for reading / writing temporary files.

Parameters
  • fill: True if a dummy hyperspectral core database should be added to the sandbox directory. If this is set, a shed will be returned rather than the directory path.
  • vis: True if .png previews should be generated in the shed.
  • mosaic: True if .png mosiacs should be generated for each drillcore.
Returns

A Path defining the sandbox directory or a Shed instance (if fill = True).

def set_sandbox(path):
167def set_sandbox( path ):
168    """
169    Set the sandbox directory for hycore to use.
170    :param path: A path to the new sandbox directory
171    :return: None
172    """
173    global sandbox
174    sandbox = sandbox

Set the sandbox directory for hycore to use.

Parameters
  • path: A path to the new sandbox directory
Returns

None

def empty_sandbox():
176def empty_sandbox():
177    """
178    Remove the sandbox directory (if it exists).
179    :return: None
180    """
181    shutil.rmtree( get_sandbox() )

Remove the sandbox directory (if it exists).

Returns

None