基于OpenCV实现海岸线变化检测

重磅干货,第一时间送达

介绍

海岸是一个动态系统,其中因侵蚀现象导致的海岸线后退、或是由众多因素如气象,地质,生物和人类活动所导致线前进的是常见现象。

在海洋磨损作用大于沉积物的情况下,有明显的海岸侵蚀,我们称之为地球表面的崩解和破坏。

资料来源:弗林德斯大学(CC0)

本文的目标

在本文中,我们将对Landsat 8平台上的OLI(陆地成像仪)传感器获取的卫星图像使用Canny Edge Detection算法。

通过这种方法,我们将能够可视化的估计特定欧洲地区遭受强腐蚀作用的海岸线随时间的推移:霍德内斯海岸。

一下是处理流程:

处理流程

在开始之前让我们先介绍一下OLI数据...

0.关于Landsat OLI数据的简要介绍

Landsat 8是一个轨道平台,安装在称为OLI(陆地成像仪)的11波段多光谱传感器上。

具体来说,在本文中,我们将仅使用分辨率为30米(即前7个)的波段。

美国地质调查局陆地卫星8号

该数据可以免费下载,注册后,获得USGS:https://earthexplorer.usgs.gov/。

而且,通常我摸并不使用入射太阳光作为原始数据,而是使用反射率,即从地球表面反射的太阳光量[0-1]。

1.包导入

在各种常见的包,我们将使用rasterio处理图像,利用OpenCV中的Canny 算法和Scikit-Learn分割图像。

from glob import globimport numpy as np
import rasterioimport json, re, itertools, os
import matplotlib.pyplot as plt
import cv2 as cvfrom sklearn import preprocessingfrom sklearn.cluster import KMeans

2.数据导入

让我们定义一个变量,该变量告诉我们要保留的波段数以及在JSON中输入的辅助数据:

N_OPTICS_BANDS = 7
with open("bands.json","r") as bandsJson: bandsCharacteristics = json.load(bandsJson)

这个Json是Landsat OLI成像仪的信息集合。类似于一种说明手册:

# 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文件包含有关我们将要使用的频段的所有有用信息。

注意,我们将仅使用分辨率为30 m的频段,因此仅使用前7个频段。如果您愿意使用较低的分辨率(100m),则也可以嵌入TIRS 1和TIRS 2频段。

正如上面几行已经提到的那样,我们将使用从Landsat-8 OLI上获取两组不同的数据:

· 2014/02/01

· 2019/07/25

为了简化两次采集的所需操作,我们将定义一个Acquisition()类,其中将封装所有必要的函数。

在执行代码期间,我们能够执行一些基础支持性的功能,例如:

· 在指定路径中搜索GeoTIFF;

· 加载采购;

· 购置登记 (调整);

· 收购子集

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

好的,让我们现在开始启动整个代码:

DATES = ["2014-02-01", "2019-07-25"]acquisitionsObjects = []
for date in DATES: singleAcquisitionObject = Acquisition("Data/"+date, "tif", N_OPTICS_BANDS) acquisitionsObjects.append( singleAcquisitionObject )

运行结果如下:

现在我们已加载了14张OLI图像(在7个波段中各采集2个)。

2.1 子集多光谱立方体

在这个阶段中,先对两个多光谱立方体进行“对齐”(或正式注册),再切出不感兴趣的部分。

我们可以使用ImageImages()函数“剪切”不需要的数据。

因此,我们定义AOI(感兴趣的区域),并使用Acquisition()类中的subsetImages()函数进行设置:

W1, W2 = 950, 2300H1, H2 = 4500, 5300
subAcquisitions = [acquisition.subsetImages(W1, W2, H1, H2, 552285.0) for acquisition in acquisitionsObjects].

完成!

3.数据探索

3.1可视化多光谱立方体

让我们尝试查看2019/07/25收购的所有范围。出于纯粹的美学原因,在绘制图像之前,让我们使用

StandardScaler()对图像进行标准化。

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()

以下是运行结果。

这些图中,有些波段比其他波段更亮。这很正常。

3.2可视化复合RGB中的多光谱立方体

现在,让我们尝试可视化使用波段4(红色),3(绿色)和2(蓝色)获得的RGB复合图像中的两次采集。

定义BIAS和GAIN 仅是为了获得更好的效果。

BIAS = 1.5GAIN = [2.3,2.4,1.4]
r1 = (subAcquisitions[0][3] - subAcquisitions[0][3].min()) / (subAcquisitions[0][3].max()-subAcquisitions[0][3].min()) * GAIN[0] * BIASg1 = (subAcquisitions[0][2] - subAcquisitions[0][2].min()) / (subAcquisitions[0][2].max()-subAcquisitions[0][2].min()) * GAIN[1] * BIASb1 = (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] * BIASg2 = (subAcquisitions[1][2] - subAcquisitions[1][2].min()) / (subAcquisitions[1][2].max()-subAcquisitions[1][2].min()) * GAIN[1] * BIASb2 = (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, r2rgbImage1[:,:,1], rgbImage2[:,:,1] = g1, g2rgbImage1[:,:,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()

结果如下图所示!有趣的是,这两次获取的反射率完全的不同。

好的,继续进行海岸线检测。

4.自动化海岸线检测

在本段中,我们将使用Canny的算法执行边缘检测。

在进行实际检测之前,有必要准备数据集,尝试通过聚类算法对数据集进行分割以区分海洋和陆地。

4.1数据准备

在此阶段,我们将重塑两个多光谱立方体以进行聚类操作。

4.2用K均值进行图像分割

我们通过k均值对这两次采集进行细分(使用自己喜欢的模型即可)。

4.3细分结果

这是确定的代表新兴土地和水体的两个集群。

4.4Canny边缘检测算法

Canny的传统键技术分为以下几个阶段:

1. 高斯滤波器通过卷积降低噪声;

2. 四个方向(水平,垂直和2个倾斜)的图像梯度计算;

3. 梯度局部最大值的提取;

4. 带有滞后的阈值,用于边缘提取。

让我们开始,将聚类结果转换为图像,然后通过具有15x15内核的高斯滤波器降低噪声:

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)

在单行代码中,我们获得了梯度,提取了局部最大值,然后对每次采集都应用了带有滞后的阈值。

注意:我们可以使用不同参数Canny()来探索处理结果。

4.5结果

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()

以下是一些详细信息:

5结论

从结果中可以看到,Canny的算法在其原始管道中运行良好,但其性能通常取决于所涉及的数据。

实际上,所使用的聚类算法使我们能够对多光谱立方体进行细分。并行使用多个聚类模型可以总体上改善结果。

交流群

(0)

相关推荐

  • 高斯混合模型(GMM):理念、数学、EM算法和python实现

    高斯混合模型是一种流行的无监督学习算法.GMM方法类似于K-Means聚类算法,但是由于其复杂性,它更健壮,因此更有用. K-means聚类使用欧式距离函数来发现数据中的聚类.只要数据相对于质心呈圆形 ...

  • python画双y轴图像

    很多时候可能需要在一个图中画出多条函数图像,但是可能y轴的物理含义不一样,或是数值范围相差较大,此时就需要双y轴. matplotlib和seaborn都可以画双y轴图像.一个例子: import s ...

  • 使用python的seaborn绘制折线图与柱状图的组合图

    前言 代码 结果 前言 今天入职,小组长给我们布置了数据可视化的作业,让大家浏览一个可视化系统,然后找到三个结论,其实很简单,但是自己又拓展一点.然后需要画一个折线图与柱状图的组合图,下面是我的代码和 ...

  • 你真的了解微信好友吗

    今天发现了一个好玩的 python 第三方库 itchat,它的功能很强大:只要你扫一下它所生成的二维码即可模拟登陆你的微信号,然后可以实现自动回复,爬取微信列表好友信息等功能.这么强大的功能简直是相 ...

  • 边缘和轮廓检测——计算机视觉的应用

    计算机视觉的重点是从计算机中的视频和图像中提取有意义的信息.在本文中,我们将从初学者开始探索一个使用 OpenCV 的出色计算机视觉项目. 其标题是"使用计算机视觉进行边缘和轮廓检测&quo ...

  • 我们在程序员节组织了一场游戏,竟还用Python去验证其公平性?

    程序员节,公司举办了一个抽奖活动,采用的方式是掷六次骰子,组成一个六位数,再对群里的人数取模,计算的结果就是中奖的人的编号.但这种方式公平吗?让我们用Python来验证下. 一. 验证 掷六次骰子,那 ...

  • 基于OpenCV实战:车牌检测

    重磅干货,第一时间送达 拥有思维导图或流程将引导我们朝着探索和寻找实现目标的正确道路的方向发展.如果要给我一张图片,我们如何找到车牌并提取文字? 一般思维步骤: 识别输入数据是图像. 扫描图像以查看由 ...

  • 基于OpenCV实战的图像处理:色度分割

    重磅干货,第一时间送达 通过HSV色阶使用彩色图像可以分割来分割图像中的对象,但这并不是分割图像的唯一方法.为什么大多数人偏爱色度而不是RGB / HSV分割? 可以获得RGB / HSV通道之间的比 ...

  • 基于OpenCV的实战:轮廓检测(附代码解析)

    重磅干货,第一时间送达 利用轮廓检测物体可以看到物体的各种颜色,在这种情况下放置在静态和动态物体上.如果是统计图像,则需要将图像加载到程序中,然后使用OpenCV库,以便跟踪对象. 每当在框架中检测到 ...

  • 基于OpenCV实战:绘制图像轮廓(附代码)

    重磅干货,第一时间送达 山区和地形图中海拔高的区域划出的线称为地形轮廓,它们提供了地形的高程图.这些线条可以手动绘制,也可以由计算机生成.在本文中,我们将看到如何使用OpenCV在简单图像上绘制轮廓线 ...

  • 基于OpenCV实战:动态物体检测

    重磅干货,第一时间送达 最近,闭路电视安全系统运行着多种算法来确保安全,例如面部识别,物体检测,盗窃检测,火灾警报等.我们在运动检测的基础上实现了许多算法,因为在空闲帧上运行所有这些进程没有任何意义. ...

  • 基于OpenCV实战:对象跟踪

    重磅干货,第一时间送达 介绍 跟踪对象的基本思想是找到对象的轮廓,基于HSV颜色值. 轮廓:突出显示对象的图像片段.例如,如果将二进制阈值应用于具有(180,255)的图像,则大于180的像素将以白色 ...

  • (2条消息) 基于OpenCV使用OpenPose进行多个人体姿态估计

    目录 1.网络的体系结构 2.下载模型的权重文件 3. 第一步:生成图片对应的输出 3.1 读取神经网络 3.2 读取图像并生成输入blob 3.3 向前通过网络 3.4 样本输出 4. 第二步:关键 ...

  • 实战:基于OpenCV 的车牌识别

    重磅干货,第一时间送达 车牌识别是一种图像处理技术,用于识别不同车辆.这项技术被广泛用于各种安全检测中.现在让我一起基于OpenCV编写Python代码来完成这一任务. 车牌识别的相关步骤 1.车牌检 ...

  • 实战:基于OpenCV进行长时间曝光(内含彩蛋)

    重磅干货,第一时间送达 在本文中,我们将学习长时间曝光摄影技术,以及如何使用Python和OpenCV(开源计算机视觉库)对其进行仿真. 一.什么是"长时间曝光"? 直接来自维基百 ...