Engee 文档
Notebook

卫星图像分割,第 2 部分

数字图像处理系列的第二个例子。在 第 1 部分 中,我们探讨了卫星图像分割问题及其基本解决方法。在第二部分中,我们将考虑可供新手开发人员使用的其他方法,特别是

  • 颜色分割

  • 索贝尔滤波器

  • SRG 算法

加载所需库函数,导入图像 {#加载所需库函数,导入数据} * SRG 算法

如果应用代码中缺少某些内容,则应取消注释下一行代码:

In [ ]:
# Pkg.add(["Images", "ImageShow", "ImageContrastAdjustment", "ImageBinarization", "ImageMorphology", "ImageFiltering", "ImageSegmentation"])

连接必要的库:

In [ ]:
using Images, ImageShow, ImageContrastAdjustment, ImageBinarization, ImageMorphology, ImageFiltering, ImageSegmentation

加载原始彩色图像(卫星图像):

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

颜色分割

在第一部分中,我们几乎没有涉及颜色信息,但显而易见的是,森林区域大部分是绿色的,而城市则含有大量的灰色和白色。这意味着我们可以尝试提取与图像中绿色色调颜色相近的区域。我们将对图像的各个通道进行二值化处理,然后像之前一样使用函数channelview 对其进行访问:

In [ ]:
(h, w) = size(I);
CV = channelview(I);
[ RGB.(CV[1,:,:], 0.0, 0.0) RGB.(0.0, CV[2,:,:], 0.0) RGB.(0.0, 0.0, CV[3,:,:]) ]
Out[0]:
No description has been provided for this image

我们可以假设,一个典型的 "绿色像素 "位于图像的中心。我们选择 "中心 "像素,知道图像的宽度和高度,然后查看其颜色通道的强度值:

In [ ]:
midh = Int(round(h/2));
midw = Int(round(w/2));
midpixel = CV[:,midh, midw]
Out[0]:
3-element Array{N0f8,1} with eltype N0f8:
 0.22N0f8
 0.267N0f8
 0.118N0f8

现在,我们使用标准的逻辑比较操作,对每个通道进行二值化处理。在红色通道中,强度为 0.15 至 0.25 的像素将对应一个逻辑值,在绿色通道中,强度为 0.2 至 0.3 的像素将对应一个逻辑值,在蓝色通道中,强度为 0.05 至 0.15 的像素将对应一个逻辑值。

In [ ]:
BIN_RED = (CV[1,:,:] .> 0.15) .& (CV[1,:,:] .< 0.25) ;
BIN_GREEN = (CV[2,:,:] .> 0.2) .& (CV[2,:,:] .< 0.3);
BIN_BLUE = (CV[3,:,:] .> 0.05) .& (CV[3,:,:] .< 0.15);
simshow([BIN_RED BIN_GREEN BIN_BLUE])
Out[0]:
No description has been provided for this image

现在,让我们通过逻辑 "AND "操作将三个二进制掩码合并为一个掩码--现在,只有在原始彩色图像中满足所有三个条件(范围)的地方才会出现白色像素:

In [ ]:
BIN = BIN_RED .& BIN_GREEN .& BIN_BLUE;
simshow(BIN)
Out[0]:
No description has been provided for this image

形态学 将再次帮助我们将这组杂乱无章的像素制作成遮罩。这一次,我们将选取一个菱形的小结构元素(7x7 像素):

In [ ]:
se = strel_diamond((7,7))
Out[0]:
7×7 ImageMorphology.StructuringElements.SEDiamondArray{2, 2, UnitRange{Int64}, 0} with indices -3:3×-3:3:
 0  0  0  1  0  0  0
 0  0  1  1  1  0  0
 0  1  1  1  1  1  0
 1  1  1  1  1  1  1
 0  1  1  1  1  1  0
 0  0  1  1  1  0  0
 0  0  0  1  0  0  0

并评估形态学封闭操作的结果:

In [ ]:
closeBW = closing(BIN,se);
simshow(closeBW)
Out[0]:
No description has been provided for this image

我们通过去除小 "斑点 "并再次执行闭合操作来获得遮罩,现在是为了平滑合并后白色像素中主要 "大 "区域的边界:

In [ ]:
openBW = area_opening(closeBW; min_area=500) .> 0;
se2 = Kernel.gaussian(3) .> 0.0025;
MASK_colorseg = closing(openBW,se2);
simshow(MASK_colorseg)
Out[0]:
No description has been provided for this image

让我们用熟悉的方法将倒置遮罩应用到原始图像中:

In [ ]:
sv_colorseg = StackedView(CV[1,:,:] + (.!MASK_colorseg./3), CV[2,:,:] + 
                            (.!MASK_colorseg./3), CV[3,:,:]);
view_colorseg = colorview(RGB, sv_colorseg)
Out[0]:
No description has been provided for this image

索贝尔滤波器

索贝尔滤波器是图像处理中的一种运算器,通过计算水平和垂直方向上的亮度梯度检测边界(物体的边缘)。它应用导数的离散模拟,突出像素强度急剧变化的区域。

我们将暂时忘记颜色,而使用亮度图,即灰度图:

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

索贝尔算子使用两个核(小矩阵)。

X轴(垂直边界):

 [ -1 0 1 ]
 [ -2 0 2 ]
 [ -1 0 1 ]

Y 轴(水平边界):

 [ -1 -2 -1 ]
 [ 0 0 0 ]
 [ 1 2 1 ]

操作原则

  • 每个核对图像进行卷积,突出其方向上的亮度变化。

  • 将结果应用于原始图像,以获得图像:

    Gx (X 梯度)、

    Gy(Y 梯度)。

  • 总梯度定义为 GxGy 的平方和之根

In [ ]:
# Ядра Собеля для осей X и Y
sobel_x = Kernel.sobel()[1]  # Горизонтальный градиент (вертикальные границы)
sobel_y = Kernel.sobel()[2]  # Вертикальный градиент (горизонтальные границы)

# Применение свертки
gradient_x = imfilter(imgray, sobel_x)
gradient_y = imfilter(imgray, sobel_y)

# Общий градиент (объединение X и Y)
gradient_magnitude = sqrt.(gradient_x.^2 + gradient_y.^2);
imsobel = gradient_magnitude ./ maximum(gradient_magnitude)
Out[0]:
No description has been provided for this image

用大津方法对滤波结果进行二值化处理,无需额外参数:

In [ ]:
BW = binarize(imgray, Otsu());
simshow(BW)
Out[0]:
No description has been provided for this image

让我们添加一些形态学魔法,得到结果掩码:

In [ ]:
se = Kernel.gaussian(3) .> 0.0035;
closeBW = closing(BW,se);
noobj = area_opening(closeBW; min_area=1000) .> 0;
se2 = Kernel.gaussian(5) .> 0.0027;
smooth = closing(noobj,se2);
smooth_2 = opening(smooth,se2);
MASK_sobel = area_opening(.!smooth_2; min_area=500) .> 0;
simshow(MASK_sobel)
Out[0]:
No description has been provided for this image

将结果可视化:

In [ ]:
sv_sobel = StackedView(CV[1,:,:] + (.!MASK_sobel./3), CV[2,:,:] + 
                            (.!MASK_sobel./3), CV[3,:,:]);
view_sobel = colorview(RGB, sv_sobel)
Out[0]:
No description has been provided for this image
In [ ]:
sv_sobel = StackedView(CV[1,:,:] + (MASK_sobel./3), CV[2,:,:] + 
                            (MASK_sobel./3), CV[3,:,:]);
view_sobel = colorview(imsobel, sv_sobel)

我们使用 Sobel 滤镜作为另一种纹理滤镜。我们利用了森林和城市区域亮度均匀性的差异。

SRG 算法

种子区域生长(SRG) 是一种经典的图像分割算法,其基本思想是以预定义的 "种子点 "为起点,根据相似特征将像素或区域分组。

基本工作原理:

1.**选择种子点* 1.

  • 用户或自动方法选择一个或多个属于感兴趣对象的起始点(像素)。

2.相似性标准定义

  • 通常使用的是相邻像素之间在强度、颜色或纹理上的差异。

  • 例如,如果一个像素的强度与区域平均值相差不超过临界值,则将其添加到区域中 T

3.迭代区域扩展

  • 该算法会检查已包含像素的邻域,如果符合标准,就会将其添加到区域中。

  • 这个过程一直持续到无法添加新像素为止。

让我们选择坐标为[200, 50][200,300] 的点作为初始点。让我们目测一下它们的颜色--算法的成功与否取决于此:

In [ ]:
[ I[200,50] I[200,300] ]
Out[0]:
No description has been provided for this image

设置初始点的坐标,并通过函数seeded_region_growing 获取线段(分割结果),同时将初始彩色图像传递给它。段内的平均颜色值可通过函数segments_mean 获得:

In [ ]:
seeds = [(CartesianIndex(200,50),1), (CartesianIndex(200,300),2)]
segments = seeded_region_growing(I, seeds);
sm = segment_mean(segments);
[ sm[1] sm[2] ]
Out[0]:
No description has been provided for this image
In [ ]:
simshow(map(i->segment_mean(segments,i), labels_map(segments)))
Out[0]:
No description has been provided for this image

我们从标签矩阵中获取二进制掩码。我们感兴趣的是标签为1 的像素:

In [ ]:
lmap = labels_map(segments);
BW_smart = lmap .== 1;
simshow(BW_smart)
Out[0]:
No description has been provided for this image

以及一些简单的变形:

In [ ]:
se = Kernel.gaussian(2) .> 0.004;
closeBW = closing(BW_smart,se);
MASK_smart = area_opening(.!closeBW; min_area=500) .> 0;
simshow(MASK_smart)
Out[0]:
No description has been provided for this image

让我们叠加原始图像:

In [ ]:
sv_smart = StackedView(CV[1,:,:] + (.!MASK_smart./3), CV[2,:,:] + 
                            (.!MASK_smart./3), CV[3,:,:]);
view_smart = colorview(RGB, sv_smart)
Out[0]:
No description has been provided for this image

SRG 算法虽然 "聪明",但并不属于机器学习技术。它是一种经典算法,没有学习步骤,也不能直接从数据中自动提取特征。不过,它可以与机器学习技术相结合,例如自动选择起点。

结论

在第二部分中,我们回顾了用于图像分割任务的其他图像处理技术,如阈值色彩分割、用于纹理分析的索贝尔滤波器和 SRG 算法。

接下来,我们将探讨数字图像处理任务中的机器学习。