<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Russell Rogers</title>
<link>https://russjas.github.io/</link>
<atom:link href="https://russjas.github.io/index.xml" rel="self" type="application/rss+xml"/>
<description>Geoscience and hyperspectral imaging</description>
<generator>quarto-1.10.18</generator>
<lastBuildDate>Sat, 03 Oct 2026 00:00:00 GMT</lastBuildDate>
<item>
  <title>Hyperspectral data is big!</title>
  <dc:creator>Russell Rogers</dc:creator>
  <link>https://russjas.github.io/notes/hyperspectra-data-big.html</link>
  <description><![CDATA[ 




<p>Compared to remote sensing, hyperspectral core scanning produces fairly manageable file sizes.</p>
<p>For a single core box (SWIR data in this example, as that is what I mostly work with):</p>
<table class="caption-top table">
<colgroup>
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
<col style="width: 25%">
</colgroup>
<thead>
<tr class="header">
<th>Dataset</th>
<th>Size</th>
<th>Data type</th>
<th>Format</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Raw data</td>
<td>~400 MB</td>
<td>float32</td>
<td>ENVI</td>
</tr>
<tr class="even">
<td>Cropped reflectance</td>
<td>~170 MB</td>
<td>float32</td>
<td>npy/ENVI</td>
</tr>
<tr class="odd">
<td><em>Derived data</em></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="even">
<td>Smoothed</td>
<td>~170 MB</td>
<td>float32</td>
<td>npy/ENVI</td>
</tr>
<tr class="odd">
<td>Normalised (continuum removed)</td>
<td>~300 MB</td>
<td>float64</td>
<td>npy/ENVI</td>
</tr>
<tr class="even">
<td>Mask, bands, metadata, interpretation images</td>
<td>~10 MB</td>
<td>various</td>
<td>npy, ENVI, jpg, json, xml</td>
</tr>
</tbody>
</table>
<p>But there are a lot of them!</p>
<p>A typical project is 10–12 holes of ~80 boxes each, so call it 1000 boxes for a small to medium project. At ~1 GB per box, that is <strong>~1 TB</strong>, and the derived data accounts for almost half of it.</p>
<p>But it is <em>derived</em> data. Why not just derive it when you need it?</p>
<p>If you have used CoreSpecViewer, you know that I do store it. All of it, for every box. Here is why.</p>
<section id="three-strategies" class="level2">
<h2 class="anchored" data-anchor-id="three-strategies">Three strategies</h2>
<p>A system working with hyperspectral data has three resources to spend:</p>
<ul>
<li><strong>Disk</strong></li>
<li><strong>Time</strong></li>
<li><strong>RAM</strong></li>
</ul>
<p>And there are three ways to handle derived products:</p>
<ol type="1">
<li><strong>Derive on demand.</strong> Compute it when needed, use it, throw it away. Costs time.</li>
<li><strong>Cache in RAM.</strong> Compute everything once at startup and hold it. Costs RAM.</li>
<li><strong>Cache to disk.</strong> Compute once, store it, read it back. Costs disk.</li>
</ol>
<p>Let’s go through them, worst first.</p>
</section>
<section id="cache-in-ram" class="level2">
<h2 class="anchored" data-anchor-id="cache-in-ram">Cache in RAM</h2>
<p>Many of my processes need both the smoothed and the normalised data. We could compute it for a whole hole at startup: a one-time slowdown, then fast iterative work and no wasted disk.</p>
<p>For an 80-box hole at ~300 MB per normalised dataset, that is <strong>24 GB of RAM</strong>, before any algorithm allocates a single intermediate array, and before you meet a hole longer than average.</p>
<p>I do not see a &gt;64 GB machine in my professional near future, never mind &gt;128 GB. An 8 GB laptop is probably standard for the average geo-about-town. So this one is out.</p>
</section>
<section id="derive-on-demand" class="level2">
<h2 class="anchored" data-anchor-id="derive-on-demand">Derive on demand</h2>
<p>This is the option that deserves a proper look. It costs no disk, and its RAM footprint is small, because you only hold one box at a time:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Dataset</th>
<th>Size</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Cropped reflectance</td>
<td>~170 MB</td>
</tr>
<tr class="even">
<td>Smoothed</td>
<td>~170 MB</td>
</tr>
<tr class="odd">
<td>Normalised</td>
<td>~300 MB</td>
</tr>
<tr class="even">
<td><strong>Inputs held in RAM</strong></td>
<td><strong>~640 MB</strong></td>
</tr>
</tbody>
</table>
<p>Add the intermediates of a feature extraction and you are still under 1 GB. That is nothing, so RAM is not the problem here. Time is.</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Derived product</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Smoothing</td>
<td>~1–2 s</td>
</tr>
<tr class="even">
<td>Continuum removal</td>
<td>~10–30 s</td>
</tr>
</tbody>
</table>
<p>Here is the call signature for feature extraction in CoreSpecViewer:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">def</span> Combined_MWL(savgol, savgol_cr, mask, bands, feature, technique<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'QUAD'</span>,</span>
<span id="cb1-2">                 use_width<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">False</span>, cached_arrays<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">None</span>):</span></code></pre></div></div>
<p>It takes <code>savgol</code> (the smoothed reflectance) and <code>savgol_cr</code> (the normalised reflectance). Mask and bands have to be stored regardless. So, starting from cropped reflectance:</p>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Step</th>
<th>Derive on demand</th>
<th>Cached to disk</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Smoothing</td>
<td>~1 s</td>
<td>–</td>
</tr>
<tr class="even">
<td>Continuum removal</td>
<td>~10 s</td>
<td>–</td>
</tr>
<tr class="odd">
<td>Read from disk</td>
<td>–</td>
<td>~1 s</td>
</tr>
<tr class="even">
<td>Feature extraction</td>
<td>~15 s</td>
<td>~15 s</td>
</tr>
<tr class="odd">
<td><strong>Per box</strong></td>
<td><strong>~26 s</strong></td>
<td><strong>~16 s</strong></td>
</tr>
<tr class="even">
<td><strong>Per 80-box hole</strong></td>
<td><strong>~35 min</strong></td>
<td><strong>~21 min</strong></td>
</tr>
<tr class="odd">
<td><strong>Per 10-hole project</strong></td>
<td><strong>~5.8 h</strong></td>
<td><strong>~3.5 h</strong></td>
</tr>
</tbody>
</table>
<p>In this straightforward path, caching saves about 40%, which is real, but a slow feature extraction is still slow.</p>
<p>You will never run a feature extraction <em>once</em>. You pick parameters, look at the result, change a threshold, try a different fitting method, look again. You flick between boxes in the viewer, and you build downhole plots. Every one of those is an access.</p>
<p>Derive on demand pays the derivation cost on <strong>every access</strong>. Caching pays it <strong>once</strong>, and every access after that costs a disk read.</p>
<p>Ten iterations of tuning across one hole means 800 box accesses. At ~11 s of re-derivation each, that is <strong>nearly 2.5 hours spent recomputing data that has not changed</strong>. The cached version spends about 13 minutes reading it back. In exploratory, iterative work, the work this software exists for, the number of accesses explodes and the gap explodes with it.</p>
</section>
<section id="so-disk" class="level2">
<h2 class="anchored" data-anchor-id="so-disk">So, disk</h2>
<p>Disk caching vastly increases the access speed for derived data, but what pushes it over the edge into the absolute preferred option?<br>
Memmapping.</p>
<p>Because everything lives on disk as arrays, CoreSpecViewer can memory-map it. That lets me have a 1 km hole “open” (over 150 GB of data) on an 8 GB RAM machine. Arrays are paged in as they are read and dropped back to the memmap when I am done with them.</p>
<p>You cannot memmap an array that does not exist yet. A whole-hole view built on derive-on-demand would mean deriving the whole hole, which drops us straight back into the RAM problem.</p>
<p>Caching everything looked wasteful when I started, since it nearly doubles the storage. But of the three resources, disk is by far the most abundant and the cheapest. A terabyte costs less than an afternoon of a geologist’s time.</p>
<p>What looked extremely wasteful is actually spending the abundant resource to protect the scarce ones.</p>
</section>
<section id="conclusions" class="level2">
<h2 class="anchored" data-anchor-id="conclusions">“Conclusions”…</h2>
<p><strong>This conclusion depends on my stack.</strong></p>
<p>“You fool!”, I hear you cry, “you wrote it in Python! Of course it is slow!”</p>
<p>You would not be wrong. Derivation could be pushed into compiled kernels, rewritten in another language, made blazingly fast. If continuum removal took one second instead of ten, the access-count argument would shrink a lot and I would revisit this. Maybe the commercial software world has already solved it. But Python gives me too much (NumPy, SciPy, hylite) for me to move away from it, and with this stack, disk wins.</p>
<p>In a nod to the fact disk caching doubles the storage CoreSpecViewer has an archive file type for long-term storage. This is the minimum dataset needed to deterministically reproduce a fully analysed box. Cache everything while you are working, and archive the minimum when you are done. The rehydrate process is the time penalty up-front when you open an archive, then you are back to working iteratively on memmaps.</p>
<p>The <a href="https://www.linkedin.com/posts/russell-j-rogers_hyperspectral-activity-7428891479508451328-QGRn?">Original Linkedin post</a> had some good points made by commenters that are worth reading, especially if you made it all the way through this!</p>


</section>

 ]]></description>
  <category>hyperspectral</category>
  <category>CoreSpecViewer</category>
  <guid>https://russjas.github.io/notes/hyperspectra-data-big.html</guid>
  <pubDate>Sat, 03 Oct 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Hyperspectral core scanning interpretation made easy - sort of!</title>
  <dc:creator>Russell Rogers</dc:creator>
  <link>https://russjas.github.io/notes/hyperspectral-made-easy.html</link>
  <description><![CDATA[ 




<p>Hyperspectral core scanning can be daunting for the average geologist. The file types won’t be something you have used before, you may not even recognise them. You will be looking for jpegs or tiffs, but the chances are you will get a directory of many files with <code>.dat</code>, <code>.bil</code>, or <code>.raw</code> extensions.</p>
<p><a href="https://github.com/Russjas/CoreSpecViewer">CoreSpecViewer</a> simplifies this. It ingests multi-file directories directly: Specim Lumo exports, which it was built for, and other acquisition formats with a little more manual input.</p>
<p>All of the examples in this article are from core scanned by the Alberta Energy Regulator (AER) <a href="https://experience.arcgis.com/experience/1167cc6050f142bdb14a3a6c58e0f584/#data_s=id%3AdataSource_1-186dd8a4977-layer-6%3A724">here</a>.</p>
<p>I have randomly chosen Hole NWG-05-03, box 303.</p>
<p><a href="https://aerccgrsprdmindat02.blob.core.windows.net/core-scanning/HSI/NWG-05-03/NWG-05-03_SWIR.zip"><em>This</em></a> <em>is the hole. It is 13GB of SWIR data, be warned.</em></p>
<section id="opening-raw-data" class="level3">
<h3 class="anchored" data-anchor-id="opening-raw-data">Opening raw data</h3>
<p>CoreSpecViewer exposes a number of data open options through it’s load dialogue.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="hyperspectral-made-easy-ims/open_dialogue.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="The CoreSpecViewer load dialogue."><img src="https://russjas.github.io/notes/hyperspectral-made-easy-ims/open_dialogue.png" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="The CoreSpecViewer load dialogue."></a></p>
</figure>
</div>
<figcaption>The CoreSpecViewer load dialogue.</figcaption>
</figure>
</div>
<p>Six different load modes</p>
<ul>
<li>Open processed dataset</li>
<li>Open hole directory</li>
</ul>
<p>These two refer to CoreSpecViewer’s own created data files, these files are what get saved after you have worked with a scan in the software.</p>
<ul>
<li>Open raw dataset from Lumo output directory</li>
<li>Open raw dataset from individual ENVI files</li>
</ul>
<p>These are for raw data from core scans. CoreSpecViewer will expect <em>at least</em> six files.</p>
<table class="caption-top table">
<colgroup>
<col style="width: 33%">
<col style="width: 33%">
<col style="width: 33%">
</colgroup>
<thead>
<tr class="header">
<th>File</th>
<th>Extension</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><code>&lt;hole_id_box_number&gt;</code></td>
<td>.hdr</td>
<td>Header file for the core scan</td>
</tr>
<tr class="even">
<td><code>&lt;hole_id_box_number&gt;</code></td>
<td>.raw, .bil, .bsq, .bip, etc</td>
<td>Binary file for the core scan data</td>
</tr>
<tr class="odd">
<td>WHITE_<code>&lt;hole_id_box_number&gt;</code></td>
<td>.hdr</td>
<td>Header file for the white reference</td>
</tr>
<tr class="even">
<td>WHITE_<code>&lt;hole_id_box_number&gt;</code></td>
<td>.raw, .bil, .bsq, .bip, etc</td>
<td>Binary file for the white reference</td>
</tr>
<tr class="odd">
<td>DARK_<code>&lt;hole_id_box_number&gt;</code></td>
<td>.hdr</td>
<td>Header file for the dark reference</td>
</tr>
<tr class="even">
<td>DARK_<code>&lt;hole_id_box_number&gt;</code></td>
<td>.raw, .bil, .bsq, .bip, etc</td>
<td>Binary file for the dark reference</td>
</tr>
<tr class="odd">
<td><code>&lt;hole_id_box_number&gt;</code></td>
<td>.xml</td>
<td>metadata file - optional</td>
</tr>
</tbody>
</table>
<p>As I built CoreSpecViewer to work with data from the Specim Lumo acquisition software, clicking “from Lumo output directory” just requires the whole output directory, and all of the file discovery is automated and the metadata is parsed nicely.</p>
<p>If your data was acquired any other way, or your directory structure got mangled, the “from ENVI files” allows you to browse to each required file. The XML will be brute force parsed, but maybe not effectively, and CoreSpecViewer will prompt for the required metadata (hole id, box number, from depth, to depth).</p>
<ul>
<li>Open reflectance data</li>
</ul>
<p>This button allows you to open a core scan that has already been converted to reflectance and stored in an ENVI file. It will also support existing masks (depending on the format).</p>
<ul>
<li>Open archive file</li>
</ul>
<p>This is another file type produced by CoreSpecViewer, the need for which is discussed in this <a href="../notes/hyperspectra-data-big.html">note</a></p>
</section>
<section id="pre-processing-raw-data" class="level3">
<h3 class="anchored" data-anchor-id="pre-processing-raw-data">Pre-processing raw data</h3>
<p>With hyperspectral data, you cannot just open the file and start interpreting the data, that would be far too easy. The cameras themselves will <em>usually</em> handle some geometric corrections, any spectral binning and some other correction before you get any data.<br>
That just leaves correcting the radiance data to reflectance, which is why 6 files are needed.</p>
<p><img src="https://latex.codecogs.com/png.latex?%0AReflectance%20=%20%5Cfrac%7BData-DarkReference%7D%7BWhiteReference-DarkReference%7D%0A"></p>
<p>BUT! CoreSpecViewer handles all of this for you! If you want to see the implementation it is <a href="https://github.com/Russjas/CoreSpecViewer/blob/baa9a60ee1a77c17661bb5322a23ef603d4a61b3/app/spectral_ops/IO.py#L295">here</a></p>
<p>Simply find your directory, or selection of files, click load and voilà</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="hyperspectral-made-easy-ims/uncropped_core.webp" class="lightbox" data-gallery="quarto-lightbox-gallery-2" title="A reflectance corrected core box, at the click of a button"><img src="https://russjas.github.io/notes/hyperspectral-made-easy-ims/uncropped_core.webp" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="A reflectance corrected core box, at the click of a button"></a></p>
</figure>
</div>
<figcaption>A reflectance corrected core box, at the click of a button</figcaption>
</figure>
</div>
<p>As this is python application, all of the details of the reflectance correction performed are in the source and parts of the configuration is adjustable in the UI. All of the configuration is adjustable in the source code.</p>
<p>This raw data can be cropped in the UI, a mask can be created using a variety of methods, and the pre-processing pipeline completed with a few button clicks:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="hyperspectral-made-easy-ims/cropped-and-masked.webp" class="lightbox" data-gallery="quarto-lightbox-gallery-3" title="View of the visualise window after masking tools have been used."><img src="https://russjas.github.io/notes/hyperspectral-made-easy-ims/cropped-and-masked.webp" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="View of the visualise window after masking tools have been used."></a></p>
</figure>
</div>
<figcaption>View of the visualise window after masking tools have been used.</figcaption>
</figure>
</div>
<p>This image is fully interactive, and individual pixel spectra can be examined using mouse clicks.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="hyperspectral-made-easy-ims/pixel-vis.webp" class="lightbox" data-gallery="quarto-lightbox-gallery-4" title="Examine reflectance specrta or continuum-removed spectra"><img src="https://russjas.github.io/notes/hyperspectral-made-easy-ims/pixel-vis.webp" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="Examine reflectance specrta or continuum-removed spectra"></a></p>
</figure>
</div>
<figcaption>Examine reflectance specrta or continuum-removed spectra</figcaption>
</figure>
</div>
<p>So far, so easy, but we haven’t actually learned anything about our core yet.</p>
<p>CoreSpecViewer has a number of tools to actually extract information from the core. I am not familiar with the geology of Alberta, or this drillhole, I am just using free data selected at random so…these interpretations will be less valid than those of a geologist who knows the geology!</p>
</section>
<section id="early-exploration" class="level3">
<h3 class="anchored" data-anchor-id="early-exploration">Early exploration</h3>
<p>I will perform a quick unsupervised clustering to see what variation my core has:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="hyperspectral-made-easy-ims/clustering.webp" class="lightbox" data-gallery="quarto-lightbox-gallery-5" title="K-means output using 5 clusters for 50 iterations"><img src="https://russjas.github.io/notes/hyperspectral-made-easy-ims/clustering.webp" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="K-means output using 5 clusters for 50 iterations"></a></p>
</figure>
</div>
<figcaption>K-means output using 5 clusters for 50 iterations</figcaption>
</figure>
</div>
<p>I used the default settings of 5 clusters for 50 iterations (these will obviously need tweaking with geological knowledge). The image shows that the core is dominated by 3 main mineralogical domains (Classes 3, 2, and 1) with small distinct “blobs” of class 4. But what are the classes? How different are they?</p>
<p>We can interrogate the cluster centres:</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="hyperspectral-made-easy-ims/cluster-centres.webp" class="lightbox" data-gallery="quarto-lightbox-gallery-6" title="Viewing the cluster centres as spectra"><img src="https://russjas.github.io/notes/hyperspectral-made-easy-ims/cluster-centres.webp" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="Viewing the cluster centres as spectra"></a></p>
</figure>
</div>
<figcaption>Viewing the cluster centres as spectra</figcaption>
</figure>
</div>
<p>The spectra for Class 1 (blue line), Class 2 (orange line) and Class 3 (green line) are very similar. There are differences in intensity at shorter wavelengths (which explains the variation in the false colour image), but they all have the same features with varying depths. Class 4 (red line) is different, while it shares the shorter wavelength features as the other classes, it has a distinctly different feature around 2335nm.</p>
<p>Now that we know a little bit more about the spectral variation in the core, we can try to simply match these cluster centres to spectra from the Ecostress library.</p>
<p><em>Note, I didnt save the data, and when I came back to it I had to start from raw, thus a different mask and the clustering came out differently. Don’t be me, the save button is right there!</em></p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="hyperspectral-made-easy-ims/cluster-matches.webp" class="lightbox" data-gallery="quarto-lightbox-gallery-7" title="Cluster centre table after matching against library spectra using three metrics"><img src="https://russjas.github.io/notes/hyperspectral-made-easy-ims/cluster-matches.webp" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="Cluster centre table after matching against library spectra using three metrics"></a></p>
</figure>
</div>
<figcaption>Cluster centre table after matching against library spectra using three metrics</figcaption>
</figure>
</div>
<p>The direct library matches are giving us a mixture of usefully recognised minerals and nonsense. The matches have been performed using three different metrics; Pearson correlation, Spectral Angle Mapping and Modified Spectral Angle Mapping.</p>
<p>Class 4 is confidently identified as Calcite by two of the three metrics, and Classes 2 and 3 are identified as Montmorillonite. Class 1 is identified as elemental Sulfur by the Pearson correlation which is…unlikely. This class is clearly being matched on noise, and doesn’t reach the threshold for identification in the other two methods.</p>
<p>We can also just directly compare each individual spectra against the library directly, using any of the three techniques to produce a mineral map.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="hyperspectral-made-easy-ims/full-lib-minmap.webp" class="lightbox" data-gallery="quarto-lightbox-gallery-8" title="Direct mineral mapping against full library"><img src="https://russjas.github.io/notes/hyperspectral-made-easy-ims/full-lib-minmap.webp" class="img-fluid quarto-figure quarto-figure-center figure-img" style="width:80.0%" alt="Direct mineral mapping against full library"></a></p>
</figure>
</div>
<figcaption>Direct mineral mapping against full library</figcaption>
</figure>
</div>
<p>Again a mixture of usefully recognised minerals and nonsense.</p>
</section>
<section id="take-away" class="level3">
<h3 class="anchored" data-anchor-id="take-away">Take-Away</h3>
<p>In under 10 minutes, without writing code, we can open, correct and interpret hyperspectral core scanning data, easily!</p>
<p>I can <em>confidently</em> say that there is <em>probably</em> some carbonate in discrete areas and the rest is <em>probably</em> some kind of clay or mica, and the key scientific conclusion in everything ever done: <strong>Further work is needed</strong>.</p>
<p>To go further, and be more confident in your interpretations you will need to;</p>
<ul>
<li>examine the individual features (tools exist in CoreSpecViewer),</li>
<li>curate the library to ensure matches are checked against realistic options (tools exist in CoreSpecViewer),</li>
<li>use your own library (open it in CoreSpecViewer),</li>
<li>select spectra from your data and build your own library (tools exist in CoreSpecViewer).</li>
</ul>
<p>That’s the point: Hyperspectral interpretation still requires geologists, not just algorithms — but the barrier to entry shouldn’t be the software.</p>
<p>If you have hyperspectral core scanning data in raw Lumo output files, check out CoreSpecViewer and send me all your complaints!</p>
<p>If you have hyperspectral core scanning data from other acquisition methods, let’s see if we can collaborate to extend CoreSpecViewer to smooth file discovery and metadata parsing!</p>
<p>If you don’t have any data, but want to play with the software, there are links to some open source data on the GitHub landing page.</p>
<p>The <a href="https://www.linkedin.com/pulse/hyperspectral-core-scanning-interpretation-made-easy-russell-rogers-kyd1e/">Original Linkedin post.</a></p>
</section>
<section id="data-and-licence" class="level3">
<h3 class="anchored" data-anchor-id="data-and-licence">Data and licence</h3>
<p>The hyperspectral core scans used in this note (hole NWG-05-03, box 303) are published by the Alberta Geological Survey (AGS) and were downloaded from:</p>
<p>Alberta Geological Survey (2023): Core Data Interactive Map; Alberta Energy Regulator / Alberta Geological Survey, AER/AGS Interactive App or Map 014, <a href="https://ags.aer.ca/publications/all-publications/iam-014" class="uri">https://ags.aer.ca/publications/all-publications/iam-014</a> [accessed August 2026].</p>
<p>The scanning programme is indexed in Spectrum Geosciences Ltd.&nbsp;and TerraCore Geospectral Imaging (2026): Index to hyperspectral core scanning imagery for mineral core from the Athabasca Basin, Canadian Shield, and Western Canada Sedimentary Basin in Alberta; Alberta Energy Regulator / Alberta Geological Survey, AER/AGS Special Report 129, 15 p.</p>
<p>Contains information licensed under the <a href="https://open.alberta.ca/licence">Open Government Licence – Alberta</a>.</p>


</section>

 ]]></description>
  <category>hyperspectral</category>
  <category>interpretation</category>
  <category>CoreSpecViewer guides</category>
  <guid>https://russjas.github.io/notes/hyperspectral-made-easy.html</guid>
  <pubDate>Sat, 03 Oct 2026 00:00:00 GMT</pubDate>
</item>
<item>
  <title>Notes</title>
  <link>https://russjas.github.io/notes/</link>
  <description><![CDATA[ 




<p>These are deliberately not papers. They are a public notebook: small pieces of work that seem worth making findable and permanent.</p>
<p>Some are analyses. Some are explanations. Some are records of an unexpected result. The level of polish varies with the problem.</p>




<div class="quarto-listing quarto-listing-container-default" id="listing-listing">
<div class="list quarto-listing-default">
<div class="quarto-post image-right" data-index="0" data-categories="aHlwZXJzcGVjdHJhbCUyQ0NvcmVTcGVjVmlld2Vy" data-listing-date-sort="1790985600000" data-listing-file-modified-sort="1791188136692" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="6" data-listing-word-count-sort="1056">
<div class="thumbnail"><a href="../notes/hyperspectra-data-big.html" class="no-external">

<!-- img(9CEB782EFEE6)[progressive=false, height=, lazy=true]:listing:notes/hyperspectra-data-big.html -->

</a></div>
<div class="body">
<h3 class="no-anchor listing-title">
<a href="../notes/hyperspectra-data-big.html" class="no-external">Hyperspectral data is big!</a>
</h3>
<div class="listing-categories">

<div class="listing-category" onclick="window.quartoListingCategory('aHlwZXJzcGVjdHJhbA=='); return false;">hyperspectral</div>

<div class="listing-category" onclick="window.quartoListingCategory('Q29yZVNwZWNWaWV3ZXI='); return false;">CoreSpecViewer</div>

</div>
<div class="delink listing-description"><a href="../notes/hyperspectra-data-big.html" class="no-external">
<p>Development trade-offs in hyperspectral software</p>
</a></div>
</div>
<div class="metadata">
<a href="../notes/hyperspectra-data-big.html" class="no-external">
<div class="listing-date">
Oct 3, 2026
</div>
<div class="listing-author">
Russell Rogers
</div>
</a>
</div>
</div>
<div class="quarto-post image-right" data-index="1" data-categories="aHlwZXJzcGVjdHJhbCUyQ2ludGVycHJldGF0aW9uJTJDQ29yZVNwZWNWaWV3ZXIlMjBndWlkZXM=" data-listing-date-sort="1790985600000" data-listing-file-modified-sort="1791188136693" data-listing-date-modified-sort="NaN" data-listing-reading-time-sort="7" data-listing-word-count-sort="1354">
<div class="thumbnail"><a href="../notes/hyperspectral-made-easy.html" class="no-external">

<!-- img(9CEB782EFEE6)[progressive=false, height=, lazy=true]:listing:notes/hyperspectral-made-easy.html -->

</a></div>
<div class="body">
<h3 class="no-anchor listing-title">
<a href="../notes/hyperspectral-made-easy.html" class="no-external">Hyperspectral core scanning interpretation made easy - sort of!</a>
</h3>
<div class="listing-categories">

<div class="listing-category" onclick="window.quartoListingCategory('aHlwZXJzcGVjdHJhbA=='); return false;">hyperspectral</div>

<div class="listing-category" onclick="window.quartoListingCategory('aW50ZXJwcmV0YXRpb24='); return false;">interpretation</div>

<div class="listing-category" onclick="window.quartoListingCategory('Q29yZVNwZWNWaWV3ZXIlMjBndWlkZXM='); return false;">CoreSpecViewer guides</div>

</div>
<div class="delink listing-description"><a href="../notes/hyperspectral-made-easy.html" class="no-external">
<p>A shallow dive into CoreSpecViewer.</p>
</a></div>
</div>
<div class="metadata">
<a href="../notes/hyperspectral-made-easy.html" class="no-external">
<div class="listing-date">
Oct 3, 2026
</div>
<div class="listing-author">
Russell Rogers
</div>
</a>
</div>
</div>
</div>
<div class="listing-no-matching d-none">No matching items</div>
</div> ]]></description>
  <guid>https://russjas.github.io/notes/</guid>
  <pubDate>Mon, 05 Oct 2026 08:15:57 GMT</pubDate>
</item>
</channel>
</rss>
