【GEE笔记】最大类间方差法(otsu、大津法)算法实现——计算阈值、图像二值化分割

这篇具有很好参考价值的文章主要介绍了【GEE笔记】最大类间方差法(otsu、大津法)算法实现——计算阈值、图像二值化分割。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

主要内容

1、最大类间方差法原理概述

2、GEE频率分布统计,直方图绘制

3、算法具体实现,以GEE JavaScript版本为例

4、目标像元提取,以遥感影像提取水体为示例

算法原理

概念

最大类间方差法(又名otsu、大津法)是由日本学者OTSU于1979年提出的一种对图像进行二值化的高效算法。算法假定该图像根据频率分布直方图把包含两类像元(前景像元和背景像元),计算能将两类分开的最佳阈值,使得它们的类内方差最小;由于两两平方距离恒定,所以即它们的类间方差最大。

优点:计算简单快速,不受图像亮度和对比度的影响。

缺点:对图像噪声敏感;如果图像中的前景像元和背景像元的面积相差很大,直方图没有明显的双峰,或者两个峰的大小相差很大,分割效果不佳。实际应用中,常结合其他方法。

原理

大津法借助穷举法搜索能使类内方差最小的阈值,计算两个类的方差的加权和,权值为两类各自的概率,前人证明了最小化类内方差和最大化类间方差是相同的。

图像的总平均灰度为:M=P1(t) * M0 + P2(t) * M1

前景与背景像元类间方差:S=P1(t) * (M1 - M) * (M1 - M) + P2(t) * (M2 - M) * (M2 - M)

t为前景与背景的分割阈值,前景像元占图像比例为P1(t),平均灰度为M1;背景像元占图像比例为P2(t),平均灰度为M1。

算法实现

数据准备

1、原始影像:定义示例矢量区域geometry(山东省潍坊市峡山水库周边,便于提取水体),时间范围,云量低于20%,筛选出符合条件的Landsat8影像集dataset,中值合成得到示例影像l8_image 

var geometry = 
    ee.Geometry.Polygon(
        [[[119.3140376290338, 36.559328749628065],
          [119.3140376290338, 36.263933411986294],
          [119.62234146204162, 36.263933411986294],
          [119.62234146204162, 36.559328749628065]]], null, false);

var dataset = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterDate('2021-10-01', '2021-12-01')
    .filterBounds(geometry)
    .filter(ee.Filter.lt('CLOUD_COVER', 20));


function applyScaleFactors(image) {
    var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
    var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
    return image.addBands(opticalBands, null, true)
        .addBands(thermalBands, null, true);
}

//获取图像 中值合成
var l8_image = dataset
    .map(applyScaleFactors)
    .median().clip(geometry);

//可视化
var visualization = {
    bands: ['SR_B4', 'SR_B3', 'SR_B2'],
    min: 0.0,
    max: 0.3,
};
Map.centerObject(geometry);
Map.addLayer(l8_image, visualization, 'True Color (432)');

原始影像真彩色显示:

【GEE笔记】最大类间方差法(otsu、大津法)算法实现——计算阈值、图像二值化分割

2、提取NDWI:后续用于计算阈值,识别水体和非水体

NDWI(Normalized Difference Water Index,归一化水指数),用遥感影像的特定波段进行归一化差值处理,以凸显影像中的水体信息。其表达式为:

NDWI =(p(Green)-p(NIR))/(p(Green)+p(NIR))

是基于绿波段与近红外波段的归一化比值指数,一般用来提取影像中的水体信息,效果较好。

var ndwi = l8_image.normalizedDifference(['SR_B3', 'SR_B5']).float().rename('l8_NDWI');
print("ndwi", ndwi)
var visParams1 = {
    min: 0, max: 1, palette: ['FFFFFF', 'CE7E45', 'DF923D', 'F1B555', 'FCD163', '99B718',
        '74A901', '66A000', '529400', '3E8601', '207401', '056201',
        '004C00', '023B01', '012E01', '011D01', '011301']
};
Map.addLayer(ndwi, visParams1, "l8_NDWI");

NDWI灰度显示:

数据查看

NDWI频数分布直方图计算并显示,可见有明显双峰,且两类没有重叠,非常便于运用大津法计算分割阈值,其中参数: 最大组数maxBuckets 最小组距minBucketWidth设置较为关键,具体其他参数参阅官方文档

GEE右上角“Download”可以将csv数据下载到本地进行分析

//频数分布直方图
var chart = ui.Chart.image.histogram({
    image: ndwi,
    region: geometry,
    scale: 30,
    maxBuckets: 1000,//最大组数
    minBucketWidth: 0.01, //最小组距
    // maxRaw, 
    maxPixels: 1e13
})
print(chart)

【GEE笔记】最大类间方差法(otsu、大津法)算法实现——计算阈值、图像二值化分割

 计算阈值

首先计算频数分布数据,同前文注意参数设置,之后利用穷举法计算类内方差,得到类间方差结果表,按照方差排序,得到方差最大对应的值即为最佳阈值,

阈值=0.06508403641771252,可见符合频数分布直方图示意

详细过程见代码注释

//计算OTSU阈值 
var yuzhi = otsu(ndwi)
print("阈值", yuzhi)

//OTSU
function otsu1(histogram) {
    // 各组频数
    var counts = ee.Array(ee.Dictionary(histogram).get('histogram'))
    // 各组的值
    var means = ee.Array(ee.Dictionary(histogram).get('bucketMeans'))
    // 组数
    var size = means.length().get([0])
    // 总像元数量
    var total = counts.reduce(ee.Reducer.sum(), [0]).get([0])
    // 所有组的值之和
    var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]).get([0])
    // 整幅影像的均值
    var mean = sum.divide(total)

    // 与组数相同长度的索引
    var indices = ee.List.sequence(1, size)
    // 穷举法计算类内方差
    var bss = indices.map(function (i) {
        // 当 i = 1, aCounts = [counts[0]], 当 i = 2, aCounts = [counts[0], counts[1]] 
        //从i分割为两类A、B 计算A方差
        var aCounts = counts.slice(0, 0, i)
        var aCount = aCounts.reduce(ee.Reducer.sum(), [0]).get([0])
        var aMeans = means.slice(0, 0, i)
        // 类别A均值
        var aMean = aMeans.multiply(aCounts)
            .reduce(ee.Reducer.sum(), [0]).get([0])
            .divide(aCount)

        var bCount = total.subtract(aCount)
        // 类别B均值
        var bMean = sum.subtract(aCount.multiply(aMean)).divide(bCount)
        //类间方差公式
        return aCount.multiply(aMean.subtract(mean).pow(2)).add(
            bCount.multiply(bMean.subtract(mean).pow(2)))
    })

    print('类间方差', ui.Chart.array.values(ee.Array(bss), 0, means))

    // 排序选出最适阈值
    return means
        .sort(bss)
        .get([-1])
}
function otsu(image) {
    var histogram = image.reduceRegion({
        reducer: ee.Reducer.histogram(1000, 0.01),// 自行修改合适的最大组数,最小组距
        geometry: geometry,
        scale: 30,
        bestEffort: true,
        // tileScale:16
    });
    print("频数分布", histogram)
    return otsu1(histogram.get(histogram.keys().get(0)));
}

分割图像

借助前文得到的的阈值进行影像二值化分割,得到水体示意图

var result = ndwi.gt(yuzhi)
Map.addLayer(result.randomVisualizer(), "", "water");

结果图:

【GEE笔记】最大类间方差法(otsu、大津法)算法实现——计算阈值、图像二值化分割

代码附录

链接:https://code.earthengine.google.com/4456dc4c799a8673d0f1aec1431250f4文章来源地址https://www.toymoban.com/news/detail-460476.html

var geometry = 
    /* color: #d63000 */
    /* shown: false */
    /* displayProperties: [
      {
        "type": "rectangle"
      }
    ] */
    ee.Geometry.Polygon(
        [[[119.3140376290338, 36.559328749628065],
          [119.3140376290338, 36.263933411986294],
          [119.62234146204162, 36.263933411986294],
          [119.62234146204162, 36.559328749628065]]], null, false);

var dataset = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterDate('2021-10-01', '2021-12-01')
    .filterBounds(geometry)
    .filter(ee.Filter.lt('CLOUD_COVER', 20));


function applyScaleFactors(image) {
    var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
    var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
    return image.addBands(opticalBands, null, true)
        .addBands(thermalBands, null, true);
}

//获取图像 中值合成
var l8_image = dataset
    .map(applyScaleFactors)
    .median().clip(geometry);

//可视化
var visualization = {
    bands: ['SR_B4', 'SR_B3', 'SR_B2'],
    min: 0.0,
    max: 0.3,
};
Map.centerObject(geometry);
Map.addLayer(l8_image, visualization, 'True Color (432)');

var ndwi = l8_image.normalizedDifference(['SR_B3', 'SR_B5']).float().rename('l8_NDWI');
print("ndwi", ndwi)
var visParams1 = {
    min: 0, max: 1
};
Map.addLayer(ndwi, visParams1, "l8_NDWI");

//频数分布直方图
var chart = ui.Chart.image.histogram({
    image: ndwi,
    region: geometry,
    scale: 30,
    maxBuckets: 1000,//最大组数
    minBucketWidth: 0.01, //最小组距
    // maxRaw, 
    maxPixels: 1e13
})
print(chart)

//计算OTSU阈值 分割图像
var yuzhi = otsu(ndwi)
print("阈值", yuzhi)
var result = ndwi.gt(yuzhi)
Map.addLayer(result.randomVisualizer(), "", "water");
//
OTSU/

function otsu1(histogram) {
    // 各组频数
    var counts = ee.Array(ee.Dictionary(histogram).get('histogram'))
    // 各组的值
    var means = ee.Array(ee.Dictionary(histogram).get('bucketMeans'))
    // 组数
    var size = means.length().get([0])
    // 总像元数量
    var total = counts.reduce(ee.Reducer.sum(), [0]).get([0])
    // 所有组的值之和
    var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]).get([0])
    // 整幅影像的均值
    var mean = sum.divide(total)

    // 与组数相同长度的索引
    var indices = ee.List.sequence(1, size)
    // 穷举法计算类内方差
    var bss = indices.map(function (i) {
        // 当 i = 1, aCounts = [counts[0]], 当 i = 2, aCounts = [counts[0], counts[1]] 
        //从i分割为两类A、B 计算A方差
        var aCounts = counts.slice(0, 0, i)
        var aCount = aCounts.reduce(ee.Reducer.sum(), [0]).get([0])
        var aMeans = means.slice(0, 0, i)
        // 类别A均值
        var aMean = aMeans.multiply(aCounts)
            .reduce(ee.Reducer.sum(), [0]).get([0])
            .divide(aCount)

        var bCount = total.subtract(aCount)
        // 类别B均值
        var bMean = sum.subtract(aCount.multiply(aMean)).divide(bCount)
        //类间方差公式
        return aCount.multiply(aMean.subtract(mean).pow(2)).add(
            bCount.multiply(bMean.subtract(mean).pow(2)))
    })

    print('类间方差', ui.Chart.array.values(ee.Array(bss), 0, means))

    // 排序选出最适阈值
    return means
        .sort(bss)
        .get([-1])
}
function otsu(image) {
    var histogram = image.reduceRegion({
        reducer: ee.Reducer.histogram(1000, 0.01),
            // .combine('mean', null, true)
            // .combine('variance', null, true),
        geometry: geometry,
        scale: 30,
        bestEffort: true,
        // tileScale:16
    });
    print("频数分布", histogram)
    return otsu1(histogram.get(histogram.keys().get(0)));
}

到了这里,关于【GEE笔记】最大类间方差法(otsu、大津法)算法实现——计算阈值、图像二值化分割的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • GEE使用 Sentinel-1 SAR影像 和 Otsu 方法绘制洪水地图

            洪水是世界上最常见、破坏性最大的自然灾害之一,造成了巨大的生命和财产损失。此外,随着气候变化的影响,近年来,洪灾变得更加频繁和不可预测。为了最大限度地减少生命和财产损失,必须迅速发现洪水蔓延的情况,并及时采取必要的干预措施。洪水蔓延

    2024年02月19日
    浏览(26)
  • 大津算法的matlab实现

    一、算法功能 ​ 图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析的关键步骤。 ​ 大津算法也称最大类间差法,由大津于1979年提出,被认为是图像分割中阈值选取的最佳算法,计算简单,不受图像亮

    2024年02月08日
    浏览(23)
  • Matlab实现 遗传算法 无向图结点分成两类使得两类间边数最少 数学建模作业

    输入:一个图的邻接矩阵G,n1,n2 (举例n1=16,n2=1) 输出:节点的分类id(第一类为0,第二类为1,0的个数为n1个, 1的个数为n2个) 目标:使得两类之间的边数最少 算法:遗传算法 目录 步骤1:初始化种群,种群个数,随机生成初始种群 步骤2:交叉算子 步骤3:突变算子 步骤

    2024年02月11日
    浏览(60)
  • [图像处理]14.分割算法比较 OTSU算法+自适应阈值算法+分水岭

    参考文献: OTSU阈值分割+孔洞填充+海陆分离_SwordKii的博客-CSDN博客 drawContours函数_普通网友的博客-CSDN博客_drawcontours R329-opencv阈值分割算法——自适应阈值_Third Impact的博客-CSDN博客_opencv自适应阈值分割 分水岭算法的python实现及解析_进不去的博客-CSDN博客_python分水岭算法 分水

    2024年02月09日
    浏览(42)
  • 机器学习实战教程(四):从特征分解到协方差矩阵:详细剖析和实现PCA算法

    方差和标准差的原理和实例演示,请参考 方差 方差(Variance)是度量一组数据的分散程度。方差是各个样本与样本均值的差的平方和的均值: 标准差 标准差是数值分散的测量。 标准差的符号是 σ (希腊语字母 西格马,英语 sigma) 公式很简单:方差的平方根。 协方差 通俗

    2024年02月02日
    浏览(40)
  • Numpy中统计函数的讲解:平均值、中位数、标准差、方差、最大最小值、求和、加权平均数

    目录 统计函数: Numpy 能方便地求出统计学常见的描述性统计量 一:Numpy中统计函数--平均值 求平均值 二:Numpy中统计函数--中位数 中位数 np.median 平均数和中位数的区别 三:Numpy中统计函数--标准差 求标准差ndarray.std() 四:Numpy中统计函数--方差 求方差ndarray.var() 标准差和方差

    2024年02月06日
    浏览(37)
  • LeetCode刷题笔记【23】:贪心算法专题-1(分发饼干、摆动序列、最大子序和)

    贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 例如,有一堆钞票,你可以拿走十张,如果想达到最大的金额,你要怎么拿? 指定每次拿最大的,最终结果就是拿走最大数额的钱。 每次拿最大的就是局部最优,最后拿走最大数额的钱就是推出全局最优。 感觉像

    2024年02月09日
    浏览(42)
  • 分词算法----正向和逆向最大匹配算法(含Python代码实现)

    分词算法(Segmentation Method) 在文本处理流程中,对语句进行分词(Segmentation)操作对于计算机认识并理解人类语言是基础且重要的。 对于中文来讲,不同于英文直接采用空格符进行分隔,并且中文词语内涵丰厚,语义丰富,所以只有采用合适的分词算法,才能准确迅速地向计

    2024年03月25日
    浏览(43)
  • GEE初学者笔记之快速上手篇

    (1)谷歌云平台         整个GEE是基于Google Cloud云平台的一整套API开发环境。因此整个数据的处理全部都是在Google Cloud平台上实现的,无需本地机器参与运算。一般开发流程是在线/离线编辑代码,然后提交服务器端运行,完成之后会输出给我们一些结果。这个思路适合离线

    2024年02月07日
    浏览(61)
  • LeetCode刷题笔记【25】:贪心算法专题-3(K次取反后最大化的数组和、加油站、分发糖果)

    参考前文 参考文章: LeetCode刷题笔记【23】:贪心算法专题-1(分发饼干、摆动序列、最大子序和) LeetCode刷题笔记【24】:贪心算法专题-2(买卖股票的最佳时机II、跳跃游戏、跳跃游戏II) LeetCode链接:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/description/ 首先 sor

    2024年02月09日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包