Matlab K-means聚類算法改進對多光譜遙感圖像進行分類(二)

上一篇Matlab K-means聚類算法對多光譜遙感圖像進行分類(一)中,自編K-means函數運行時間長,是因爲程序中Kmeans_of_muldim()函數中使用了逐像元循環,用了139秒,下面對逐像元循環進行改進,把數據reshape爲列向量,以整體進行運算。

function:MKmeans_of_muldim()

(注:muldim = multiple dimensions)

function [new_class_label] = MKmeans_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,實驗發現爲3的時候基本就實現變化閾值小於0.05了。
% 輸出:new_class_label爲聚類後的矩陣,賦予每個行列號一個類別標籤,之後可在GIS或者ENVI中出圖
% Reference:https://www.cnblogs.com/dongteng/p/5415071.html
    [fl,s,b] = size(data);
    tfl = fl*s;
    dat = zeros(tfl,b);
    for i=1:b
         dat(:,i) = reshape(data(:,:,i),tfl,1);
    end
    %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()*tfl);
        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(tfl,1);%改進的地方
    while n
        distance_matrix = zeros(tfl,k);
        for kind = 1:k
            sum = 0;
            for i=1:b
               temp = power(abs(dat(:,i)-old_seed(kind,i)),2);
               sum = sum+temp;
            end
            %每個像元與初始7個類別中心的歐式距離
            ou_distance = sqrt(sum);%sum數組爲tfl行,1列數據,存放了圖像所有像元與第kind類中心的歐式距離
            %size(ou_distance)
            distance_matrix(:,kind) = ou_distance;
        end
        %給給各類別賦值類別標註
        [M,I] = min(distance_matrix,[],2);%行取最小值,並返回最小值在該行的列標,即爲距離最小所在的類別
        new_class_label = I;
        %計算新的各類別中心
        for i=1:k
            id = find(new_class_label==i);
            for j=1:b
                temp1 = dat(id,j);
                new_seed(i,j)= mean(temp1); 
            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
            new_class_label = reshape(new_class_label,fl,s);
            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

main函數

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 = MKmeans_of_muldim(data,5,0.05,30);
geotiffwrite('MK-means_class.tif',class_result,r,'GeoKeyDirectoryTag',info.GeoTIFFTags.GeoKeyDirectoryTag);
figure, imshow(label2rgb(class_result))   % 顯示分割結果
title('MKmeans of muldim聚類結果');
t1 = cputime;
during = t1 - t0;
disp('耗時:');
disp(during);

改進後,耗時:

速度飛起!

耗時:
                 14.328125

而使用kmeans()matlab自帶函數耗時:

耗時:
                 38.796875

結果圖展示

MKmeans_of_muldim()

在這裏插入圖片描述

kmeans()matlab自帶函數結果圖

在這裏插入圖片描述
效果一模一樣,說明只要迭代次數達到一定程度,對於多光譜遙感圖像,二者效果是相當的。但改進版速度更快,可以填寫變化閾值及迭代次數,靈活調整。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章