Marking a Mineral on Core Sample Using Color Spaces + Contours in Python

Mochamad Risyad Rizkyafdhal
DigiGeo
Published in
5 min readOct 29, 2020

This python script is under the terms of MIT License

Illustration of conventional ore marking ( Adwo / stock.adobe.com )

As we know that marking the ore was conventionally carried out by using markers, this work to be sure requires a high level of accuracy and can take a long time. But can you imagine that there is a technology which can make this problem solved more efficiently in time?

In this project, I will show you how image processing with unsupervised learning (Because it’s easy to code) works to mark the ore on the core sample. For example, I’m gonna use Quartz and Sulfide Minerals.

The most frequently unsupervised learning used for image classification is K-Mean. But the reason for choosing Color Spaces segmentation over K-Mean Clustering is because the K-Mean will have a different color predictions in every single core sample image due to N partition (K value for color object) and iteration. While Color Spaces segmentation has the constant color that we want to predict, so make it more universal to apply on any image.

Before we’re start to coding, make sure you have these three python libraries:

  1. OpenCV
  2. NumPy
  3. Matplotlib

Workflow

1. Import OpenCV, NumPy, and Matplotlib

First, you must convert your core image into the HSV (Hue, Saturation, Value) format. This will change your discrete image color continuously. HSV color is also helpful to reduce light reflectance.

import cv2 as cv2
import numpy as np
import matplotlib.pyplot as plt

2. Insert Core Sample Image

img = *Image Location*

3. Convert image color from BGR to RGB & HSV

OpenCV currently uses BGR as the build-in color. So, you must convert the core images into the RGB and HSV (Hue, Saturation, Value) color. RGB color is just optional to make sure you can see the normal color. Although HSV will change your discrete image color continuously, this color also helps to reduce light reflectance.

image_RGB = cv2.cvtColor (img, cv2.COLOR_BGR2RGB)
image_HSV = cv2.cvtColor (image_RGB, cv2.COLOR_RGB2HSV)

4. Create Color Range

Color spaces are the most important part of this project. It is the one from many clustering syntaxes in python. With this, you can easily search for the same color in the core sample. This functions also helps to reduce light reflectance by making color range (e.g. gold ore color at normal light as the lower color and shiny one as the upper color). The value in numpy array was representing the HSV color. lower is the color that we want, while the upper is the color that we want to predict.

## Color Reference:
#AU & CHALCOPYRITE
#lower = np.array([20,70,150])
#upper = np.array([55,255,255])
#QUARTZ
#lower = np.array([20,0,180])
#upper = np.array([240,100,255])
#SODALITE
#lower = np.array([40,80,0)
#upper = np.array([240,255,255])
lower = np.array([20,70,150])
upper = np.array([55,255,255])

5. Mask it

In this step, we’re separate the visual between minerals. Mask is useful for recalculating the pixel color that we want to predict.

mask = cv2.inRange(image_HSV, lower, upper)

6. Create a contours

This syntax will work as a “Real-life marker” that bounding you’re mask layer. In this example, I’m using red as a boundary color that is represented in numpy array (255, 0, 0). The last value at cv2.drawContours was the stroke that you can adjust as much as you needed.

contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
VirtualMarker = cv2.drawContours(image_RGB, contours, -1, (255,0,0), 2)

7. Optional: Insert core depth and width

For making a better result, inserting depth and width can reduce data error caused by exchange. Image size, I recommend use built-in pixel by remove the figsize. Just the example I’m going to use (4, 20) for vertical or (20, 4) for horizontal. You can recalculate the scale between pixel and real value of measurement.

#Adjust image size
plt.figure(figsize=(4,20))
#Insert Depth & Width Value
plt.xticks([0, 200, 400, 600, 805], [0, 1.9, 3.8, 5.7, 7.6])
plt.yticks([400, 1000], [354, 354.5])
#Labeling X & Y axes with Depth & Width
plt.xlabel('Width (cm)')
plt.ylabel('Depth (m)')

8. Visualize the result

Finally, you can visualize and having fun with it. And don’t forget to make sure that the algorithm is predict your core sample correctly.

#Visualize the result
plt.imshow(VirtualMarker)

Accuracy test

To test the accuracy of this code, I already try it on a hand-specimen which containing sodalite. While capturing the sample, I’m using a cell phone (7 MP). The result shows that this code can predict more detail up to 7% from my estimation before. It was like you are using marker and loupe at the same time.

Conclusion

From this project, we can conclude the advantage of this code can produce more faster than conventional marking. But the disadvantage was the marker may be too much detail that makes a little bit dizzy to see by the eyes. The important key of this code is by choosing representative colors properly.

Tips while capturing the sample image

To make a better image quality and constant prediction, you can do these tips:

  1. Make sure you have already noted the camera setting.
  2. Search someplace with constant lighting or you can use lightroom/lightbox.

Disclaimer: I don’t recommend using this method. if you want to, make sure you’ve already validate between result and direct core description.

Paper Reference

Jurio, A., Pagola, M., et. al. (2010). A Comparison Study of Different Color Spaces in Clustering Based Image Segmentation. Communications in Computer and Information Science 81:532–541. DOI: 10.1007/978–3–642–14058–7_55

Code Reference

--

--

Mochamad Risyad Rizkyafdhal
DigiGeo
Editor for

Exploration Geologist | Mineral Exploration | Mining Valuation | FMVA® Candidate