基于python的遥感影像灰色关联矩阵纹理特征计算

遥感影像纹理特征是描述影像中像素间空间关系的统计特征,常用于地物分类、目标识别和变化检测等遥感应用中。常见的纹理特征计算方式包括灰度共生矩阵(GLCM)、灰度差异矩阵(GLDM)、灰度不均匀性矩阵(GLRLM)等。这些方法通过对像素灰度值的统计分析,揭示了影像中像素间的空间分布规律,从而提取出纹理特征。

常用的纹理特征包括

1. 对比度(Contrast): 描述图像中灰度级之间的对比程度。

2. 同质性(Homogeneity): 描述图像中灰度级分布的均匀程度。

3. 熵(Entropy): 描述图像中灰度级分布的不确定性。

4. 方差(Variance): 描述图像中灰度级的离散程度。

5. 相关性(Correlation): 描述图像中像素间的灰度值相关程度。

6. 能量(Energy): 是灰度共生矩阵各元素值的平方和。

7. 均值(Mean): 描述图像中每个灰度级出现的平均频率。

8. 不相似度(Dissimilarity): 描述图像中不同灰度级之间的差异程度。

这些纹理特征可以通过GLCM等方法计算得到,用于描述遥感影像的纹理信息,对于遥感影像的分类和分析具有重要意义。

在ENVI中可以直接使用工具箱的工具直接计算得到输出影像

在这里插入图片描述

此外也可以使用python的skimage.feature库,这个库的greycoprops函数只有contrast、dissimilarity、homogeneity、ASM、energy和correlation这几个特征没有均值、方差和熵。因此下面对这个库的原函数进行修正,添加了方差等计算的greycoprops函数

def greycoprops(P, prop='contrast'):"""Calculate texture properties of a GLCM.Compute a feature of a grey level co-occurrence matrix to serve asa compact summary of the matrix. The properties are computed asfollows:- 'contrast': :math:`\\sum_{i,j=0}^{levels-1} P_{i,j}(i-j)^2`- 'dissimilarity': :math:`\\sum_{i,j=0}^{levels-1}P_{i,j}|i-j|`- 'homogeneity': :math:`\\sum_{i,j=0}^{levels-1}\\frac{P_{i,j}}{1+(i-j)^2}`- 'ASM': :math:`\\sum_{i,j=0}^{levels-1} P_{i,j}^2`- 'energy': :math:`\\sqrt{ASM}`- 'correlation':.. math:: \\sum_{i,j=0}^{levels-1} P_{i,j}\\left[\\frac{(i-\\mu_i) \\(j-\\mu_j)}{\\sqrt{(\\sigma_i^2)(\\sigma_j^2)}}\\right]Each GLCM is normalized to have a sum of 1 before the computation of textureproperties.Parameters----------P : ndarrayInput array. `P` is the grey-level co-occurrence histogramfor which to compute the specified property. The value`P[i,j,d,theta]` is the number of times that grey-level joccurs at a distance d and at an angle theta fromgrey-level i.prop : {'contrast', 'dissimilarity', 'homogeneity', 'energy', \'correlation', 'ASM'}, optionalThe property of the GLCM to compute. The default is 'contrast'.Returns-------results : 2-D ndarray2-dimensional array. `results[d, a]` is the property 'prop' forthe d'th distance and the a'th angle.References----------.. [1] The GLCM Tutorial Home Page,http://www.fp.ucalgary.ca/mhallbey/tutorial.htmExamples--------Compute the contrast for GLCMs with distances [1, 2] and angles[0 degrees, 90 degrees]>>> image = np.array([[0, 0, 1, 1],...                   [0, 0, 1, 1],...                   [0, 2, 2, 2],...                   [2, 2, 3, 3]], dtype=np.uint8)>>> g = greycomatrix(image, [1, 2], [0, np.pi/2], levels=4,...                  normed=True, symmetric=True)>>> contrast = greycoprops(g, 'contrast')>>> contrastarray([[0.58333333, 1.        ],[1.25      , 2.75      ]])"""check_nD(P, 4, 'P')(num_level, num_level2, num_dist, num_angle) = P.shapeif num_level != num_level2:raise ValueError('num_level and num_level2 must be equal.')if num_dist <= 0:raise ValueError('num_dist must be positive.')if num_angle <= 0:raise ValueError('num_angle must be positive.')# normalize each GLCMP = P.astype(np.float32)glcm_sums = np.apply_over_axes(np.sum, P, axes=(0, 1))glcm_sums[glcm_sums == 0] = 1P /= glcm_sums# create weights for specified propertyI, J = np.ogrid[0:num_level, 0:num_level]if prop == 'contrast':weights = (I - J) ** 2elif prop == 'dissimilarity':weights = np.abs(I - J)elif prop == 'homogeneity':weights = 1. / (1. + (I - J) ** 2)elif prop in ['ASM', 'energy', 'correlation', 'entropy', 'mean', 'variance']:passelse:raise ValueError('%s is an invalid property ?' % (prop))# compute property for each GLCMif prop == 'energy':asm = np.apply_over_axes(np.sum, (P ** 2), axes=(0, 1))[0, 0]results = np.sqrt(asm)elif prop == 'ASM':results = np.apply_over_axes(np.sum, (P ** 2), axes=(0, 1))[0, 0]elif prop == 'entropy':results = np.apply_over_axes(np.sum, -P * np.log10(P+0.00001), axes=(0, 1))[0, 0]elif prop == 'correlation':results = np.zeros((num_dist, num_angle), dtype=np.float64)I = np.array(range(num_level)).reshape((num_level, 1, 1, 1))J = np.array(range(num_level)).reshape((1, num_level, 1, 1))diff_i = I - np.apply_over_axes(np.sum, (I * P), axes=(0, 1))[0, 0]diff_j = J - np.apply_over_axes(np.sum, (J * P), axes=(0, 1))[0, 0]std_i = np.sqrt(np.apply_over_axes(np.sum, (P * (diff_i) ** 2),axes=(0, 1))[0, 0])std_j = np.sqrt(np.apply_over_axes(np.sum, (P * (diff_j) ** 2),axes=(0, 1))[0, 0])cov = np.apply_over_axes(np.sum, (P * (diff_i * diff_j)),axes=(0, 1))[0, 0]# handle the special case of standard deviations near zeromask_0 = std_i < 1e-15mask_0[std_j < 1e-15] = Trueresults[mask_0] = 1# handle the standard casemask_1 = mask_0 == Falseresults[mask_1] = cov[mask_1] / (std_i[mask_1] * std_j[mask_1])elif prop in ['contrast', 'dissimilarity', 'homogeneity']:weights = weights.reshape((num_level, num_level, 1, 1))results = np.apply_over_axes(np.sum, (P * weights), axes=(0, 1))[0, 0]elif prop == 'mean':I = np.array(range(num_level)).reshape((num_level, 1, 1, 1))results = np.apply_over_axes(np.sum, (P * I), axes=(0, 1))[0, 0]elif prop == 'variance':I = np.array(range(num_level)).reshape((num_level, 1, 1, 1))mean = np.apply_over_axes(np.sum, (P * I), axes=(0, 1))[0, 0]results = np.apply_over_axes(np.sum, (P * (I - mean) ** 2), axes=(0, 1))[0, 0]return results

具体影像分析时还需要考虑灰色关联矩阵计算的角度、步长、灰度级数和窗口大小。以一张多光谱影像为例,相关性使用了greycoprops,其他的特征使用公式计算,实际上导入上面的新greycoprops函数后其他特征都可以用函数计算,具体代码如下,输出结果为多光谱各个波段的纹理特征的多通道影像:

from osgeo import gdal, osr
import os
import numpy as np
import cv2
from skimage import data
from skimage.feature import greycopropsdef export_tif(out_tif_name, var_lat, var_lon, NDVI, bandname=None):# 判断数组维度if len(NDVI.shape) > 2:im_bands, im_height, im_width = NDVI.shapeelse:im_bands, (im_height, im_width) = 1, NDVI.shapeLonMin, LatMax, LonMax, LatMin = [min(var_lon), max(var_lat), max(var_lon), min(var_lat)]# 分辨率计算Lon_Res = (LonMax - LonMin) / (float(im_width) - 1)Lat_Res = (LatMax - LatMin) / (float(im_height) - 1)driver = gdal.GetDriverByName('GTiff')out_tif = driver.Create(out_tif_name, im_width, im_height, im_bands, gdal.GDT_Float32)  # 创建框架# 设置影像的显示范围# Lat_Res一定要是-的geotransform = (LonMin, Lon_Res, 0, LatMax, 0, -Lat_Res)out_tif.SetGeoTransform(geotransform)# 获取地理坐标系统信息,用于选取需要的地理坐标系统srs = osr.SpatialReference()srs.ImportFromEPSG(4326)  # 定义输出的坐标系为"WGS 84",AUTHORITY["EPSG","4326"]out_tif.SetProjection(srs.ExportToWkt())  # 给新建图层赋予投影信息# 数据写出if im_bands == 1:out_tif.GetRasterBand(1).WriteArray(NDVI)else:for bands in range(im_bands):# 为每个波段设置名称if bandname is not None:out_tif.GetRasterBand(bands + 1).SetDescription(bandname[bands])out_tif.GetRasterBand(bands + 1).WriteArray(NDVI[bands])# 生成 ENVI HDR 文件hdr_file = out_tif_name.replace('.tif', '.hdr')with open(hdr_file, 'w') as f:f.write('ENVI\n')f.write('description = {Generated by export_tif}\n')f.write('samples = {}\n'.format(im_width))f.write('lines   = {}\n'.format(im_height))f.write('bands   = {}\n'.format(im_bands))f.write('header offset = 0\n')f.write('file type = ENVI Standard\n')f.write('data type = {}\n'.format(gdal.GetDataTypeName(out_tif.GetRasterBand(1).DataType)))f.write('interleave = bsq\n')f.write('sensor type = Unknown\n')f.write('byte order = 0\n')band_names_str = ', '.join(str(band) for band in bandname)f.write('band names = {%s}\n'%(band_names_str))del out_tifdef fast_glcm(img, vmin=0, vmax=255, levels=8, kernel_size=5, distance=1.0, angle=0.0):'''Parameters----------img: array_like, shape=(h,w), dtype=np.uint8input imagevmin: intminimum value of input imagevmax: intmaximum value of input imagelevels: intnumber of grey-levels of GLCMkernel_size: intPatch size to calculate GLCM around the target pixeldistance: floatpixel pair distance offsets [pixel] (1.0, 2.0, and etc.)angle: floatpixel pair angles [degree] (0.0, 30.0, 45.0, 90.0, and etc.)Returns-------Grey-level co-occurrence matrix for each pixelsshape = (levels, levels, h, w)'''mi, ma = vmin, vmaxks = kernel_sizeh,w = img.shape# digitizebins = np.linspace(mi, ma+1, levels+1)gl1 = np.digitize(img, bins) - 1# make shifted imagedx = distance*np.cos(np.deg2rad(angle))dy = distance*np.sin(np.deg2rad(-angle))mat = np.array([[1.0,0.0,-dx], [0.0,1.0,-dy]], dtype=np.float32)gl2 = cv2.warpAffine(gl1, mat, (w,h), flags=cv2.INTER_NEAREST,borderMode=cv2.BORDER_REPLICATE)# make glcmglcm = np.zeros((levels, levels, h, w), dtype=np.uint8)for i in range(levels):for j in range(levels):mask = ((gl1==i) & (gl2==j))glcm[i,j, mask] = 1kernel = np.ones((ks, ks), dtype=np.uint8)for i in range(levels):for j in range(levels):glcm[i,j] = cv2.filter2D(glcm[i,j], -1, kernel)# 灰色关联矩阵归一化,之后结果与ENVI相同glcm = glcm.astype(np.float32)glcm_sums = np.apply_over_axes(np.sum, glcm, axes=(0, 1))glcm_sums[glcm_sums == 0] = 1glcm /= glcm_sumsreturn glcmdef fast_glcm_texture(img, vmin=0, vmax=255, levels=8, ks=5, distance=1.0, angle=0.0):'''calc glcm texture'''h,w = img.shapeglcm = fast_glcm(img, vmin, vmax, levels, ks, distance, angle)mean = np.zeros((h,w), dtype=np.float32)var = np.zeros((h,w), dtype=np.float32)cont = np.zeros((h,w), dtype=np.float32)diss = np.zeros((h,w), dtype=np.float32)homo = np.zeros((h,w), dtype=np.float32)asm = np.zeros((h,w), dtype=np.float32)ent = np.zeros((h,w), dtype=np.float32)cor = np.zeros((h, w), dtype=np.float32)for i in range(levels):for j in range(levels):mean += glcm[i,j] * ihomo += glcm[i,j] / (1.+(i-j)**2)asm  += glcm[i,j]**2cont += glcm[i,j] * (i-j)**2diss += glcm[i,j] * np.abs(i-j)ent -= glcm[i, j] * np.log10(glcm[i, j] + 0.00001)for i in range(levels):for j in range(levels):var += glcm[i, j] * (i - mean)**2greycoprops(glcm, 'correlation')  # 上面计算的几个特征均可这样写cor[cor == 1.0] = 0.homo[homo == 1.] = 0asm[asm == 1.] = 0return [mean, var, cont, diss, homo, asm, ent, cor]# 遥感影像
image = r'..\path\to\your\file\image.tif'
# 文件输出路径
out_path = r'..\output\path'
dataset = gdal.Open(image)  # 读取数据
adfGeoTransform = dataset.GetGeoTransform()
nXSize = dataset.RasterXSize  # 列数
nYSize = dataset.RasterYSize  # 行数
im_data = dataset.ReadAsArray(0, 0, nXSize, nYSize)  # 读取数据
im_data[im_data==65536] = 0
var_lat = []  # 纬度
var_lon = []  # 经度
for j in range(nYSize):lat = adfGeoTransform[3] + j * adfGeoTransform[5]var_lat.append(lat)
for i in range(nXSize):lon = adfGeoTransform[0] + i * adfGeoTransform[1]var_lon.append(lon)
result = []
band_name=[]
for i, img in enumerate(im_data):img = np.uint8(255.0 * (img - np.min(img))/(np.max(img) - np.min(img))) # normalizationfast_result = fast_glcm_texture(img, vmin=0, vmax=255, levels=32, ks=3, distance=1.0, angle=0.0)result += fast_resultvariable_names = ['mean', 'variance', 'contrast', 'dissimilarity', 'homogeneity', 'ASM', 'entropy', 'correlation']for names in variable_names:band_name.append('band_'+str(i+1)+'_'+names)
name = os.path.splitext(os.path.basename(image))[0]
export_tif(os.path.join(out_path, '%s_TF.tif' % name), var_lat, var_lon, np.array(result), bandname=band_name)  
print('over')

总结

目前熵值特征计算结果与ENVI有差异,不过只是数值差异,使用影像打开的结果显示一致,说明只是值的范围差异,不影响分析,其他特征均与ENVI的计算结果一致

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

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

相关文章

51_蓝桥杯_led流水灯

一 原理图分析 二 三八译码器工作原理 三八译码器&#xff1a;3个输入控制8路互斥的低电平有效输出。 C B A 输出 0 0 0 Y0 0 0 1 Y1 0 1 0 Y2 0 1 1 Y3 1 0 0 Y4 1 0 1 Y5 1 1 0 Y6 1 1 1 Y7 三 锁存器工作原理 锁存器&#xff1a;当使…

OpenAI 全新发布文生视频模型 Sora,支持 60s 超长长度,有哪些突破?将带来哪些影响?

Sora大模型简介 OpenAI 的官方解释了在视频数据基础上进行大规模训练生成模型的方法。 我们下面会摘取其中的关键部分罗列让大家快速get重点。 喜欢钻研的伙伴可以到官网查看技术报告&#xff1a; https://openai.com/research/video-generation-models-as-world-simulator…

BDD - Python Behave 用户自定义配置文件

BDD - Python Behave 用户自定义配置文件 引言默认 behave.ini 配置文件自定义配置文件json 格式的配置文件ini 格式的配置文件 实例应用项目结构代码BDD/Features/user_data.feature 文件BDD/steps/user_data_steps.py 文件BDD/environment.py 文件默认配置文件 behave.ini自定…

BUGKU-WEB 留言板1

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 之间写过一题类似的&#xff0c;所以这题应该是有什么不同的那就按照之前的思路进行测试试试提示说&#xff1a;需要xss平台接收flag&#xff0c;这个和之前说的提示一样 相关工具 xss平台&#xf…

外包干了2个月,感觉技术明显退步...

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

BUGKU-WEB 头等舱

题目描述 题目截图如下&#xff1a; 进入场景看看&#xff1a; 解题思路 先看看源码再看看F12请求和响应 相关工具 略 解题步骤 查看源码&#xff0c;好家伙真的什么也没有 2. 看看F12请求和响应&#xff0c;找到了 得到Flag flag{a49c7aba1014c3673ec9982946d0545a…

鸿蒙新手入门-环境准备问题解析

Node.js版本与API配套关系 由于SDK的部分工具依赖Node.js运行时&#xff0c;推荐使用配套API版本的Node.js&#xff0c;保证工程的兼容性。 匹配关系见下表&#xff1a; API LevelNode.js支持范围API Level≤914.x&#xff08;≥14.19.1&#xff09;、16.xAPI Level>914.…

移动端App自动化之触屏操作自动化

工作中我们经常需要对应用的页面进行手势操作&#xff0c;比如滑动、长按、拖动等&#xff0c;AppiumDriver 为我们提供一个模拟手势操作的辅助类 TouchAction&#xff0c;可以通过它对手机屏幕进行手势操作。 具体用法参见链接&#xff1a;chromedriver下载地址与webview自动…

【开源】JAVA+Vue.js实现农村物流配送系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统登录、注册界面2.2 系统功能2.2.1 快递信息管理&#xff1a;2.2.2 位置信息管理&#xff1a;2.2.3 配送人员分配&#xff1a;2.2.4 路线规划&#xff1a;2.2.5 个人中心&#xff1a;2.2.6 退换快递处理&#xff1a;…

docker (七)-部署容器

实战开始&#xff1a; 1 docker 部署 kafka 集群&#xff0c;并验证 参考 Docker搭建Kafka集群 优秀文档 2 docker 部署 mysql 参考上一篇docker(六) 3.docker 部署 zabbix 参考 docker部署zabbix 优秀文档 BUG&#xff1a;根据这篇文章部署后&#xff0c;发现zabbix-s…

春节专题|产业7问:区块链厂商的现在和未来——混合技术厂商

2023转瞬即逝&#xff0c;不同于加密领域沉寂一整年后在年末集中爆发&#xff0c;对于我国的区块链厂商而言&#xff0c;稳中求胜才是关键词&#xff0c;在平稳发展的基调下&#xff0c;产业洗牌也悄无声息的到来。 从产业总体而言&#xff0c;在经过了接近3年的快速发展后&…

MySQL-锁(LOCK)

文章目录 1. 锁是什么&#xff1f;2. 全局锁2.1 相关语法2.2 特点 3. 表级锁3.1 表锁3.1.1 共享读锁&#xff08;S&#xff09;3.1.2 排它写锁&#xff08;X&#xff09; 3.2 元数据锁&#xff08;MDL&#xff09;3.2 意向锁&#xff08;IS、IX&#xff09; 4. 行级锁4.1 行锁 …

基于SpringBoot的药品管理系统

基于SpringBoot的药品管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatis工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 药品详情 个人中心 员工界面 管理员界面 摘要 随着医疗技术的不断发展和人们健…

鸿蒙应用模型开发-更新SDK后报错解决

更新SDK后提示 “ohos.application.Ability”/“ohos.application.AbilityStage”等模块找不到或者无相关类型声明 问题现象 更新SDK后报错“Cannot find module ‘ohos.application.AbilityStage’ or its corresponding type declarations”&#xff0c;“Cannot find modu…

有什么办法解决SQL注入问题

随着互联网的普及和数字化进程的加速&#xff0c;Web攻击已经成为网络安全领域的一大威胁。Web攻击不仅可能导致个人隐私泄露、财产损失&#xff0c;还可能对企业和国家的安全造成严重影响。下面德迅云安全就分享一种常见的web攻击方式-SQL注入&#xff0c;了解下什么是SQL注入…

五分钟快速了解软件测试是干什么的

软件测试是互联网技术中一门重要的学科&#xff0c;它是软件生命周期中不可或缺的一个环节&#xff0c;担负着把控、监督软件的质量的重任。 目前&#xff0c;软件测试工程师缺口达30万&#xff0c;其中在我国大中型发达城市的人才需求就突破20万&#xff0c;并以每年20%的速度…

使用傅里叶实现100倍的压缩效果(附Python源码)

傅里叶变换&#xff08;Fourier Transform&#xff09;是一种将一个函数&#xff08;在时间或空间域&#xff09;转换为另一个函数&#xff08;在频率域&#xff09;的数学变换方法。它在信号处理、图像处理、通信等领域有广泛应用。 实现过程 将傅里叶系数核心的1%保留&…

Gin框架: HTML模板渲染之配置与语法详解

Gin的HTML模板配置 1 &#xff09;单一目录的配置 配置模板目录&#xff0c;在与main.go同级下, 新建目录&#xff0c;下面二选一&#xff0c;仅作举例, 这里选择 tpls templatestpls 在 tpls 目录下新建 news.html <!-- 最简单的 --> <h1>News Page</h1>&l…

Java实现停车场收费系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 停车位模块2.2 车辆模块2.3 停车收费模块2.4 IC卡模块2.5 IC卡挂失模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 停车场表3.2.2 车辆表3.2.3 停车收费表3.2.4 IC 卡表3.2.5 IC 卡挂失表 四、系统实现五、核心代码…

17-k8s控制器资源-job控制

job控制器&#xff1a;就是一次性任务的pod控制器&#xff0c;pod完成作业后不会重启&#xff0c;其重启策略是&#xff1a;Never 1&#xff0c;job控制器案例描述 启动一个pod&#xff0c;执行完成一个事件&#xff0c;然后pod关闭&#xff1b; 事件&#xff1a;计算π的值&a…