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