
簡介面向畢業(yè)設計、課程設計與項目開發(fā)場景這套基于Python的遙感影像滑坡場景分類代碼與項目文檔提供了一個可直接運行的完整參考方案。項目核心是利用SVM分類器完成滑坡場景識別技術路線清晰先從遙感影像中提取光譜特征平均值、標準差與GLCM紋理統(tǒng)計特征隨后運用K-Means算法對特征向量聚類形成視覺單詞再借助LDA主題模型對視覺詞袋作主題分析得到抽象的高層特征并存儲為Libsvm格式的訓練樣本最終調用Libsvm工具完成分類。源碼經(jīng)過嚴格測試配有項目說明文檔便于讀者理解算法流程并二次開發(fā)。資源包共21個文件壓縮后僅1.86MB包含Python源碼、模型文件model、pkl、state、npy、文本數(shù)據(jù)與說明文檔等體量輕巧目錄結構清楚。目前已有56人學習下載適合作為遙感圖像處理、機器學習類畢業(yè)設計或課程設計的實戰(zhàn)藍本。1. 遙感影像滑坡場景分類從一塊影像到SVM的完整決策鏈做滑坡災害調查時最耗人的不是外業(yè)而是內業(yè)看圖——從一堆高分遙感影像里把滑坡區(qū)域框出來。這個基于 Python 實現(xiàn)的遙感影像滑坡場景分類項目解決的正是這件事它不靠人去逐塊標注而是把影像切塊、提特征、聚簇、主題抽象最后交給 SVM 分類器判定每一塊是不是滑坡場景。整條鏈路包括特征提取、特征聚類、LDA 主題抽象和 Libsvm 分類四個環(huán)節(jié)源碼加項目文檔都在壓縮包里適合畢業(yè)設計、課程設計也適合想快速上手遙感影像分類做橫向項目的開發(fā)者。亮點是它沒有用深度學習而是走視覺詞袋加主題模型的經(jīng)典路線特征可解釋性強、訓練不需要 GPU對滑坡這種樣本量不大的場景反而更穩(wěn)。2. 特征提取與視覺詞袋GLCM參數(shù)和K-Means聚類怎么配2.1 光譜特征為什么選均值加標準差遙感影像分類的第一步是把影像變成數(shù)字。項目在 py_files/feature.py 里做特征提取光譜特征只取兩個統(tǒng)計量每個波段的平均值和標準差。平均值代表整體亮度標準差代表波段內的起伏程度——滑坡區(qū)通常植被少、裸土多光譜曲線和周圍林地差異明顯但單看某一個像素容易受陰影、云影干擾所以取整塊的統(tǒng)計量更穩(wěn)定。常見做法是先對影像做切塊每塊大小固定比如 64×64 或 128×128 像素然后逐波段算均值與標準差。如果影像有三個波段特征維度就是 3×26 維。這部分代碼核心邏輯如下# py_files/feature.py 中光譜特征提取的邏輯片段 import numpy as np def spectral_features(img_block, band_count3): feats [] for b in range(band_count): band img_block[:, :, b] feats.append(np.mean(band)) # 平均值反映整體亮度 feats.append(np.std(band)) # 標準差反映波段起伏程度 return np.array(feats) # 返回 2*band_count 維特征這段代碼里band_count 默認 3對應 R/G/B 或 R/G/NIR 波段。np.mean 和 np.std 分別算均值和標準差順序是先均值后標準差每個波段貢獻兩個維度。如果你拿到的是多光譜影像比如 8 波段直接把 band_count 改成 8 就行特征維度會自動變成 16。注意一點影像塊在送入這個函數(shù)前最好先做大氣校正或歸一化否則不同時相的影像亮度差異會直接影響均值特征這是遙感分類最容易翻車的地方。2.2 GLCM紋理特征距離、方向、灰度級怎么定光譜特征只捕捉顏色信息區(qū)分不開裸土和水泥地這種顏色相近、紋理不同的地物所以項目引入了 GLCM灰度共生矩陣紋理特征。GLCM 統(tǒng)計的是圖像中相距一定距離、方向的兩個像素對出現(xiàn)的頻率它能反映紋理的粗糙度、對比度和規(guī)則性?;麦w表面往往是碎屑堆積紋理比完整林地要雜亂得多這正是 GLCM 擅長捕捉的信息。項目里用到了多個統(tǒng)計值包括對比度、相異性、同質性、能量、相關性和 ASM角二階矩每個統(tǒng)計值從不同角度描述紋理。相關實現(xiàn)如下# py_files/feature.py 中 GLCM 紋理特征提取 from skimage.feature import graycomatrix, graycoprops def texture_features(gray_img, distances[1], angles[0, np.pi/4, np.pi/2, 3*np.pi/4]): glcm graycomatrix(gray_img, distancesdistances, anglesangles, levels256, symmetricTrue, normedTrue) props [] for key in [contrast, dissimilarity, homogeneity, energy, correlation, ASM]: props.extend(graycoprops(glcm, key).flatten()) return np.array(props) # 6個統(tǒng)計量 x 1個距離 x 4個方向 24維參數(shù)上distances 取 1 意味著只統(tǒng)計相鄰像素的灰度關系適合識別滑坡體這種中等尺度的紋理如果影像分辨率高紋理很細碎可以試 distances[1, 3, 5] 把三個尺度的紋理串起來。angles 取四個方向是為了消除方向性偏差滑坡紋理不一定有主方向四個方向平均更穩(wěn)妥。levels256 對應 256 級灰度注意輸入圖像必須是灰度圖且值域在 [0, 255] 內否則 graycomatrix 會直接報錯。最終 GLCM 特征維度是 6×1×424 維加上前面光譜的 6 維單塊影像的特征向量就是 30 維。2.3 K-Means聚類成視覺詞袋K值是核心參數(shù)特征提出來后每個影像塊是一條 30 維的特征向量。但直接拿這種向量做分類缺少場景層面的語義。項目采用視覺詞袋思路先對所有影像塊的特征向量做 K-Means 聚類把特征空間切成若干簇每個簇中心就是一個視覺單詞?;聢鼍袄锍R姷慕M合是高亮度高紋理對比度低同質性聚類后這些組合會自然落到某個簇里。K-Means 的實現(xiàn)很簡單但 K 的取值直接影響分類效果# py_files/generate_samples_and_labels.py 中K-Means聚類的關鍵邏輯 from sklearn.cluster import KMeans kmeans KMeans(n_clusters300, random_state42, n_init10) kmeans.fit(all_feature_matrix) # 形狀為 (N_samples, 30) visual_dict kmeans.cluster_centers_ # 300 x 30即視覺詞典 # 為每個樣本打上視覺單詞編號 word_ids kmeans.predict(all_feature_matrix)n_clusters 就是視覺詞典的大小。這個值不能太小太小了區(qū)分度不夠不同地物落到同一個簇也不能太大太大了每個簇只有零星樣本詞袋向量會很稀疏。對滑坡分類這種類別少、樣本量幾百到幾千的任務我一般取 200 到 300先跑一輪分類看準確率再微調。random_state42 是固定隨機種子保證每次聚類結果一致方便復現(xiàn)實驗。n_init10 是讓 K-Means 用 10 個初始中心各跑一次取最優(yōu)結果避免陷入局部最優(yōu)。聚類完成后每個影像塊就變成一個單詞編號整幅影像就變成一段單詞序列這為下一步 LDA 主題分析準備了原料。3. LDA主題抽象與libsvm格式特征如何變成SVM能吃的樣本3.1 從視覺詞袋到LDA語料視覺詞袋只是把每個影像塊映射成單個單詞它缺少上下文信息——一塊滑坡影像中出現(xiàn)的視覺單詞組合是有規(guī)律的比如碎石紋理單詞裸土光譜單詞低植被單詞經(jīng)常同時出現(xiàn)。LDA 模型就是用來捕捉這種共現(xiàn)規(guī)律的。LDA 把每個影像塊看成一篇文檔文檔由多個主題混合而成每個主題是視覺單詞上的概率分布。訓練完 LDA 后每個影像塊可以用一個主題分布向量表示這個向量就是高級特征。項目里 models/visual_lda.model 就是訓練好的 LDA 模型models/visual_dict 是視覺詞典。實現(xiàn)時用 gensim 庫# py_files/data_tool.py 中LDA訓練的典型流程 from gensim import corpora, models # bow_corpus 是詞袋語料每個樣本是 [(word_id, count), ...] 形式 dictionary corpora.Dictionary([word_ids_list]) # 提前構建詞典 bow_corpus [dictionary.doc2bow(doc) for doc in word_ids_list] lda models.LdaModel( corpusbow_corpus, id2worddictionary, num_topics20, # 主題數(shù)滑坡任務一般10~30 passes10 # 迭代輪數(shù)越大越收斂但越慢 ) lda.save(models/visual_lda.model)num_topics 是 LDA 最重要的參數(shù)。對滑坡場景分類來說類別就滑坡/非滑坡兩類但主題數(shù)不能只設 2因為非滑坡里面還包含林地、水體、農(nóng)田、人工建筑等多種場景20 個主題讓每個場景有自己獨立的主題分布SVM 才分得開。passes 控制訓練輪數(shù)數(shù)據(jù)集小的時候 10 輪足夠數(shù)據(jù)集大了可以提到 20。一個容易被忽略的點是LDA 訓練用的語料必須是詞袋格式也就是每個樣本是 (word_id, count) 的列表而不是直接的單詞編號數(shù)組doc2bow 就是做這個轉換的。3.2 libsvm格式index從1開始是硬規(guī)矩LDA 輸出的主題分布是浮點向量需要轉成 Libsvm 的文本格式才能喂給 SVM 分類器。Libsvm 格式是標簽 索引:值 索引:值索引從 1 開始且按升序排列。很多初學者在這里栽跟頭用 Python 的 enumerate 從 0 編號結果 Libsvm 直接拒絕加載。項目里 training.txt、training2.txt、test2.txt 就是這個格式的樣本文件。轉換邏輯如下# 將LDA主題分布轉為libsvm文本格式 def to_libsvm_line(label, topic_dist): parts [str(label)] for idx, val in enumerate(topic_dist, start1): # 注意start1 if abs(val) 1e-6: # 過濾接近0的值減小文件體積 parts.append(f{idx}:{val:.6f}) return .join(parts)enumerate 的 start1 是這里的關鍵少寫這一步導出的文件就是廢的。過濾接近 0 的主題分量子不是為了偷懶而是 LDA 輸出的主題分布里本來就有大量極小值保留它們只會讓文件變大、SVM 訓練變慢對精度幾乎沒有貢獻。label 在二分類里通常用 1 表示滑坡、-1 或 0 表示非滑坡具體看 classify.py 里的定義別搞反了。3.3 從原始影像到訓練樣本的完整鏈路整個數(shù)據(jù)流向是原始影像 → 切塊 → spectral_features texture_features 拼成 30 維向量 → K-Means 聚類得到視覺詞典 → doc2bow 成詞袋 → LDA 得到主題分布 → 轉 libsvm 格式寫入 txt。generate_samples_and_labels.py 負責前兩步和最后一步data_tool.py 是中間的數(shù)據(jù)組裝角色。實際跑的時候建議按順序執(zhí)行先跑 generate_samples_and_labels.py 生成采樣樣本再單獨跑特征提取和聚類最后訓練 LDA 并導出 libsvm 文件。不要指望一個腳本全自動跑完遙感數(shù)據(jù)處理中間經(jīng)常要人工檢查中間結果——比如某個影像塊全是云特征異常得先剔掉再往下走。4. 源碼走讀與復現(xiàn)路徑classify.py和四個py文件怎么串起來4.1 文件清單與各模塊職責壓縮包里 py_files 目錄下有四個核心 Python 文件加上 models 里的模型文件和幾個 txt 數(shù)據(jù)文件。先用表格理清職責文件職責feature.py光譜特征均值/標準差與 GLCM 紋理特征提取generate_samples_and_labels.py切分影像塊、調用特征提取、生成訓練/測試樣本與標簽data_tool.py數(shù)據(jù)加載、預處理、詞袋構建與 libsvm 格式轉換classify.pyLDA 模型加載、SVM 訓練與預測主入口models/visual_lda.model訓練好的 LDA 主題模型models/visual_dict視覺詞典K-Means 簇中心models/text_clt.pklGLCM 紋理特征的聚類模型models/spec_clt.pkl光譜特征的聚類模型training.txt / training2.txt / test2.txt不同劃分下的 libsvm 格式樣本集注意 text_clt.pkl 和 spec_clt.pkl 的存在意味著聚類過程實際上分了兩路一路對光譜特征聚類一路對紋理特征聚類而不是像我前面的示例代碼那樣拼在一起聚。這種做法的好處是光譜和紋理的分布尺度差異很大混在一起聚類會被數(shù)值大的特征主導分開聚再合并詞袋更合理。你拿到代碼后可以打開 spec_clt.pkl 看看里面的 n_clusters再和 text_clt.pkl 對比通常光譜聚類簇數(shù)少一點、紋理聚類簇數(shù)多一點。4.2 classify.py 的SVM訓練主流程classify.py 是項目入口完成 LDA 特征加載和 SVM 訓練。它用 Libsvm 工具包完成分類核心代碼如下# py_files/classify.py 中SVM訓練與預測的核心邏輯 from libsvm.svmutil import svm_train, svm_predict, svm_parameter # 讀取libsvm格式數(shù)據(jù) y_train, x_train svm_read_problem(training2.txt) y_test, x_test svm_read_problem(test2.txt) # 構造參數(shù)-t 2 表示RBF核-c 是懲罰系數(shù)-g 是gamma param svm_parameter(-t 2 -c 8 -g 0.5 -b 1) model svm_train(y_train, x_train, param) # 預測并輸出準確率 p_label, p_acc, p_val svm_predict(y_test, x_test, model) print(準確率:, p_acc)svm_read_problem 把 libsvm 文本文件解析成 Python 的列表結構y 是標簽數(shù)組x 是特征字典列表。svm_parameter 里 -t 2 是 RBF 徑向基核這是處理非線性分類最常用的核滑坡和非滑坡的特征邊界不是直線線性核很難分開。-c 8 是懲罰系數(shù)越大越容易過擬合訓練集-g 0.5 是 RBF 核的 gamma控制單個樣本的影響半徑。這對參數(shù)基本決定了 SVM 的上限先按項目默認值跑后面再調。如果訓練集和測試集是同一個數(shù)據(jù)集切出來的準確率會虛高真正的驗證要看獨立測試集。4.3 復現(xiàn)時的執(zhí)行順序與驗證方法拿到項目后不要急著跑 classify.py它依賴前面生成的 libsvm 文件和 LDA 模型第一次運行會報文件缺失。正確順序是先看 README.md 了解數(shù)據(jù)說明再依次執(zhí)行 generate_samples_and_labels.py → data_tool.py如果它有 main 入口→ 訓練 LDA 并存模型 → 最后跑 classify.py。中間每步生成的結果文件都檢查一下內容feature 輸出的 txt 維度對不對、詞袋文件非零比例如何、libsvm 文件里 index 是不是從 1 開始。用一個小數(shù)據(jù)集先把流程跑通再上全量數(shù)據(jù)這是最省時間的方式。項目源碼已經(jīng)經(jīng)過測試理論上按順序執(zhí)行不會有問題但環(huán)境差異可能導致個別庫版本沖突后面避坑章節(jié)專門講這些。5. 避坑指南五條能直接省半天的報錯與誤用記錄5.1 訓練集和測試集文件選錯準確率虛高現(xiàn)象用 training2.txt 訓練、test2.txt 測試準確率 95% 以上感覺模型很好換到自己的影像上預測效果一塌糊涂。原因training2.txt 和 test2.txt 可能來自同一次切塊劃分或者干脆就是同一個數(shù)據(jù)集按比例拆的樣本分布高度重合模型等于背了答案。解決先打印兩個文件的標簽分布看正負樣本比例如果比例幾乎一致且來源相同把結果當作過擬合測試集看待真正泛化性能要在新影像上驗證。我一般會留出三分之一的數(shù)據(jù)完全不用等模型定稿后再拿去測。5.2 LDA模型和visual_dict對不上現(xiàn)象classify.py 加載 visual_lda.model 時報 id2word 不匹配或者主題分布全是同樣的數(shù)值。原因visual_dict 和 visual_lda.model 是兩個階段分別生成的只要重跑過 K-Means 而沒同步重訓 LDA詞典編號和 LDA 內部的詞表編號就對不上。解決聚類和 LDA 必須成對更新改過 visual_dict 之后強制重訓 visual_lda.model并把兩者一起保存。修改代碼時在保存模型前加一行斷言檢查兩個模型的詞表長度一致。5.3 GLCM直接喂RGB影像導致報錯現(xiàn)象運行 feature.py 時 skimage 報Input image must be 2-D或者levels must be integer錯誤。原因graycomatrix 只接受二維灰度圖直接傳三波段影像進去或者影像像素類型是 float 且值域不在 [0, levels-1] 區(qū)間。解決先轉灰度用 cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) 或 np.mean(img, axis2) 都行然后轉成 np.uint8 類型再送進 graycomatrix。levels 參數(shù)必須大于圖像最大像素值否則也要報錯。5.4 libsvm的index從0開始導致訓練中斷現(xiàn)象svm_train 報Wrong input format at line 某行或者直接解析失敗。原因生成 libsvm 行時用了 enumerate(topic_dist) 沒有指定 start1index 從 0 開始Libsvm 約定從 1 開始。解決生成代碼里強制 start1并且過濾掉值為 0 的特征。這個坑幾乎每個第一次寫 libsvm 格式的人都會踩寫完 txt 后先 head 看前三行確認 index 是 1 2 3 而不是 0 1 2。5.5 K值太大導致詞袋稀疏和訓練緩慢現(xiàn)象K-Means 的 n_clusters 設到 2000LDA 訓練卡到出不了結果且主題分布退化成一個主分量加一堆零。原因視覺詞典太大每個影像塊只命中極少幾個單詞詞袋向量 99% 都是零LDA 學不到有效共現(xiàn)信息。解決把 n_clusters 降到 100~300 之間重新聚類同時 LDA 的 num_topics 也相應調小。判斷標準是詞袋非零比例統(tǒng)計所有樣本的詞袋非零元素占比如果平均不到 1%說明詞典過大或樣本過小。6. 進階驗證交叉驗證、混淆矩陣與調參技巧6.1 滑坡是少類準確率會騙人很多課程設計報告只看準確率但滑坡場景里滑坡樣本往往只占百分之幾。你全預測成非滑坡準確率也有 95% 以上這個模型沒有任何用處。正確做法是看混淆矩陣和分類報告重點盯滑坡類別的召回率——漏判一個滑坡比誤判十塊農(nóng)田嚴重得多。用 sklearn 的接口可以一目了然from sklearn.metrics import confusion_matrix, classification_report # y_pred來自SVM預測結果y_test是真實標簽 print(confusion_matrix(y_test, y_pred)) print(classification_report( y_test, y_pred, target_names[非滑坡, 滑坡], digits4 ))混淆矩陣的四個格子里看右下角滑坡正確預測數(shù)和左下角滑坡被漏判數(shù)。如果左下角明顯大于右下角說明模型在犧牲滑坡召回率換整體準確率。實踐中我要求滑坡召回率不低于 80%哪怕整體準確率降到 90% 都可以接受因為漏掉的滑坡意味著實地調查時要重新跑一遍疑似區(qū)域。6.2 參數(shù)調優(yōu)先用網(wǎng)格搜索再手動微調SVM 的 C 和 gamma 對結果影響顯著。Libsvm 自帶 grid.py 做網(wǎng)格搜索或者用 sklearn 的 GridSearchCVfrom sklearn.model_selection import GridSearchCV from sklearn.svm import SVC param_grid { C: [0.5, 1, 2, 4, 8, 16], gamma: [0.05, 0.1, 0.2, 0.5, 1.0], kernel: [rbf] } clf GridSearchCV(SVC(probabilityTrue), param_grid, cv5, scoringf1_macro) clf.fit(X_train_vec, y_train_vec) print(clf.best_params_)搜索時要用 F1 而不是準確率做評分指標否則還是掉進少類陷阱。cv5 用五折交叉驗證比單次劃分可信度高。搜索完得到一組好參數(shù)后再在 C 附近縮小范圍手動試一兩個值看看穩(wěn)定性——網(wǎng)格搜索選出的參數(shù)如果在小范圍內波動導致結果劇烈變化說明數(shù)據(jù)本身不穩(wěn)這時候優(yōu)先檢查特征質量而不是繼續(xù)調參。6.3 一個提高泛化的實用習慣項目默認流程是聚類、LDA、SVM 各自獨立訓練參數(shù)都是單獨的。我習慣在最終實驗里把 LDA 主題數(shù)也放進網(wǎng)格搜索一起調雖然慢一點但能避免單個模塊最優(yōu)、整體不是最優(yōu)的問題。另外在切塊生成樣本時相鄰影像塊高度相關直接隨機劃分會讓驗證集泄漏——切塊時按區(qū)域劃分保證同一景影像不出現(xiàn)在訓練集和測試集里這才是嚴格的驗證方法。用 libsvm 自帶的交叉驗證命令 svm_train 加 -v 5 可以快速看穩(wěn)定性參數(shù)不改的前提下如果 5 折準確率波動超過 5 個百分點說明樣本不夠或者分布不均衡先去補樣本再談調參。從那以后我每次跑這個項目都強制走一遍區(qū)域劃分、主題數(shù)網(wǎng)格搜索、漏判統(tǒng)計這三件事寧可多花半小時也不交一個看起來高分的廢模型。希望幫到你。本文還有配套的精品資源點擊獲取