Temperature is a key parameter to measure in any process. It helps us to understand if its under control of its behaving in a way that is dangerous or it could turn in a dangerous one. Therefore measuring and controlling temperature has always been an area of interest for the people responsible for the processes to keep going.
Usually we tend to measure temperature with just a sensor or with an array of them. Thermal images help us to go a bit further giving us thousands of temperature measurements with a simple photograph!
Thermal images is a broad field of application and its mainly used in the industries by manufacturing and maintenance teams to perform process control, predictive maintenance, quality control, etc.
Unfortunately some thermographic cameras and their applications come with an issue, they can take the picture where you can see the different temperatures but that picture does not show you specific temperatures that might be of interest.
Another problem that you can face when handling thermal images is when you try to compare two of them. To exemplify this last point we are going to run a quick test:
Can you conclude from the pictures below which one was taken in a warmer environment?
Note: Iron palette goes from yellow (warmest) to deep purple (coldest)
Given that the second image is yellowish and that the first one is blueish it might make us think that the second one corresponds to a warmer environment, when it actually isn't!
Truth is that first image was taken during the day (that's why the window on the left side is hotter) whereas the second one was taken during the night. Thus, first image was taken in a warmer environment, the exact opposite of what we might had thought while comparing them!
With that example what I'm pointing is that is not easy to raise conclusions from thermal images just by comparing them by their colors. Explanation is that thermographic cameras software (in my case Flir) generates images emphasizing the different gradient temperatures of the image to create a greater contrasts and make the thermal image neater. But that does not mean that we can compare the contrasts between two different images! In other words, temperatures represented in yellow in the first image are not the same temperatures represented in yellow in the second one.
In this short tutorial we will develop a program that will extract the temperature data from each pixel of each image and then it will compare them using the same scales in order to make better conclusions.
What You'll NeedYou'll need the following:
- A Thermographic camera. In this case I'm using the one that comes with the Blackview BV6600Pro. You do not need to buy this exact one, in fact there are very cool devices to take thermaographic images as the OpenMV + Flir ones!
This tutorial shows how to run the code in a Python interpreter by running the main.py
file.
This code will:
- Open a thermal image JPG file
- Check for its temperature range in its meta data
- Convert images to grayscale in order to obtain individual pixel temperatures
- Create a matrix where each cell value will be the measured temperature of that pixel
- Generate and save palette images of the normalized and non-normalized temperatures
- Save measured temperatures in an excel file
Important: FLIR software on Blackview BV6600Pro does not allow you to access to the original thermal image files. It only allows you to download a JPG file of the thermal image losing some relevant data as maximum and minimum temperatures. Thus, I will need to manually upload them in the program. You can check if your thermal image has those temperature values saved in image meta data. If it does, you can automate this step.
# Thermal Image meta data example
# main.py shows how to extract this data from any image
GPSInfo : 1724
ResolutionUnit : 2
ExifOffset : 226
Make : FLIR Systems AB
Model : BV6600Pro
Software : Common_fileformat
Orientation : 1
DateTime : 2023:02:16 21:32:28
YCbCrPositioning : 1
XResolution : 72.0
YResolution : 72.0
Each thermographic camera software will have their own color scale, to get rid of them we will convert the image to grayscale with a normalization intent.
# MyFlir allows us to check for temperature range of the image but does not give us access to the original file
# While storing the file into the Photos library its already modified losing its temperature metadata (tmin, tmax, emissivity, scale, etc.)
# As I couldn't access to the original file I have to work with the only one that I have and I have to set the temperature range manually
import PIL
from PIL import Image
from PIL.ExifTags import TAGS
import cv2
import pandas as pd
import numpy as np
from numpy import asarray
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
def metadata ():
#checking for metadata and if the image stores its min and max temperatures
exifdata = image.getexif()
for tag_id in exifdata:
# get the tag name, instead of human unreadable tag id
tag = TAGS.get(tag_id, tag_id)
data = exifdata.get(tag_id)
# decode bytes
if isinstance(data, bytes):
data = data.decode()
print(f"{tag:25}: {data}")
# Open thermal images, as I'm comparing two, I have to run this program two times, one for the file ending in 323 and the following one for the one ending in 247. In this case it will be running the one ending in 323, to run the following one simply comment the next line and uncomment the other one
base = "flir_20230216T171323" # tmin = 29.6; tmax = 44.1
#base = "flir_20230216T213247" # tmin = 22.6; tmax = 28.1
ext = ".jpg"
image_source = base + ext
image = PIL.Image.open(image_source)
metadata()
gray16_image = cv2.imread(image_source, cv2.IMREAD_ANYDEPTH) # Convert image to a grayscale so we can get each pixels temperature
np_gray16 = asarray(gray16_image)
np_gray16_min = np_gray16.min()
np_gray16_max = np_gray16.max()
np_gray16_norm = (np_gray16 - np_gray16_min) * (1/(np_gray16_max - np_gray16_min)) # Normalize temperatures
# Set an standard temperature range
tmin = float(input("Enter images minimum temperature: ")) # tmin = 22.6
tmax = float(input("Enter images maximum temperature: ")) # tmax = 28.1
np_temp = tmin + (np_gray16_norm) * (tmax - tmin)
dest = base + "_temp_mx.xlsx"
df = pd.DataFrame (np_temp)
df.to_excel(dest, header = False, index=False) # creates an excel file with the temperature data of each image
trangemin = 20
trangemax = 50
np_temp_aux = tmin + (np_gray16_norm) * (tmax - tmin)
# Temperature ranges for standardized images require us to make a tiny modification in images data because we will need the same maximum and minimum temperature value in every image. Doing this we are setting the range references for the color pallette. We will set first cell as the minimum temperature of the range and the last one as the maximum
np_temp_aux[0,0] = trangemin # first pixel of the image will have its temperature value equal to trangemin
x = np_temp.shape[0]
y = np_temp.shape[1]
np_temp_aux[x-1,y-1] = trangemax # # last pixel of the image will have its temperature value equal to trangemax
np_temp_norm = (np_temp - tmin) * (1/(tmax - tmin))
np_temp_aux_norm = (np_temp - trangemin) * (1/(trangemax - trangemin))
# Set the heat maps, note that heach specific heatmap will have different temperature ranges
# Normalized heat map ranges will be independent of input image temperatures and will allways go from 20 to 50
inferno = plt.cm.get_cmap('inferno')
np_temp_hm = inferno(np_temp_norm)
np_temp_norm_hm = inferno(np_temp_aux_norm)
# Save normalized images as JPG files
np_temp_hm = Image.fromarray((np_temp_hm[:, :, :3] * 255).astype(np.uint8))
np_temp_norm_hm = Image.fromarray((np_temp_norm_hm[:, :, :3] * 255).astype(np.uint8))
image_temp = np_temp_hm.convert('RGB')
image_temp_norm = np_temp_norm_hm.convert('RGB')
image_temp_dest = base + "_col" + ext
image_temp_norm_dest = base + "_col_norm" + ext
image_temp.save(image_temp_dest, format='JPEG', quality=95) # save thermal image now with inferno heatmap rather than iron
image_temp_norm.save(image_temp_norm_dest, format='JPEG', quality=95) # save normalized thermal image now with inferno heatmap rather than iron
ConclusionsWe've standardized images palettes. Thus, an specific color in one image has the exact same temperature than that color in another image,
So now we can compare images and even continue with more extensive analysis.
Differences are really standing out now!
Analyzing images can lead us to conclude that:
- First image was taken in a warmer environment (yellow and orange colors take over the image)
- First image had the maximum temperaturefrom both (44.1 vs 28.1 deg C). Thus, its normalized image will has the strongest yellow of both images
- Second image had the minimum temperature (22.6 vs 29.6 deg C). Thus, its normalized image has the darkest blue of both images
- Temperature range (the difference between maximum and minimum temperature) is greater in the first image (44.1 - 29.6 = 14.5) than in the second one (28.1 - 22.6 = 5.5). Consequence of this is that first image has a better contrast than the second one. Second image has a poor contrast given that the temperatures are quite similar making more difficult to differentiate shapes. Thus, second image is a good example to show why the software automatically tries to make contrasts bigger, to make the image clearer.
Lastly, I'd also like to show how palette's normalization modified each one of the images
Comments
Please log in or sign up to comment.