Detecting areas in an image with high temperature¶
In this example, we will show how you can automatically detect objects with high temperature in an image. By analysing the image, we will highlight hot areas and also determine the temperature of that area. In essence, this mimics the operation of a thermal imager.
Let's connect the necessary packages¶
import Pkg
Pkg.add("Images")
Pkg.add("ColorSchemes")
Pkg.add("ImageDraw")
Pkg.add("OpenCV")
Pkg.add("ImageMorphology")
using Images # Для работы с изображениями
using ColorSchemes # Для применения воспринимаемых цветовых карт
using ImageDraw # Для рисования на изображениях
using OpenCV # Для работы с OpenCV
using ImageMorphology # Для выполнения морфологических операций над изображениями
Let's upload an image with a lighter that shows an area of high temperature. Using image processing techniques, we will highlight the high temperature region and estimate the temperature of this region.
image = Images.load("$(@__DIR__)/lighter.jpg")
Reduce the size of the image for easy display:
image = imresize(image, (550, 712))
Image conversion¶
Let's convert the image to shades of grey:
image_gray = Gray.(image)
Load a colour map, which is used to visualise data with different intensities. On the map, bright and saturated colours indicate higher values, and dark colours indicate lower values. In this example, it will be applied to show areas with different temperature levels, improving the perception of temperature differences in the image.
colormap_ = ColorSchemes.hot
Apply the colour map to the original image using apply_colorscheme
:
function apply_colorscheme(img, colorscheme)
colored_img = [get(colorscheme, pixel) for pixel in img]
return colorview(RGB, reshape(colored_img, size(img)...))
end
inferno_img = apply_colorscheme(image_gray, colormap_)
Binarisation and morphological operations¶
In the following, binarisation and morphological operations will be applied to select objects with elevated temperature.
Binarisation: this method converts the image into a binary (black and white) image. This helps to highlight only those areas that have an intensity corresponding to the range of interest.
Morphological operations: morphological operations such as erosion and dilatation will be used to improve the results of binarisation. Erosion reduces the size of objects by removing noise and small details, while dilatation enlarges them.
Let us define the threshold of binarisation:
threshold = 240 / 255
We perform binarisation by assigning a logical one to pixels exceeding the intensity threshold and a logical zero to all others:
binary_thresh = Gray.(image_gray .> threshold)
As you can see from the figure above, the resulting binary mask still has the area with the flame from the lighter. However, there is noise that we will remove using morphological operations.
Let's set the kernel required for erosion and dilatation:
kernel = strel_diamond((9, 9), r=2)
Let's look at the result of applying morphological operations:
BWerode = erode(binary_thresh, kernel)
BWdilate = dilate(BWerode, kernel)
As you can see from the figure above, we are left with a clearly marked region with high temperature.
Highlighting the hot area into a bounding rectangle¶
Next, we need to restrict the area of interest. To do this, let's apply methods from the OpenCV package.
It is necessary to play with image formats again. First, let's convert the image into RGB format:
BWdilate = RGB.(BWdilate)
typeof(BWdilate)
Next, let's convert the image into a format that OpenCV can work with:
img_bw_raw = collect(rawview(channelview(BWdilate)));
img_gray_CV = OpenCV.cvtColor(img_bw_raw, OpenCV.COLOR_RGB2GRAY);
Now our image is in OpenCV's MAT format. Next we look for contours of our area:
contours, _ = OpenCV.findContours(img_gray_CV, 1, 2)
Let's calculate the coordinates of the bounding rectangle of the area and see what they represent:
rect = OpenCV.boundingRect(contours[1])
println("Bounding box: x=$(rect.x), y=$(rect.y), width=$(rect.width), height=$(rect.height)")
Visualise the image with the bounding rectangle¶
img_with_rect = draw(image, Polygon(RectanglePoints(CartesianIndex(rect.y, rect.x), CartesianIndex(rect.y + rect.height, rect.x + rect.width))), RGB{N0f8}(1.0, 0, 0.0))
Temperature definition¶
Next, we will determine the temperature of the selected region. The idea is to use the average brightness value of the pixels in this area to calculate the temperature by applying a predetermined calibration factor.
Let us describe a function that takes into account the calibration factor for the average pixel value - convert_to_temperature
:
function convert_to_temperature(pixel_avg, calibration_factor=4.6)
return pixel_avg * calibration_factor
end;
Let's repeat the transformations for the original image to calculate the area mean value taking into account the mask. In this context, a mask is an image after morphological operations. It allows us to isolate only the area for which we want to calculate the average intensity value.
img_raw = collect(rawview(channelview(image)));
img_gray_CV_img = OpenCV.cvtColor(img_raw, OpenCV.COLOR_RGB2GRAY);
Let's calculate the average intensity value by region:
mean_value = OpenCV.mean(img_gray_CV_img, img_gray_CV)[1]
And convert it into temperature. The temperature values are taken on the Celsius scale:
println("Температура области:", convert_to_temperature(mean_value))
Conclusions¶
In this case study, we demonstrated the process of detecting and determining the temperature of a hot region in an image using image processing techniques. We started by converting the image into a suitable format, then used binarisation to select regions of interest and applied morphological operations to improve the results. We then calculated the temperature of the selected region using a mask and calibration factor to convert pixel brightness to temperature. This process ultimately allows us to identify hot areas and measure their temperature, simulating the operation of a thermal imager and providing useful information for analysis.