
今天給大家推薦一篇高大上的文章:基于OpenCV實(shí)現(xiàn)海岸線變化檢測(cè)。OpenCV大家都知道,一款開源的計(jì)算機(jī)視覺庫,平常大家看到的都是OpenCV人臉識(shí)別,圖像處理之類的,今天跟小編一起來看他如何實(shí)現(xiàn)海岸線變化檢測(cè)的吧。
文章來源: 小白學(xué)視覺
作者:努比
介紹
海岸是一個(gè)動(dòng)態(tài)系統(tǒng),其中因侵蝕現(xiàn)象導(dǎo)致的海岸線后退、或是由眾多因素如氣象,地質(zhì),生物和人類活動(dòng)所導(dǎo)致線前進(jìn)的是常見現(xiàn)象。
在海洋磨損作用大于沉積物的情況下,有明顯的海岸侵蝕,我們稱之為地球表面的崩解和破壞。
資料來源:弗林德斯大學(xué)(CC0)
本文的目標(biāo)
在本文中,我們將對(duì)Landsat 8平臺(tái)上的OLI(陸地成像儀)傳感器獲取的衛(wèi)星圖像使用Canny Edge Detection算法。
通過這種方法,我們將能夠可視化的估計(jì)特定歐洲地區(qū)遭受強(qiáng)腐蝕作用的海岸線隨時(shí)間的推移:霍德內(nèi)斯海岸。
一下是處理流程:
處理流程
在開始之前讓我們先介紹一下OLI數(shù)據(jù)...
0.關(guān)于Landsat OLI數(shù)據(jù)的簡(jiǎn)要介紹
Landsat 8是一個(gè)軌道平臺(tái),安裝在稱為OLI(陸地成像儀)的11波段多光譜傳感器上。
具體來說,在本文中,我們將僅使用分辨率為30米(即前7個(gè))的波段。
美國地質(zhì)調(diào)查局陸地衛(wèi)星8號(hào)
該數(shù)據(jù)可以免費(fèi)下載,注冊(cè)后,獲得USGS:https://earthexplorer.usgs.gov/。
而且,通常我摸并不使用入射太陽光作為原始數(shù)據(jù),而是使用反射率,即從地球表面反射的太陽光量[0-1]。
1.包導(dǎo)入
在各種常見的包,我們將使用rasterio處理圖像,利用OpenCV中的Canny 算法和Scikit-Learn分割圖像。
from glob import glob import numpy as np import rasterio import json, re, itertools, os import matplotlib.pyplot as plt import cv2 as cv from sklearn import preprocessing from sklearn.cluster import KMeans
2.數(shù)據(jù)導(dǎo)入
讓我們定義一個(gè)變量,該變量告訴我們要保留的波段數(shù)以及在JSON中輸入的輔助數(shù)據(jù):
N_OPTICS_BANDS = 7 with open("bands.json","r") as bandsJson: bandsCharacteristics = json.load(bandsJson)
這個(gè)Json是Landsat OLI成像儀的信息集合。類似于一種說明手冊(cè):
# bands.json [{'id': '1', 'name': 'Coastal aerosol', 'span': '0.43-0.45', 'resolution': '30'}, {'id': '2', 'name': 'Blue', 'span': '0.45-0.51', 'resolution': '30'}, {'id': '3', 'name': 'Green', 'span': '0.53-0.59', 'resolution': '30'}, {'id': '4', 'name': 'Red', 'span': '0.64-0.67', 'resolution': '30'}, {'id': '5', 'name': 'NIR', 'span': '0.85-0.88', 'resolution': '30'}, {'id': '6', 'name': 'SWIR 1', 'span': '1.57-1.65', 'resolution': '30'}, {'id': '7', 'name': 'SWIR 2', 'span': '2.11-2.29', 'resolution': '30'}, {'id': '8', 'name': 'Panchromatic', 'span': '0.50-0.68', 'resolution': '15'}, {'id': '9', 'name': 'Cirrus', 'span': '1-36-1.38', 'resolution': '30'}, {'id': '10', 'name': 'TIRS 1', 'span': '10.6-11.9', 'resolution': '100'}, {'id': '11', 'name': 'TIRS 2', 'span': '11.50-12.51', 'resolution': '100'}]
bands.json文件包含有關(guān)我們將要使用的頻段的所有有用信息。
注意,我們將僅使用分辨率為30 m的頻段,因此僅使用前7個(gè)頻段。如果您愿意使用較低的分辨率(100m),則也可以嵌入TIRS 1和TIRS 2頻段。
正如上面幾行已經(jīng)提到的那樣,我們將使用從Landsat-8 OLI上獲取兩組不同的數(shù)據(jù):
? 2014/02/01
? 2019/07/25
為了簡(jiǎn)化兩次采集的所需操作,我們將定義一個(gè)Acquisition()類,其中將封裝所有必要的函數(shù)。
在執(zhí)行代碼期間,我們能夠執(zhí)行一些基礎(chǔ)支持性的功能,例如:
? 在指定路徑中搜索GeoTIFF;
? 加載采購;
? 購置登記 (調(diào)整);
? 收購子集
class Acquisition: def __init__(self, path, ext, nOpticsBands): self.nOpticsBands = nOpticsBands self._getGeoTIFFs(path, ext) self.images = self._loadAcquisition() def _getGeoTIFFs(self, path, ext): # It searches for GeoTIFF files within the folder. print("Searching for '%s' files in %s" % (ext, path)) self.fileList = glob(os.path.join(path,"*."+ext)) self.opticsFileList = [ [list(filter(re.compile(r"band%s\."%a).search, self.fileList))[0] for a in range(1,self.nOpticsBands+1)] print("Found %d 'tif' files" % len(self.opticsFileList)) def _loadAcquisition(self): # It finally reads and loads selected images into arrays. print("Loading images") self.loads = [rasterio.open(bandPath) for bandPath in self.opticsFileList] images = [load.read()[0] for load in self.loads] print("Done") return images def subsetImages(self, w1, w2, h1, h2, leftBound): # This function subsets images according the defined sizes. print("Subsetting images (%s:%s, %s:%s)" % (w1, w2, h1, h2)) cols = (self.loads[0].bounds.left - leftBound)/30 registered = [np.insert(band,np.repeat(0,cols),0,axis=1) for band in self.images] subset = [band[w1:w2,h1:h2] for band in registered] print("Done") return subset
好的,讓我們現(xiàn)在開始啟動(dòng)整個(gè)代碼:
DATES = ["2014-02-01", "2019-07-25"] acquisitionsObjects = [] for date in DATES: singleAcquisitionObject = Acquisition("Data/"+date, "tif", N_OPTICS_BANDS) acquisitionsObjects.append( singleAcquisitionObject )
運(yùn)行結(jié)果如下:
Searching for 'tif' files in Data/2014-02-01
Found 7 'tif' files
Loading images
Done
Searching for 'tif' files in Data/2019-07-25
Found 7 'tif' files
Loading images
Done
現(xiàn)在我們已加載了14張OLI圖像(在7個(gè)波段中各采集2個(gè))。
2.1 子集多光譜立方體
在這個(gè)階段中,先對(duì)兩個(gè)多光譜立方體進(jìn)行“對(duì)齊”(或正式注冊(cè)),再切出不感興趣的部分。
我們可以使用ImageImages()函數(shù)“剪切”不需要的數(shù)據(jù)。
因此,我們定義AOI(感興趣的區(qū)域),并使用Acquisition()類中的subsetImages()函數(shù)進(jìn)行設(shè)置:
W1, W2 = 950, 2300 H1, H2 = 4500, 5300 subAcquisitions = [acquisition.subsetImages(W1, W2, H1, H2, 552285.0) for acquisition in acquisitionsObjects].
完成!
3.數(shù)據(jù)探索
3.1可視化多光譜立方體
讓我們嘗試查看2019/07/25收購的所有范圍。出于純粹的美學(xué)原因,在繪制圖像之前,讓我們使用
StandardScaler()對(duì)圖像進(jìn)行標(biāo)準(zhǔn)化。
axs = range(N_OPTICS_BANDS) fig, axs = plt.subplots(2, 4, figsize=(15,12)) axs = list(itertools.chain.from_iterable(axs)) for b in range(N_OPTICS_BANDS): id_ = bandsCharacteristics[b]["id"] name_ = bandsCharacteristics[b]["name"] span_ = bandsCharacteristics[b]["span"] resolution_ = bandsCharacteristics[b]["resolution"] title = "%s - %s\n%s (%s m)" % (id_, name_, span_, resolution_) axs[b].imshow(preprocessing.StandardScaler().fit_transform(subAcquisitions[1][b]), cmap="Greys_r") axs[b].set_title(title); axs[b].set_xticklabels([]); axs[b].set_yticklabels([]) plt.axis("off"); plt.tight_layout(w_pad=-10); plt.show()
以下是運(yùn)行結(jié)果。
這些圖中,有些波段比其他波段更亮。這很正常。
3.2可視化復(fù)合RGB中的多光譜立方體
現(xiàn)在,讓我們嘗試可視化使用波段4(紅色),3(綠色)和2(藍(lán)色)獲得的RGB復(fù)合圖像中的兩次采集。
定義BIAS和GAIN 僅是為了獲得更好的效果。
BIAS = 1.5 GAIN = [2.3,2.4,1.4] r1 = (subAcquisitions[0][3] - subAcquisitions[0][3].min()) / (subAcquisitions[0][3].max()-subAcquisitions[0][3].min()) * GAIN[0] * BIAS g1 = (subAcquisitions[0][2] - subAcquisitions[0][2].min()) / (subAcquisitions[0][2].max()-subAcquisitions[0][2].min()) * GAIN[1] * BIAS b1 = (subAcquisitions[0][1] - subAcquisitions[0][1].min()) / (subAcquisitions[0][1].max()-subAcquisitions[0][1].min()) * GAIN[2] * BIAS r2 = (subAcquisitions[1][3] - subAcquisitions[1][3].min()) / (subAcquisitions[1][3].max()-subAcquisitions[1][3].min()) * GAIN[0] * BIAS g2 = (subAcquisitions[1][2] - subAcquisitions[1][2].min()) / (subAcquisitions[1][2].max()-subAcquisitions[1][2].min()) * GAIN[1] * BIAS b2 = (subAcquisitions[1][1] - subAcquisitions[1][1].min()) / (subAcquisitions[1][1].max()-subAcquisitions[1][1].min()) * GAIN[2] * BIAS rgbImage1, rgbImage2 = np.zeros((W2-W1,H2-H1,3)), np.zeros((W2-W1,H2-H1,3)) rgbImage1[:,:,0], rgbImage2[:,:,0] = r1, r2 rgbImage1[:,:,1], rgbImage2[:,:,1] = g1, g2 rgbImage1[:,:,2], rgbImage2[:,:,2] = b1, b2 fig, (ax1,ax2) = plt.subplots(1,2,figsize=(16,12)) ax1.imshow(rgbImage1); ax2.imshow(rgbImage2) ax1.set_title("RGB\n(Bands 4-3-2)\n2014-02-01"); ax2.set_title("RGB\n(Bands 4-3-2)\n2019-07-25") plt.show()
結(jié)果如下圖所示!有趣的是,這兩次獲取的反射率完全的不同。
好的,繼續(xù)進(jìn)行海岸線檢測(cè)。
4.自動(dòng)化海岸線檢測(cè)
在本段中,我們將使用Canny的算法執(zhí)行邊緣檢測(cè)。
在進(jìn)行實(shí)際檢測(cè)之前,有必要準(zhǔn)備數(shù)據(jù)集,嘗試通過聚類算法對(duì)數(shù)據(jù)集進(jìn)行分割以區(qū)分海洋和陸地。
4.1數(shù)據(jù)準(zhǔn)備
在此階段,我們將重塑兩個(gè)多光譜立方體以進(jìn)行聚類操作。
4.2用K均值進(jìn)行圖像分割
我們通過k均值對(duì)這兩次采集進(jìn)行細(xì)分(使用自己喜歡的模型即可)。
4.3細(xì)分結(jié)果
這是確定的代表新興土地和水體的兩個(gè)集群。
4.4Canny邊緣檢測(cè)算法
Canny的傳統(tǒng)鍵技術(shù)分為以下幾個(gè)階段:
1. 高斯濾波器通過卷積降低噪聲;
2. 四個(gè)方向(水平,垂直和2個(gè)傾斜)的圖像梯度計(jì)算;
3. 梯度局部最大值的提取;
4. 帶有滯后的閾值,用于邊緣提取。
讓我們開始,將聚類結(jié)果轉(zhuǎn)換為圖像,然后通過具有15x15內(nèi)核的高斯濾波器降低噪聲:
clusteredImages = [clusterLabels.reshape(subAcquisitions[0][0].shape).astype("uint8") for clusterLabels in clusters] blurredImages = [cv.GaussianBlur(clusteredImage, (15,15), 0) for clusteredImage in clusteredImages] fig, (ax1, ax2) = plt.subplots(1,2,figsize=(16,13)) ax1.imshow(blurredImages[0]) ax1.set_title("2014-02-01\nGaussian Blurred Image") ax2.imshow(blurredImages[1]) ax2.set_title("2019-07-25\nGaussian Blurred Image") plt.show()
在圖像稍微模糊之后,我們可以使用OpenCV Canny()模塊:
rawEdges = [cv.Canny(blurredImage, 2, 5).astype("float").reshape(clusteredImages[0].shape) for blurredImage in blurredImages] edges = [] for edge in rawEdges: edge[edge == 0] = np.nan edges.append(edge)
在單行代碼中,我們獲得了梯度,提取了局部最大值,然后對(duì)每次采集都應(yīng)用了帶有滯后的閾值。
注意:我們可以使用不同參數(shù)Canny()來探索處理結(jié)果。
4.5結(jié)果
plt.figure(figsize=(16,30)) plt.imshow(rgbImage2) plt.imshow(edges[0], cmap = 'Set3_r') plt.imshow(edges[1], cmap = 'Set1') plt.title('CoastLine') plt.show()
以下是一些詳細(xì)信息:
5結(jié)論
從結(jié)果中可以看到,Canny的算法在其原始管道中運(yùn)行良好,但其性能通常取決于所涉及的數(shù)據(jù)。
實(shí)際上,所使用的聚類算法使我們能夠?qū)Χ喙庾V立方體進(jìn)行細(xì)分。并行使用多個(gè)聚類模型可以總體上改善結(jié)果。
數(shù)據(jù)分析咨詢請(qǐng)掃描二維碼
若不方便掃碼,搜微信號(hào):CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實(shí)戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫管理中,“大表” 始終是性能優(yōu)化繞不開的話題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動(dòng)態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價(jià)值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實(shí)戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫)處理 Excel 數(shù)據(jù)時(shí),“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗(yàn)與 t 檢驗(yàn):差異、適用場(chǎng)景與實(shí)踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計(jì)學(xué)領(lǐng)域,假設(shè)檢驗(yàn)是驗(yàn)證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計(jì)劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計(jì)劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對(duì)象的 text 與 content:區(qū)別、場(chǎng)景與實(shí)踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請(qǐng)求開發(fā)時(shí)(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價(jià)值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請(qǐng)求工具對(duì)比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請(qǐng)求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長(zhǎng)浮點(diǎn)數(shù)據(jù)的科學(xué)計(jì)數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長(zhǎng)浮點(diǎn)數(shù)據(jù)時(shí)的科學(xué)計(jì)數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價(jià)值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運(yùn)營問題、提升執(zhí)行效率的核心手段,其價(jià)值 ...
2025-09-12用 SQL 驗(yàn)證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實(shí)戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計(jì)” 與 “用戶體驗(yàn) ...
2025-09-11塔吉特百貨孕婦營銷案例:數(shù)據(jù)驅(qū)動(dòng)下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價(jià)值 在數(shù)據(jù)驅(qū)動(dòng)決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實(shí)踐到業(yè)務(wù)價(jià)值挖掘 在數(shù)據(jù)分析場(chǎng)景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計(jì)模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價(jià)值導(dǎo)向 統(tǒng)計(jì)模型作為數(shù)據(jù)分析的核心工具,并非簡(jiǎn)單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10