小成本大幅度增幅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.mzph.cn/news/25013.shtml

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

相关文章

CAS之AtomicReference原理解析

如果你了解了AtomicInteger的工作原理,或者看了如下文章,知道了AtomicInteger只能对当个int类型共享变量做cas的缺点。 CAS之AtomicInteger原理解析_z275598733的博客-CSDN博客 那么AtomicReference就是来解决这个问题的。原理很类似,只是A…

SAS-数据集SQL水平合并

一、SQL水平合并基本语法 sql的合并有两步,step1:进行笛卡尔乘积运算,第一个表的每一行合并第二个表的每一行,即表a有3行,表b有3行,则合并后3*39行。笛卡尔过程包含源数据的所有列,相同列名会合…

怎么加密文件夹才更安全?安全文件夹加密软件推荐

文件夹加密可以让其中数据更加安全,但并非所有加密方式都能够提高极高的安全强度。那么,怎么加密文件夹才更安全呢?下面我们就来了解一下那些安全的文件夹加密软件。 文件夹加密超级大师 如果要评选最安全的文件夹加密软件,那么文…

STM32入门学习之定时器中断

1.STM32的通用定时器是可编程预分频驱动的16位自动装载计数器。 STM32 的通用定时器可以被用于:测量输入信号的脉冲长度 ( 输入捕获 ) 或者产生输出波 形 ( 输出比较和 PWM) 等。 使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形 周…

[BabysqliV3.0]phar反序列化

文章目录 [BabysqliV3.0]phar反序列化 [BabysqliV3.0]phar反序列化 开始以为是sql注入 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ST1jvadM-1691302941344)(https://raw.githubusercontent.com/leekosss/photoBed/master/202308032140269.png)…

LabVIEW开发3D颈动脉图像边缘检测

LabVIEW开发3D颈动脉图像边缘检测 近年来,超声图像在医学领域对疾病诊断具有重要意义。边缘检测是图像处理技术的重要组成部分。边缘包含图像信息。边缘检测的主要目的是根据强度和纹理等属性识别图像中均匀区域的边界。超声(US)图像存在视觉…

应急响应-勒索病毒的处理思路

0x00 关于勒索病毒的描述 勒索病毒入侵方式:服务弱口令,未授权,邮件钓鱼,程序木马植入,系统漏洞等 勒索病毒的危害:主机文件被加密,且几乎难以解密,对主机上的文件信息以及重要资产…

在政策+市场双轮驱动下,深眸科技助力机器视觉行业走向成熟

近年来,随着人工智能发展的不断提速,机器视觉作为其重要的前沿分支,凭借着机器代替人眼来做测量和判断的能力,广泛应用于工业领域的制造生产环节,用来保证产品质量、控制生产流程、感知环境等,并迸发出强劲…

【SOP】最佳实践之 TiDB 业务写变慢分析

作者: 李文杰_Jellybean 原文来源: https://tidb.net/blog/d3d4465f 前言 在日常业务使用或运维管理 TiDB 的过程中,每个开发人员或数据库管理员都或多或少遇到过 SQL 变慢的问题。这类问题大部分情况下都具有一定的规律可循,…

ES6基础知识十:你是怎么理解ES6中 Decorator 的?使用场景?

一、介绍 Decorator,即装饰器,从名字上很容易让我们联想到装饰者模式 简单来讲,装饰者模式就是一种在不改变原类和使用继承的情况下,动态地扩展对象功能的设计理论。 ES6中Decorator功能亦如此,其本质也不是什么高大…

eclipse was unable to locate its companion shared library

当转移或者Copy工程时, eclipse was unable to locate its companion shared library eclipse.ini 里面的路径配置错误导致 --launcher.library C:/Users/**/.p2/pool/plugins/org.eclipse.equinox. launcher.win32.win32.x86_64_1.2.700.v20221108-1024 -product …

Tomcat的介绍和安装配置、eclipse中动态web项目的创建和运行、使用IDEA创建web项目并运行

一、Tomcat的介绍和安装配置 安装tomcat: 环境变量的配置: 配置之后重启cmd,执行startup命令,启动tomcat 在localhost:8080,能进入tomcat主界面,说明配置成功 二、eclipse中动态web项目的创建和运行 tomca…

【雕爷学编程】Arduino动手做(180)---Seeeduino Lotus开发板2

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…

Linux下C/C++的gdb工具与Python的pdb工具常见用法之对比

1、gdb和pdb分别是什么? 1.1、gdb GDB(GNU Debugger)是一个功能强大的命令行调试工具,由GNU项目开发,用于调试C、C等编程语言的程序。它在多个操作系统中都可以使用,包括Linux、MacOS和Windows&#xff0…

【Spring Boot】Spring Boot 集成 RocketMQ 实现简单的消息发送和消费

文章目录 前言基本概念消息和主题相关发送普通消息 发送顺序消息RocketMQTemplate的API介绍参考资料: 前言 本文主要有以下内容: 简单消息的发送顺序消息的发送RocketMQTemplate的API介绍 环境搭建: RocketMQ的安装教程:在官网…

Qt下载慢/无法下载解决方式

文章目录 一. Qt在线安装下载二. 安装方式 一. Qt在线安装下载 官网下载:https://www.qt.io/download清华源下载:https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/online_installers/ 二. 安装方式 进入下载好的目录 在目录栏输入CMD&…

常州同和采购益高观光车提升服务品质

同和纺织机械制造有限公司坐落于江苏省常州市戚墅堰经济开发区,是中国纺织工业联合会常务理事单位、国家高新技术企业。公司占地面积30万平方米,现代化厂房建筑面积20万平方米。 随着公司发展,企业意识到通过提供高品质的客户接待服务来增强竞争力。为了满足这一需求,常州同和…

MyBatis 查询数据库之二(增、删、改、查操作)

目录 1. 配置打印 MyBatis 执行的SQL 2. 查询操作 2.1 通过用户 ID 查询用户信息、查询所有用户信息 (1) Mapper 接口 (2)UserMapper.xml 查询所有用户的具体实现 SQL (3)进行单元测试 3. 增加操作 3.1 在 mapper(interface)里面添加增加方法的声…

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

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

WebGL Shader着色器GLSL语言

在2D绘图中的坐标系统,默认情况下是与窗口坐标系统相同,它以canvas的左上角为坐标原点,沿X轴向右为正值,沿Y轴向下为正值。其中canvas坐标的单位都是’px’。 WebGL使用的是正交右手坐标系,且每个方向都有可使用的值的…