Engee 文档
Notebook

检测图像中温度较高的区域

在本例中,我们将向您展示如何自动检测图像中温度升高的物体。 通过分析图像,我们将识别热点区域,以及确定该区域的温度。 本质上,这模拟了热成像仪的操作。

我们将连接必要的软件包

In [ ]:
import Pkg
Pkg.add("Images")
Pkg.add("ColorSchemes")
Pkg.add("ImageDraw")
Pkg.add("OpenCV")
Pkg.add("ImageMorphology")
In [ ]:
using Images                # Для работы с изображениями
using ColorSchemes          # Для применения воспринимаемых цветовых карт
using ImageDraw             # Для рисования на изображениях 
using OpenCV                # Для работы с OpenCV
using ImageMorphology       # Для выполнения морфологических операций над изображениями

让我们上传一个打火机的图像,它显示了一个温度升高的区域。 使用图像处理技术,我们将识别高温区域,以及估计该区域的温度。

In [ ]:
image = Images.load("$(@__DIR__)/lighter.jpg")
Out[0]:
No description has been provided for this image

缩小图像尺寸,以便于显示:

In [ ]:
image = imresize(image, (550, 712))
Out[0]:
No description has been provided for this image

图像转换

让我们将图像转换为灰色阴影:

In [ ]:
image_gray = Gray.(image)
Out[0]:
No description has been provided for this image

让我们上传一个颜色表,用于可视化具有不同强度的数据。 在其上,明亮和饱和的颜色表示较高的值,而深色表示较低的值。 在这个例子中,它将用于显示具有不同温度水平的区域,提高了图像中温度差异的感知。

In [ ]:
colormap_ = ColorSchemes.hot
Out[0]:
No description has been provided for this image

让我们使用函数将颜色表应用于原始图像 apply_colorscheme:

In [ ]:
function apply_colorscheme(img, colorscheme)

    colored_img = [get(colorscheme, pixel) for pixel in img]
    
    return colorview(RGB, reshape(colored_img, size(img)...))
end
Out[0]:
apply_colorscheme (generic function with 1 method)
In [ ]:
inferno_img = apply_colorscheme(image_gray, colormap_)
Out[0]:
No description has been provided for this image

二值化和形态学操作

接下来,将应用二值化和形态学操作来识别温度升高的物体。

二值化:此方法将图像转换为二进制(黑白)。 这有助于仅识别具有对应于我们感兴趣的范围的强度的那些区域。

形态学操作:将应用侵蚀和扩张等形态学操作来改善二值化结果。 侵蚀通过去除噪声和小细节来减小对象的大小,而扩张则增加它们。

让我们定义二值化阈值:

In [ ]:
threshold = 240 / 255
Out[0]:
0.9411764705882353

让我们通过将逻辑单元分配给超过强度阈值的像素来执行二值化,并将逻辑零分配给所有其他像素。:

In [ ]:
binary_thresh = Gray.(image_gray .> threshold)
Out[0]:
No description has been provided for this image

从上图中可以看到,生成的二进制掩模有一个带有来自打火机的火焰的区域。 但是,我们将使用形态学操作去除噪声。

定义侵蚀和扩张所需的核心:

In [ ]:
kernel = strel_diamond((9, 9), r=2)
Out[0]:
9×9 ImageMorphology.StructuringElements.SEDiamondArray{2, 2, UnitRange{Int64}, 0} with indices -4:4×-4:4:
 0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0
 0  0  0  0  1  0  0  0  0
 0  0  0  1  1  1  0  0  0
 0  0  1  1  1  1  1  0  0
 0  0  0  1  1  1  0  0  0
 0  0  0  0  1  0  0  0  0
 0  0  0  0  0  0  0  0  0
 0  0  0  0  0  0  0  0  0

让我们来看看应用形态学操作的结果:

In [ ]:
BWerode = erode(binary_thresh, kernel)
Out[0]:
No description has been provided for this image
In [ ]:
BWdilate = dilate(BWerode, kernel)
Out[0]:
No description has been provided for this image

正如你可以从上面的图片中看到,我们留下了一个明确定义的高温区域。

将热区域选择为边界矩形

接下来,我们需要限制感兴趣的区域。 为此,我们将使用OpenCV包中的方法。

我们需要再次玩弄图像格式。 首先,让我们将图像转换为RGB格式。:

In [ ]:
BWdilate = RGB.(BWdilate)
typeof(BWdilate)
Out[0]:
Matrix{RGB{N0f8}} (alias for Array{RGB{Normed{UInt8, 8}}, 2})

接下来,我们将以OpenCV可以使用的格式呈现图像。:

In [ ]:
img_bw_raw =  collect(rawview(channelview(BWdilate)));
img_gray_CV = OpenCV.cvtColor(img_bw_raw, OpenCV.COLOR_RGB2GRAY);

现在我们的图像是从OpenCV的MAT格式。 接下来,我们正在寻找我们地区的轮廓。:

In [ ]:
contours, _ = OpenCV.findContours(img_gray_CV, 1, 2)
Out[0]:
(OpenCV.Mat[Int32[209; 341;;; 208; 342;;; 202; 342;;; … ;;; 212; 343;;; 211; 342;;; 210; 342]], Int32[-1; -1; -1; -1;;;])

让我们计算区域的边界矩形的坐标,看看它们是什么。:

In [ ]:
rect = OpenCV.boundingRect(contours[1])
println("Bounding box: x=$(rect.x), y=$(rect.y), width=$(rect.width), height=$(rect.height)")
Bounding box: x=145, y=341, width=79, height=26

用边界矩形可视化图像

In [ ]:
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))
Out[0]:
No description has been provided for this image

温度检测

接下来,我们将确定选定区域的温度。 这个想法是通过应用预设的校准因子来使用该区域中的平均像素亮度值来计算温度。

让我们描述一个函数,它考虑了平均像素值的校准系数。 - convert_to_temperature:

In [ ]:
function convert_to_temperature(pixel_avg, calibration_factor=4.6)
    return pixel_avg * calibration_factor
end;

让我们重复原始图像的变换,以便计算区域的平均值,同时考虑到掩码。 在此上下文中,遮罩是形态学操作后的图像。 它允许我们只隔离要计算平均强度值的区域。

In [ ]:
img_raw =  collect(rawview(channelview(image)));
img_gray_CV_img = OpenCV.cvtColor(img_raw, OpenCV.COLOR_RGB2GRAY);

计算区域的平均强度值:

In [ ]:
mean_value = OpenCV.mean(img_gray_CV_img, img_gray_CV)[1]
Out[0]:
241.00212916962386

并将其转换为温度。 温度值以摄氏度为单位:

In [ ]:
println("Температура области:", convert_to_temperature(mean_value))
Температура области:1108.6097941802695

结论

在这个例子中,我们演示了使用图像处理技术检测和确定图像中热区域温度的过程。 我们首先将图像转换为合适的格式,然后使用二值化来突出显示感兴趣的区域,并应用形态学操作来改善结果。 之后,我们使用掩模和校准系数计算所选区域的温度,以将像素亮度转换为温度。 该过程最终允许您识别热点并测量其温度,模拟热成像仪的操作并为分析提供有用的信息。