灰度共生矩阵(GLCM,Gray-Level Co-occurrence Matrix)

简介: 概念

概念

由于纹理是由灰度分布在空间位置上反复出现而形成的,因而在图像空间中相隔某距离的两像素之间会存在一定的灰度关系,即图像中灰度的空间相关特性。灰度共生矩阵就是一种通过研究灰度的空间相关特性来描述纹理的常用方法。


灰度共生矩阵是涉及像素距离和角度的矩阵函数,它通过计算图像中一定距离和一定方向的两点灰度之间的相关性,来反映图像在方向、间隔、变化幅度及快慢上的综合信息。


灰度直方图是对图像上单个像素具有某个灰度进行统计的结果,而灰度共生矩阵是对图像上保持某距离的两像素分别具有某灰度的状况进行统计得到的。




GLCM 所代表的含义

灰度共生矩阵元素所表示的含义,以(1,1)点为例,GLCM(1,1)值为1说明左侧原图只有一对灰度为1的像素水平相邻。GLCM(1,2)值为2,是因为原图有两对灰度为1和2的像素水平相邻。


image.png

image.png

灰度共生矩阵的特征


1) 角二阶矩(Angular Second Moment, ASM)

公式:ASM = sum(p(i,j).^2),其中  p(i,j) 表示归一后的灰度共生矩阵

意义:角二阶矩是图像灰度分布均匀程度和纹理粗细的一个度量,当图像纹理绞细致、灰度分布均匀时,能量值较大,反之,较小。


2) 熵(Entropy, ENT)

公式:ENT=sum(p(i,j)*(-log(p(i,j)))

意义:描述图像具有的信息量的度量,表明图像的复杂程度,当复杂程度高时,熵值较大,反之则较小。


3) 反差分矩阵(Inverse Differential Moment, IDM)

公式:IDM=sum(p(i,j)/(1+(i-j)^2))

意义:反映了纹理的清晰程度和规则程度,纹理清晰、规律性较强、易于描述的,值较大;杂乱无章的,难于描述的,值较小。



OpenCV 代码

// 0°灰度共生矩阵
void getGLCM0(Mat& src, Mat& dst, int gray_level)// 0度灰度共生矩阵
{
  CV_Assert(1 == src.channels());
  int height = src.rows;
  int width = src.cols;
  dst.create(gray_level, gray_level, CV_32SC1);
  dst = Scalar::all(0);
  for (int i = 0; i < height; i++)
  {
    int*srcdata = src.ptr<int>(i);
    for (int j = 0; j < width - 1; j++)
    {
      // 同样的像素对,水平相邻
      int rows = srcdata[j];
      int cols = srcdata[j + 1];
      dst.ptr<int>(rows)[cols]++;
    }
  }
}
// 90°灰度共生矩阵
void getGLCM90(Mat& src, Mat& dst, int gray_level)
{
  CV_Assert(1 == src.channels());
  int height = src.rows;
  int width = src.cols;
  dst = Mat(gray_level, gray_level, CV_32SC1, Scalar(0));
  for (int i = 0; i < height - 1; i++)
  {
    int*srcdata = src.ptr<int>(i);
    int*srcdata1 = src.ptr<int>(i + 1);
    for (int j = 0; j < width; j++)
    {
      // 同样的像素对,垂直相邻
      int rows = srcdata[j];
      int cols = srcdata1[j];
      dst.ptr<int>(rows)[cols]++;
    }
  }
}
// 45°灰度共生矩阵
void getGLCM45(Mat& src, Mat& dst, int gray_level)
{
  CV_Assert(1 == src.channels());
  int height = src.rows;
  int width = src.cols;
  dst = Mat(gray_level, gray_level, CV_32SC1, Scalar(0));
  for (int i = 0; i < height - 1; i++)
  {
    int*srcdata = src.ptr<int>(i);
    int*srcdata1 = src.ptr<int>(i + 1);
    for (int j = 0; j < width - 1; j++)
    {
      // 同样的像素对,45°相邻
      int rows = srcdata[j];
      int cols = srcdata1[j + 1];
      dst.ptr<int>(rows)[cols]++;
    }
  }
}
// 135°灰度共生矩阵
void getGLCM135(Mat& src, Mat& dst, int gray_level)
{
  CV_Assert(1 == src.channels());
  int height = src.rows;
  int width = src.cols;
  dst = Mat(gray_level, gray_level, CV_32SC1, Scalar(0));
  for (int i = 0; i < height - 1; i++)
  {
    int*srcdata = src.ptr<int>(i);
    int*srcdata1 = src.ptr<int>(i + 1);
    for (int j = 1; j < width; j++)
    {
      // 同样的像素对,135°相邻
      int rows = srcdata[j];
      int cols = srcdata1[j - 1];
      dst.ptr<int>(rows)[cols]++;
    }
  }
}
// 计算特征值
void featureGLCM(Mat&src, double& Asm, double& Ent, double& Con, double& Idm)
{
  CV_Assert(src.channels() == 1);
  int height = src.rows;
  int width = src.cols;
  int total = 0;
  //求图像所有像素的灰度值的和
  for (int i = 0; i < height; i++)
  {
    int*srcdata = src.ptr<int>(i);
    for (int j = 0; j < width; j++)
    {
      total += srcdata[j];
    }
  }
  //图像每一个像素的的值除以像素总和
  Mat mean;
  mean.create(height, width, CV_64FC1);
  for (int i = 0; i < height; i++)
  {
    int*srcdata = src.ptr<int>(i);
    double*copydata = mean.ptr<double>(i);
    for (int j = 0; j < width; j++)
    {
      copydata[j] = (double)srcdata[j] / (double)total;
    }
  }
  for (int i = 0; i < height; i++)
  {
    double*srcdata = mean.ptr<double>(i);
    for (int j = 0; j < width; j++)
    {
      // 能量
      Asm += srcdata[j] * srcdata[j];
      // 熵(Entropy) 
      if (srcdata[j]>0)
        Ent -= srcdata[j] * log(srcdata[j]);
      // 对比度
      Con += (double)(i - j)*(double)(i - j)*srcdata[j];
      // 逆差矩
      Idm += srcdata[j] / (1 + (double)(i - j)*(double)(i - j));
    }
  }
}

注:本代码以 offset = 1 为例



参考自:

http://baike.baidu.com/link?url=3cuLq2FM6QHWNxgMaswYbKBacMCQ1ptYU6H-T1c8YpcFxmnMEuCtYC9hvCAScZcnxEQDl9a8TXrNntgkoEFliL5tuWapiC3Ovf_vabsEFa1_CouZwLTUByMUhUqLaExrt1KAdEr9ralX-LQKLCj_qq

http://blog.csdn.net/weiyuweizhi/article/details/5724050

http://blog.csdn.net/yanxiaopan/article/details/52356777

http://blog.csdn.net/u014488388/article/details/52877710



目录
相关文章
|
数据可视化 Linux 开发者
Processing有哪些常见的用途或者优势呢
Processing有哪些常见的用途或者优势呢
699 0
|
算法 计算机视觉 Python
OpenCV中Canny边缘检测和霍夫变换的讲解与实战应用(附Python源码)
OpenCV中Canny边缘检测和霍夫变换的讲解与实战应用(附Python源码)
965 0
|
9月前
|
人工智能 Java 程序员
一文彻底搞定C语言的表达式和语句
本文介绍了C语言中的表达式和语句,涵盖算术、关系等表达式及各类语句的用法,帮助初学者理解核心概念。本文介绍C语言表达式(算术、关系等)和语句(表达式、复合、控制、函数、空语句),助你掌握核心概念。
665 0
一文彻底搞定C语言的表达式和语句
|
存储 编解码 人工智能
中科星图——Sentinel-2_MSI_L2A数据集
中科星图——Sentinel-2_MSI_L2A数据集
467 1
|
11月前
|
SQL 弹性计算 安全
阿里云服务器租用价格:包年包月收费标准与最新活动价格参考
本文为大家分享阿里云服务器包年包月收费标准,云服务器最新活动价格,以及后续费挂载数据盘、设置密码和安全组等操作教程,以供参考。
|
缓存 Nacos 数据库
nacos常见问题之日志一直报403如何解决
Nacos是阿里云开源的服务发现和配置管理平台,用于构建动态微服务应用架构;本汇总针对Nacos在实际应用中用户常遇到的问题进行了归纳和解答,旨在帮助开发者和运维人员高效解决使用Nacos时的各类疑难杂症。
|
机器学习/深度学习 自然语言处理 JavaScript
信息论、机器学习的核心概念:熵、KL散度、JS散度和Renyi散度的深度解析及应用
在信息论、机器学习和统计学领域中,KL散度(Kullback-Leibler散度)是量化概率分布差异的关键概念。本文深入探讨了KL散度及其相关概念,包括Jensen-Shannon散度和Renyi散度。KL散度用于衡量两个概率分布之间的差异,而Jensen-Shannon散度则提供了一种对称的度量方式。Renyi散度通过可调参数α,提供了更灵活的散度度量。这些概念不仅在理论研究中至关重要,在实际应用中也广泛用于数据压缩、变分自编码器、强化学习等领域。通过分析电子商务中的数据漂移实例,展示了这些散度指标在捕捉数据分布变化方面的独特优势,为企业提供了数据驱动的决策支持。
1464 2
信息论、机器学习的核心概念:熵、KL散度、JS散度和Renyi散度的深度解析及应用
|
机器学习/深度学习 文字识别 算法
[Halcon&图像] 缺陷检测的一些思路、常规检测算法
[Halcon&图像] 缺陷检测的一些思路、常规检测算法
6381 2
|
运维 监控 容器
一行超长日志引发的 “血案” - Containerd 频繁 OOM 背后的真相
在Sealos公有云中,6月10日北京和广州可用区服务器遭遇突发问题,内存使用率飙升导致服务中断。疑似内存泄露,但升级服务器配置后问题仍重现。排查发现Containerd进程内存占用异常,升级Containerd至1.7.18未解决问题。通过pprof分析和日志检查,发现因`max_container_log_line_size`配置为-1,导致超长日志一次性加载内存。修复该参数为16384后,问题解决。事件强调了默认配置合理性、日志管理、监控和源码理解的重要性。
736 1
一行超长日志引发的 “血案” - Containerd 频繁 OOM 背后的真相