遥感影像的面向对象方法

news2024/11/25 16:21:50

面向对象分割算法是一种将图像中的像素分割成不同的对象的算法。它通过对像素进行聚类,将相似的像素分为同一个对象,从而实现图像分割的目的。常见的面向对象分割算法包括基于区域的分割算法、基于边缘的分割算法和基于能量的分割算法等。

其中,基于区域的分割算法是将图像分成若干个区域,每个区域内的像素具有相似的颜色、纹理或亮度等特征。基于边缘的分割算法则是通过检测图像中的边缘来实现分割,常见的边缘检测算法包括Sobel算子、Canny算子等。基于能量的分割算法则是通过最小化能量函数来实现分割,常见的能量函数包括距离度量、灰度差异度量等。

介绍

遥感影像的面向对象方法是一种基于高分辨率影像的信息提取技术,它主要包括以下几个步骤:

  • 影像分割:将影像划分为若干个具有相似光谱、形状、纹理等特征的同质对象,作为分类或提取的基本单元。
  • 对象属性计算:根据对象的光谱、形状、纹理、上下文等特征,计算对象的多种属性值,用于后续的分类或提取。
  • 对象分类或提取:根据对象的属性值,采用不同的方法对对象进行分类或提取,如监督分类、基于规则的分类、模糊分类等。
  • 结果输出:将分类或提取的结果输出为影像或矢量数据,进行后续的分析或应用。

面向对象方法的优点是能够充分利用高分辨率影像的空间、光谱、纹理等信息,提高信息提取的精度和效率。它也能够解决传统基于像元的方法存在的同物异谱、同谱异物等问题。面向对象方法的难点是如何选择合适的分割参数、对象属性和分类规则,以达到最佳的信息提取效果。

eCongnition软件

在eCongnition软件中面向对象分割方法较多,主要有棋盘分割,四叉树分割,反差切割分割,多尺度分割,光谱差异分割,多阈值分割,反差过滤分割及分水岭分割等分割方式。但其中最常用的分割方法一般为棋盘分割,四叉树分割,多阈值分割以及多尺度分割方法。

棋盘分割:该方法将影像划分为大小一致的正方形图像对象,沿着固定大小的网格线进行切割。该方法运行速度快,适用于借用本底矢量或进行边界修正的情况。但该方法也会导致多种地类混淆,难以进行光谱信息提取。

四叉树分割:该方法将影像划分为不同尺寸的正方形图像对象,根据光谱差异进行切割。该方法运行速度快,且可以综合考虑不同波段和颜色因子的情况,适用于某些略微复杂的地块或地类提取。但该方法也会受到地类混淆的限制,且分割边界不够理想。

反差切割分割:该方法根据影像中不同区域的反差值进行切割,可以得到较为精细和自然的图像对象。该方法适用于边界清晰且反差明显的地物提取,如建筑物、道路等。但该方法也会受到噪声和阴影的影响,且需要设置合适的反差阈值。

多尺度分割:该方法根据影像中不同波段的权重、紧致度和平滑度进行分割,可以得到不同尺寸和形状的图像对象。该方法可以充分利用影像的空间、光谱、纹理等信息,适用于复杂地区或细致地类的提取。但该方法运行效率低,且需要设置合适的分割参数。

光谱差异分割:该方法根据影像中不同波段之间的光谱差异进行切割,可以得到较为均匀和一致的图像对象。该方法适用于光谱特征明显且区别较大的地物提取,如植被、水体等。但该方法也会忽略影像中的空间和纹理信息,且需要设置合适的光谱阈值。

多阈值分割:该方法根据波段的反射率值设定阈值,将影像划分为不同的类别。该方法运行速度极快,且基于像素值进行操作,适用于边界清晰的目标地类,如水体、植被等。但该方法也会导致分割结果呈现出锯齿和畸形,且难以处理复杂地类。

反差过滤分割:该方法根据影像中不同区域的反差值进行过滤和平滑处理,然后再进行切割。该方法可以消除噪声和阴影对分割结果的影响,提高分割质量。但该方法也会降低影像中细节信息的保留,且需要设置合适的过滤参数。

分水岭分割:该方法将影像看作一幅灰度图,并将其转化为一幅拓扑表面。然后根据表面上的局部极小值和局部极大值进行切割,类似于水流从高处向低处流动的过程。该方法可以得到较为细致和自然的图像对象,适用于边界复杂且曲率变化大的地物提取。但该方法也会受到噪声和过分割的影响,且需要设置合适的标记参数。

Google earth engine

Google earth engine是一个基于云计算的地理空间数据分析平台,它提供了多种面向对象方法的实现,如:

SNIC:简单非迭代聚类算法,根据影像中不同波段的权重、紧致度和平滑度进行分割,可以得到不同尺寸和形状的图像对象。
KMeans:K均值聚类算法,根据影像中不同波段的光谱距离进行分割,可以得到较为均匀和一致的图像对象。
Weiss:Weiss分割算法,根据影像中不同区域的反差值进行切割,可以得到较为精细和自然的图像对象。

面向对象分类的基本原理就是先分割影像 、再计算特征、最后分类。
目前使用比较广泛的是SNIC方法,下载着重介绍和给出代码。

代码示例

这段代码转载至网络,流传也比较广泛,带来的问题可能使GEE内存的限制导致提取效果存在一定差异。

 
//-------------------------------去云  ----------------------------------------------//
function sentinel2toa(img) {
  var toa = img.select(['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9','B10', 'B11','B12'],  
                       ['aerosol', 'blue', 'green', 'red', 're1','re2','re3', 'nir','nir2', 'h2o', 'cirrus','swir1', 'swir2'])
                       .divide(10000)
                       .addBands(img.select(['QA60']))
                       .set('solar_azimuth',img.get('MEAN_SOLAR_AZIMUTH_ANGLE'))
                       .set('solar_zenith',img.get('MEAN_SOLAR_ZENITH_ANGLE'))
    return toa;
}
function ESAcloud(toa) {
  var qa = toa.select('QA60');
  var cloudBitMask = Math.pow(2, 10);
  var cirrusBitMask = Math.pow(2, 11);
  var clear = qa.bitwiseAnd(cloudBitMask).eq(0).and(
             qa.bitwiseAnd(cirrusBitMask).eq(0));
  var cloud = clear.eq(0);
  return cloud;
}
function shadowMask(toa,cloud){
  var azimuth =ee.Number(toa.get('solar_azimuth')).multiply(Math.PI).divide(180.0).add(ee.Number(0.5).multiply(Math.PI));
  var zenith  =ee.Number(0.5).multiply(Math.PI ).subtract(ee.Number(toa.get('solar_zenith')).multiply(Math.PI).divide(180.0));
  var nominalScale = cloud.projection().nominalScale();
  var cloudHeights = ee.List.sequence(200,10000,500);
  var shadows = cloudHeights.map(function(cloudHeight){
    cloudHeight = ee.Number(cloudHeight);
    var shadowVector = zenith.tan().multiply(cloudHeight);
    var x = azimuth.cos().multiply(shadowVector).divide(nominalScale).round();
    var y = azimuth.sin().multiply(shadowVector).divide(nominalScale).round();
    return cloud.changeProj(cloud.projection(), cloud.projection().translate(x, y));
  });
  var potentialShadow = ee.ImageCollection.fromImages(shadows).max();
  potentialShadow = potentialShadow.and(cloud.not());
  var darkPixels = toa.normalizedDifference(['green', 'swir2']).gt(0.25).rename(['dark_pixels']);
  var shadow = potentialShadow.and(darkPixels).rename('shadows');
  return shadow;
}
 
function cloud_and_shadow_mask(img) {
  var toa = sentinel2toa(img);
  var cloud = ESAcloud(toa);
  var shadow = shadowMask(toa,cloud);
  var mask = cloud.or(shadow).eq(0);
  return toa.updateMask(mask);
}
//-------------------------------Main----------------------------------------------------------------------------------------//
var table = ee.FeatureCollection("users/xzhangsx/sample200");
var bands =['B1','B2', 'B3', 'B4', 'B5', 'B6','B7','B8','B8A','B9'];
var composite = ee.ImageCollection('COPERNICUS/S2')
    .filterDate('2020-06-01', '2020-06-15')
    .filterBounds(table)
    .mean();
var image = ee.Image(composite).divide(255).select(bands);
print(image);
//设置种子
var seeds = ee.Algorithms.Image.Segmentation.seedGrid(36);
//利用 SNIC 进行分割,得到对象。参数的设置根据自己的需求来
var snic = ee.Algorithms.Image.Segmentation.SNIC({
  image: image, 
  size: 100,
  compactness: 5,
  connectivity: 8,
  neighborhoodSize:256,
  seeds: seeds
}).select(['B1_mean','B2_mean','B3_mean','B4_mean','B5_mean','B6_mean','B7_mean','B8_mean','B8A_mean','B9_mean', 'clusters'], ['B1','B2','B3','B4','B5','B6','B7','B8','B8A','B9', 'clusters']);
var clusters = snic.select('clusters');//
print("snic",snic);
//计算每个对象的特征
var stdDev = image.addBands(clusters).reduceConnectedComponents(ee.Reducer.stdDev(), 'clusters', 256);//为啥和上面的均值不一样?
var area = ee.Image.pixelArea().addBands(clusters).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256);
var minMax = clusters.reduceNeighborhood(ee.Reducer.minMax(), ee.Kernel.square(1));
var perimeterPixels = minMax.select(0).neq(minMax.select(1)).rename('perimeter');
var perimeter = perimeterPixels.addBands(clusters).reduceConnectedComponents(ee.Reducer.sum(), 'clusters', 256);
var sizes = ee.Image.pixelLonLat().addBands(clusters).reduceConnectedComponents(ee.Reducer.minMax(), 'clusters', 256);
var width = sizes.select('longitude_max').subtract(sizes.select('longitude_min')).rename('width');
var height = sizes.select('latitude_max').subtract(sizes.select('latitude_min')).rename('height');
//分类器参数设置,选择分类依据:包括了area,width等
var objectPropertiesImage = ee.Image.cat([
  snic.select(bands),
  //stdDev,
 // area,
  //perimeter,
  //width,
  //height
]).float();
print(objectPropertiesImage);
//var img2 = ee.Image(objectPropertiesImage).divide(255);
//选择训练样本
var training = objectPropertiesImage.sampleRegions({
  collection: table,
  properties: ['value'],
  scale: 30,
  tileScale:8
});
print("training",training);
 
/*var training = objectPropertiesImage.addBands(table.select('value'))
    .updateMask(seeds)
    .sample(table, 5);
print("training2",training2);*/
//分类
var classifier = ee.Classifier.smileCart().train(training, 'value');
print(classifier);
var result=objectPropertiesImage.classify(classifier,'Classified objects');
//Export.image.toCloudStorage(result,"202012172236");
//var resultshp = result.updateMask(seeds).sample(table, 5);
//Export.table.toCloudStorage(resultshp,"202012172120");
print(result);
Map.centerObject(table);
Map.addLayer(result.randomVisualizer(), {}, 'Classified objects2');
// 计算混淆矩阵
var test=training.classify(classifier,'classification');
var confusionMatrix = test.errorMatrix('value', 'classification');
print('Confusion Matrix', confusionMatrix);

简单非迭代聚类(SNIC)超像素分割

在本文中,我们主要介绍一种常用的面向对象分割算法——简单非迭代聚类(SNIC)算法。该算法是一种基于超像素(superpixel)概念的分割方法。超像素是指具有相似颜色和空间位置的像素组成的小区域。超像素可以有效地减少图像中需要处理的数据量,并保留图像中重要的边缘和结构信息。

SNIC算法是一种基于K均值聚类(K-means clustering)思想的超像素分割方法。它从规则网格上创建一些种子点作为初始聚类中心,然后根据每个像素与聚类中心之间在颜色和空间上的距离来将其分配到最近的聚类中。距离计算公式如下:
在这里插入图片描述

其中,d(x,y)是像素x和聚类中心y之间的距离,dc​(x,y)是它们在CIELAB颜色空间上的欧氏距离,ds​(x,y)是它们在图像空间上的欧氏距离,α是一个权重参数,用于控制颜色和空间的相对重要性。一般来说,α的值越大,分割结果越紧致,越小则越平滑。
SNIC算法的执行流程如下所示:

  • 首先,将图像划分为一个规则网格,每个网格单元的大小为s×s像素。然后,在每个网格单元的中心位置创建一个种子点作为初始聚类中心,并将其周围的s×s像素作为初始聚类成员。

  • 其次,对于每个种子点,计算其与其邻域内的所有像素之间的距离,并将距离最小的像素添加到相应的聚类中。邻域的大小为m×m像素,一般取m=2s+1。同时,更新聚类中心的颜色和空间坐标为聚类成员的平均值。

  • 然后,重复上一步骤,直到所有像素都被分配到最近的聚类中,或者达到最大迭代次数为止。最后,输出每个聚类的颜色、空间和形状等属性,以及每个像素所属的聚类标签。

下面是一个简单的例子来展示SNIC算法的输入和输出:

  • 输入是一幅高分辨率遥感影像,大小为512 × 512像素,包含多种地物类型。
  • 输出是一个包含超像素属性和标签的图像对象集合。我们可以看到,超像素具有较好的边缘保持性和形状适应性,能够有效地提取出不同地物类型。

SNIC算法中需要设置的参数主要有四个:

  • 种子距离s:决定了初始网格单元和邻域大小的参数。一般来说,s越大,分割出来的超像素越少,越小则越多。根据影像的分辨率和目标地物类型的大小来选择合适的s值。
  • 分割紧密度α:决定了颜色和空间距离的相对重要性的参数。一般来说,α越大,分割结果越紧致,越小则越平滑。根据影像中地物类型的光谱差异和空间分布来选择合适的α值。
  • 连通性c:决定了超像素是否允许出现孔洞或裂缝的参数。一般来说,c=4表示只考虑上下左右四个方向的连通性,c=8表示考虑八个方向的连通性。根据影像中地物类型的形状复杂度和连通性要求来选择合适的c值。
  • 邻域大小m:决定了每次迭代时考虑的邻域范围的参数。一般来说,m=2s+1是一个比较合理的选择,可以保证每个种子点能够覆盖到其周围所有可能属于同一聚类的像素。

SNIC算法的执行过程和结果如下:

  • 首先,我们需要设置好SNIC算法的参数,如种子距离s,分割紧密度α,连通性c和邻域大小m。1这些参数会影响分割结果的数量、质量和形状。我们可以根据影像的特点和目标来选择合适的参数值,也可以通过试验和评估来找到最佳的参数组合。
  • 其次,我们需要导入一幅高分辨率遥感影像,作为SNIC算法的输入。我们可以使用Google earth engine平台提供的各种遥感数据源,如Landsat、Sentinel、MODIS等,也可以上传自己的遥感影像数据。我们可以根据需要对影像进行预处理,如裁剪、投影、波段选择等。
  • 然后,我们需要调用Google earth engine平台提供的SNIC算法函数,对影像进行分割。该函数会返回一个包含超像素属性和标签的图像对象集合。我们可以对该集合进行后处理,如去除噪声、合并小对象、提取边界等。
  • 最后,我们可以将分割结果输出为影像或矢量数据,进行后续的分析或应用。23我们可以使用Google earth engine平台提供的各种可视化和统计工具,对分割结果进行展示和评估。我们也可以将分割结果导出到本地或云端,进行其他操作或使用。

以下是一个使用Google earth engine平台实现SNIC算法的代码示例:

// Import a high-resolution Landsat 8 image
var image = ee.Image('LANDSAT/LC08/C01/T1_SR/LC08_044034_20140318');

// Define the SNIC parameters
var size = 32; // the seed distance in pixels
var compactness = 5; // the segmentation compactness factor
var connectivity = 8; // the connectivity mode (4 or 8)
var neighborhoodSize = 256; // the neighborhood size in pixels

// Apply the SNIC algorithm to the image
var snic = ee.Algorithms.Image.Segmentation.SNIC({
  image: image, 
  size: size,
  compactness: compactness,
  connectivity: connectivity,
  neighborhoodSize: neighborhoodSize
});

// Display the original image and the segmentation result
Map.centerObject(image, 10);
Map.addLayer(image, {bands: ['B4', 'B3', 'B2'], min: 0, max: 3000}, 'Original Image');
Map.addLayer(snic.randomVisualizer(), {}, 'Segmentation Result');

下面的代码同样也转载至网络,他可能会使你从过程上了解面向对象的具体过程。
将下面的代码复制到新的脚本中:

// 1.1 Unsupervised k-Means classification
 
// This function does unsupervised clustering classification 
// input = any image. All bands will be used for clustering.
// numberOfUnsupervisedClusters = tunable parameter for how 
//        many clusters to create.
var afn_Kmeans = function(input, numberOfUnsupervisedClusters,
    defaultStudyArea, nativeScaleOfImage) {
 
    // Make a new sample set on the input. Here the sample set is 
    // randomly selected spatially. 
    var training = input.sample({
        region: defaultStudyArea,
        scale: nativeScaleOfImage,
        numPixels: 1000
    });
 
    var cluster = ee.Clusterer.wekaKMeans(
            numberOfUnsupervisedClusters)
        .train(training);
 
    // Now apply that clusterer to the raw image that was also passed in. 
    var toexport = input.cluster(cluster);
 
    // The first item is the unsupervised classification. Name the band.
    var clusterUnsup = toexport.select(0).rename(
        'unsupervisedClass');
    return (clusterUnsup);
};

我们还需要一个函数来将频带值归一化为从0到1的公共刻度。当我们创建对象时,这将是最有用的。此外,我们还需要一个函数将平均值添加到波段名称中。将以下函数粘贴到代码中。注意,代码编号故意从1.2跳到1.4;稍后我们将添加第1.3节:

// 1.2 Simple normalization by maxes function.
var afn_normalize_by_maxes = function(img, bandMaxes) {
    return img.divide(bandMaxes);
};
 
// 1.4 Simple add mean to Band Name function
var afn_addMeanToBandName = (function(i) {
    return i + '_mean';
});

我们将创建一个小节,定义您可以调整的变量。一个重要的可调参数是集群器使用的集群数量。将以下代码添加到函数定义下面:

 // 2. Parameters to function calls
 
 
// 2.1. Unsupervised KMeans Classification Parameters
var numberOfUnsupervisedClusters = 4;

该脚本将允许您放大到指定的区域以更好地查看,并且已经存在于代码存储库检查点中。添加下面的代码:

 // 2.2. Visualization and Saving parameters
// For different images, you might want to change the min and max 
// values to stretch. Useful for images 2 and 3, the normalized images.
var centerObjectYN = true;

现在,有了这些函数、参数和标志之后,让我们定义一个新图像,并设置有助于分析图像的特定图像值。我们将把它放在代码的一个新部分中,其中包含来自多个传感器的图像的“if”语句。我们像这样设置代码,因为我们将在接下来的部分中使用来自不同传感器的几张图像,因此它们是预加载的,所以你所要做的就是改变参数“whohimage”。在这张特别的Sentinel-2图像中,专注于区分美国华盛顿普吉特海湾的森林和非森林地区。脚本将自动缩放到感兴趣的区域:

//
// 3. Statements
//
 
// 3.1  Selecting Image to Classify 
var whichImage = 1; // will be used to select among images
if (whichImage == 1) {
    // Image 1. 
    // Puget Sound, WA: Forest Harvest
    // (April 21, 2016)
    // Harvested Parcels
    // Clear Parcel Boundaries
    // Sentinel 2, 10m
    var whichCollection = 'COPERNICUS/S2';
    var ImageToUseID = '20160421T191704_20160421T212107_T10TDT';
    var originalImage = ee.Image(whichCollection + '/' +
    ImageToUseID);
    print(ImageToUseID, originalImage);
    var nativeScaleOfImage = 10;
    var threeBandsToDraw = ['B4', 'B3', 'B2'];
    var bandsToUse = ['B4', 'B3', 'B2'];
    var bandMaxes = [1e4, 1e4, 1e4];
    var drawMin = 0;
    var drawMax = 0.3;
    var defaultStudyArea = ee.Geometry.Polygon(
        [
            [
                [-123.13105468749993, 47.612974066532004],
                [-123.13105468749993, 47.56214700543596],
                [-123.00179367065422, 47.56214700543596],
                [-123.00179367065422, 47.612974066532004]
            ]
        ]);
    var zoomArea = ee.Geometry.Polygon(
        [
            [
                [-123.13105468749993, 47.612974066532004],
                [-123.13105468749993, 47.56214700543596],
                [-123.00179367065422, 47.56214700543596],
                [-123.00179367065422, 47.612974066532004]
            ]
        ], null, false);
}
Map.addLayer(originalImage.select(threeBandsToDraw), {
    min: 0,
    max: 2000
}, '3.1 ' + ImageToUseID, true, 1);

现在,让我们将图像剪辑到我们感兴趣的研究区域,然后提取用于分类过程的波段:

 
// 4. Image Preprocessing 
 
var clippedImageSelectedBands = originalImage.clip(defaultStudyArea)
    .select(bandsToUse);
var ImageToUse = afn_normalize_by_maxes(clippedImageSelectedBands,
    bandMaxes);
 
Map.addLayer(ImageToUse.select(threeBandsToDraw), {
        min: 0.028,
        max: 0.12
    },
    '4.3 Pre-normalized image', true, 0);

现在,让我们查看使用k-means分类器生成的逐像素无监督分类。请注意,正如前面所做的,我们跳过了代码编号的一部分(从第4节移动到第6节),我们将在稍后进一步开发脚本时填充该部分:

 
// 6. Execute Classifications
 
 
// 6.1 Per Pixel Unsupervised Classification for Comparison
var PerPixelUnsupervised = afn_Kmeans(ImageToUse,
    numberOfUnsupervisedClusters, defaultStudyArea,
    nativeScaleOfImage);
Map.addLayer(PerPixelUnsupervised.select('unsupervisedClass')
    .randomVisualizer(), {}, '6.1 Per-Pixel Unsupervised', true, 0
);
print('6.1b Per-Pixel Unsupervised Results:', PerPixelUnsupervised);

然后插入此代码,以便在需要时可以缩放:

 
// 7. Zoom if requested
 
if (centerObjectYN === true) {
    Map.centerObject(zoomArea, 14);
}

运行脚本。它将以真彩色视图绘制研究区域,在那里您可以检查景观的复杂性,就像2016年拍摄图像时您所看到的那样。
在这里插入图片描述
S2A原始影像
在这里插入图片描述
SNIC分割结果

在绘制真彩色图像时,Earth Engine还执行k-means分类,并将其添加到图层集中。打开6.1每像素无监督层的可见性,它显示了使用随机选择的颜色的每像素四类分类结果。结果应该如图所示。
在这里插入图片描述
您在基于像素的分类中注意到的噪声现在将使用基于对象的图像分析的两步方法进行改进。首先,您将使用SNIC算法分割图像,然后使用k-means无监督分类器对其进行分类。返回到脚本,我们将在其中添加一个新函数。请注意,代码的部分是编号的,找到代码部分1.2并将下面的函数添加到它下面:

// 1.3 Seed Creation and SNIC segmentation Function
var afn_SNIC = function(imageOriginal, SuperPixelSize, Compactness,
    Connectivity, NeighborhoodSize, SeedShape) {
    var theSeeds = ee.Algorithms.Image.Segmentation.seedGrid(
        SuperPixelSize, SeedShape);
    var snic2 = ee.Algorithms.Image.Segmentation.SNIC({
        image: imageOriginal,
        size: SuperPixelSize,
        compactness: Compactness,
        connectivity: Connectivity,
        neighborhoodSize: NeighborhoodSize,
        seeds: theSeeds
    });
    var theStack = snic2.addBands(theSeeds);
    return (theStack);
};

如您所见,该函数组装了运行SNIC所需的参数(Achanta和Süsstrunk 2017, Crowley等人,2019),该函数在图像中描绘对象。对SNIC的调用需要几个参数,我们将探讨这些参数。在代码节2.2下面添加以下代码:

// 2.3 Object-growing parameters to change
// Adjustable Superpixel Seed and SNIC segmentation Parameters:
// The superpixel seed location spacing, in pixels.
var SNIC_SuperPixelSize = 16;
// Larger values cause clusters to be more compact (square/hexagonal). 
// Setting this to 0 disables spatial distance weighting.
var SNIC_Compactness = 0;
// Connectivity. Either 4 or 8. 
var SNIC_Connectivity = 4;
// Either 'square' or 'hex'.
var SNIC_SeedShape = 'square';
 
// 2.4 Parameters that can stay unchanged
// Tile neighborhood size (to avoid tile boundary artifacts). Defaults to 2 * size.
var SNIC_NeighborhoodSize = 2 * SNIC_SuperPixelSize;

现在添加一个对SNIC函数的调用。您将注意到,它接受代码第2节中指定的参数,并将它们发送给SNIC算法。将下面的代码放入脚本中,作为代码的第5节,位于第4节和第6节之间:

 
// 5. SNIC Clustering
 
 
// This function returns a multi-banded image that has had SNIC
// applied to it. It automatically determine the new names 
// of the bands that will be returned from the segmentation.
print('5.1 Execute SNIC');
var SNIC_MultiBandedResults = afn_SNIC(
    ImageToUse,
    SNIC_SuperPixelSize,
    SNIC_Compactness,
    SNIC_Connectivity,
    SNIC_NeighborhoodSize,
    SNIC_SeedShape
);
 
var SNIC_MultiBandedResults = SNIC_MultiBandedResults
    .reproject('EPSG:3857', null, nativeScaleOfImage);
print('5.2 SNIC Multi-Banded Results', SNIC_MultiBandedResults);
 
Map.addLayer(SNIC_MultiBandedResults.select('clusters')
    .randomVisualizer(), {}, '5.3 SNIC Segment Clusters', true, 1);
 
var theSeeds = SNIC_MultiBandedResults.select('seeds');
Map.addLayer(theSeeds, {
    palette: 'red'
}, '5.4 Seed points of clusters', true, 1);
 
var bandMeansToDraw = threeBandsToDraw.map(afn_addMeanToBandName);
print('5.5 band means to draw', bandMeansToDraw);
var clusterMeans = SNIC_MultiBandedResults.select(bandMeansToDraw);
print('5.6 Cluster Means by Band', clusterMeans);
Map.addLayer(clusterMeans, {
    min: drawMin,
    max: drawMax
}, '5.7 Image repainted by segments', true, 0);

现在运行脚本。它将绘制几个图层,下图所示的图层在最上面。
在这里插入图片描述
这显示了SNIC在发送给它的图像上的工作——在这种情况下,在波段8、11和12的合成上。如果你仔细观察彩色图层,你可以看到红色的小“种子”像素。为了启动这个过程,需要创建这些种子,并按照传递给函数的参数所给出的间隔形成正方形或六角形的“超级像素”。然后,这些块的边缘被推拉,并在输入图像的边缘处停止。作为算法的一部分,一些超级像素被合并成更大的块,这就是为什么你会发现一些形状包含两个或更多的种子像素。通过改变第5层的透明度来探索结构,以判断对于给定的参数值集图像分割的表现。你也可以比较5.7层和3.1层。5.7层是3.1层的重新解释,其中5.3层中给定形状中的每个像素都被分配了形状内像素的平均值。当以一种对给定项目目标有用的方式进行参数化时,图像中同质的部分将获得相同的颜色,而高异质性的区域将获得多种颜色。
现在你可以花些时间研究控制代码参数的效果来回答下面的问题。

问题1:改变参数SNIC_SuperPixelSize对SNIC集群有什么影响?

问题2:改变参数SNIC_Compactness会有什么影响?

问题3:改变参数SNIC_Connectivity和SNIC_SeedShape会有什么影响?

本教程中使用的k-means分类器没有意识到我们通常更喜欢将相邻像素分组到同一类中——它没有物理空间的感觉。这就是为什么你会在无监督分类中看到噪音。但是,因为我们重新着色了SNIC集群中的像素以共享完全相同的频带值,k-means将每个集群中的所有像素分组为具有相同的类。在最好的情况下,这允许我们从基于像素增强我们的分类,以显示景观中干净和明确的对象。在本节中,我们将对这些对象进行分类,探索在此图像中寻找对象的优势和局限性。返回SNIC设置的第一个值,即:

// The superpixel seed location spacing, in pixels.
var SNIC_SuperPixelSize = 16;
// Larger values cause clusters to be more compact (square/hexagonal). 
// Setting this to 0 disables spatial distance weighting.
var SNIC_Compactness = 0;
// Connectivity. Either 4 or 8. 
var SNIC_Connectivity = 4;
// Either 'square' or 'hex'.
var SNIC_SeedShape = 'square';

作为代码6.2节,添加这段代码,它将调用SNIC函数并绘制结果:

// 6.2 SNIC Unsupervised Classification for Comparison
var bandMeansNames = bandsToUse.map(afn_addMeanToBandName);
print('6.2 band mean names returned by segmentation', bandMeansNames);
var meanSegments = SNIC_MultiBandedResults.select(bandMeansNames);
var SegmentUnsupervised = afn_Kmeans(meanSegments,
    numberOfUnsupervisedClusters, defaultStudyArea,
    nativeScaleOfImage);
Map.addLayer(SegmentUnsupervised.randomVisualizer(), {},
    '6.3 SNIC Clusters Unsupervised', true, 0);
print('6.3b Per-Segment Unsupervised Results:', SegmentUnsupervised);

当您运行脚本时,新函数将在5.7层中对图像进行分类,这是根据第5层中显示的片段对原始图像进行重新着色。比较超级像素的分类(6.3)和逐像素值的无监督分类(6.1)。您应该能够更改这两个层的透明度,以便直接比较它们。

SNIC分割算法有效解决了大区域计算数量的难题,关于其中最优参数的调节要根据具体数据的使用情况来看,如果研究区域太大,可以将研究区分为几个小瓦片进行同样也可以完成分割。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1089753.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【2023年11月第四版教材】专题1 - 计算题考点汇总 (合集篇)

专题1 - 计算题考点汇总 (合集篇) 1 进度类1.1 PERT三点估算1.1.1 β分布1.1.2 三角分布 1.2 单代号网络图1.2.1 画图1.2.2 找关键路径1.2.3 计算总工期1.2.4 总时差1.2.5 自由时差1.2.6 工期压缩 1.3 双代号网络图1.4 双代号时标网络图1.4.1 画图1.4.2 找关键路径1…

大公司产品经理都用哪些原型工具?

原型设计工具的应用场景包括产品展示、产品需求规划和抽象到具体呈现,那么如何根据应用场景选择合适的原型工具呢?不用说,本文列出了常用的原型设计工具,看看你最想选择哪一个! 即时设计 即时设计是国内一款专业级的…

java非文本文件copy

文本文件使用字符流来处理 非文本文件使用字节流来处理 字节流处理代码整理 public void copyFile(String srcPath, String desPath) {FileInputStream fileInputStream null;FileOutputStream fileOutputStream null;try {File srcFile new File(srcPath);File desFile ne…

链表(3):双链表

引入 我们之前学的单向链表有什么缺点呢? 缺点:后一个节点无法看到前一个节点的内容 那我们就多设置一个格子prev用来存放前面一个节点的地址,第一个节点的prev存最后一个节点的地址(一般是null) 这样一个无头双向…

Dart-C、Dart-Kotlin/Java/Swift/Object-C、Kotlin-C数据类型对照表

参考一:Dart FFI 数据类型映射 一、Dart—C 的数据类型对照 二、Dart—Java/Kotlin/Object-C/Swift 的数据类型对照 三、C—Kotlin 的数据类型对照

WordPress发布文章上传图片如何默认选择全尺寸

最近发现每次上传图片插入到文章中,图片默认选择缩略图大小并靠左,每次都需要手动修改一下图片信息,比较麻烦。 今天为大家提供修改默认上传图片大小和对齐方式等。 将代码添加到functions.php: //WordPress 设置图片的默认显示…

Qt 样式表大全整理

【QT】史上最全最详细的QSS样式表用法及用例说明_qt样式表使用大全_半醒半醉日复日,花落花开年复年的博客-CSDN博客 QT样式表的使用_qt 设置按下 release hover 按钮样式表_create_right的博客-CSDN博客 QPushButton {border-image: url(:/Start_Stop.png); } QPu…

H5营销观察:场景应用的重要性

H5营销是很常见的营销方式,通常用于各种营销活动和推广活动。对于品牌部或市场部人员,提到“场景化营销”,很多人的第一反应就是如何制作一个有创意、能快速传播的H5。 似乎H5营销已经成为市场人专业度的考量,不论是品牌宣传、活动…

001flutter基础学习

flutter基础学习 参考:https://book.flutterchina.club/chapter1/flutter_intro.html Flutter是谷歌的移动UI框架跨平台: Linux,Android, IOS,Fuchsia原生用户界面:它是原生的,让我们体验更好,性能更好开源免费:完全开源,可以进行商用Flutter与主流框架的对比 Cor…

Rt-Thread 移植4--对象容器实现(KF32)

1.对象 1,1 什么是对象 所有的数据结构都是对象 1.2代码实现 1.2.1 对象类型枚举定义 rtdef.h 添加rt_object_class_type enum rt_object_class_type{RT_Object_Class_NULL0,RT_Object_Class_Thread ,RT_Object_Class_Semaphore,RT_Object_Class_Mutex,RT_Object_Class_E…

【java学习】JavaBean(28)

文章目录 1. 概念 1. 概念 JavaBean 是一种 Java 语言写成的可重用组件。 所谓 javaBean ,是指符合如下标准的 Java 类: (1) 类是公共的 (2) 有一个无参的公共的构造器 (3) 有属性,属性一般是私有的,且有对应的 get 、set 方法 …

cad问题:无法识别的版本,不能读取

cad安装目录或文件名、新建时的文件模板,含有“无”这个字就会出现此问题,只要把 无这个字改成没,即可解决

Kafka进阶

Kafka进阶 Kafka事务 kafka的事务机制是指kafka支持跨多个主题和分区的原子性写入,即在一个事务中发送的所有消息要么全部成功,要么全部失败。 kafka的事务机制涉及到以下几个方面: 事务生产者(transactional producer&#x…

【牛客面试必刷TOP101】Day12.BM72 连续子数组的最大和和BM80 买卖股票的最好时机(一)

作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:牛客面试必刷TOP101 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!&…

StatefulSet 简单实践 Kubernetes

概述 在Kubernetes集群中部署MySQL和Mongodb的StatefulSet服务。 MySQL有官方文档的指引 其他网站博客的指引实现 Mongodb修改operator的Deployment进行简单的实现 MySQL-StatefulSet 参考官方文档:运行一个有状态的应用程序 | Kubernetes 深入剖析Kubernete…

matlab第三方硬件支持包下载和安装

1、在使用matlab内部的附加功能安装时,由于matlab会验证是否正版无法打开 2、在matlab官网直接找到对应的硬件支持包下载,但是是下图的安装程序 可以直接在matlab中跳转到该程序所在的文件夹双击安装,但是安装到最后出错了 3.根据出错时mala…

创邻科技Galaxybase—激活数据要素的核心引擎

10月11日下午,创邻科技创始人张晨博士受杭州电子科技大学邀请,前往杭电校园开展交流分享。交流会中,张晨博士为现场的师生带来一场题为《图数据库——激活数据要素的新基建》的精彩分享,探讨数字经济时代底层技术的创新价值与图技…

CRM系统管理多渠道客户的方法

很多企业同时拥有多个销售渠道,由于客户来自不同的销售渠道,数据非常分散,管理起来费时费力。或许您可以使用CRM客户管理系统来管理不同渠道的客户,下面说说企业常见的销售渠道有哪些?CRM系统如何管理多渠道客户&#…

一招搞定,终止端口号进程

场景:聪明的小明写了个到点执行关机的脚本,再次启动项目时发现端口号占用,操作步骤来了。 步骤1: winr,cmd走起 netstat -ano | findstr "端口号" 步骤2: 查询该进程 tasklist | findstr "P…

苹果macOS Sonoma 14正式版 “黑苹果”且用且珍惜

9月下旬,苹果正式发布了全新的桌面操作系统macOS Sonoma 14,对于一众的“黑苹果”用户来说,这是个让人既兴奋又害怕的消息,兴奋的是又有新系统可以升级了,害怕的是“黑苹果”距离寿终正寝的时间也越来越近了。 所谓的“…