小成本大幅度增幅CNN鲁棒性,完美的结合GLCM+CNN

news/2024/6/4 19:02:36/文章来源:https://blog.csdn.net/qq_51831335/article/details/132128068

        本文以实验为导向,使用vgg16+GLCM实现一场精彩的新冠肺炎的分类识别,并且对比不加GLCM后的效果。在这之前,我们需要弄明白一些前缀知识和概念问题:

GLCM(Gray-Level Co-occurrence Matrix),中文称为灰度共生矩阵,是一种用于图像纹理特征提取的统计方法。它是由Tamura等人在1978年首次提出的,用于描述图像中灰度级别之间的相互关系。GLCM在图像处理和计算机视觉领域中广泛应用,特别是在纹理分析、目标识别和图像分类等任务中作为单独特征提取的一环,并与CNN结合达到非凡的效果。

灰度级别:是指图像中每个像素的灰度值的取值范围。在数字图像中,每个像素的灰度值表示了该像素在灰度图像中的亮度程度。灰度级别通常用整数表示,其取值范围取决于图像的位深度。在一个8位灰度图像中,灰度级别的范围为0到255,其中0表示最暗的黑色,255表示最亮的白色。这意味着该图像中每个像素的灰度值可以取256个不同的值,这些值之间以等间距分布。对于一个黑白图像,每个像素只有一个灰度值,而对于彩色图像,每个像素则有多个通道,每个通道都有自己的灰度级别范围。

一、GLCM算法原理🍉 

1.1 GLCM计算原理🎈

        共生矩阵用两个位置的像素的联合概率密度来定义,它不仅反映亮度的分布特性,也反映具有同样亮度或接近亮度的象素之间的位置分布特性,是有关图象亮度变化的二阶统计特征。它是定义一组纹理特征的基础。一幅图象的灰度共生矩阵能反映出图象灰度关于方向、相邻间隔、变化幅度的综合信息,它是分析图象的局部模式和它们排列规则的基础。

f(x,y)为一幅二维数字图像,其大小为M × N,灰度级别为N_{g},则满足一定空间关系的灰度共生矩阵为:

P_{(i,j)} ={(x1,y1),(x2,y2)∈M×N|f(x1,y1)=i, f(x2,y2)=j}
其中f_{(x)}表示集合x中的元素个数,显然P为Ng×Ng的矩阵,若(x1,y1)与(x2,y2)间距离为d,两者与坐标横轴的夹角为θ,则可以得到各种间距及角度的灰度共生矩阵:

P_{(i,j,d,\Theta )}

  • i:为f(x,y)中灰度值为i的元素位置列表;
  • j:为f(x,y)中灰度值为j的元素位置列表;
  • d:为(x1,y1)(x2,y2)之间的距离;
  • θ:为(x1,y1)(x2,y2)之间连线与横坐标的夹角;

最后我们遍历i,j列表,找出和(d,θ)所描述的空间位置一样的一对位置(x1,y1)和(x2,y2)有多少个,从而得到P(i,j)的值。也就是说,这其实不是最终形态的灰度共生矩阵,真正的灰度共生矩阵应该是一个大小和f(x,y)一样的P(x,y),但它可以从P_{(i,j,d,\Theta )}中得到:

假设我们令(d=1,θ=0°), 以P(x,y,1,0°)点为例:

  • P(1,1,1,0°)= 1 ,即GLCM(1,1),说明左侧原图只有一对灰度为1的像素水平相邻。
  • P(1,2,1,0°)= 2, 即GLCM(1,2),说明左侧原图有两对灰度为1和2的像素水平相邻。

在这里插入图片描述

根据不同的(d, θ)组合,其实我们可以得到不同纹理的灰度共生矩阵,在GLCM(灰度共生矩阵)中,不同的距离和角度意味着在图像中计算纹理特征时考虑的像素之间的相对位置和方向,从而影响到后续纹理特征的提取。

  1. 距离(Distance): 距离指的是在GLCM中计算像素对共现频率时像素之间的间隔距离。通常,距离会影响纹理特征的大小和尺度。较小的距离可以捕捉图像中更细小的纹理细节,而较大的距离则能够考虑更广阔的像素关系,提取出更大范围的纹理特征。选择合适的距离取决于应用场景和所关注的纹理细节大小。

  2. 角度(Angle): 角度是指在GLCM中计算像素对共现频率时相对于水平方向的偏转角度。常用的角度通常是0°、45°、90°和135°。不同的角度能够捕捉图像中不同方向的纹理特征。例如,0°角度对应着水平方向的纹理,能够检测到图像中水平的纹理结构;45°和135°角度对应着对角线方向的纹理,能够检测到图像中的对角线纹理结构;90°角度对应着垂直方向的纹理,能够检测到图像中垂直的纹理结构。因此,选择不同的角度可以从不同方向上提取纹理信息。

在实际应用中,通常会对多个距离和角度进行计算,得到多个GLCM,然后结合这些GLCM来计算一系列的纹理特征,如对比度、能量、相关性等。通过考虑不同的距离和角度,可以全面地捕捉图像中的纹理信息,使得GLCM在纹理分析、图像分类和目标识别等任务中发挥出更强大的能力。

1.2 GLCM纹理特征提取原理🎈 

        纹理特征提取的一种有效方法是以灰度级的空间相关矩阵即共生矩阵为基础的,因为图像中相距(Δx,Δy)的两个灰度像素同时出现的联合频率分布可以用灰度共生矩阵来表示。若将图像的灰度级定为N级,那么共生矩阵为N×N矩阵,可表示为M(Δx,Δy)(h,k),其中位于(h,k)的元素m(h,k)的值表示一个灰度为h而另一个灰度为k的两个相距为(Δx,Δy)的像素对出现的次数。
对粗纹理的区域,其灰度共生矩阵的m(h,k)值较集中于主对角线附近。因为对于粗纹理,像素对趋于具有相同的灰度。而对于细纹理的区域,其灰度共生矩阵中的mhk值则散布在各处。
为了能更直观地以共生矩阵描述纹理状况,从共生矩阵导出一些反映矩阵状况的参数,典型的有以下几种:
(1)能量:是灰度共生矩阵元素值的平方和,所以也称能量,反映了图像灰度分布均匀程度和纹理粗细度。如果共生矩阵的所有值均相等,则ASM值小;相反,如果其中一些值大而其它值小,则ASM值大。当共生矩阵中元素集中分布时,此时ASM值大。ASM值大表明一种较均一和规则变化的纹理模式。
(2)对比度:反映了图像的清晰度和纹理沟纹深浅的程度。纹理沟纹越深,其对比度越大,视觉效果越清晰;反之,对比度小,则沟纹浅,效果模糊。灰度差即对比度大的象素对越多,这个值越大。灰度公生矩阵中远离对角线的元素值越大,CON越大。
(3相关:它度量空间灰度共生矩阵元素在行或列方向上的相似程度,因此,相关值大小反映了图像中局部灰度相关性。当矩阵元素值均匀相等时,相关值就大;相反,如果矩阵像元值相差很大则相关值小。如果图像中有水平方向纹理,则水平方向矩阵的COR大于其余矩阵的COR值。
(4)熵:是图像所具有的信息量的度量,纹理信息也属于图像的信息,是一个随机性的度量,当共生矩阵中所有元素有最大的随机性、空间共生矩阵中所有值几乎相等时,共生矩阵中元素分散分布时,熵较大。它表示了图像中纹理的非均匀程度或复杂程度。
(5)逆差距:反映图像纹理的同质性,度量图像纹理局部变化的多少。其值大则说明图像纹理的不同区域间缺少变化,局部非常均匀。

1.3 GLCM代码实践🥒

#import package
from skimage.feature import graycomatrix, graycoprops
import numpy as np
import pandas as pd#Feature Extraction with GLCM
def feature_extractor(images):image_dataset = pd.DataFrame()for image in images:df = pd.DataFrame()#greycomatrix(image, distances, angles, levels=256, symmetric=False, normed=False)#distances - List of pixel pair distance offsets.#angles - List of pixel pair angles in radians.#5 configuration for the grey-level co-occurrence matrix calculationdists = [[1],[3],[5],[3],[3]]angles = [[0],[0],[0],[np.pi/4],[np.pi/2]]for n ,(dist, angle) in enumerate(zip(dists, angles)):GLCM = graycomatrix(image, dist, angle)GLCM_Energy = graycoprops(GLCM, 'energy')[0]df['Energy'+str(n)] = GLCM_EnergyGLCM_corr = graycoprops(GLCM, 'correlation')[0]df['Corr'+str(n)] = GLCM_corrGLCM_diss = graycoprops(GLCM, 'dissimilarity')[0]df['Diss_sim'+str(n)] = GLCM_dissGLCM_hom = graycoprops(GLCM, 'homogeneity')[0]df['Homogen'+str(n)] = GLCM_homGLCM_contr = graycoprops(GLCM, 'contrast')[0]df['Contrast'+str(n)] = GLCM_contrimage_dataset = image_dataset.append(df)return image_dataset

        看懂上面的理论知识,相信这份code已经不需要解释了。

二、GLCM+CNN网络构成👑

2.1 数据集构成🎈

2.2.2 CNN网络训练数据集 😊

train_images = torch.tensor(images_train,dtype=torch.float32).unsqueeze(1)#Convert the shape of the training set images to [*, 1, 256, 256].
train_labels = torch.tensor(labels,dtype=torch.int64)
val_images = torch.tensor(images_val,dtype=torch.float32).unsqueeze(1)#Convert the shape of the validation set images to [*, 1, 256, 256].
val_labels = torch.tensor(labels_val,dtype=torch.int64)
test_images = torch.tensor(images_test,dtype=torch.float32).unsqueeze(1)#Convert the shape of the test set images to [*, 1, 256, 256].
test_labels = torch.tensor(labels_test,dtype=torch.int64)

2.2.3 GLCM网络训练数据集😀

NOTE:images_train、images_val、images_test是numpy数组形式的数据集,用于提取GLCM特征。

train_extr_features = feature_extractor(images_train)
val_extr_features = feature_extractor(images_val)
test_extr_features = feature_extractor(images_test)

NOTE: 提取完特征后,变成torch.tensor类型,用于CNN网络训练。

trainFeatures = np.array(train_extr_features)
train_features = torch.tensor(trainFeatures,dtype=torch.float32)
validFeatures = np.array(val_extr_features)
valid_features = torch.tensor(validFeatures,dtype=torch.float32)
testFeatures = np.array(test_extr_features)
test_features = torch.tensor(testFeatures,dtype=torch.float32)

2.2 GLCM_CNN网络结构🎈


class GLCM_CNN(nn.Module):def __init__(self):super(GLCM_CNN,self).__init__()# 构建VGG16网络self.img_output = nn.Sequential(#input is (*,1,256,256)#nn.Conv2d(in_channels=1,out_channels=64,kernel_size=3,stride=1,padding='same'),nn.Conv2d(in_channels=1,out_channels=64,kernel_size=3,stride=1,padding=(1, 1)),# nn.BatchNorm2d(64),nn.ReLU(inplace=True),# nn.Conv2d(in_channels=64,out_channels=64,kernel_size=3,stride=1,padding='same'),nn.Conv2d(in_channels=64,out_channels=64,kernel_size=3,stride=1,padding=(1, 1)),# nn.BatchNorm2d(64),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2,stride=2),# input is (*,64,128,128)# nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(128),nn.ReLU(inplace=True),# nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(128),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),# input is (*,128,64,64)# nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(256),nn.ReLU(inplace=True),# nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(256),nn.ReLU(inplace=True),# nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(256),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2,stride=2),# input is (*,256,32,32)# nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(512),nn.ReLU(inplace=True),# nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(512),nn.ReLU(inplace=True),# nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(512),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),# input is (*,512,16,16)# nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(512),nn.ReLU(inplace=True),# nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(512),nn.ReLU(inplace=True),# nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding='same'),nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=(1, 1)),# nn.BatchNorm2d(512),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),# input is (*,512,8,8)nn.AdaptiveAvgPool2d((7, 7)),nn.Flatten(),nn.Linear(in_features=512*7*7,out_features=4096),nn.ReLU(inplace=True),nn.Dropout(0.5),nn.Linear(in_features=4096,out_features=4096),nn.ReLU(inplace=True),nn.Dropout(0.5),nn.Linear(in_features=4096,out_features=8))# 构建GLCM特征提取分类网络self.feature_output = nn.Sequential(nn.Linear(in_features=25,out_features=8),nn.ReLU(),nn.Linear(in_features=8,out_features=4),# nn.ReLU(),)# 构建整合网络self.model = nn.Sequential(nn.Linear(in_features=12,out_features=8),nn.ReLU(),nn.Linear(in_features=8,out_features=2),)# 前向传播def forward(self,train_extr_features,imgs):img_output = self.img_output(imgs)feature= self.feature_output(train_extr_features)concat = torch.cat([feature,img_output],dim=1)return self.model(concat)
  • self.img_output是一个VGG16的CNN网络,用于提取原数据的特征进行前向传播,得到各个神经元的激活值,也就是 原始数据的各个特征值。
  • self.feature_output是一个线性分类器,是用GLCM从源数据中提取的特征,是一个大小为25的向量(通过1.3代码可知),然后投入线性分类器做与上述一样的操作。
  • 最后将两者得到的特征值进行合并,传入最后一个融合网络,得到输出层最终的预测结果,用于反向传播,权重更新等进行网络训练。

三、实验结果👑

3.1 GLCM+CNN🎈

3.1.1 前10个epoch🥒

3.1.2 后10个epoch🥒

3.2 CNN🎈

哎呀,实验的时候忘记加验证集了,反正最后结果是valid Accuracy:93.012几来着,哈哈,尴尬了这就,写到这里才发现,,ԾㅂԾ,,

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

比特鹏哥-数据类型和变量【自用笔记】

这里写目录标题 1.数据类型介绍字符,整型,浮点型,布尔类型 2.signed 和unsigned3.数据类型的取值范围sizeof 展示字节大小--- 计算机中单位:字节 4.变量 常量4.1 变量创建变量(数据类型 变量名)创建变量的时…

基于react-native的简单消息确认框showModel

基于react-native的简单消息确认框showModel 效果示例图组件代码ShowModel/index.jsx使用案例device.js安装线性渐变色 效果示例图 组件代码ShowModel/index.jsx import React, {forwardRef, useImperativeHandle, useState} from react; import {View,Text,Modal,TouchableOp…

2023,哪些大厂不再值钱?

2023年,摘下口罩的第一年,虽然经济复苏没那么强劲,但对于在资本寒冬中熬了许久的互联网科技股来说,春天的步伐好像越来越近了。今年以来,主要互联网科技公司的股价基本都涨了不少,尤其美国那边,…

ROS添加发布者和订阅者机制实现

一. ROS的节点和包 ✨Node: ROS的基本单位,实现某个功能的节点。比如实现超声波传感器就是一个节点,雷达传感器就可以是一个节点 ✨Package: 多个有联系的节点组成的单位,比如你要控制无人机姿态,可能需要…

【Linux命令详解 | pwd命令】Linux系统中用于显示当前工作目录的命令

文章标题 简介一,参数列表二,使用介绍1. pwd命令的基本使用2. pwd命令中的参数3. pwd命令的工作机制4. pwd命令的实际应用 总结 简介 pwd命令是Linux中的基础命令之一,使用该命令可以快速查看当前工作目录。在掌握Linux命令时,pw…

在Raspberry Pi 4上安装Ubuntu 20.04 + ROS noetic(不带显示器)

在Raspberry Pi 4上安装Ubuntu 20.04 ROS noetic(不带显示器) 1. 所需设备 所需设备: 树莓派 4 B 型 wifi microSD 卡:最小 32GB MicroSD 转 SD 适配器 (可选)显示器,鼠标等 2. 树莓派…

CDN安全面临的问题及防御架构

CDN安全 SQL注入攻击(各开发小组针对密码和权限的管理,和云安全部门的漏洞扫描和渗透测试) Web Server的安全(运营商和云安全部门或者漏洞纰漏第三方定期发布漏洞报告修复,例如:nginx版本号和nginx resol…

Spring5.2.x 源码使用Gradle成功构建

一 前置准备 1 Spring5.2.x下载 1.1 Spring5.2.x Git下载地址 https://gitcode.net/mirrors/spring-projects/spring-framework.git 1.2 Spring5.2.x zip源码包下载,解压后倒入idea https://gitcode.net/mirrors/spring-projects/spring-framework/-/…

《数据同步-NIFI系列》Nifi配置UpdateAttribute实现字符串时间戳转日期

Nifi配置UpdateAttribute实现字符串时间戳转日期 数据处理流程如下:查询源数据库,将Avro转为Json格式,然后使用EvaluateJsonPath修改字段名,最后使用replaceText将参数组成SQL,最后PutSQL。 一、字段串时间戳导致无法插…

转运相关的征兆,大家可以来看看

转运是一种喜讯,意味着运势将逐渐好转,人生会迎来一系列积极的变化。 虽然没有确切的科学根据可以证明转运的存在, 但是在许多传统文化和民俗中,人们都相信转运的征兆是实实在在的。 虽然无法确保这些征兆会在每种情况下都适用&am…

MySQL索引3——Explain关键字和索引使用规则(SQL提示、索引失效、最左前缀法则)

目录 Explain关键字 索引性能分析 Id ——select的查询序列号 Select_type——select查询的类型 Table——表名称 Type——select的连接类型 Possible_key ——显示可能应用在这张表的索引 Key——实际用到的索引 Key_len——实际索引使用到的字节数 Ref ——索引命…

测试工程师的工作

目录 1.何为软件测试工程师? 2.软件测试工程师的职责? 3.为什么要做软件测试? 4.软件测试的前途如何? 5.工具和思维谁更重要? 6.测试和开发相差大吗? 7.成为测试工程师的必备条件 8.测试的分类有哪…

【Spring Boot】(二)Spring Boot 配置文件的探索之旅

文章目录 前言一、配置文件的作用二、配置文件的格式2.1 Spring Boot 配置文件格式2.2 properties 和 yml 的区别 三、properties 配置文件3.1 properties 基本语法3.2 配置文件的读取3.3 properties 优缺点分析 四、yml 配置文件说明4.1 yml 基本语法4.2 yml 使用案例4.3 yml …

Git报错合集

本文记录了笔者在使用 github 过程中遇到的问题,仅供个人使用。 目录 Could not resolve hostlocal changes to the following files would be overwritten by mergeTLS connection was non-properly terminatedUpdates were rejected because the remote contains …

EVE-NG MPLS 静态 LSP

1 拓扑 2 配置步骤 2.1 配置接口IP 和路由 LER1 interface GigabitEthernet1/0ip address 10.1.1.1 255.255.255.0quitinterface GigabitEthernet2/0ip address 11.1.1.1 255.255.255.0quitip route-static 21.1.1.0 24 10.1.1.2VPC1 ip 11.1.1.100/24 11.1.1.1 配置完成后…

如何申请中国境内提供金融信息服务业务许可

依据《外国机构在中国境内提供金融信息服务管理规定》《外国机构在中国境内提供金融信息服务申请许可说明》等政策,外国机构在中国境内提供金融信息服务业务许可要求如下: 金融信息服务定义 所称的外国机构,是指外国金融信息服务提供者。 …

栈和队列的实现以及OJ题讲解

💓博主个人主页:不是笨小孩👀 ⏩专栏分类:数据结构与算法👀 刷题专栏👀 C语言👀 🚚代码仓库:笨小孩的代码库👀 ⏩社区:不是笨小孩👀 🌹欢迎大家三连关注&…

SQL Server数据库如何添加Oracle链接服务器(Windows系统)

SQL Server数据库如何添加Oracle链接服务器 一、在添加访问Oracle的组件1.1 下载Oracle的组件 Oracle Provider for OLE DB1.2 注册该组件1.2.1 下载的压缩包解压位置1.2.2 接着用管理员运行Cmd 此处一定要用管理员运行,否则会报错 二、配置环境变量三、 重启SQL Se…

SAP-FI-发票校验-总账科目录

1、业务场景 (1)如果某司机是按月结账,没有参照PO,而且每次记账的科目都不同,可能是办公费、原材料费,那么就需要直接记账到某一科目,输入基本数据的“CNY”,细节的“发票方”。 (2)如果项目期初上线,物料已收货,但是没有开票,不需要收货到系统,收到发票后,因…

XML基础知识讲解

文章目录 1. xml简介2. xml快速入门3. xml的元素(标签)定义4. xml标签的命名规范5. xml的属性定义和注释6. 转义字符7. CDATA区8. xml的处理指令9. xml的约束 1. xml简介 XML(eXtensible Markup Language)是一种用于描述数据的标记语。 它以纯文本的方…