RAG Thresholding

This morning I read some news from different sources. I am amazed how facts are edited to provide some information but with a lot of bias in favor of the group reporting.

The first one was regarding how 50% of animal species have been decimated. The actual news mentioned that about 50% of species in the world are in decline. Yet some 3% are flourishing. 

On a different set of news, wildfires are out of control in Canada. The effects on the weather in different states in the USA is being felt including in Minnesota. For the past week or so we have had high values in the air quality which indicate many pollutants coming from the fires in Canada. The news stated that this is all due to global warming.

I am not stating that global warming is or is not an issue. But like has been happening for over a decade in California, arsonists are behind most wildfires. Seems like blaming the issue on global warming could get some people convinced that arsonists and global warming are the same..

In addition some articles were all in favor of stopping oil production. That is a bad idea. Our societies need so many products that come from oil including EVs (). On a separate set of news it seems that several countries are already starting to deploy and use nuclear power plants. The amount of energy produced by renewable sources is not enough to power all the EVs that would be needed to replace ICE vehicles. Since such an idea is not going to work, people need to be told the truth and promote ways in which we can reduce energy consumption all over the world. At this time, that seems the only way our species will continue to prosper.

I forgot one more piece of news regarding New York City. It seems that due to the weight of large buildings in the area, the floor is sinking at a rate of about 1 mm per year. A centimeter contains 10 mm. An inch is equivalent to 2.54 cm or 25.4 mm. This implies that in about 25 years NYC will sink about an inch. This event is in any shape or form related to global warming.

OK, enough is enough. Let’s dive into the main subject of this post, which is image segmentation. The idea of image segmentation is to partition an image with segments containing pixels that have values in some predefined range. The results are images that are easier to comprehend. That said, the course uses an image of a lake with some trees and mountains in the background. If you take a look at the Wikipedia article it contains a bone. In my opinion such an image conveys the object of segmentation much better.

You might also wish to refresh your knowledge on k-means clustering which uses concepts similar to image segmentation.

# **** folder of interest ****
cd C:\Documents\_Image Processing\scikit-image-building-image-processing-applications\02\demos

# **** open file of interest using VSCode ****
(base) C:\Documents\_Image Processing\scikit-image-building-image-processing-applications\02\demos>code RAGThresholding.py

# **** execute python script of interest ****
(base) C:\Documents\_Image Processing\scikit-image-building-image-processing-applications\02\demos>python RAGThresholding.py

Let’s start by opening an Anaconda prompt and getting to the folder of interest in which we keep our Python scripts. The path you choose might be different from the one I used.

Once there we need to open the IDE with the name of the Python script of interest. In our case I am using VSCode with GitHub Copilot. I should disclose that I am a Microsoft employee and have been using Visual Studio and VSCode for many years. I used several different IDEs when using a different programming language. Today I tend to use Visual Studio and VSCode for most (if not all of my coding). I am sure that some IDEs might have a few features not supported by Visual Studio and VSCode, but the simplicity of learning and always using the same reduced set of tools reduces the time needed to switch between IDEs.

Getting back to the screen capture, we open the Python script of interest. Of course you may use a different name. Once the script is opened make sure that you save the code before running it.

Finally we invoke the Python interpreted to run the script of interest. The last two steps are repeated as many times as we edit the Python script.

# **** Imports ****
from matplotlib import pyplot as plt

from skimage import data, io, segmentation, color

#from skimage.future import graph
import skimage.graph as graph

We start the Python script of interest by importing the libraries of interest. The author of the course this post is based on uses a different version of the libraries. This is why the last line of imports had to be modified. This tends to happen when you use the latest and greatest set of libraries.

# **** Read image ****
nature = io.imread('./images/pexels-nature.jpg')

# **** Display image ****
plt.figure(figsize=(8, 8))
plt.imshow(nature)
plt.title('Nature')
plt.show()

We now read the image of interest and display it. Please note that the images were provided as part of the PluralSIght course.

The image shows a lake with plants and trees and in the background some mountains and clouds in the sky. Nice picture!

# **** Segments regions using k-means clustering
#      Balances color and space proximity -
#      high values emphasize spacial closeness
#      and the segments are squarish ****
labels1 = segmentation.slic(nature, 
                            compactness=35,
                            n_segments=500)

# **** Print labels1.shape ****
print(f'labels1.shape: {labels1.shape}')

# **** Print labels1 ****
print(f'labels1:\n{labels1}')

We segment the image using some random values for the last two arguments. Please take a look at the documentation on segmentation.slic (https://scikit-image.org/docs/stable/api/skimage.segmentation.html) to understand what the arguments do for the resulting segmentation.

(base) C:\Documents\_Image Processing\scikit-image-building-image-processing-applications\02\demos>python RAGThresholding.py
labels1.shape: (413, 640)
labels1:
[[  1   1   1 ...  27  27  27]
 [  1   1   1 ...  27  27  28]
 [  1   1   1 ...  28  28  28]
 ...
 [474 474 474 ... 465 465 465]
 [474 474 474 ... 465 465 465]
 [474 474 474 ... 465 465 465]]

Information about the shape and contents of the labels1 variable are then displayed.

# **** segmented_overlay ****
segmented_overlay = color.label2rgb(labels1,
                                    nature,
                                    kind='overlay')

# **** Display segmented_overlay ****
plt.figure(figsize=(8, 8))
plt.imshow(segmented_overlay)
plt.title('Segmented Overlay')
plt.show()

We now generate a segmented_overlay using the original nature image and the contents of labels1. The segmented image is displayed.

# **** segmented_avg ****
segmented_avg = color.label2rgb(labels1,
                                nature,
                                kind='avg')

# **** Display segmented_avg ****
plt.figure(figsize=(8, 8))
plt.imshow(segmented_avg)
plt.title('Segmented Average')
plt.show()

We repeat creating a new overlay by changing the third argument to ‘avg’. The new segmented image is displayed.

# **** RAG thresholding merges segments of an image
#      based on how similar or dissimilar they are -
#      edbes are the difference in the mean color ****
g = graph.rag_mean_color(   nature,
                            labels1)

# **** labels2 - Combine regions separated by a 
#      weight less than threshold ****
labels2 = graph.cut_threshold(  labels1,
                                g,
                                thresh=35)

segmented_rag = color.label2rgb(labels2,
                                nature,
                                kind='avg')

# **** Display segmented_rag ****
plt.figure(figsize=(8, 8))
plt.imshow(segmented_rag)
plt.title('Segmented RAG - Threshold = 35')
plt.show()

We now use RAG (Region Adjacency Graph) and merge the nature image with the labes1. We combine the images with a threshold to general labels2. We create a new segmented_rag image which is then displayed.

 

Finally we repeat the last set of steps with different arguments. The resulting image is then displayed.

# **** RAG thresholding merges segments of an image
#      based on how similar or dissimilar they are -
#      edbes are the difference in the mean color ****
g = graph.rag_mean_color(   nature,
                            labels1)

# **** labels2 - Combine regions separated by a 
#      weight less than threshold ****
labels2 = graph.cut_threshold(  labels1,
                                g,
                                thresh=15)

segmented_rag = color.label2rgb(labels2,
                                nature,
                                kind='avg')

# **** Display segmented_rag ****
plt.figure(figsize=(8, 8))
plt.imshow(segmented_rag)
plt.title('Segmented RAG - Threshold = 15')
plt.show()

Given the different values to the arguments the last segmented image contains more detail than the previous one.

Hope you enjoyed reading this post and experimenting with the Python code. It is interesting to not just change the value of the arguments but also use different images that might be of more interest to you.

Remember that one of the best ways to learn is to read, experiment, and repeat as many times as needed.

If interested in the code you may find it in the RAGThresholding GitHub repository.

Enjoy,

John

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.