Matlab K-means聚类算法对多光谱遥感图像进行分类(一)

news/2024/5/20 9:13:33 标签: matlab, 机器学习, 聚类, 算法, kmeans算法

Matlab K-means聚类算法对多光谱遥感图像进行分类

作者: 白艺亭

测试了下matlab自带kmeans函数,作者编写函数,以及ENVI下的Kmeans方法,对比其效果,代码及结果图展示见下。(K均值聚类matlab代码,对其算法进行实现。)

1. K-Means无监督聚类算法

ENVI中,在主菜单上,选择Classification>>Unsupervised>>K-Means,在Classification Input File中选择TM影像,单击OK。打开K-means Parameters对话框中,设置以下的参数:
1)分类数量(Number of Classes):一般为最终输出分类数量的2-3倍。
2)变换阈值(Change Threshold):5。每当一类的变化像元数小于阈值时,结束迭代过程。这个值越小得到的结果越精确,运算量也越大。
3)最大迭代次数(Maximum Iterations):30(我选的).迭代次数越大,精度越高。
4)距离类别的值的最大误差(Maximum Stdev From Mean)。此数可选。
5)允许的最大距离误差:(Maximum Distance Error);可选
6)选择路径,OK执行。
在这里插入图片描述
以上参考东腾的博客。

matlab_13">2. 自编matlab函数实现

2.1被调function

function [new_class_label] = Kmeans_of_muldim(data,k,change_threshold,iteration)
% 功能:实现多光谱遥感数据非监督分类算法之K-means聚类算法
%Author: Mr. BAI
% 输入:data是s*fl*b的矩阵,s为列数(sample),fl为行数(fileline),b为波段数(band);
%       k 为类别数,如果有背景值,背景值会归到某一地类中去,到时再用矢量边界图形裁剪一下即可。我考虑过将出现次数最多
%       的背景值单独划归一类,但是程序设计时不好判断,取数组中元素出现次数最多的像元为一类,有点大胆,因为无背
%       景的图像像元值也可能出现这种情况;
%       change_threshold变化阈值,ENVI中默认为0.05%       iteration为最大迭代次数,ENVI中默认为1
% 输出:new_class_label为聚类后的矩阵,赋予每个行列号一个类别标签,之后可在GIS或者ENVI中出图
% Reference:https://www.cnblogs.com/dongteng/p/5415071.html
    [fl,s,b] = size(data);
    %original_seed为迭代前的种子,存放一个k行,b个波段数值列的数组
    old_seed = zeros(k,b);
    %newseed为迭代后的新种子,存放一个k行,b个波段数值列的数组
    new_seed = zeros(k,b);
    %-------------------------------------------------------------------------------------------------
    % 产生k个随机种子作为遥感图像各地物类别的种子像元
    %-------------------------------------------------------------------------------------------------
    index_record = zeros(1,k);
    for i = 1:k 
        index_i = round(rand()*fl*s);
        judge = find(index_record == index_i);
        %如果已经有这个值了,那么重新循环取值
        if isempty(judge) == 0
            i = i-1;
            continue;
        end
        index_record(i) = index_i;
        %计算取到的随机值对应图像的行列号
        fl_index = floor(index_i/s);%行号
        sample_index = index_i - fl_index*s;%列号
        %将该种子像元的b个波段值存入
        old_seed(i,:) = data(fl_index,sample_index,:);
    end
    %--------------------------------------------------------------------------------------
    % 下面进行迭代,如果本次分别所有类新得到的像元数目变化在change_threshold内,则认为分类完毕。
    %--------------------------------------------------------------------------------------
    n = 1;
    new_class_label = zeros(fl,s);
    while n
        distance_matrix = zeros(fl,s,k);
        for kind = 1:k
            sum = 0;
            for i=1:b
               temp = power(abs(data(:,:,i)-old_seed(kind,i)),2);
               sum = sum+temp;
            end
            %每个像元与初始7个类别中心的欧式距离
            ou_distance = sqrt(sum);
            distance_matrix(:,:,kind) = ou_distance;
        end
        %给给各类别赋值类别标注
        for i=1:fl
            for j=1:s
                currentpixel_vector = distance_matrix(i,j,:);
                currentpixel_class = find(currentpixel_vector == min(currentpixel_vector));
                new_class_label(i,j) = currentpixel_class(1);
            end
        end
        %计算新的各类别中心
        for i=1:k
            id = find(new_class_label==i);
            for j=1:b
                temp1 = data(:,:,j);
                temp2 = temp1(id);
                new_seed(i,j)= mean(temp2(:)); 
            end
        end    
        new_class_pixcel_number = zeros(1,k);
        for i=1:k
            new_class_pixcel_number(i) = length(find(new_class_label(:)==i));
        end
        %Change threshold:0.05
        if n == 1
            old_class_pixcel_number = ones(1,k);
        end
        %size(new_class_pixcel_number)
        if max(abs((new_class_pixcel_number-old_class_pixcel_number)./old_class_pixcel_number)) < change_threshold || n>iteration
            break;
        end
        n=n+1;
        if max(abs((new_class_pixcel_number-old_class_pixcel_number)./old_class_pixcel_number)) >change_threshold
            %old_class_label = new_class_label;
            old_class_pixcel_number = new_class_pixcel_number;
            old_seed = new_seed;
            continue;
        end 
    end
end

2.2 main函数调用上述function

clc;
clear;
t0 = cputime;
cd 'E:\MATLAB\'
data=imread('nantong_city_landsat8.tif');%读取纯数据
[multi_data,r]=geotiffread('nantong_city_landsat8.tif');  % read the geo information
info=geotiffinfo('nantong_city_landsat8.tif');   % read the geo information
class_result = Kmeans_of_muldim(data,5,0.05,30);
geotiffwrite('K-means_class.tif',class_result,r,'GeoKeyDirectoryTag',info.GeoTIFFTags.GeoKeyDirectoryTag);
t1 = cputime;
during = t1 - t0;
disp('耗时:');
disp(during);
耗时:
                 139.59375

时间长是因为程序中Kmeans_of_muldim()函数中使用了逐像元循环,用了139秒,后面附上改进的算法, MKmeans_of_muldim(),Matlab K-means聚类算法改进对多光谱遥感图像进行分类(二)。

matlabkmeans_132">3 matlab库中的kmeans()

clc;
clear;
%matlab自带的kmeans使用方法:
t0 = cputime;
cd 'E:\MATLAB\'
data=imread('nantong_city_landsat8.tif');%读取纯数据
[multi_data,r]=geotiffread('nantong_city_landsat8.tif');  % read the geo information
info=geotiffinfo('nantong_city_landsat8.tif');   % read the geo information
[fl,s,b] = size(data);
dat = zeros(fl*s,b);%matlab K-means算法要求输入矩阵是一个列向量组成的矩阵,列数为波段数,每一列为fl*s的像元值
for i=1:b
    dat(:,i) = reshape(data(:,:,i),fl*s,1);
end
class_result = kmeans(dat,5);只能传两参
out_data = reshape(class_result,fl,s);
geotiffwrite('K-means_class_matlab.tif',out_data,r,'GeoKeyDirectoryTag',info.GeoTIFFTags.GeoKeyDirectoryTag);
t1 = cputime;
during = t1 - t0;
disp('耗时:');
disp(during);
耗时:
                 38.796875

4 结果展示

4.1ENVI操作结果展示:

在这里插入图片描述
0.05,30.

matlab_167">4.2 Kmeans_of_muldim,作者的matlab代码结果展示:

在这里插入图片描述
0.05,30

matlab_170">4.3K-means matlab自带函数结果展示:

在这里插入图片描述
效果相当,下面对Kmeans_of_muldim进行改进。
见下一篇:
Matlab K-means聚类算法改进对多光谱遥感图像进行分类(二)


后来,我们都学会了勇敢,不遗憾,不留恋。417看完了刘若英的线上演唱会,1500w人同时在线的,很壮观。


http://www.niftyadmin.cn/n/517009.html

相关文章

张艾迪(创始人): 辍学的互联网天才

&#xff08;20岁&#xff09;离开学校&#xff1b;&#xff08;21岁&#xff09;成立自己的第一家Newspaper广告公司; 艾迪是一个大学辍学生&#xff08;修读2年&#xff09; 艾迪并没有上完大学四年的课程.修读了2年.用艾迪的话说.提前2年离开了学校.艾迪说.因为提前离开学校…

Matlab K-means聚类算法改进对多光谱遥感图像进行分类(二)

上一篇Matlab K-means聚类算法对多光谱遥感图像进行分类&#xff08;一&#xff09;中&#xff0c;自编K-means函数运行时间长&#xff0c;是因为程序中Kmeans_of_muldim&#xff08;&#xff09;函数中使用了逐像元循环&#xff0c;用了139秒&#xff0c;下面对逐像元循环进行…

JAVA 1.8.0入门学习(1)按照作用域将变量分级

◼ 在Java中&#xff0c;变量的作用域分为四个级别&#xff1a;  类级&#xff1a;类级变量又称全局级变量或静态变量&#xff0c;需要使用static关键字修饰&#xff0c;在类定义后就已经存在&#xff0c;占用内存空间&#xff0c;可以通过类名来访问&#xff0c;不需要实例化…

JAVA 1.8.0入门学习(2)递归乘法例子

直接看代码&#xff0c;如图&#xff1a; 主类为公开类&#xff0c;类名为factorial. 里面包含了一个主函数以及一个方法块。 1主函数 main函数中执行递归计算&#xff0c;使用的是factorial_cal方法&#xff0c;输入的测试数字是5. 递归计算结果的变量应该为递归类型及比递归…

JAVA 1.8.0入门学习(3)访问控制符和构造函数

一、JAVA的访问控制符有四种&#xff0c;设定客户端程序员可以使用和不可以使用的界限&#xff0c;将接口和具体实现进行分离&#xff1a; public 公共类&#xff0c;可以被其他类访问和引用&#xff0c;实例化调用内部的属性和方法。 protected 用protected修饰的成员变量…

window下安装zookeeper

本地zookeeper安装(win7)下载zookeeper-3.3.6.zip文件解压zookeeper-3.3.6.zip文件到d:盘在D:\zookeeper-3.3.6\conf下增添 zoo.cfgcopy此zoo_sample.cfg生成zoo.cfg文件# The number of milliseconds of each ticktickTime2000# The number of ticks that the initial # synch…

IDL科学计数法乘方注意事项

c11.4385* 10^4 c21.189* 10^8 在命令行里输入上述变量&#xff1a; IDL> c11.4385*10^4 IDL> c21.189*10^8结果查看&#xff1a; IDL> c114385.000 IDL> c2-9435.9043c2明显是错误的&#xff0c;且不是由于位数太多而显示为负数. 正确的输入方式是&#xff1a;…

boostrap 模板收集

http://www.js-css.cn/a/css/template/admin/2013/1108/1023.html转载于:https://www.cnblogs.com/linksgo2011/p/3782672.html