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

        本文以实验为导向,使用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.rhkb.cn/news/78314.html

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

相关文章

使用ChatGPT编写技术文档

技术文档对于任何项目都是至关重要的,因为它确保所有利益相关者都在同一层面上,并允许有效的沟通和协作。创建详细而准确的技术文档可能既耗时又具有挑战性,特别是对于那些不熟悉主题或缺乏强大写作技巧的人来说。ChatGPT 是一个强大的人工智…

解密爬虫ip是如何被识别屏蔽的

在当今信息化的时代,网络爬虫已经成为许多企业、学术机构和个人不可或缺的工具。然而,随着网站安全防护的升级,爬虫ip往往容易被识别并屏蔽,给爬虫工作增加了许多困扰。在这里,作为一家专业的爬虫ip供应商,…

torchvision.datasets数据加载失败

torchvision.datasets数据加载失败 如何使用torchvision.datasets进行自动下载数据失败,可以使用手动下载数据 Ctrl点击可以进入相关包文件,查找下载地址:https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 手动下载之后解压&#x…

使用Vscode编辑keil工程

一、需要安装的插件 1. Keil Assistant 2. C/C 3. 中文配置: 二、插件配置 1. Keil Assistant 添加Keil的安装路径 接下来就可以使用vscode编辑Keil的工程了,调试编译和下载程序需要返回到Keil中进行操作。 三、Vscode常用快捷键 可以自定义进行配置…

微信小程序开通账号

https://mp.weixin.qq.com/ 在该页面使用一个新邮箱注册一个账号,并且绑定一个微信号作为管理者用户,下次登录,在该页面,直接使用微信扫码后,选择账号登录

Spring Cloud Alibaba (一)

1 微服务介绍 1.1 系统架构演变 随着互联网的发展,网站应用的规模也在不断的扩大,进而导致系统架构也在不断的进行变化。 从互联网早起到现在,系统架构大体经历了下面几个过程: 单体应用架构--->垂直应用架构--->分布 式架构--->S…

新手入门吉他买什么好?千元内VEAZEN费森VZ200和恩雅X1pro综合评测,你会选新型材质HPL还是传统木吉他?

千元内入门吉他少不了VEAZEN费森VZ200单板系列和恩雅X1 PRO系列这两款热门系列,最近很多初学者朋友来私信,咨询这两款琴有什么优缺点,哪一款更值得初学者选购,那么今天,就以它们为本期的评测主角,全方位评测…

《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(19)-Fiddler精选插件扩展安装,将你的Fiddler武装到牙齿

1.简介 Fiddler本身的功能其实也已经很强大了,但是Fiddler官方还有很多其他扩展插件功能,可以更好地辅助Fiddler去帮助用户去开发、测试和管理项目上的任务。Fiddler已有的功能已经够我们日常工作中使用了,为了更好的扩展Fiddler&#xff0c…

【数据结构与算法——TypeScript】算法的复杂度分析、 数组和链表的对比

【数据结构与算法——TypeScript】 算法的复杂度分析 什么是算法复杂度(现实案例)? ❤️‍🔥 前面已经解释了什么是算法? 其实就是解决问题的一系列步骤操作、逻辑。 ✅ 对于同一个问题,我们往往有很多种解决思路和方法&#x…

flink1.17 eventWindow不要配置processTrigger

理论上可以eventtime processtime混用,但是下面代码测试发现bug,输入一条数据会一直输出. flink github无法提bug/问题. apache jira账户新建后竟然flink又需要一个账户,放弃 bug复现操作 idea运行代码后 往source kafka发送一条数据 a,1,1690304400000 可以看到无限输出…

迭代器模式(Iterator)

迭代器模式是一种行为设计模式,可以在不暴露底层实现(列表、栈或树等)的情况下,遍历一个聚合对象中所有的元素。 Iterator is a behavior design pattern that can traverse all elements of an aggregate object without exposing the internal imple…

排序八卦炉之归并、计数

文章目录 1.归并排序1.1初识代码1.2代码分析1.3复杂度1.4非递归版本1.01.初识代码2.代码分析 1.5非递归版本2.01.初识代码2.代码分析 2.计数排序2.1初始代码2.2代码分析 1.归并排序 1.1初识代码 //归并排序 时间复杂度:O(N*logN) 空间复杂度:O(N) vo…

java中io流、属性集Properties、缓冲流、转换流、序列化和反序列化、打印流、网络编程(TCP通信程序、文件复制案例、文件上传案例、B/S服务案例)

IO流: io流中i表示input输入,o表示output输出,流表示数据(字符,字节,1个字符2个字节8个位);这里的输入输出是以内存为基础,将数据从内存中输出到硬盘的过程称为输出&…

复旦大学计算机考研分析

关注我们的微信公众号 姚哥计算机考研 更多详情欢迎咨询 24计算机考研|上岸指南 复旦大学 复旦大学计算机考研招生学院是计算机科学与技术学院,软件学院,工程与应用技术研究院。目前均已出拟录取名单。 复旦大学计算机学科创建于中国计算机事业的起…

C语言数组笔试题(详解)

目录 插入知识: 一.指向函数指针数组的指针 二.回调函数 什么是回调函数? 三.数组笔试题 个人名片: 🐼作者简介:一名乐于分享在学习道路上收获的大二在校生🐻‍❄个人主页:GOTXX &#x1f4…

试用AI生成代码工具Fauxpilot,详细安装过程

设置服务 预先说明 需要预先安装支持NVIDIA的docker,docker compose > 1.28不能再容器里运行,否则出现以下报错: rootc536ca0dbd64:/test/fauxpilot-main# ./setup.sh Checking for curl ... /usr/bin/curl Checking for zstd ... /opt/conda/bin…

计算机网络-性能指标

计算机网络-性能指标 文章目录 计算机网络-性能指标简介速率比特速率 带宽吞吐量时延时延计算 时延带宽积往返时间网络利用率丢包率总结 简介 性能指标可以从不同的方面来度量计算机网络的性能 常用的计算机网络的性能指标有以下8个 速率带宽吞吐量时延时延带宽积往返时间利…

Windows server上用nginx部署vue3项目

Windows server上用nginx部署vue3项目 一、Node中node_modules文件夹及package.json文件的作用说明二、VUE3项目打包三、Windows Server上的Nginx部署 一、Node中node_modules文件夹及package.json文件的作用说明 node_modules是安装node后用来存放用包管理工具下载安装的包的…

【Python | 进阶】提高你的Python技能,99个让代码更简洁、更快的秘密技巧, 确定不来看看?

🤵‍♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…

突破传统监测模式:业务状态监控HM的新思路 | 京东云技术团队

一、传统监控系统的盲区,如何打造业务状态监控。 在系统架构设计中非常重要的一环是要做数据监控和数据最终一致性,关于一致性的补偿,已经由算法部的大佬总结过就不再赘述。这里主要讲如何去补偿?补偿的方案哪些?这就…