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

我们在进行二值化处理时,会给超过强度阈值的像素分配一个逻辑 1,而给其他所有像素分配一个逻辑 0:

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

结论

在本案例研究中,我们演示了利用图像处理技术检测和确定图像中高温区域温度的过程。我们首先将图像转换成合适的格式,然后使用二值化选择感兴趣的区域,并应用形态学操作来改进结果。然后,我们使用掩码和校准因子计算所选区域的温度,将像素亮度转换为温度。这一过程最终使我们能够识别热区并测量其温度,模拟热成像仪的操作,为分析提供有用的信息。