基于卷积神经网络的高光谱分类(1D、2D、3D-CNN)

news2024/12/26 0:37:05

算法原理

卷积神经网络(Convolutional Neural Networks,CNN)是深度学习中最常见的一种
算法,它具有强大的特征学习能力。CNN 通过结合局部感知区域、共享权重、空间或者
时间上的降采样来充分利用数据本身包含的局部性等特征,优化网络结构,并且保证一
定程度上的位移和变形的不变性。因此,CNN 被广泛应用在图像分类,语音识别,目标
检测和人脸识别等领域。一般而言,一个简单的卷积神经网络结构通常由若干个卷积层,
池化层和全连接层组成,如图 1 所示。
在这里插入图片描述
图1 基本的卷积神经网络结构

(1)卷积层。卷积层是一个特征学习的过程,其核心是利用卷积核在输入的图像中
上下滑动,图像上的像素值与卷积核内的值做卷积操作。卷积层的功能是对输入数据进
行特征提取,其内部包含多个卷积核,组成卷积核的每个元素都对应一个权重系数和一
个偏置值。卷积层内每个神经元都与前一层中位置接近的区域的多个神经元相连,区域
的大小取决于卷积核的大小。卷积是一种特殊的线性操作,卷积核会有规律地扫过输入
图像,在感受野内对输入特征做矩阵元素乘法求和并叠加偏值量,由公式(2-1)所示。
在这里插入图片描述
(2)池化层。也被称为下采样层,通常用于卷积层之后。池化层包含预设定的池化
函数,其功能是将特征图中单个点的值替换为其相邻区域的特征图统计量。池化层选取
池化区域与卷积核扫描特征图步骤相同,由池化大小(Size)、步长(Stride)和填充
(Padding)控制。池化的目的是用来缩小卷积后的特征图尺寸,池化后的特征图保留了
原始特征图的轮廓信息,以提高计算速度,加强特征的鲁棒性。

(3)全连接层。将前层学习到的局部特征进行重组,得到全局特征信息。全连接层
的输出向量维度(CN× 1)与分类个数(N)一致,全连接层的输出值通过输出层的分类
器映射为相对概率,根据概率值判断并输出最终所属结果。常用的分类器有逻辑回归函
数(Softmax Function)、支持向量机(Support Vector Machine, SVM)等。

为了强化网络的特征的学习能力,通常在卷积层后加入非线性激活函数,用于提升
特征信息的非线性化。常见的激活函数有 Sigmoid 函数,Tanh 函数和 ReLU(Rectified
Linear Unit, ReLU)函数]等。相比 Sigmoid 和 Tanh,ReLU 函数更简单,它具有更快
的收敛速度,在一定程度上避免了梯度爆炸和梯度消失问题。计算如式(2-2)所示。

在这里插入图片描述

其中,x 为输入特征张量。

数据集

在这里插入图片描述
Pavia University 数据集来源于 ROSIS 传感器,反映了意大利北部地区帕维
亚大学校园及其周边场景,影像大小 610 像素×340 像素,波长范围 0.43-8.6 um,
空间分辨率 1.3m,去除噪声波段后剩余 103 个波段用于分类。该数据集共有 9
类地物,42776 个样本,详细类别信息见表 2.2。该区域的假彩色图像和地面参
考图像如图 2 所示。其中图左为该区域的假彩色图(合成波段:红光
波段 90、绿光波段 60 和蓝光波段 30),图 右为该区域的地面参考图像。
在这里插入图片描述
在这里插入图片描述
KSC数据由 AVIRIS 传感器在佛罗里达州肯尼迪太空中心于1996年3月23日拍摄。这个数据包含了224个波段,经过水汽噪声去除后还剩下176个波段,空间分辨率是18米,一共有13个类别。

下面链接有很多数据集 该程序适用于很多高光谱数据集
https://blog.csdn.net/weixin_39860349/article/details/111263380

程序运行环境: python 3.6 TensorFlow 1.15 keras 2.3.1

1D-CNN

注:没怎么调参,可根据实际情况进行优化

#1DCNN光谱特征分类
import keras
from keras.models import Sequential
from keras.layers import Flatten,Dense,Conv1D,MaxPooling1D,BatchNormalization,Dropout
from sklearn.model_selection import train_test_split
from keras.optimizers import Adam
from keras.losses import categorical_crossentropy
import matplotlib.pyplot as plt
import fun
#PU
path='PaviaU.mat'
name='paviaU'
path_gt='PaviaU_gt.mat'
name_gt='paviaU_gt'
shape=(103,1) # 根据实际波段进行修改
save_path="PaviaU_1DCNN.h5"
classes=10 # 根据实际波段进行修改
#KSC
# path='KSC.mat'
# name='KSC'
# path_gt='KSC_gt.mat'
# name_gt='KSC_gt'
# shape=(176,1)
# save_path="KSC_1DCNN.h5"
# classes=14


model = Sequential()
model.add(Conv1D(32, kernel_size=1, activation='relu', input_shape=shape))
model.add(BatchNormalization())
model.add(Conv1D(48, kernel_size=1, activation='relu'))
model.add(BatchNormalization())
model.add(Conv1D(120, kernel_size=1, activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling1D(pool_size=1))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(classes, activation='softmax'))
model.compile(loss=categorical_crossentropy,
              optimizer=keras.optimizers.Adam(lr=0.001),
              metrics=['accuracy'])

data_D,data_L=fun.data_get_1D(path,name,path_gt,name_gt)
train_D,test_D,train_L,test_L=train_test_split(data_D,data_L,test_size=0.8)

histoty=model.fit(train_D,train_L,epochs=50,batch_size=64,validation_data=(test_D ,test_L))
model.save(save_path)
plt.plot(histoty.history['loss'],label='loss')
plt.plot(histoty.history['val_loss'],label='val_loss')
plt.legend()
plt.show()
plt.plot(histoty.history['accuracy'],label='acc')
plt.plot(histoty.history['val_accuracy'],label='val_acc')
plt.legend()
plt.show()
con, acc, pred_D=fun.pred(model,data_D,data_L)
print('**********混淆矩阵**********')
print(con)
fun.show(path_gt, name_gt)
fun.pred_show(path_gt,name_gt,pred_D,100)


子函数 fun.py

from scipy.io import loadmat
from keras.utils import to_categorical
import numpy as np
from sklearn import preprocessing
from sklearn.metrics import accuracy_score,confusion_matrix
from functools import reduce
import spectral
import cv2
def data_get_1D(path,name,path_gt,name_gt):
    input_image = loadmat(path)[name]
    output_image = loadmat(path_gt)[name_gt]
    data_list = []
    label_list = []
    for i in range(output_image.shape[0]):
        for j in range(output_image.shape[1]):
            if output_image[i][j] != 0:
                data_list.append(input_image[i][j])
                label_list.append(output_image[i][j])
    data_D = np.array([data_list])
    data_L = np.array(label_list)
    data_L = to_categorical(data_L)
    data_D=data_D.reshape([data_D.shape[1],data_D.shape[2]])
    data_D= preprocessing.StandardScaler().fit_transform(data_D)
    data_D = data_D.reshape([data_D.shape[0], data_D.shape[1], 1])
    return data_D,data_L

def standardScaler(X):
    means = np.mean(X, axis=(0, 2))  # 计算均值,先计算第0维度的,后计算第2维度的,得到一个shape为3,的矩阵
    stds = np.std(X, axis=(0, 2))  # 计算方差,得到一个shape为3,的矩阵
    means = means.reshape(1, -1, 1)  # 转换为和X相同维度的矩阵,此时reshape后的矩阵维度为(1,3,1)
    stds = stds.reshape(1, -1, 1)  # 同上
    X = (X - means) / stds
    return  X

def data_get(path,name,path_gt,name_gt,len):
    a=int((len-1)/2)
    input_image = loadmat(path)[name]
    output_image = loadmat(path_gt)[name_gt]
    #边缘填充
    input_image=cv2.copyMakeBorder(input_image, a, a, a, a,borderType=cv2.BORDER_REFLECT_101)
    output_image=cv2.copyMakeBorder(output_image, a, a, a, a,borderType=cv2.BORDER_REFLECT_101)
    data_list = []
    label_list = []
    for i in range(a, output_image.shape[0] - a):
        for j in range(a, output_image.shape[1] - a):
            if output_image[i][j] != 0:
                data_list.append((np.float32(standardScaler(input_image[i - a:i + a+1, j - a:j + a+1, :]))))
                label_list.append(output_image[i][j])
    data_D = np.array([data_list])
    data_L = np.array(label_list)
    data_L = to_categorical(data_L)
    data_2D = data_D.reshape([data_D.shape[1], len, len, data_D.shape[4]])
    data_3D = data_D.reshape([data_D.shape[1],len, len, data_D.shape[4],1])
    return data_2D,data_3D,data_L

def pred(model,data_D,data_L):
    pred_D = np.argmax(model.predict(data_D), axis=1)
    con = confusion_matrix(np.argmax(data_L, axis=1), pred_D)
    acc = accuracy_score(np.argmax(data_L, axis=1), pred_D)
    return con,acc,pred_D

def number(path_gt,name_gt):
    output_image = loadmat(path_gt)[name_gt]
    dict_k = {}
    for i in range(output_image.shape[0]):  # 行
        for j in range(output_image.shape[1]):  # 列
            # if output_image[i][j] in [m for m in range(1,17)]:
            if output_image[i][j] in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]:
                if output_image[i][j] not in dict_k:
                    dict_k[output_image[i][j]] = 0
                dict_k[output_image[i][j]] += 1
    s=reduce(lambda x, y: x + y, dict_k.values())
    return dict_k,s

def show(path_gt,name_gt):
    output_image = loadmat(path_gt)[name_gt]
    return spectral.imshow(classes=output_image.astype(int), figsize=(9, 9))

def pred_show(path_gt,name_gt,predict_label,len):
    a=int((len-1)/2)
    output_image = loadmat(path_gt)[name_gt]
    output_image=cv2.copyMakeBorder(output_image, a, a, a, a,borderType=cv2.BORDER_CONSTANT, value=0)
    new_show = np.zeros((output_image.shape[0], output_image.shape[1]))
    k = 0
    for i in range(a,output_image.shape[0]-a):
        for j in range(a,output_image.shape[1]-a):
            if output_image[i][j] != 0:
                new_show[i][j] = predict_label[k]
                k += 1
    return spectral.imshow(classes=new_show.astype(int), figsize=(9, 9))

1D-CNN 结果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

真实值:
在这里插入图片描述
预测值:
在这里插入图片描述

2D-CNN

import keras
from keras.layers import Flatten, Dense, BatchNormalization, Dropout, Conv2D, MaxPooling2D
from  keras.models import Sequential
from sklearn.model_selection import train_test_split
from keras.optimizers import Adam
from keras.losses import categorical_crossentropy
from matplotlib import pyplot as plt
import fun

# PU
path='PaviaU.mat'
name='paviaU'
path_gt='PaviaU_gt.mat'
name_gt='paviaU_gt'
shape=(11,11,103)
classes=10
save_path="paviaU_2DCNN.h5"
#KSC
# path='data/KSC.mat'
# name='KSC'
# path_gt='data/KSC_gt.mat'
# name_gt='KSC_gt'
# shape=(11,11,176)
# save_path="KSC_2DCNN.h5"
# classes=14

model = Sequential()
model.add(Conv2D(32, kernel_size=(2, 2), activation='relu', input_shape=shape))
model.add(BatchNormalization())
model.add(Conv2D(48, kernel_size=(2, 2), activation='relu'))
model.add(BatchNormalization())
model.add(Conv2D(120, kernel_size=(2, 2), activation='relu'))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(classes, activation='softmax'))
model.compile(loss=categorical_crossentropy,
              optimizer=keras.optimizers.Adam(lr=0.001),
              metrics=['accuracy'])


data_D,data_3D,data_L=fun.data_get(path,name,path_gt,name_gt,11)

train_D,test_D,train_L,test_L=train_test_split(data_D,data_L,test_size=0.8,random_state=1)

histoty=model.fit(train_D,train_L,epochs=200,batch_size=64,validation_data=(test_D ,test_L))
model.save(save_path)

3D-CNN

from keras.layers import Conv3D,MaxPooling3D,Flatten,Dropout,Dense
from keras.models import Sequential
from sklearn.model_selection import train_test_split
from keras.optimizers import Adam
from keras.losses import categorical_crossentropy
from matplotlib import pyplot as plt
import fun

#PU
path='PaviaU.mat'
name='paviaU'
path_gt='PaviaU_gt.mat'
name_gt='paviaU_gt'
shape=(11,11,103,1)
#KSC
# path='data/KSC.mat'
# name='KSC'
# path_gt='data/KSC_gt.mat'
# name_gt='KSC_gt'
#shape=(11,11,176,1)
save_path="PU_3DCNN.h5"
classes=10

model=Sequential([
     Conv3D(6,(5,5,5),strides=(1,1,1),input_shape=shape,padding="same",activation='relu'),
     MaxPooling3D((2,2,2),padding="valid"),
     Conv3D(12,(3,3,3),strides=(1,1,3),padding="valid",activation="relu"),
     Conv3D(24,(3,1,3),strides=(1,1,3),padding="valid",activation="relu"),
     Conv3D(48,(1,3,3),strides=(1,1,3),padding="valid",activation="relu"),
     Flatten(),
     Dropout(0.5),
     Dense(96,activation='relu'),
     Dense(classes,activation="softmax")
 ])

data_2D,data_D,data_L=fun.data_get(path,name,path_gt,name_gt,11)

train_D,test_D,train_L,test_L=train_test_split(data_D,data_L,test_size=0.9)
model.compile(optimizer=Adam(lr=0.001),loss=categorical_crossentropy,metrics=['acc'])
histoty=model.fit(train_D,train_L,epochs=200,batch_size=100)
model.save(save_path)
plt.plot(histoty.history['loss'],label='loss')
#plt.plot(histoty.history['val_loss'],label='val_loss')
plt.legend()
plt.show()
plt.plot(histoty.history['acc'],label='acc')
#plt.plot(histoty.history['val_acc'],label='val_acc')
plt.legend()
plt.show()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132602.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

绘图仪 与 示波器 Plotter Oscilloscope

【后台管理,这哪里是广告了?图都是百度搜的,又没有销售信息,就事论事而已!】 Plotter : 对低频信号持续测量并绘制到一张很长的纸上,通常是卷纸。 常见的比如传统心电图机(图左&am…

『分分钟玩转VueRouter●下』我对VueRouter在项目中如何使用的理解

路由的设置会根据系统中用户角色的数量而有所不同,大致分为三种单角色同权限、单角色不同权限、多角色。这里的角色均是只一种身份,而不是用户量。接下来的讲解纯属个人见解,大型项目会将不同权限的用户直接分开开发不同的系统。如果是小型多…

c++基础——for循环

for循环是循环的一种 以下是 for 循环的结构: for (初始化; 判断条件; 更新) {循环体; } 执行顺序: for 语句的三个部分中,任何一个部分都可以省略。其中,若省略了判断条件,相当于判断条件永远为真。 for (int i …

fpga实操训练(从模块到系统开发)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 前面我们学习了fpga的一些基本操作,熟悉了这些操作,基本上说fpga已经入门了。但是距离我们用fpga开发产品,这中…

Faster RCNN网络源码解读(Ⅷ) --- RPN网络代码解析(下)RegionProposalNetwork类解析

目录 一、代码作用(rpn_function.py) 二、代码解析 2.1 RegionProposalNetwork类 2.1.1 正向传播过程forward 接着上篇博客的2.1.2节 2.1.2 assign_targets_to_anchors 2.1.3 det_utils.Matcher传入参数 2.1.4 compute_loss 2.1.5 smooth_l1_lo…

你真的会正确使用wait和notify么?

目录 wait和notify原理 API wait 与 sleep的区别 wait 和 notify的正确使用 step1 step2 step3 step4 step5 总结waitnotify wait和notify原理 当我们线程获取某个对象的monitor锁的时候就会成为owner线程,当owner线程条件不满足的时候,就会调用wait方法,该线程就会进…

惠州市政企信息化(互联网)市场调研报告

1.引言 1.1.编写目的 据广东省惠州市惠东县的政企信息化市场调研的客观性数据,分析相关数据,确定市场规模、市场潜力、市场需求,以及需求价值,为后续的市场决策、服务组合决策提供依据,也作为未来根据市场变化而调整…

Nacos 注册中心

Nacos 注册中心 目录概述需求:设计思路实现思路分析1.增加 Maven 依赖2.Client端配置注册中心3.Server端配置注册中心4.Nacos 注册中心参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c…

Java--Map接口详解

目录 Map接口的特点 代码实现 代码实现 Map的常用方法 代码实现 Map接口的4种遍历方法 代码实现 第一种方式 第二种方式 第三种方式 第四种方式 Map接口的特点 1)Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value 2)Map中的key和value可以…

如何在星巴克连接家中Windows台式机?(安卓,iOS, Windows, macOS配合frp穿透公网IP实现)

zhaoolee 最近热衷于和海外热心老哥们交换硬盘中的单机游戏资源(BT下载),家中有Windows台式机, 适合长时间挂机下载BT资源,zhaoolee希望能随时连接到Windows台式机新增下载任务,安装体积超大的主机游戏。 …

End-to-End Object Detection with Transformers论文阅读笔记

End-to-End Object Detection with Transformers 端到端,不需要NMS后处理了,直接出结果。 1、Abstract 将目标检测作为一个集合预测问题来解决。简化了检测的整体流程,有效的消除了许多人工设计的部分,比如NMS,anch…

数据库连接池(C++11实现)

目的: 因为对数据库的操作实质上是对磁盘的IO操作,所以如果对数据库访问次数过多,就会到导致大量的磁盘IO,为了提高MySQL数据库(基于C/S设计)的访问瓶颈,除了在服务器端增加缓存服务器缓存常用的…

还在用BERT做文本分类?分享一套基于预训练模型ERNIR3.0的文本多分类全流程实例【文本分类】

目录🍀一、前言🌱二、多分类场景简介🍃三、前期准备阶段🟥3.1 运行环境准备🟧3.2 文心ERNIE系列模型介绍🟨3.3 预训练模型加载⬜3.4 加载项目代码💐四、数据准备阶段🟩4.1 数据处理流…

变不可能为可能——记房产推销员佟鑫海

有勤奋,就会有所收获。傲人的成绩和背后的努力密切相关。俗话说得好,没卖不掉的房子,仅有卖不掉房子的艺人经纪人。关键是你是否有恒心。 在明升,总会有这样一群影子,他们每天精力旺盛,衣着光鲜&#xff0…

【C/C++ SOCKET编程】基于TCP协议实现服务器客户端的简单通信

什么是SOCKET Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。 TCP/IP协议 从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议…

unsafe.Pointer和uintptr的区别

unsafe 包 func Alignof(x ArbitraryType) uintptr func Offsetof(x ArbitraryType) uintptr func Sizeof(x ArbitraryType) uintptr type ArbitraryType int type Pointer *ArbitraryType在unsafe包中,只提供了3个函数,两个类型。就这么少的量&#xf…

【数据结构进阶】布隆(Bloom Filter)过滤器【哈希+位图的整合】

布隆(Bloom Filter)过滤器【哈希位图的整合】 1、什么是布隆过滤器? 布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空…

物联网与射频识别技术,课程实验(四)

实验4—— 基于帧的时隙ALOHA(FSA)算法的实现与性能分析 实验说明: 利用Python或Matlab模拟基于帧的时隙ALOHA算法; 分析标签数量k、帧中所含时隙个数n对信道利用率的影响,其中, 信道利用率发送数据的时间/(发送数据的时间信道空…

【JavaEE】线程的状态转换

新年快乐! 祝新的一年万事胜意! 魅力无限! 随心所欲! 蒸蒸日上! 文章目录1. 线程的基本状态2.Java中线程的状态3. 线程的转换1. 线程的基本状态 操作系统中线程有三个基本状态,就绪状态,运行状态,阻塞状态. 就绪状态, 已经获得除CPU之外的所有资源,只要得到CPU,可立即执行. …

(二十五)大白话数据库无法连接故障的定位,Too many connections

文章目录 1、你是否遇到过Too many connections?2、linux的文件句柄数量被限制1、你是否遇到过Too many connections? 今天要给大家分析另外一个真实的大家都经常会碰到的数据库生产故障,就是数据库无法连接的问题。 大家会看到的异常信息往往是“ERROR 1040(HY000): Too …