2019年上半年参加了珠海欧比特公司举办的高光谱大赛,本意是想着看看数据质量如何,简单的拿着我们团队自己开发的深度学习模型,去参加了一下高光谱竞赛,也没怎么准备,就是简单的应用一下而已,我们花了一个星期东西凑了点东西,介绍文档不到7页,居然拿了个二等奖。。。。主题是云检测。如果大家有任何问题,请与我联系,Email:1044625113@qq.com,qq:1044625113.加我时,请备注:高精度云检测。
大家都知道云、雪、高亮地物在没有短波红外波段加入区分时,这几种地物是很容易混淆的,虽然有很多文章宣称可以做到高精度云雪检测,但是真正落地应用的时候,基本上都不行,效果很差,直到深度学习方法出来,这种现象才有了很大的改观。而我们团队主要是深度学习语义分割这一块的,因此云雪自然是我们的一个小目标而已,我们已经在国产高分系列卫星上面实现高精度云检测,在珠海一号高光谱卫星上,表现如何呢?下面我会用实验记录这一次竞赛的情况,不说了,show code and result,首先使用爬虫技术,爬取了欧比特高光谱竞赛官网上所有影像,之所以不手动下载,主要是因为数据太多了。。。
爬虫代码如下所示:
# -*- coding: utf-8 -*- # Purpose: 下载珠海一号数据 # Author: Mr Zhipan wang, if you have any question,Email:1044625113@qq.com import os import re import urllib.error import urllib.request import requests from bs4 import BeautifulSoup from win32com.client import Dispatch # 调用迅雷下载 # 使用正则表达式获取下载连接,refer: https://zhuanlan.zhihu.com/p/52198820 # 顺便说一句,正则表达式实在是太过于强大... def findURL(stringName): """ :param stringName: 字符串 :return: 返回字符串中的URL下载网址, 示例:http://218.13.181.222:8000/f/c9f1805f87/?raw=1 """ # findall() 查找匹配正则表达式的字符串 pattern = r"\w{4}\W{3}\d{3}.\d{2}.\d{3}.\d{3}.\d{4}\W\w\W\w{10}\W{2}.{5}" url = re.findall(pattern, stringName) return url# 创建文件夹 def mkdir(pathName): """ :pathName : 待创建的路径名 """ folder = os.path.exists(pathName) if not folder: # 判断是否存在文件夹如果不存在则创建为文件夹 os.makedirs(pathName) # makedirs 创建文件时如果路径不存在会创建这个路径 # print "--- 新文件夹创建成功... ---" else: print("--- 文件夹已存在! ---") # 下载文件-urllib.request def getDown_urllib(url, file_path): # 需要写明文件名称,否则无法写入 try: urllib.request.urlretrieve(url, filename=file_path) return True except urllib.error.URLError as e: # hasttr(e, \'code\'),判断e 是否有.code属性,因为不确定是不是HTTPError错误,URLError包含HTTPError,但是HTTPError以外的错误是不返回错误码(状态码)的 if hasattr(e, \'code\'): print(e.code) # 打印服务器返回的错误码(状态码),如403,404,501之类的 return False elif hasattr(e, \'reason\'): print(e.reason) # 打印错误原因 return False def getDownFile(url, savePath): """ :param url:下载的页面URL :param savePath: 保存影像路径 :return: 下载地址,文件夹名称 """ # savePath = "E:\\珠海欧比特遥感应用大赛\\影像数据" headers = {\'User-Agent\': \'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6\'} temp_Page = requests.get(url, headers=headers) soup = BeautifulSoup(temp_Page.text, "lxml") Contents = soup.contents[0].text # 转成string字符串 downURL = findURL(Contents) imgPlace = findPlaceName(Contents) saveImagePath = [] for path in imgPlace: # 创建影像文件名 Path = os.path.join(savePath, path + ".rar") saveImagePath.append(Path) if (len(downURL) == len(imgPlace)): for i in range(0, len(downURL)): urlImg = downURL[i] FileName = saveImagePath[i] if os.path.exists(FileName): print("文件已经存在...") else: down_Type = getDown_urllib(urlImg, FileName) # true 表示当前ts文件下载成功a print(\'第\' + str(i) + \'个影像爬取完成...\') else: print("该页面爬取错误...") # 调用迅雷进行下载 def XunLeiDownLaod(url, savePath): """ :param url: :param savePath: :return: """ headers = {\'User-Agent\': \'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6\'} temp_Page = requests.get(url, headers=headers) soup = BeautifulSoup(temp_Page.text, "lxml") Contents = soup.contents[0].text # 转成string字符串 downURL = findURL(Contents) imgPlace = findPlaceName(Contents) saveImagePath = [] for path in imgPlace: # 创建影像文件名 Path = os.path.join(savePath, path + ".rar") saveImagePath.append(Path) Xunlei = Dispatch("ThunderAgent.Agent64.1") # print(len(downURL)) # print(len(imgPlace)) if (len(downURL) == len(imgPlace)): for i in range(0, len(downURL)): urlImg = downURL[i] FileName = saveImagePath[i] if os.path.exists(FileName): print("文件已经存在...") else: Xunlei.AddTask(urlImg, FileName, savePath) print(\'第\' + str(i) + \'个迅雷下载任务添加完毕...\') Xunlei.CommitTasks() # 开始下载任务 else: print("该页面爬取错误...") if __name__ == \'__main__\': URL_page = [ "https://web30.obtdata.com/web/dataDownload/page?pageNo=0&pageSize=20&token=a22ca3ec-a644-44d2-b281-bf1e8309e015", "https://web30.obtdata.com/web/dataDownload/page?pageNo=1&pageSize=20&token=a22ca3ec-a644-44d2-b281-bf1e8309e015", "https://web30.obtdata.com/web/dataDownload/page?pageNo=2&pageSize=20&token=a22ca3ec-a644-44d2-b281-bf1e8309e015", "https://web30.obtdata.com/web/dataDownload/page?pageNo=3&pageSize=20&token=a22ca3ec-a644-44d2-b281-bf1e8309e015", "https://web30.obtdata.com/web/dataDownload/page?pageNo=4&pageSize=20&token=a22ca3ec-a644-44d2-b281-bf1e8309e015"] savePath = "E:\\珠海欧比特遥感应用大赛\\影像数据" # pool = Pool(5) # # Task1 = pool.map(getDownFile, URL_page[0]) # Task2 = pool.map(getDownFile, URL_page[1]) # Task3 = pool.map(getDownFile, URL_page[2]) # Task4 = pool.map(getDownFile, URL_page[3]) # Task5 = pool.map(getDownFile, URL_page[4]) # # pool.close() # pool.join() # # requests 下载 # getDownFile(URL_page[0], savePath) # getDownFile(URL_page[1], savePath) # getDownFile(URL_page[2], savePath) # getDownFile(URL_page[3], savePath) # getDownFile(URL_page[4], savePath) # 迅雷下载 # XunLeiDownLaod(URL_page[0], savePath) # XunLeiDownLaod(URL_page[1], savePath) # XunLeiDownLaod(URL_page[2], savePath) XunLeiDownLaod(URL_page[3], savePath) # XunLeiDownLaod(URL_page[4], savePath) print("全部完成...")
数据搞完了后,就要进行处理了,我把所有的波段组合成一个影像,并生成一个真彩色影像,如下图:
图1 雪样本
图2 云雪混合样本
同样,我只是举一个例子来说明我所采用的影像数据源,真正的实验过程,我把它裁剪成了512*512大小的图像块,采用GPU进行训练,深度学习模型如下图所示,比赛已经结束,可以开源了:
这个架构中,我们自己在四个空洞卷积层进行了改进,后续接四个池化层,聚合特征,经过实验来看,效果会有一定损失,但是效果会提升2%-5%左右,相比于Unet就会好更多了,经过我们的实验,发现Unet很难区分云雪,尤其是高山雪,我们自己的这个网络架构,基本上把云雪进行了区分,结果还是比较好的,同时,我们也设计一个GUI界面,用来简单的给用户训练模型和持续迭代,这个才真正有点工程的味道了。
总体上来说,包含了模型训练,云检测,批量云检测功能,其实,从应用的角度上来说,这个东西不仅仅可以用来做云雪检测,也可以用来做其他地物监测,我看到了那些一等奖之类的,基本上都是特定地物识别,还取得了不错的成果,如果能结合这个工程化的思路,我相信能够真正的落地应用!
在实际系统设计时,我主要用了python+matlab混合编程实现,python主要负责的功能是栅格矢量化,调用GDAL实现,matlab是调用深度学习模型进行云雪检测,并实现部分后处理流程,两者调用通过import类实现,这个算是比较简单的,无需复杂配置,即可完成,后期可以考虑使用并行编程,来提高处理速度。来看看结果:
图3 测试图像真彩色
图4 云检测结果矢量化
可以看到,结果还是非常nice的。 如果大家有任何问题,或者想交流的,请加我qq联系,在此抛砖引玉,如有任何技术不当之处,烦请高手指正。