卫星图像分割,第2部分
第二个例子来自数字图像处理系列。 在[第一部分](https://engee.com/community/ru/catalogs/projects/segmentatsiia-sputnikovogo-snimka-chast-1 我们考虑了卫星图像的分割问题及其解决方案的基本方法。 在第二部分中,我们将介绍新手开发人员可用的其他方法,特别是:
*颜色分割
*Sobel滤波器
*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)
[形态]将帮助我们再次从这组杂乱无章的像素中制作一个遮罩(https://engee.com/community/ru/catalogs/projects/morfologicheskie-operatsii-chast-1 )。 这次我们将采用菱形形状的小型结构元素(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)
Sobel滤波器
Sobel滤波器是图像处理中使用的基于水平和垂直方向上亮度梯度的计算来检测边界(对象的边缘)的运算符。 它使用导数的离散模拟,强调像素强度急剧变化的区域。
暂时忘记颜色,我们将使用亮度图,即灰度:
imgray = Gray.(I)
Sobel运算符使用两个内核(小矩阵)。
*在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)
使用Otsu方法对过滤结果进行二值化,无需附加参数:
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)
Sobel滤波器被我们用作另一个纹理滤波器。 我们利用了森林和城市地区亮度变化均匀性的差异。
SRG算法
**Seeded Region Growing(SRG)**是一个经典的图像分割算法,基于相似特征将像素或区域组合成组的思想,从预定义的"种子点"开始。
操作的基本原则:
-
选择起点(种子)
*用户或自动方法选择属于感兴趣对象的一个或多个起始点(像素)。
-
定义相似性标准
*通常使用相邻像素之间的强度,颜色或纹理差异。
*例如,如果像素的强度与区域的平均值相差不超过阈值,则将像素添加到区域
T. -
区域的迭代扩展
*该算法检查已包含像素的邻居,并在满足条件时将其添加到区域中。
*该过程继续进行,直到可以添加新的像素。
让我们选择以坐标为起点的点。 [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算法虽然"智能",但不适用于机器学习技术。 这是一个经典的算法,其中没有训练阶段,直接从数据中自动提取特征。 然而,它可以结合机器学习技术,例如,自动选择起点。
结论
在第二部分中,我们研究了用于图像分割任务的其他图像处理方法,例如阈值颜色分割,用于纹理分析的Sobel滤波器和SRG算法。
接下来,机器学习等待着我们完成数字图像处理任务。

















