加载所需库函数,导入图像 {#加载所需库函数,导入数据} * SRG 算法¶
如果应用代码中缺少某些内容,则应取消注释下一行代码:
# Pkg.add(["Images", "ImageShow", "ImageContrastAdjustment", "ImageBinarization", "ImageMorphology", "ImageFiltering", "ImageSegmentation"])
连接必要的库:
using Images, ImageShow, ImageContrastAdjustment, ImageBinarization, ImageMorphology, ImageFiltering, ImageSegmentation
加载原始彩色图像(卫星图像):
I = load("$(@__DIR__)/map_small.jpg")
颜色分割¶
在第一部分中,我们几乎没有涉及颜色信息,但显而易见的是,森林区域大部分是绿色的,而城市则含有大量的灰色和白色。这意味着我们可以尝试提取与图像中绿色色调颜色相近的区域。我们将对图像的各个通道进行二值化处理,然后像之前一样使用函数channelview
对其进行访问:
(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,:,:]) ]
我们可以假设,一个典型的 "绿色像素 "位于图像的中心。我们选择 "中心 "像素,知道图像的宽度和高度,然后查看其颜色通道的强度值:
midh = Int(round(h/2));
midw = Int(round(w/2));
midpixel = CV[:,midh, midw]
现在,我们使用标准的逻辑比较操作,对每个通道进行二值化处理。在红色通道中,强度为 0.15 至 0.25 的像素将对应一个逻辑值,在绿色通道中,强度为 0.2 至 0.3 的像素将对应一个逻辑值,在蓝色通道中,强度为 0.05 至 0.15 的像素将对应一个逻辑值。
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])
现在,让我们通过逻辑 "AND "操作将三个二进制掩码合并为一个掩码--现在,只有在原始彩色图像中满足所有三个条件(范围)的地方才会出现白色像素:
BIN = BIN_RED .& BIN_GREEN .& BIN_BLUE;
simshow(BIN)
形态学 将再次帮助我们将这组杂乱无章的像素制作成遮罩。这一次,我们将选取一个菱形的小结构元素(7x7 像素):
se = strel_diamond((7,7))
并评估形态学封闭操作的结果:
closeBW = closing(BIN,se);
simshow(closeBW)
我们通过去除小 "斑点 "并再次执行闭合操作来获得遮罩,现在是为了平滑合并后白色像素中主要 "大 "区域的边界:
openBW = area_opening(closeBW; min_area=500) .> 0;
se2 = Kernel.gaussian(3) .> 0.0025;
MASK_colorseg = closing(openBW,se2);
simshow(MASK_colorseg)
让我们用熟悉的方法将倒置遮罩应用到原始图像中:
sv_colorseg = StackedView(CV[1,:,:] + (.!MASK_colorseg./3), CV[2,:,:] +
(.!MASK_colorseg./3), CV[3,:,:]);
view_colorseg = colorview(RGB, sv_colorseg)
索贝尔滤波器¶
索贝尔滤波器是图像处理中的一种运算器,通过计算水平和垂直方向上的亮度梯度来检测边界(物体的边缘)。它应用导数的离散模拟,突出像素强度急剧变化的区域。
我们将暂时忘记颜色,而使用亮度图,即灰度图:
imgray = Gray.(I)
索贝尔算子使用两个核(小矩阵)。
X轴(垂直边界):
[ -1 0 1 ]
[ -2 0 2 ]
[ -1 0 1 ]
Y 轴(水平边界):
[ -1 -2 -1 ]
[ 0 0 0 ]
[ 1 2 1 ]
操作原则:
每个核对图像进行卷积,突出其方向上的亮度变化。
将结果应用于原始图像,以获得图像:
Gx (X 梯度)、
Gy(Y 梯度)。
总梯度定义为 Gx 和 Gy 的平方和之根
# Ядра Собеля для осей 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)
用大津方法对滤波结果进行二值化处理,无需额外参数:
BW = binarize(imgray, Otsu());
simshow(BW)
让我们添加一些形态学魔法,得到结果掩码:
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)
将结果可视化:
sv_sobel = StackedView(CV[1,:,:] + (.!MASK_sobel./3), CV[2,:,:] +
(.!MASK_sobel./3), CV[3,:,:]);
view_sobel = colorview(RGB, sv_sobel)
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]
的点作为初始点。让我们目测一下它们的颜色--算法的成功与否取决于此:
[ I[200,50] I[200,300] ]
设置初始点的坐标,并通过函数seeded_region_growing
获取线段(分割结果),同时将初始彩色图像传递给它。段内的平均颜色值可通过函数segments_mean
获得:
seeds = [(CartesianIndex(200,50),1), (CartesianIndex(200,300),2)]
segments = seeded_region_growing(I, seeds);
sm = segment_mean(segments);
[ sm[1] sm[2] ]
simshow(map(i->segment_mean(segments,i), labels_map(segments)))
我们从标签矩阵中获取二进制掩码。我们感兴趣的是标签为1
的像素:
lmap = labels_map(segments);
BW_smart = lmap .== 1;
simshow(BW_smart)
以及一些简单的变形:
se = Kernel.gaussian(2) .> 0.004;
closeBW = closing(BW_smart,se);
MASK_smart = area_opening(.!closeBW; min_area=500) .> 0;
simshow(MASK_smart)
让我们叠加原始图像:
sv_smart = StackedView(CV[1,:,:] + (.!MASK_smart./3), CV[2,:,:] +
(.!MASK_smart./3), CV[3,:,:]);
view_smart = colorview(RGB, sv_smart)
SRG 算法虽然 "聪明",但并不属于机器学习技术。它是一种经典算法,没有学习步骤,也不能直接从数据中自动提取特征。不过,它可以与机器学习技术相结合,例如自动选择起点。